source: mainline/uspace/srv/hid/display/window.c@ 5d86797

ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 5d86797 was 3c54869, checked in by Jiri Svoboda <jiri@…>, 3 years ago

Highlight active window in task bar

  • Property mode set to 100644
File size: 25.4 KB
RevLine 
[c8cf261]1/*
[3c54869]2 * Copyright (c) 2023 Jiri Svoboda
[c8cf261]3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup display
30 * @{
31 */
32/**
[4d8002d]33 * @file Display server window
[c8cf261]34 */
35
[0008c0f]36#include <gfx/bitmap.h>
[c8cf261]37#include <gfx/color.h>
[0008c0f]38#include <gfx/coord.h>
[c8cf261]39#include <gfx/context.h>
40#include <gfx/render.h>
41#include <io/log.h>
[946a666]42#include <io/pixelmap.h>
[9b502dd]43#include <macros.h>
[dbef30f]44#include <memgfx/memgc.h>
[c8cf261]45#include <stdlib.h>
[7cc30e9]46#include <str.h>
[f1f433d]47#include <wndmgt.h>
[b3c185b6]48#include "client.h"
[6af4b4f]49#include "display.h"
[9901f267]50#include "seat.h"
[6af4b4f]51#include "window.h"
[f1f433d]52#include "wmclient.h"
[c8cf261]53
[2ab8ab3]54static void ds_window_invalidate_cb(void *, gfx_rect_t *);
55static void ds_window_update_cb(void *);
[6301a24f]56static void ds_window_get_preview_rect(ds_window_t *, gfx_rect_t *);
[0008c0f]57
[1215db9]58static mem_gc_cb_t ds_window_mem_gc_cb = {
59 .invalidate = ds_window_invalidate_cb,
60 .update = ds_window_update_cb
61};
62
[6af4b4f]63/** Create window.
[c8cf261]64 *
65 * Create graphics context for rendering into a window.
66 *
[8e9781f]67 * @param client Client owning the window
[3434233]68 * @param params Window parameters
[c8cf261]69 * @param rgc Place to store pointer to new GC.
70 *
71 * @return EOK on success or an error code
72 */
[3434233]73errno_t ds_window_create(ds_client_t *client, display_wnd_params_t *params,
74 ds_window_t **rgc)
[c8cf261]75{
[6af4b4f]76 ds_window_t *wnd = NULL;
[9e84d2c]77 ds_seat_t *seat;
[946a666]78 gfx_context_t *dgc;
79 gfx_coord2_t dims;
80 gfx_bitmap_params_t bparams;
81 gfx_bitmap_alloc_t alloc;
[c8cf261]82 errno_t rc;
83
[6af4b4f]84 wnd = calloc(1, sizeof(ds_window_t));
85 if (wnd == NULL) {
[c8cf261]86 rc = ENOMEM;
87 goto error;
88 }
89
[7cc30e9]90 wnd->caption = str_dup(params->caption);
91 if (wnd->caption == NULL) {
92 rc = ENOMEM;
93 goto error;
94 }
95
[b3c185b6]96 ds_client_add_window(client, wnd);
[fd777a2]97 ds_display_add_window(client->display, wnd);
[6af4b4f]98
[a8eed5f]99 gfx_bitmap_params_init(&bparams);
[946a666]100 bparams.rect = params->rect;
101
[84e74ea]102 dgc = ds_display_get_gc(wnd->display);
[946a666]103 if (dgc != NULL) {
104 rc = gfx_bitmap_create(dgc, &bparams, NULL, &wnd->bitmap);
105 if (rc != EOK)
106 goto error;
107
108 rc = gfx_bitmap_get_alloc(wnd->bitmap, &alloc);
109 if (rc != EOK)
110 goto error;
111
[0e6e77f]112 gfx_rect_dims(&params->rect, &dims);
[946a666]113 wnd->pixelmap.width = dims.x;
114 wnd->pixelmap.height = dims.y;
115 wnd->pixelmap.data = alloc.pixels;
[dbef30f]116 } else {
117 /* This is just for unit tests */
118 gfx_rect_dims(&params->rect, &dims);
119 alloc.pitch = dims.x * sizeof(uint32_t);
120 alloc.off0 = 0;
121 alloc.pixels = calloc(1, alloc.pitch * dims.y);
[946a666]122 }
123
[1215db9]124 rc = mem_gc_create(&params->rect, &alloc, &ds_window_mem_gc_cb,
125 (void *)wnd, &wnd->mgc);
[dbef30f]126 if (rc != EOK)
127 goto error;
128
[3434233]129 wnd->rect = params->rect;
[9b502dd]130 wnd->min_size = params->min_size;
[dbef30f]131 wnd->gc = mem_gc_get_ctx(wnd->mgc);
[9242ad9]132 wnd->cursor = wnd->display->cursor[dcurs_arrow];
[9e84d2c]133 wnd->flags = params->flags;
134
[90f1f19]135 if ((params->flags & wndf_setpos) != 0) {
136 /* Specific window position */
137 wnd->dpos = params->pos;
138 } else {
139 /* Automatic window placement */
140 wnd->dpos.x = ((wnd->id - 1) & 1) * 400;
141 wnd->dpos.y = ((wnd->id - 1) & 2) / 2 * 300;
142 }
[9e84d2c]143
[88d828e]144 // TODO Multi-seat: which seat should own the new window?
[9e84d2c]145 seat = ds_display_first_seat(client->display);
146
147 if ((params->flags & wndf_popup) != 0)
148 ds_seat_set_popup(seat, wnd);
149 else
150 ds_seat_set_focus(seat, wnd);
151
[29a5a99]152 if ((params->flags & wndf_avoid) != 0)
153 ds_display_update_max_rect(wnd->display);
154
[9e84d2c]155 (void) ds_display_paint(wnd->display, NULL);
156
[6af4b4f]157 *rgc = wnd;
[c8cf261]158 return EOK;
159error:
[946a666]160 if (wnd != NULL) {
[5877de74]161 ds_client_remove_window(wnd);
162 ds_display_remove_window(wnd);
163 if (wnd->mgc != NULL)
164 mem_gc_delete(wnd->mgc);
[946a666]165 if (wnd->bitmap != NULL)
166 gfx_bitmap_destroy(wnd->bitmap);
[7cc30e9]167 if (wnd->caption != NULL)
168 free(wnd->caption);
[6af4b4f]169 free(wnd);
[946a666]170 }
171
[c8cf261]172 return rc;
173}
174
[0e6e77f]175/** Destroy window.
[c8cf261]176 *
[0e6e77f]177 * @param wnd Window
[c8cf261]178 */
[da412547]179void ds_window_destroy(ds_window_t *wnd)
[c8cf261]180{
[cc90846]181 ds_display_t *disp;
182
183 disp = wnd->display;
184
[b3c185b6]185 ds_client_remove_window(wnd);
[fd777a2]186 ds_display_remove_window(wnd);
[cc90846]187
[29a5a99]188 if ((wnd->flags & wndf_avoid) != 0)
189 ds_display_update_max_rect(disp);
190
[dbef30f]191 mem_gc_delete(wnd->mgc);
192
[946a666]193 if (wnd->bitmap != NULL)
194 gfx_bitmap_destroy(wnd->bitmap);
[c8cf261]195
[7cc30e9]196 free(wnd->caption);
[6af4b4f]197 free(wnd);
[cc90846]198
199 (void) ds_display_paint(disp, NULL);
[c8cf261]200}
201
[1a1271d]202/** Bring window to top.
203 *
204 * @param wnd Window
205 */
[b5c7cee]206void ds_window_bring_to_top(ds_window_t *wnd)
207{
[913add60]208 ds_display_window_to_top(wnd);
[2e0a2e7]209 (void) ds_display_paint(wnd->display, NULL);
[b5c7cee]210}
211
[6af4b4f]212/** Get generic graphic context from window.
[c8cf261]213 *
[6af4b4f]214 * @param wnd Window
[c8cf261]215 * @return Graphic context
216 */
[6af4b4f]217gfx_context_t *ds_window_get_ctx(ds_window_t *wnd)
[c8cf261]218{
[6af4b4f]219 return wnd->gc;
[c8cf261]220}
221
[06176e1]222/** Determine if window is visible.
223 *
224 * @param wnd Window
225 * @return @c true iff window is visible
226 */
227bool ds_window_is_visible(ds_window_t *wnd)
228{
229 return (wnd->flags & wndf_minimized) == 0;
230}
231
[2012fe0]232/** Paint a window using its backing bitmap.
[946a666]233 *
[2012fe0]234 * @param wnd Window to paint
235 * @param rect Display rectangle to paint to
[946a666]236 * @return EOK on success or an error code
237 */
[2012fe0]238errno_t ds_window_paint(ds_window_t *wnd, gfx_rect_t *rect)
[946a666]239{
[2012fe0]240 gfx_rect_t srect;
241 gfx_rect_t *brect;
242 gfx_rect_t crect;
243
[d19d15b]244 log_msg(LOG_DEFAULT, LVL_DEBUG2, "ds_window_paint");
[2012fe0]245
[06176e1]246 /* Skip painting the window if not visible */
247 if (!ds_window_is_visible(wnd))
248 return EOK;
249
[2012fe0]250 if (rect != NULL) {
251 gfx_rect_rtranslate(&wnd->dpos, rect, &srect);
252
253 /* Determine if we have anything to do */
[01c2759]254 gfx_rect_clip(&srect, &wnd->rect, &crect);
[2012fe0]255 if (gfx_rect_is_empty(&crect))
256 return EOK;
257
258 brect = &srect;
259 } else {
260 brect = NULL;
261 }
262
[f5191b4]263 /* This can happen in unit tests */
264 if (wnd->bitmap == NULL)
265 return EOK;
266
[2012fe0]267 return gfx_bitmap_render(wnd->bitmap, brect, &wnd->dpos);
[946a666]268}
269
[6301a24f]270/** Get the preview rectangle for a window.
271 *
272 * Get the preview rectangle if the window is being resized or moved.
273 * If the window is not being resized or moved, return an empty rectangle.
[a40ae0d]274 *
275 * @param wnd Window
[6301a24f]276 * @param rect Place to store preview rectangle
[a40ae0d]277 */
[6301a24f]278static void ds_window_get_preview_rect(ds_window_t *wnd, gfx_rect_t *rect)
279{
280 switch (wnd->state) {
281 case dsw_idle:
282 break;
283 case dsw_moving:
284 gfx_rect_translate(&wnd->preview_pos, &wnd->rect, rect);
285 return;
286 case dsw_resizing:
287 gfx_rect_translate(&wnd->dpos, &wnd->preview_rect, rect);
288 return;
289 }
290
291 rect->p0.x = 0;
292 rect->p0.y = 0;
293 rect->p1.x = 0;
294 rect->p1.y = 0;
295}
296
297/** Paint window preview if the window is being moved or resized.
298 *
299 * If the window is not being resized or moved, take no action and return
300 * success.
301 *
302 * @param wnd Window for which to paint preview
303 * @param rect Clipping rectangle
304 * @return EOK on success or an error code
305 */
306errno_t ds_window_paint_preview(ds_window_t *wnd, gfx_rect_t *rect)
[a40ae0d]307{
[6301a24f]308 errno_t rc;
[1b443cc0]309 gfx_color_t *color;
[6301a24f]310 gfx_rect_t prect;
[a65b0c8]311 gfx_rect_t dr;
312 gfx_rect_t pr;
[6301a24f]313 gfx_context_t *gc;
[1b443cc0]314
[6301a24f]315 /*
316 * Get preview rectangle. If the window is not being resized/moved,
317 * we should get an empty rectangle.
318 */
319 ds_window_get_preview_rect(wnd, &prect);
320 if (gfx_rect_is_empty(&prect)) {
321 /* There is nothing to paint */
322 return EOK;
323 }
[a40ae0d]324
[1b443cc0]325 rc = gfx_color_new_rgb_i16(0xffff, 0xffff, 0xffff, &color);
326 if (rc != EOK)
[6301a24f]327 return rc;
[1b443cc0]328
[84e74ea]329 gc = ds_display_get_gc(wnd->display);
[1b443cc0]330 if (gc != NULL) {
331 gfx_set_color(gc, color);
[a65b0c8]332
333 /*
334 * TODO: Ideally we'd want XOR operation to make the preview
335 * frame visible on any background. If we wanted to get really
336 * fancy, we'd fill it with a pattern
337 */
338
339 pr.p0.x = prect.p0.x;
340 pr.p0.y = prect.p0.y;
341 pr.p1.x = prect.p1.x;
342 pr.p1.y = prect.p0.y + 1;
343 gfx_rect_clip(&pr, rect, &dr);
344 gfx_fill_rect(gc, &dr);
345
346 pr.p0.x = prect.p0.x;
347 pr.p0.y = prect.p1.y - 1;
348 pr.p1.x = prect.p1.x;
349 pr.p1.y = prect.p1.y;
350 gfx_rect_clip(&pr, rect, &dr);
351 gfx_fill_rect(gc, &dr);
352
353 pr.p0.x = prect.p0.x;
354 pr.p0.y = prect.p0.y;
355 pr.p1.x = prect.p0.x + 1;
356 pr.p1.y = prect.p1.y;
357 gfx_rect_clip(&pr, rect, &dr);
358 gfx_fill_rect(gc, &dr);
359
360 pr.p0.x = prect.p1.x - 1;
361 pr.p0.y = prect.p0.y;
362 pr.p1.x = prect.p1.x;
363 pr.p1.y = prect.p1.y;
364 gfx_rect_clip(&pr, rect, &dr);
365 gfx_fill_rect(gc, &dr);
366
[1b443cc0]367 }
368
369 gfx_color_delete(color);
[6301a24f]370 return EOK;
371}
372
373/** Repaint window preview when resizing or moving.
374 *
375 * Repaint the window preview wich was previously at rectangle @a old_rect.
376 * The current preview rectangle is determined from window state. If
377 * the window did not previously have a preview, @a old_rect should point
378 * to an empty rectangle or be NULL. When window has finished
379 * moving or resizing, the preview will be cleared.
380 *
381 * @param wnd Window for which to paint preview
382 * @param rect Clipping rectangle
383 * @return EOK on success or an error code
384 */
385static errno_t ds_window_repaint_preview(ds_window_t *wnd, gfx_rect_t *old_rect)
386{
387 errno_t rc;
388 gfx_rect_t prect;
389 gfx_rect_t envelope;
390 bool oldr;
391 bool newr;
392
[d19d15b]393 log_msg(LOG_DEFAULT, LVL_DEBUG2, "ds_window_repaint_preview");
[6301a24f]394
395 /*
396 * Get current preview rectangle. If the window is not being resized/moved,
397 * we should get an empty rectangle.
398 */
399 ds_window_get_preview_rect(wnd, &prect);
400
401 oldr = (old_rect != NULL) && !gfx_rect_is_empty(old_rect);
402 newr = !gfx_rect_is_empty(&prect);
403
404 if (oldr && newr && gfx_rect_is_incident(old_rect, &prect)) {
405 /*
406 * As an optimization, repaint both rectangles in a single
407 * operation.
408 */
409
410 gfx_rect_envelope(old_rect, &prect, &envelope);
411
412 rc = ds_display_paint(wnd->display, &envelope);
413 if (rc != EOK)
414 return rc;
415 } else {
416 /* Repaint each rectangle separately */
417 if (oldr) {
418 rc = ds_display_paint(wnd->display, old_rect);
419 if (rc != EOK)
420 return rc;
421 }
422
423 if (newr) {
424 rc = ds_display_paint(wnd->display, &prect);
425 if (rc != EOK)
426 return rc;
427 }
428 }
429
430 return EOK;
431}
432
433/** Start moving a window by mouse drag.
434 *
435 * @param wnd Window
436 * @param pos Position where mouse button was pressed
437 */
438static void ds_window_start_move(ds_window_t *wnd, gfx_coord2_t *pos)
439{
440 log_msg(LOG_DEFAULT, LVL_DEBUG, "ds_window_start_move (%d, %d)",
441 (int) pos->x, (int) pos->y);
442
443 if (wnd->state != dsw_idle)
444 return;
445
446 wnd->orig_pos = *pos;
447 wnd->state = dsw_moving;
448 wnd->preview_pos = wnd->dpos;
449
450 (void) ds_window_repaint_preview(wnd, NULL);
[a40ae0d]451}
452
453/** Finish moving a window by mouse drag.
454 *
455 * @param wnd Window
[76a02db]456 * @param pos Position where mouse button was released
[a40ae0d]457 */
[76a02db]458static void ds_window_finish_move(ds_window_t *wnd, gfx_coord2_t *pos)
[a40ae0d]459{
460 gfx_coord2_t dmove;
461 gfx_coord2_t nwpos;
[6301a24f]462 gfx_rect_t old_rect;
[a40ae0d]463
464 log_msg(LOG_DEFAULT, LVL_DEBUG, "ds_window_finish_move (%d, %d)",
[76a02db]465 (int) pos->x, (int) pos->y);
[a40ae0d]466
[5f483be]467 assert(wnd->state == dsw_moving);
[a2e104e]468
[76a02db]469 gfx_coord2_subtract(pos, &wnd->orig_pos, &dmove);
[a40ae0d]470 gfx_coord2_add(&wnd->dpos, &dmove, &nwpos);
[6301a24f]471
472 ds_window_get_preview_rect(wnd, &old_rect);
473
[a40ae0d]474 wnd->dpos = nwpos;
475 wnd->state = dsw_idle;
[946a666]476
[2012fe0]477 (void) ds_display_paint(wnd->display, NULL);
[a40ae0d]478}
479
480/** Update window position when moving by mouse drag.
481 *
482 * @param wnd Window
[76a02db]483 * @param pos Current mouse position
[a40ae0d]484 */
[76a02db]485static void ds_window_update_move(ds_window_t *wnd, gfx_coord2_t *pos)
[a40ae0d]486{
487 gfx_coord2_t dmove;
488 gfx_coord2_t nwpos;
[6301a24f]489 gfx_rect_t old_rect;
[a40ae0d]490
[6e91475]491 log_msg(LOG_DEFAULT, LVL_DEBUG2, "ds_window_update_move (%d, %d)",
[76a02db]492 (int) pos->x, (int) pos->y);
[a40ae0d]493
[5f483be]494 assert(wnd->state == dsw_moving);
[a2e104e]495
[76a02db]496 gfx_coord2_subtract(pos, &wnd->orig_pos, &dmove);
[a40ae0d]497 gfx_coord2_add(&wnd->dpos, &dmove, &nwpos);
[c79545e]498
[6301a24f]499 ds_window_get_preview_rect(wnd, &old_rect);
500 wnd->preview_pos = nwpos;
[a40ae0d]501
[6301a24f]502 (void) ds_window_repaint_preview(wnd, &old_rect);
[a40ae0d]503}
504
[76a02db]505/** Start resizing a window by mouse drag.
506 *
507 * @param wnd Window
508 * @param rsztype Resize type (which part of window is being dragged)
509 * @param pos Position where mouse button was pressed
510 */
511static void ds_window_start_resize(ds_window_t *wnd,
512 display_wnd_rsztype_t rsztype, gfx_coord2_t *pos)
513{
[9901f267]514 ds_seat_t *seat;
515 display_stock_cursor_t ctype;
516
[76a02db]517 log_msg(LOG_DEFAULT, LVL_DEBUG, "ds_window_start_resize (%d, %d)",
518 (int) pos->x, (int) pos->y);
519
520 if (wnd->state != dsw_idle)
521 return;
522
523 wnd->orig_pos = *pos;
524 wnd->state = dsw_resizing;
525 wnd->rsztype = rsztype;
[71eff34]526 wnd->preview_rect = wnd->rect;
[9901f267]527
[88d828e]528 // TODO Multi-seat: need client to tell us which seat started the resize!
[9901f267]529 seat = ds_display_first_seat(wnd->display);
530 ctype = display_cursor_from_wrsz(rsztype);
531 ds_seat_set_wm_cursor(seat, wnd->display->cursor[ctype]);
[6301a24f]532
533 (void) ds_window_repaint_preview(wnd, NULL);
[76a02db]534}
535
[e022819]536/** Finish resizing a window by mouse drag.
537 *
538 * @param wnd Window
[76a02db]539 * @param pos Position where mouse button was released
[e022819]540 */
[76a02db]541static void ds_window_finish_resize(ds_window_t *wnd, gfx_coord2_t *pos)
[e022819]542{
543 gfx_coord2_t dresize;
544 gfx_rect_t nrect;
[9901f267]545 ds_seat_t *seat;
[e022819]546
547 log_msg(LOG_DEFAULT, LVL_DEBUG, "ds_window_finish_resize (%d, %d)",
[76a02db]548 (int) pos->x, (int) pos->y);
[e022819]549
[5f483be]550 assert(wnd->state == dsw_resizing);
[76a02db]551 gfx_coord2_subtract(pos, &wnd->orig_pos, &dresize);
[e022819]552
553 /* Compute new rectangle */
554 ds_window_calc_resize(wnd, &dresize, &nrect);
555
556 wnd->state = dsw_idle;
557 ds_client_post_resize_event(wnd->client, wnd, &nrect);
[9901f267]558
[88d828e]559 // TODO Multi-seat: Need to know which seat started the resize!
[9901f267]560 seat = ds_display_first_seat(wnd->display);
561 ds_seat_set_wm_cursor(seat, NULL);
[6301a24f]562
563 (void) ds_display_paint(wnd->display, NULL);
[e022819]564}
565
566/** Update window position when resizing by mouse drag.
567 *
568 * @param wnd Window
[76a02db]569 * @param pos Current mouse position
[e022819]570 */
[76a02db]571static void ds_window_update_resize(ds_window_t *wnd, gfx_coord2_t *pos)
[e022819]572{
573 gfx_coord2_t dresize;
574 gfx_rect_t nrect;
[6301a24f]575 gfx_rect_t old_rect;
[e022819]576
[d19d15b]577 log_msg(LOG_DEFAULT, LVL_DEBUG2, "ds_window_update_resize (%d, %d)",
[76a02db]578 (int) pos->x, (int) pos->y);
[e022819]579
[5f483be]580 assert(wnd->state == dsw_resizing);
[e022819]581
[76a02db]582 gfx_coord2_subtract(pos, &wnd->orig_pos, &dresize);
[e022819]583 ds_window_calc_resize(wnd, &dresize, &nrect);
584
[6301a24f]585 ds_window_get_preview_rect(wnd, &old_rect);
586 wnd->preview_rect = nrect;
587 (void) ds_window_repaint_preview(wnd, &old_rect);
[e022819]588}
589
[338d0935]590/** Post keyboard event to window.
591 *
592 * @param wnd Window
593 * @param event Event
594 *
595 * @return EOK on success or an error code
596 */
597errno_t ds_window_post_kbd_event(ds_window_t *wnd, kbd_event_t *event)
598{
599 bool alt_or_shift;
600
601 alt_or_shift = event->mods & (KM_SHIFT | KM_ALT);
602
603 if (event->type == KEY_PRESS && alt_or_shift && event->key == KC_F4) {
604 /* On Alt-F4 or Shift-F4 send close event to the window */
605 ds_client_post_close_event(wnd->client, wnd);
606 return EOK;
607 }
608
609 return ds_client_post_kbd_event(wnd->client, wnd, event);
610}
611
[a40ae0d]612/** Post position event to window.
613 *
614 * @param wnd Window
615 * @param event Position event
[35cffea]616 *
617 * @return EOK on success or an error code
[a40ae0d]618 */
619errno_t ds_window_post_pos_event(ds_window_t *wnd, pos_event_t *event)
620{
[f7fb2b21]621 pos_event_t tevent;
[a2e104e]622 gfx_coord2_t pos;
623 gfx_rect_t drect;
624 bool inside;
[f7fb2b21]625
[d19d15b]626 log_msg(LOG_DEFAULT, LVL_DEBUG2,
[78445be8]627 "ds_window_post_pos_event type=%d pos=%d,%d", event->type,
[a40ae0d]628 (int) event->hpos, (int) event->vpos);
629
[a2e104e]630 pos.x = event->hpos;
631 pos.y = event->vpos;
632 gfx_rect_translate(&wnd->dpos, &wnd->rect, &drect);
633 inside = gfx_pix_inside_rect(&pos, &drect);
[a40ae0d]634
[35cffea]635 if (event->type == POS_PRESS && event->btn_num == 2 && inside &&
636 (wnd->flags & wndf_maximized) == 0) {
[76a02db]637 ds_window_start_move(wnd, &pos);
[5f483be]638 return EOK;
639 }
[a40ae0d]640
[e022819]641 if (event->type == POS_RELEASE) {
[5f483be]642 if (wnd->state == dsw_moving) {
643 ds_window_finish_move(wnd, &pos);
644 return EOK;
645 }
646
647 if (wnd->state == dsw_resizing) {
648 ds_window_finish_resize(wnd, &pos);
649 return EOK;
650 }
[e022819]651 }
[a2e104e]652
[e022819]653 if (event->type == POS_UPDATE) {
[5f483be]654 if (wnd->state == dsw_moving) {
655 ds_window_update_move(wnd, &pos);
656 return EOK;
657 }
658
659 if (wnd->state == dsw_resizing) {
660 ds_window_update_resize(wnd, &pos);
661 return EOK;
662 }
[e022819]663 }
[a40ae0d]664
[f7fb2b21]665 /* Transform event coordinates to window-local */
666 tevent = *event;
667 tevent.hpos -= wnd->dpos.x;
668 tevent.vpos -= wnd->dpos.y;
669
670 return ds_client_post_pos_event(wnd->client, wnd, &tevent);
[a40ae0d]671}
672
[b0a94854]673/** Post focus event to window.
674 *
675 * @param wnd Window
[35cffea]676 * @return EOK on success or an error code
[b0a94854]677 */
678errno_t ds_window_post_focus_event(ds_window_t *wnd)
679{
[3c54869]680 errno_t rc;
681 ds_wmclient_t *wmclient;
682
[78445be8]683 log_msg(LOG_DEFAULT, LVL_DEBUG, "ds_window_post_focus_event");
[b0a94854]684
[3c54869]685 rc = ds_client_post_focus_event(wnd->client, wnd);
686 if (rc != EOK)
687 return rc;
688
689 /* Increase focus counter */
690 ++wnd->nfocus;
691
692 /* Notify window managers about window information change */
693 wmclient = ds_display_first_wmclient(wnd->display);
694 while (wmclient != NULL) {
695 ds_wmclient_post_wnd_changed_event(wmclient, wnd->id);
696 wmclient = ds_display_next_wmclient(wmclient);
697 }
698
699 return EOK;
[b0a94854]700}
701
702/** Post unfocus event to window.
703 *
704 * @param wnd Window
[35cffea]705 * @return EOK on success or an error code
[b0a94854]706 */
707errno_t ds_window_post_unfocus_event(ds_window_t *wnd)
708{
[3c54869]709 errno_t rc;
710 ds_wmclient_t *wmclient;
711
[78445be8]712 log_msg(LOG_DEFAULT, LVL_DEBUG, "ds_window_post_unfocus_event");
[b0a94854]713
[3c54869]714 rc = ds_client_post_unfocus_event(wnd->client, wnd);
715 if (rc != EOK)
716 return rc;
717
718 /* Decrease focus counter */
719 --wnd->nfocus;
720
721 /* Notify window managers about window information change */
722 wmclient = ds_display_first_wmclient(wnd->display);
723 while (wmclient != NULL) {
724 ds_wmclient_post_wnd_changed_event(wmclient, wnd->id);
725 wmclient = ds_display_next_wmclient(wmclient);
726 }
727
728 return EOK;
[b0a94854]729}
730
[e022819]731/** Start moving a window, detected by client.
732 *
733 * @param wnd Window
734 * @param pos Position where the pointer was when the move started
735 * relative to the window
736 * @param event Button press event
737 */
738void ds_window_move_req(ds_window_t *wnd, gfx_coord2_t *pos)
739{
[76a02db]740 gfx_coord2_t orig_pos;
741
[e022819]742 log_msg(LOG_DEFAULT, LVL_DEBUG, "ds_window_move_req (%d, %d)",
743 (int) pos->x, (int) pos->y);
744
[76a02db]745 gfx_coord2_add(&wnd->dpos, pos, &orig_pos);
746 ds_window_start_move(wnd, &orig_pos);
[e022819]747}
748
[0680854]749/** Move window.
750 *
751 * @param wnd Window
752 */
753void ds_window_move(ds_window_t *wnd, gfx_coord2_t *dpos)
754{
755 wnd->dpos = *dpos;
756 (void) ds_display_paint(wnd->display, NULL);
757}
758
[c9927c66]759/** Get window position.
760 *
761 * @param wnd Window
762 */
763void ds_window_get_pos(ds_window_t *wnd, gfx_coord2_t *dpos)
764{
765 *dpos = wnd->dpos;
766}
767
[35cffea]768/** Get maximized window rectangle.
769 *
770 * @param wnd Window
771 */
772void ds_window_get_max_rect(ds_window_t *wnd, gfx_rect_t *rect)
773{
[29a5a99]774 *rect = wnd->display->max_rect;
[35cffea]775}
776
[e022819]777/** Start resizing a window, detected by client.
778 *
779 * @param wnd Window
780 * @param rsztype Resize type (which part of window is being dragged)
781 * @param pos Position where the pointer was when the resize started
782 * relative to the window
783 * @param event Button press event
784 */
785void ds_window_resize_req(ds_window_t *wnd, display_wnd_rsztype_t rsztype,
786 gfx_coord2_t *pos)
787{
[76a02db]788 gfx_coord2_t orig_pos;
789
[195b7b3]790 log_msg(LOG_DEFAULT, LVL_DEBUG, "ds_window_resize_req (%d, %d, %d)",
[e022819]791 (int) rsztype, (int) pos->x, (int) pos->y);
792
[76a02db]793 gfx_coord2_add(&wnd->dpos, pos, &orig_pos);
794 ds_window_start_resize(wnd, rsztype, &orig_pos);
[e022819]795}
796
[0680854]797/** Resize window.
798 *
799 * @param wnd Window
[35cffea]800 * @return EOK on success or an error code
[0680854]801 */
802errno_t ds_window_resize(ds_window_t *wnd, gfx_coord2_t *offs,
803 gfx_rect_t *nrect)
804{
805 gfx_context_t *dgc;
806 gfx_bitmap_params_t bparams;
807 gfx_bitmap_t *nbitmap;
808 pixelmap_t npixelmap;
809 gfx_coord2_t dims;
810 gfx_bitmap_alloc_t alloc;
811 gfx_coord2_t ndpos;
812 errno_t rc;
813
[84e74ea]814 dgc = ds_display_get_gc(wnd->display);
[0680854]815 if (dgc != NULL) {
816 gfx_bitmap_params_init(&bparams);
817 bparams.rect = *nrect;
818
819 rc = gfx_bitmap_create(dgc, &bparams, NULL, &nbitmap);
820 if (rc != EOK)
821 return ENOMEM;
822
823 rc = gfx_bitmap_get_alloc(nbitmap, &alloc);
824 if (rc != EOK) {
825 gfx_bitmap_destroy(nbitmap);
826 return ENOMEM;
827 }
828
829 gfx_rect_dims(nrect, &dims);
830 npixelmap.width = dims.x;
831 npixelmap.height = dims.y;
832 npixelmap.data = alloc.pixels;
833
834 /* TODO: Transfer contents within overlap */
835
836 if (wnd->bitmap != NULL)
837 gfx_bitmap_destroy(wnd->bitmap);
838
839 wnd->bitmap = nbitmap;
840 wnd->pixelmap = npixelmap;
[dbef30f]841
842 /* Point memory GC to the new bitmap */
843 mem_gc_retarget(wnd->mgc, nrect, &alloc);
[0680854]844 }
845
846 gfx_coord2_add(&wnd->dpos, offs, &ndpos);
847
848 wnd->dpos = ndpos;
849 wnd->rect = *nrect;
850
[29a5a99]851 if ((wnd->flags & wndf_avoid) != 0)
852 ds_display_update_max_rect(wnd->display);
853
[0680854]854 (void) ds_display_paint(wnd->display, NULL);
855 return EOK;
856}
857
[06176e1]858/** Minimize window.
859 *
860 * @param wnd Window
861 * @return EOK on success or an error code
862 */
863errno_t ds_window_minimize(ds_window_t *wnd)
864{
865 /* If already minimized, do nothing and return success. */
866 if ((wnd->flags & wndf_minimized) != 0)
867 return EOK;
868
869 wnd->flags |= wndf_minimized;
870 (void) ds_display_paint(wnd->display, NULL);
871 return EOK;
872}
873
874/** Unminimize window.
875 *
876 * @param wnd Window
877 * @return EOK on success or an error code
878 */
879errno_t ds_window_unminimize(ds_window_t *wnd)
880{
881 /* If not minimized, do nothing and return success. */
882 if ((wnd->flags & wndf_minimized) == 0)
883 return EOK;
884
885 wnd->flags &= ~wndf_minimized;
886 (void) ds_display_paint(wnd->display, NULL);
887 return EOK;
888}
889
[35cffea]890/** Maximize window.
891 *
892 * @param wnd Window
893 * @return EOK on success or an error code
894 */
895errno_t ds_window_maximize(ds_window_t *wnd)
896{
897 gfx_coord2_t old_dpos;
898 gfx_rect_t old_rect;
899 gfx_coord2_t offs;
900 gfx_rect_t max_rect;
901 gfx_rect_t nrect;
902 errno_t rc;
903
904 /* If already maximized, do nothing and return success. */
905 if ((wnd->flags & wndf_maximized) != 0)
906 return EOK;
907
908 /* Remember the old window rectangle and display position */
909 old_rect = wnd->rect;
910 old_dpos = wnd->dpos;
911
912 ds_window_get_max_rect(wnd, &max_rect);
913
914 /* Keep window contents on the same position on the screen */
915 offs.x = max_rect.p0.x - wnd->dpos.x;
916 offs.y = max_rect.p0.y - wnd->dpos.y;
917
918 /* Maximized window's coordinates will start at 0,0 */
919 gfx_rect_rtranslate(&max_rect.p0, &max_rect, &nrect);
920
921 rc = ds_window_resize(wnd, &offs, &nrect);
922 if (rc != EOK)
923 return rc;
924
925 /* Set window flags, remember normal rectangle */
926 wnd->flags |= wndf_maximized;
927 wnd->normal_rect = old_rect;
928 wnd->normal_dpos = old_dpos;
929
930 return EOK;
931}
932
933/** Unmaximize window.
934 *
935 * @param wnd Window
936 * @return EOK on success or an error code
937 */
938errno_t ds_window_unmaximize(ds_window_t *wnd)
939{
940 gfx_coord2_t offs;
941 errno_t rc;
942
943 /* If not maximized, do nothing and return success. */
944 if ((wnd->flags & wndf_maximized) == 0)
945 return EOK;
946
947 /* Keep window contents on the same position on the screen */
948 offs.x = wnd->normal_dpos.x - wnd->dpos.x;
949 offs.y = wnd->normal_dpos.y - wnd->dpos.y;
950
951 rc = ds_window_resize(wnd, &offs, &wnd->normal_rect);
952 if (rc != EOK)
953 return rc;
954
[ad698f4]955 /* Clear maximized flag */
[35cffea]956 wnd->flags &= ~wndf_maximized;
957
958 return EOK;
959}
960
[e022819]961/** Compute new window rectangle after resize operation.
962 *
963 * @param wnd Window which is being resized (in dsw_resizing state and thus
964 * has rsztype set)
965 * @param dresize Amount by which to resize
966 * @param nrect Place to store new rectangle
967 */
968void ds_window_calc_resize(ds_window_t *wnd, gfx_coord2_t *dresize,
969 gfx_rect_t *nrect)
970{
[9b502dd]971 if ((wnd->rsztype & display_wr_top) != 0) {
972 nrect->p0.y = min(wnd->rect.p0.y + dresize->y,
973 wnd->rect.p1.y - wnd->min_size.y);
974 } else {
975 nrect->p0.y = wnd->rect.p0.y;
976 }
977
978 if ((wnd->rsztype & display_wr_left) != 0) {
979 nrect->p0.x = min(wnd->rect.p0.x + dresize->x,
980 wnd->rect.p1.x - wnd->min_size.x);
981 } else {
982 nrect->p0.x = wnd->rect.p0.x;
983 }
984
985 if ((wnd->rsztype & display_wr_bottom) != 0) {
986 nrect->p1.y = max(wnd->rect.p1.y + dresize->y,
987 wnd->rect.p0.y + wnd->min_size.y);
988 } else {
989 nrect->p1.y = wnd->rect.p1.y;
990 }
991
992 if ((wnd->rsztype & display_wr_right) != 0) {
993 nrect->p1.x = max(wnd->rect.p1.x + dresize->x,
994 wnd->rect.p0.x + wnd->min_size.x);
995 } else {
996 nrect->p1.x = wnd->rect.p1.x;
997 }
[e022819]998}
999
[9242ad9]1000/** Set window cursor.
1001 *
1002 * @param wnd Window
[7cc30e9]1003 * @param cursor New cursor
[9242ad9]1004 * @return EOK on success, EINVAL if @a cursor is invalid
1005 */
1006errno_t ds_window_set_cursor(ds_window_t *wnd, display_stock_cursor_t cursor)
1007{
1008 if (cursor >= dcurs_arrow &&
1009 cursor < (display_stock_cursor_t) dcurs_limit) {
1010 wnd->cursor = wnd->display->cursor[cursor];
1011 return EOK;
1012 } else {
1013 return EINVAL;
1014 }
1015}
1016
[7cc30e9]1017/** Set window caption.
1018 *
1019 * @param wnd Window
1020 * @param caption New caption
1021 *
1022 * @return EOK on success, EINVAL if @a cursor is invalid
1023 */
1024errno_t ds_window_set_caption(ds_window_t *wnd, const char *caption)
1025{
1026 char *dcaption;
[f1f433d]1027 ds_wmclient_t *wmclient;
[7cc30e9]1028
1029 dcaption = str_dup(caption);
1030 if (dcaption == NULL)
1031 return ENOMEM;
1032
1033 free(wnd->caption);
1034 wnd->caption = dcaption;
1035
[f1f433d]1036 /* Notify window managers about window information change */
1037 wmclient = ds_display_first_wmclient(wnd->display);
1038 while (wmclient != NULL) {
1039 ds_wmclient_post_wnd_changed_event(wmclient, wnd->id);
1040 wmclient = ds_display_next_wmclient(wmclient);
1041 }
1042
[7cc30e9]1043 return EOK;
1044}
1045
[2ab8ab3]1046/** Window memory GC invalidate callback.
[dbef30f]1047 *
[2ab8ab3]1048 * This is called by the window's memory GC when a rectangle is modified.
[dbef30f]1049 */
[2ab8ab3]1050static void ds_window_invalidate_cb(void *arg, gfx_rect_t *rect)
[dbef30f]1051{
1052 ds_window_t *wnd = (ds_window_t *)arg;
1053 gfx_rect_t drect;
1054
1055 /* Repaint the corresponding part of the display */
[d74a2b8]1056
[dbef30f]1057 gfx_rect_translate(&wnd->dpos, rect, &drect);
[d74a2b8]1058 ds_display_lock(wnd->display);
[dbef30f]1059 (void) ds_display_paint(wnd->display, &drect);
[d74a2b8]1060 ds_display_unlock(wnd->display);
[dbef30f]1061}
1062
[2ab8ab3]1063/** Window memory GC update callback.
1064 *
1065 * This is called by the window's memory GC when it is to be updated.
1066 */
1067static void ds_window_update_cb(void *arg)
1068{
1069 ds_window_t *wnd = (ds_window_t *)arg;
1070
1071 (void) wnd;
1072}
1073
[c8cf261]1074/** @}
1075 */
Note: See TracBrowser for help on using the repository browser.