source: mainline/uspace/lib/ui/src/window.c@ 453f9645

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

Prevent use after free when destroying window

Cannot access window after return from event handler (where it could
have been destroyed), cannot deliver event to window if it was
already claimed by window decoration.

  • Property mode set to 100644
File size: 31.4 KB
Line 
1/*
2 * Copyright (c) 2022 Jiri Svoboda
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 libui
30 * @{
31 */
32/**
33 * @file Window
34 */
35
36#include <congfx/console.h>
37#include <display.h>
38#include <errno.h>
39#include <gfx/bitmap.h>
40#include <gfx/context.h>
41#include <gfx/cursor.h>
42#include <gfx/render.h>
43#include <io/kbd_event.h>
44#include <io/pos_event.h>
45#include <mem.h>
46#include <memgfx/memgc.h>
47#include <stdlib.h>
48#include <ui/control.h>
49#include <ui/resource.h>
50#include <ui/ui.h>
51#include <ui/wdecor.h>
52#include <ui/window.h>
53#include "../private/control.h"
54#include "../private/dummygc.h"
55#include "../private/resource.h"
56#include "../private/ui.h"
57#include "../private/wdecor.h"
58#include "../private/window.h"
59
60static void dwnd_close_event(void *);
61static void dwnd_focus_event(void *);
62static void dwnd_kbd_event(void *, kbd_event_t *);
63static void dwnd_pos_event(void *, pos_event_t *);
64static void dwnd_resize_event(void *, gfx_rect_t *);
65static void dwnd_unfocus_event(void *);
66
67static display_wnd_cb_t dwnd_cb = {
68 .close_event = dwnd_close_event,
69 .focus_event = dwnd_focus_event,
70 .kbd_event = dwnd_kbd_event,
71 .pos_event = dwnd_pos_event,
72 .resize_event = dwnd_resize_event,
73 .unfocus_event = dwnd_unfocus_event
74};
75
76static void wd_maximize(ui_wdecor_t *, void *);
77static void wd_unmaximize(ui_wdecor_t *, void *);
78static void wd_close(ui_wdecor_t *, void *);
79static void wd_move(ui_wdecor_t *, void *, gfx_coord2_t *);
80static void wd_resize(ui_wdecor_t *, void *, ui_wdecor_rsztype_t,
81 gfx_coord2_t *);
82static void wd_set_cursor(ui_wdecor_t *, void *, ui_stock_cursor_t);
83
84static ui_wdecor_cb_t wdecor_cb = {
85 .maximize = wd_maximize,
86 .unmaximize = wd_unmaximize,
87 .close = wd_close,
88 .move = wd_move,
89 .resize = wd_resize,
90 .set_cursor = wd_set_cursor
91};
92
93static void ui_window_invalidate(void *, gfx_rect_t *);
94static void ui_window_update(void *);
95static errno_t ui_window_cursor_get_pos(void *, gfx_coord2_t *);
96static errno_t ui_window_cursor_set_pos(void *, gfx_coord2_t *);
97static errno_t ui_window_cursor_set_visible(void *, bool);
98
99/** Window memory GC callbacks */
100static mem_gc_cb_t ui_window_mem_gc_cb = {
101 .invalidate = ui_window_invalidate,
102 .update = ui_window_update,
103 .cursor_get_pos = ui_window_cursor_get_pos,
104 .cursor_set_pos = ui_window_cursor_set_pos,
105 .cursor_set_visible = ui_window_cursor_set_visible
106};
107
108static void ui_window_app_invalidate(void *, gfx_rect_t *);
109static void ui_window_app_update(void *);
110
111/** Application area memory GC callbacks */
112static mem_gc_cb_t ui_window_app_mem_gc_cb = {
113 .invalidate = ui_window_app_invalidate,
114 .update = ui_window_app_update
115};
116
117static void ui_window_expose_cb(void *);
118
119/** Initialize window parameters structure.
120 *
121 * Window parameters structure must always be initialized using this function
122 * first. By default, the window will be decorated. To get a non-decorated
123 * window, one needs to clear ui_wds_decorated
124 * (e.g. params->style &= ~ui_wds_decorated).
125 *
126 * @param params Window parameters structure
127 */
128void ui_wnd_params_init(ui_wnd_params_t *params)
129{
130 memset(params, 0, sizeof(ui_wnd_params_t));
131
132 /* Make window decorated by default. */
133 params->style = ui_wds_decorated;
134}
135
136/** Compute where window should be placed on the screen.
137 *
138 * This only applies to windows that do not use default placement or
139 * if we are running in full-screen mode.
140 *
141 * @param window Window
142 * @param drect Display rectangle
143 * @param params Window parameters
144 * @param pos Place to store position of top-left corner
145 */
146static void ui_window_place(ui_window_t *window, gfx_rect_t *drect,
147 ui_wnd_params_t *params, gfx_coord2_t *pos)
148{
149 gfx_coord2_t dims;
150
151 assert(params->placement != ui_wnd_place_default ||
152 ui_is_fullscreen(window->ui));
153
154 pos->x = 0;
155 pos->y = 0;
156
157 switch (params->placement) {
158 case ui_wnd_place_default:
159 assert(ui_is_fullscreen(window->ui));
160 /* Center window */
161 gfx_rect_dims(&params->rect, &dims);
162 pos->x = (drect->p0.x + drect->p1.x) / 2 - dims.x / 2;
163 pos->y = (drect->p0.y + drect->p1.y) / 2 - dims.y / 2;
164 break;
165 case ui_wnd_place_top_left:
166 case ui_wnd_place_full_screen:
167 pos->x = drect->p0.x - params->rect.p0.x;
168 pos->y = drect->p0.y - params->rect.p0.y;
169 break;
170 case ui_wnd_place_top_right:
171 pos->x = drect->p1.x - params->rect.p1.x;
172 pos->y = drect->p0.y - params->rect.p0.y;
173 break;
174 case ui_wnd_place_bottom_left:
175 pos->x = drect->p0.x - params->rect.p0.x;
176 pos->y = drect->p1.y - params->rect.p1.y;
177 break;
178 case ui_wnd_place_bottom_right:
179 pos->x = drect->p1.x - params->rect.p1.x;
180 pos->y = drect->p1.y - params->rect.p1.y;
181 break;
182 case ui_wnd_place_popup:
183 /* Place popup window below parent rectangle */
184 pos->x = params->prect.p0.x;
185 pos->y = params->prect.p1.y;
186 break;
187 }
188}
189
190/** Create new window.
191 *
192 * @param ui User interface
193 * @param params Window parameters
194 * @param rwindow Place to store pointer to new window
195 * @return EOK on success or an error code
196 */
197errno_t ui_window_create(ui_t *ui, ui_wnd_params_t *params,
198 ui_window_t **rwindow)
199{
200 ui_window_t *window;
201 display_info_t info;
202 gfx_coord2_t scr_dims;
203 display_wnd_params_t dparams;
204 gfx_context_t *gc = NULL;
205 ui_resource_t *res = NULL;
206 ui_wdecor_t *wdecor = NULL;
207 dummy_gc_t *dgc = NULL;
208 gfx_bitmap_params_t bparams;
209 gfx_bitmap_alloc_t alloc;
210 gfx_bitmap_t *bmp = NULL;
211 gfx_coord2_t off;
212 mem_gc_t *memgc = NULL;
213 xlate_gc_t *xgc = NULL;
214 errno_t rc;
215
216 window = calloc(1, sizeof(ui_window_t));
217 if (window == NULL)
218 return ENOMEM;
219
220 window->ui = ui;
221
222 display_wnd_params_init(&dparams);
223 dparams.rect = params->rect;
224 /* Only allow making the window larger */
225 gfx_rect_dims(&params->rect, &dparams.min_size);
226
227 if ((params->flags & ui_wndf_popup) != 0)
228 dparams.flags |= wndf_popup;
229
230 if (ui->display != NULL) {
231 if (params->placement != ui_wnd_place_default) {
232 rc = display_get_info(ui->display, &info);
233 if (rc != EOK)
234 goto error;
235 }
236
237 if (params->placement == ui_wnd_place_full_screen) {
238 /* Make window the size of the screen */
239 gfx_rect_dims(&info.rect, &scr_dims);
240 gfx_coord2_add(&dparams.rect.p0, &scr_dims,
241 &dparams.rect.p1);
242 }
243
244 if (params->placement != ui_wnd_place_default) {
245 /* Set initial display window position */
246 ui_window_place(window, &info.rect, params,
247 &dparams.pos);
248
249 dparams.flags |= wndf_setpos;
250 }
251
252 rc = display_window_create(ui->display, &dparams, &dwnd_cb,
253 (void *) window, &window->dwindow);
254 if (rc != EOK)
255 goto error;
256
257 rc = display_window_get_gc(window->dwindow, &gc);
258 if (rc != EOK)
259 goto error;
260 } else if (ui->console != NULL) {
261 gc = console_gc_get_ctx(ui->cgc);
262
263 if (params->placement == ui_wnd_place_full_screen) {
264 /* Make window the size of the screen */
265 gfx_rect_dims(&ui->rect, &scr_dims);
266 gfx_coord2_add(&dparams.rect.p0, &scr_dims,
267 &dparams.rect.p1);
268 (void) console_set_caption(ui->console,
269 params->caption);
270 }
271 } else {
272 /* Needed for unit tests */
273 rc = dummygc_create(&dgc);
274 if (rc != EOK)
275 goto error;
276
277 gc = dummygc_get_ctx(dgc);
278 }
279
280#ifdef CONFIG_UI_CS_RENDER
281 /* Create window bitmap */
282 gfx_bitmap_params_init(&bparams);
283#ifndef CONFIG_WIN_DOUBLE_BUF
284 /* Console does not support direct output */
285 if (ui->display != NULL)
286 bparams.flags |= bmpf_direct_output;
287#endif
288
289 /* Move rectangle so that top-left corner is 0,0 */
290 gfx_rect_rtranslate(&dparams.rect.p0, &dparams.rect, &bparams.rect);
291
292 rc = gfx_bitmap_create(gc, &bparams, NULL, &bmp);
293 if (rc != EOK)
294 goto error;
295
296 /* Create memory GC */
297 rc = gfx_bitmap_get_alloc(bmp, &alloc);
298 if (rc != EOK) {
299 gfx_bitmap_destroy(window->app_bmp);
300 return rc;
301 }
302
303 rc = mem_gc_create(&bparams.rect, &alloc, &ui_window_mem_gc_cb,
304 (void *) window, &memgc);
305 if (rc != EOK) {
306 gfx_bitmap_destroy(window->app_bmp);
307 return rc;
308 }
309
310 window->bmp = bmp;
311 window->mgc = memgc;
312 window->gc = mem_gc_get_ctx(memgc);
313 window->realgc = gc;
314 (void) off;
315#else
316 /* Server-side rendering */
317
318 /* Full-screen mode? */
319 if (ui->display == NULL) {
320 /* Create translating GC to translate window contents */
321 off.x = 0;
322 off.y = 0;
323 rc = xlate_gc_create(&off, gc, &xgc);
324 if (rc != EOK)
325 goto error;
326
327 window->xgc = xgc;
328 window->gc = xlate_gc_get_ctx(xgc);
329 window->realgc = gc;
330 } else {
331 window->gc = gc;
332 }
333
334 (void) ui_window_mem_gc_cb;
335 (void) alloc;
336 (void) bparams;
337#endif
338 if (ui->display == NULL) {
339 ui_window_place(window, &ui->rect, params, &window->dpos);
340
341 if (window->xgc != NULL)
342 xlate_gc_set_off(window->xgc, &window->dpos);
343 }
344
345 rc = ui_resource_create(window->gc, ui_is_textmode(ui), &res);
346 if (rc != EOK)
347 goto error;
348
349 rc = ui_wdecor_create(res, params->caption, params->style, &wdecor);
350 if (rc != EOK)
351 goto error;
352
353 ui_wdecor_set_rect(wdecor, &dparams.rect);
354 ui_wdecor_set_cb(wdecor, &wdecor_cb, (void *) window);
355 ui_wdecor_paint(wdecor);
356
357 ui_resource_set_expose_cb(res, ui_window_expose_cb, (void *) window);
358
359 window->rect = dparams.rect;
360 window->res = res;
361 window->wdecor = wdecor;
362 window->cursor = ui_curs_arrow;
363 window->placement = params->placement;
364 *rwindow = window;
365
366 list_append(&window->lwindows, &ui->windows);
367 return EOK;
368error:
369 if (wdecor != NULL)
370 ui_wdecor_destroy(wdecor);
371 if (res != NULL)
372 ui_resource_destroy(res);
373 if (memgc != NULL)
374 mem_gc_delete(memgc);
375 if (xgc != NULL)
376 xlate_gc_delete(xgc);
377 if (bmp != NULL)
378 gfx_bitmap_destroy(bmp);
379 if (dgc != NULL)
380 dummygc_destroy(dgc);
381 free(window);
382 return rc;
383}
384
385/** Destroy window.
386 *
387 * @param window Window or @c NULL
388 */
389void ui_window_destroy(ui_window_t *window)
390{
391 ui_t *ui;
392
393 if (window == NULL)
394 return;
395
396 ui = window->ui;
397
398 list_remove(&window->lwindows);
399 ui_control_destroy(window->control);
400 ui_wdecor_destroy(window->wdecor);
401 ui_resource_destroy(window->res);
402 if (window->app_mgc != NULL)
403 mem_gc_delete(window->app_mgc);
404 if (window->app_bmp != NULL)
405 gfx_bitmap_destroy(window->app_bmp);
406 if (window->mgc != NULL) {
407 mem_gc_delete(window->mgc);
408 window->gc = NULL;
409 }
410 if (window->bmp != NULL)
411 gfx_bitmap_destroy(window->bmp);
412 if (window->dwindow != NULL)
413 display_window_destroy(window->dwindow);
414
415 /* Need to repaint if windows are emulated */
416 if (ui_is_fullscreen(ui)) {
417 ui_paint(ui);
418 }
419
420 if (ui->console != NULL &&
421 window->placement == ui_wnd_place_full_screen) {
422 (void) console_set_caption(ui->console, "");
423 }
424
425 free(window);
426}
427
428/** Add control to window.
429 *
430 * Only one control can be added to a window. If more than one control
431 * is added, the results are undefined.
432 *
433 * @param window Window
434 * @param control Control
435 * @return EOK on success, ENOMEM if out of memory
436 */
437void ui_window_add(ui_window_t *window, ui_control_t *control)
438{
439 assert(window->control == NULL);
440
441 window->control = control;
442 control->elemp = (void *) window;
443}
444
445/** Remove control from window.
446 *
447 * @param window Window
448 * @param control Control
449 */
450void ui_window_remove(ui_window_t *window, ui_control_t *control)
451{
452 assert(window->control == control);
453 assert((ui_window_t *) control->elemp == window);
454
455 window->control = NULL;
456 control->elemp = NULL;
457}
458
459/** Get active window (only valid in fullscreen mode).
460 *
461 * @param ui User interface
462 * @return Active window
463 */
464ui_window_t *ui_window_get_active(ui_t *ui)
465{
466 link_t *link;
467
468 link = list_last(&ui->windows);
469 if (link == NULL)
470 return NULL;
471
472 return list_get_instance(link, ui_window_t, lwindows);
473}
474
475/** Resize or (un)maximize window.
476 *
477 * @param window Window
478 * @param rect Rectangle
479 * @param scop Size change operation
480 *
481 * @return EOK on success or an error code
482 */
483errno_t ui_window_size_change(ui_window_t *window, gfx_rect_t *rect,
484 ui_wnd_sc_op_t scop)
485{
486 gfx_coord2_t offs;
487 gfx_rect_t nrect;
488 gfx_rect_t arect;
489 gfx_bitmap_t *app_bmp = NULL;
490 gfx_bitmap_t *win_bmp = NULL;
491 gfx_bitmap_params_t app_params;
492 gfx_bitmap_params_t win_params;
493 gfx_bitmap_alloc_t app_alloc;
494 gfx_bitmap_alloc_t win_alloc;
495 errno_t rc;
496
497 /*
498 * Move rect so that p0=0,0 - keep window's coordinate system origin
499 * locked to top-left corner of the window.
500 */
501 offs = rect->p0;
502 gfx_rect_rtranslate(&offs, rect, &nrect);
503
504 /* mgc != NULL iff client-side rendering */
505 if (window->mgc != NULL) {
506#ifdef CONFIG_WIN_DOUBLE_BUF
507 /*
508 * Create new window bitmap in advance. If direct mapping,
509 * will need do it after resizing the window.
510 */
511 assert(window->bmp != NULL);
512 gfx_bitmap_params_init(&win_params);
513 win_params.rect = nrect;
514
515 rc = gfx_bitmap_create(window->realgc, &win_params, NULL,
516 &win_bmp);
517 if (rc != EOK)
518 goto error;
519
520 rc = gfx_bitmap_get_alloc(win_bmp, &win_alloc);
521 if (rc != EOK)
522 goto error;
523#endif
524 }
525
526 /* Application area GC? */
527 if (window->app_gc != NULL) {
528 /* Resize application bitmap */
529 assert(window->app_bmp != NULL);
530
531 gfx_bitmap_params_init(&app_params);
532
533 /*
534 * The bitmap will have the same dimensions as the
535 * application rectangle, but start at 0,0.
536 */
537 ui_wdecor_app_from_rect(window->wdecor->style, &nrect, &arect);
538 gfx_rect_rtranslate(&arect.p0, &arect, &app_params.rect);
539
540 rc = gfx_bitmap_create(window->gc, &app_params, NULL,
541 &app_bmp);
542 if (rc != EOK)
543 goto error;
544
545 rc = gfx_bitmap_get_alloc(app_bmp, &app_alloc);
546 if (rc != EOK)
547 goto error;
548 }
549
550 /* dwindow can be NULL in case of unit tests or fullscreen mode */
551 if (window->dwindow != NULL) {
552 switch (scop) {
553 case ui_wsc_resize:
554 rc = display_window_resize(window->dwindow, &offs,
555 &nrect);
556 if (rc != EOK)
557 goto error;
558 break;
559 case ui_wsc_maximize:
560 rc = display_window_maximize(window->dwindow);
561 if (rc != EOK)
562 goto error;
563 break;
564 case ui_wsc_unmaximize:
565 rc = display_window_unmaximize(window->dwindow);
566 if (rc != EOK)
567 goto error;
568 break;
569 }
570 }
571
572 /* Client side rendering? */
573 if (window->mgc != NULL) {
574#ifndef CONFIG_WIN_DOUBLE_BUF
575 /* Window is resized, now we can map the window bitmap again */
576 gfx_bitmap_params_init(&win_params);
577 win_params.flags |= bmpf_direct_output;
578 win_params.rect = nrect;
579
580 rc = gfx_bitmap_create(window->realgc, &win_params, NULL,
581 &win_bmp);
582 if (rc != EOK)
583 goto error;
584
585 rc = gfx_bitmap_get_alloc(win_bmp, &win_alloc);
586 if (rc != EOK)
587 goto error;
588#endif
589 mem_gc_retarget(window->mgc, &win_params.rect, &win_alloc);
590
591 gfx_bitmap_destroy(window->bmp);
592 window->bmp = win_bmp;
593 }
594
595 window->rect = nrect;
596 ui_wdecor_set_rect(window->wdecor, &nrect);
597 ui_wdecor_paint(window->wdecor);
598 gfx_update(window->gc);
599
600 /* Application area GC? */
601 if (window->app_gc != NULL) {
602 mem_gc_retarget(window->app_mgc, &app_params.rect, &app_alloc);
603
604 gfx_bitmap_destroy(window->app_bmp);
605 window->app_bmp = app_bmp;
606 }
607
608 return EOK;
609error:
610 if (app_bmp != NULL)
611 gfx_bitmap_destroy(app_bmp);
612 if (win_bmp != NULL)
613 gfx_bitmap_destroy(win_bmp);
614 return rc;
615}
616
617/** Resize/move window.
618 *
619 * Resize window to the dimensions of @a rect. If @a rect.p0 is not 0,0,
620 * the top-left corner of the window will move on the screen accordingly.
621 *
622 * @param window Window
623 * @param rect Rectangle
624 *
625 * @return EOK on success or an error code
626 */
627errno_t ui_window_resize(ui_window_t *window, gfx_rect_t *rect)
628{
629 return ui_window_size_change(window, rect, ui_wsc_resize);
630}
631
632/** Set window callbacks.
633 *
634 * @param window Window
635 * @param cb Window callbacks
636 * @param arg Callback argument
637 */
638void ui_window_set_cb(ui_window_t *window, ui_window_cb_t *cb, void *arg)
639{
640 window->cb = cb;
641 window->arg = arg;
642}
643
644/** Change window caption.
645 *
646 * @param window Window
647 * @param caption New caption
648 *
649 * @return EOK on success or an error code
650 */
651errno_t ui_window_set_caption(ui_window_t *window, const char *caption)
652{
653 return ui_wdecor_set_caption(window->wdecor, caption);
654}
655
656/** Get window's containing UI.
657 *
658 * @param window Window
659 * @return Containing UI
660 */
661ui_t *ui_window_get_ui(ui_window_t *window)
662{
663 return window->ui;
664}
665
666/** Get UI resource from window.
667 *
668 * @param window Window
669 * @return UI resource
670 */
671ui_resource_t *ui_window_get_res(ui_window_t *window)
672{
673 return window->res;
674}
675
676/** Get window GC.
677 *
678 * @param window Window
679 * @return GC (relative to window)
680 */
681gfx_context_t *ui_window_get_gc(ui_window_t *window)
682{
683 return window->gc;
684}
685
686/** Get window position.
687 *
688 * @param window Window
689 * @param pos Place to store position
690 * @return EOK on success or an error code
691 */
692errno_t ui_window_get_pos(ui_window_t *window, gfx_coord2_t *pos)
693{
694 errno_t rc;
695
696 if (window->dwindow != NULL) {
697 rc = display_window_get_pos(window->dwindow, pos);
698 if (rc != EOK)
699 return rc;
700 } else {
701 *pos = window->dpos;
702 }
703
704 return EOK;
705}
706
707/** Get window application area GC
708 *
709 * @param window Window
710 * @param rgc Place to store GC (relative to application area)
711 * @return EOK on success or an error code
712 */
713errno_t ui_window_get_app_gc(ui_window_t *window, gfx_context_t **rgc)
714{
715 gfx_bitmap_params_t params;
716 gfx_bitmap_alloc_t alloc;
717 gfx_rect_t rect;
718 mem_gc_t *memgc;
719 errno_t rc;
720
721 if (window->app_gc == NULL) {
722 assert(window->app_bmp == NULL);
723
724 gfx_bitmap_params_init(&params);
725
726 /*
727 * The bitmap will have the same dimensions as the
728 * application rectangle, but start at 0,0.
729 */
730 ui_window_get_app_rect(window, &rect);
731 gfx_rect_rtranslate(&rect.p0, &rect, &params.rect);
732
733 rc = gfx_bitmap_create(window->gc, &params, NULL,
734 &window->app_bmp);
735 if (rc != EOK)
736 return rc;
737
738 rc = gfx_bitmap_get_alloc(window->app_bmp, &alloc);
739 if (rc != EOK) {
740 gfx_bitmap_destroy(window->app_bmp);
741 return rc;
742 }
743
744 rc = mem_gc_create(&params.rect, &alloc,
745 &ui_window_app_mem_gc_cb, (void *) window, &memgc);
746 if (rc != EOK) {
747 gfx_bitmap_destroy(window->app_bmp);
748 return rc;
749 }
750
751 window->app_mgc = memgc;
752 window->app_gc = mem_gc_get_ctx(memgc);
753 }
754
755 *rgc = window->app_gc;
756 return EOK;
757}
758
759/** Get window application rectangle
760 *
761 * @param window Window
762 * @param rect Place to store application rectangle
763 */
764void ui_window_get_app_rect(ui_window_t *window, gfx_rect_t *rect)
765{
766 ui_wdecor_geom_t geom;
767
768 ui_wdecor_get_geom(window->wdecor, &geom);
769 *rect = geom.app_area_rect;
770}
771
772/** Set cursor when pointer is hovering over a control.
773 *
774 * @param window Window
775 * @param cursor Cursor
776 */
777void ui_window_set_ctl_cursor(ui_window_t *window, ui_stock_cursor_t cursor)
778{
779 display_stock_cursor_t dcursor;
780
781 dcursor = wnd_dcursor_from_cursor(cursor);
782
783 if (window->dwindow != NULL)
784 (void) display_window_set_cursor(window->dwindow, dcursor);
785}
786
787/** Paint window
788 *
789 * @param window Window
790 * @return EOK on success or an error code
791 */
792errno_t ui_window_paint(ui_window_t *window)
793{
794 return ui_window_send_paint(window);
795}
796
797/** Handle window close event. */
798static void dwnd_close_event(void *arg)
799{
800 ui_window_t *window = (ui_window_t *) arg;
801 ui_t *ui = window->ui;
802
803 ui_lock(ui);
804 ui_window_send_close(window);
805 ui_unlock(ui);
806}
807
808/** Handle window focus event. */
809static void dwnd_focus_event(void *arg)
810{
811 ui_window_t *window = (ui_window_t *) arg;
812 ui_t *ui = window->ui;
813
814 ui_lock(ui);
815
816 if (window->wdecor != NULL) {
817 ui_wdecor_set_active(window->wdecor, true);
818 ui_wdecor_paint(window->wdecor);
819 }
820
821 ui_window_send_focus(window);
822 ui_unlock(ui);
823}
824
825/** Handle window keyboard event */
826static void dwnd_kbd_event(void *arg, kbd_event_t *kbd_event)
827{
828 ui_window_t *window = (ui_window_t *) arg;
829 ui_t *ui = window->ui;
830
831 ui_lock(ui);
832 ui_window_send_kbd(window, kbd_event);
833 ui_unlock(ui);
834}
835
836/** Handle window position event */
837static void dwnd_pos_event(void *arg, pos_event_t *event)
838{
839 ui_window_t *window = (ui_window_t *) arg;
840 ui_t *ui = window->ui;
841 ui_evclaim_t claim;
842
843 /* Make sure we don't process events until fully initialized */
844 if (window->wdecor == NULL)
845 return;
846
847 ui_lock(ui);
848
849 claim = ui_wdecor_pos_event(window->wdecor, event);
850 if (claim == ui_claimed) {
851 ui_unlock(ui);
852 return;
853 }
854
855 ui_window_send_pos(window, event);
856 ui_unlock(ui);
857}
858
859/** Handle window resize event */
860static void dwnd_resize_event(void *arg, gfx_rect_t *rect)
861{
862 ui_window_t *window = (ui_window_t *) arg;
863 ui_t *ui = window->ui;
864
865 /* Make sure we don't process events until fully initialized */
866 if (window->wdecor == NULL)
867 return;
868
869 if ((window->wdecor->style & ui_wds_resizable) == 0)
870 return;
871
872 ui_lock(ui);
873 (void) ui_window_resize(window, rect);
874 (void) ui_window_paint(window);
875 ui_unlock(ui);
876}
877
878/** Handle window unfocus event. */
879static void dwnd_unfocus_event(void *arg)
880{
881 ui_window_t *window = (ui_window_t *) arg;
882 ui_t *ui = window->ui;
883
884 ui_lock(ui);
885
886 if (window->wdecor != NULL) {
887 ui_wdecor_set_active(window->wdecor, false);
888 ui_wdecor_paint(window->wdecor);
889 }
890
891 ui_window_send_unfocus(window);
892 ui_unlock(ui);
893}
894
895/** Window decoration requested window maximization.
896 *
897 * @param wdecor Window decoration
898 * @param arg Argument (window)
899 */
900static void wd_maximize(ui_wdecor_t *wdecor, void *arg)
901{
902 ui_window_t *window = (ui_window_t *) arg;
903
904 ui_window_send_maximize(window);
905}
906
907/** Window decoration requested window unmaximization.
908 *
909 * @param wdecor Window decoration
910 * @param arg Argument (window)
911 */
912static void wd_unmaximize(ui_wdecor_t *wdecor, void *arg)
913{
914 ui_window_t *window = (ui_window_t *) arg;
915
916 ui_window_send_unmaximize(window);
917}
918
919/** Window decoration requested window closure.
920 *
921 * @param wdecor Window decoration
922 * @param arg Argument (window)
923 */
924static void wd_close(ui_wdecor_t *wdecor, void *arg)
925{
926 ui_window_t *window = (ui_window_t *) arg;
927
928 ui_window_send_close(window);
929}
930
931/** Window decoration requested window move.
932 *
933 * @param wdecor Window decoration
934 * @param arg Argument (window)
935 * @param pos Position where the title bar was pressed
936 */
937static void wd_move(ui_wdecor_t *wdecor, void *arg, gfx_coord2_t *pos)
938{
939 ui_window_t *window = (ui_window_t *) arg;
940
941 if (window->dwindow != NULL)
942 (void) display_window_move_req(window->dwindow, pos);
943}
944
945/** Window decoration requested window resize.
946 *
947 * @param wdecor Window decoration
948 * @param arg Argument (window)
949 * @param rsztype Resize type
950 * @param pos Position where the button was pressed
951 */
952static void wd_resize(ui_wdecor_t *wdecor, void *arg,
953 ui_wdecor_rsztype_t rsztype, gfx_coord2_t *pos)
954{
955 ui_window_t *window = (ui_window_t *) arg;
956
957 if (window->dwindow != NULL)
958 (void) display_window_resize_req(window->dwindow, rsztype, pos);
959}
960
961/** Get display stock cursor from UI stock cursor.
962 *
963 * @param cursor UI stock cursor
964 * @return Display stock cursor
965 */
966display_stock_cursor_t wnd_dcursor_from_cursor(ui_stock_cursor_t cursor)
967{
968 display_stock_cursor_t dcursor;
969
970 dcursor = dcurs_arrow;
971
972 switch (cursor) {
973 case ui_curs_arrow:
974 dcursor = dcurs_arrow;
975 break;
976 case ui_curs_size_ud:
977 dcursor = dcurs_size_ud;
978 break;
979 case ui_curs_size_lr:
980 dcursor = dcurs_size_lr;
981 break;
982 case ui_curs_size_uldr:
983 dcursor = dcurs_size_uldr;
984 break;
985 case ui_curs_size_urdl:
986 dcursor = dcurs_size_urdl;
987 break;
988 case ui_curs_ibeam:
989 dcursor = dcurs_ibeam;
990 break;
991 }
992
993 return dcursor;
994}
995
996/** Window decoration requested changing cursor.
997 *
998 * @param wdecor Window decoration
999 * @param arg Argument (window)
1000 * @param cursor Cursor to set
1001 */
1002static void wd_set_cursor(ui_wdecor_t *wdecor, void *arg,
1003 ui_stock_cursor_t cursor)
1004{
1005 ui_window_t *window = (ui_window_t *) arg;
1006 display_stock_cursor_t dcursor;
1007
1008 if (cursor == window->cursor)
1009 return;
1010
1011 dcursor = wnd_dcursor_from_cursor(cursor);
1012
1013 if (window->dwindow != NULL)
1014 (void) display_window_set_cursor(window->dwindow, dcursor);
1015
1016 window->cursor = cursor;
1017}
1018
1019/** Send window maximize event.
1020 *
1021 * @param window Window
1022 */
1023void ui_window_send_maximize(ui_window_t *window)
1024{
1025 if (window->cb != NULL && window->cb->maximize != NULL)
1026 window->cb->maximize(window, window->arg);
1027 else
1028 ui_window_def_maximize(window);
1029}
1030
1031/** Send window unmaximize event.
1032 *
1033 * @param window Window
1034 */
1035void ui_window_send_unmaximize(ui_window_t *window)
1036{
1037 if (window->cb != NULL && window->cb->unmaximize != NULL)
1038 window->cb->unmaximize(window, window->arg);
1039 else
1040 ui_window_def_unmaximize(window);
1041}
1042
1043/** Send window close event.
1044 *
1045 * @param window Window
1046 */
1047void ui_window_send_close(ui_window_t *window)
1048{
1049 if (window->cb != NULL && window->cb->close != NULL)
1050 window->cb->close(window, window->arg);
1051}
1052
1053/** Send window focus event.
1054 *
1055 * @param window Window
1056 */
1057void ui_window_send_focus(ui_window_t *window)
1058{
1059 if (window->cb != NULL && window->cb->focus != NULL)
1060 window->cb->focus(window, window->arg);
1061}
1062
1063/** Send window keyboard event.
1064 *
1065 * @param window Window
1066 */
1067void ui_window_send_kbd(ui_window_t *window, kbd_event_t *kbd)
1068{
1069 if (window->cb != NULL && window->cb->kbd != NULL)
1070 window->cb->kbd(window, window->arg, kbd);
1071 else
1072 ui_window_def_kbd(window, kbd);
1073}
1074
1075/** Send window paint event.
1076 *
1077 * @param window Window
1078 */
1079errno_t ui_window_send_paint(ui_window_t *window)
1080{
1081 if (window->cb != NULL && window->cb->paint != NULL)
1082 return window->cb->paint(window, window->arg);
1083 else
1084 return ui_window_def_paint(window);
1085}
1086
1087/** Send window position event.
1088 *
1089 * @param window Window
1090 */
1091void ui_window_send_pos(ui_window_t *window, pos_event_t *pos)
1092{
1093 if (window->cb != NULL && window->cb->pos != NULL)
1094 window->cb->pos(window, window->arg, pos);
1095 else
1096 ui_window_def_pos(window, pos);
1097}
1098
1099/** Send window unfocus event.
1100 *
1101 * @param window Window
1102 */
1103void ui_window_send_unfocus(ui_window_t *window)
1104{
1105 if (window->cb != NULL && window->cb->unfocus != NULL)
1106 window->cb->unfocus(window, window->arg);
1107 else
1108 return ui_window_def_unfocus(window);
1109}
1110
1111/** Default window maximize routine.
1112 *
1113 * @param window Window
1114 * @return EOK on success or an error code
1115 */
1116errno_t ui_window_def_maximize(ui_window_t *window)
1117{
1118 errno_t rc;
1119 gfx_rect_t old_rect;
1120 gfx_rect_t rect;
1121
1122 old_rect = window->rect;
1123
1124 if (window->dwindow != NULL) {
1125 rc = display_window_get_max_rect(window->dwindow, &rect);
1126 if (rc != EOK)
1127 return rc;
1128 } else {
1129 rect = window->ui->rect;
1130 }
1131
1132 ui_wdecor_set_maximized(window->wdecor, true);
1133
1134 rc = ui_window_size_change(window, &rect, ui_wsc_maximize);
1135 if (rc != EOK) {
1136 ui_wdecor_set_maximized(window->wdecor, false);
1137 return rc;
1138 }
1139
1140 window->normal_rect = old_rect;
1141 (void) ui_window_paint(window);
1142 return EOK;
1143}
1144
1145/** Default window unmaximize routine.
1146 *
1147 * @param window Window
1148 * @return EOK on success or an error code
1149 */
1150errno_t ui_window_def_unmaximize(ui_window_t *window)
1151{
1152 errno_t rc;
1153
1154 ui_wdecor_set_maximized(window->wdecor, false);
1155
1156 rc = ui_window_size_change(window, &window->normal_rect,
1157 ui_wsc_unmaximize);
1158 if (rc != EOK) {
1159 ui_wdecor_set_maximized(window->wdecor, true);
1160 printf("ui_window_size_change->error\n");
1161 return rc;
1162 }
1163
1164 (void) ui_window_paint(window);
1165 return EOK;
1166}
1167
1168/** Default window keyboard event routine.
1169 *
1170 * @param window Window
1171 * @return ui_claimed iff event was claimed
1172 */
1173ui_evclaim_t ui_window_def_kbd(ui_window_t *window, kbd_event_t *kbd)
1174{
1175 if (window->control != NULL)
1176 return ui_control_kbd_event(window->control, kbd);
1177
1178 return ui_unclaimed;
1179}
1180
1181/** Default window paint routine.
1182 *
1183 * @param window Window
1184 * @return EOK on success or an error code
1185 */
1186errno_t ui_window_def_paint(ui_window_t *window)
1187{
1188 gfx_rect_t app_rect;
1189 errno_t rc;
1190
1191 rc = gfx_set_color(window->gc, window->res->wnd_face_color);
1192 if (rc != EOK)
1193 return rc;
1194
1195 ui_window_get_app_rect(window, &app_rect);
1196
1197 rc = gfx_fill_rect(window->gc, &app_rect);
1198 if (rc != EOK)
1199 return rc;
1200
1201 if (window->control != NULL)
1202 return ui_control_paint(window->control);
1203
1204 rc = gfx_update(window->res->gc);
1205 if (rc != EOK)
1206 return rc;
1207
1208 return EOK;
1209}
1210
1211/** Default window position event routine.
1212 *
1213 * @param window Window
1214 */
1215void ui_window_def_pos(ui_window_t *window, pos_event_t *pos)
1216{
1217 if (window->control != NULL)
1218 ui_control_pos_event(window->control, pos);
1219}
1220
1221/** Default window unfocus routine.
1222 *
1223 * @param window Window
1224 * @return EOK on success or an error code
1225 */
1226void ui_window_def_unfocus(ui_window_t *window)
1227{
1228 if (window->control != NULL)
1229 ui_control_unfocus(window->control);
1230}
1231
1232/** Window invalidate callback
1233 *
1234 * @param arg Argument (ui_window_t *)
1235 * @param rect Rectangle to update
1236 */
1237static void ui_window_invalidate(void *arg, gfx_rect_t *rect)
1238{
1239 ui_window_t *window = (ui_window_t *) arg;
1240 gfx_rect_t env;
1241
1242 gfx_rect_envelope(&window->dirty_rect, rect, &env);
1243 window->dirty_rect = env;
1244}
1245
1246/** Window update callback
1247 *
1248 * @param arg Argument (ui_window_t *)
1249 */
1250static void ui_window_update(void *arg)
1251{
1252 ui_window_t *window = (ui_window_t *) arg;
1253
1254 if (!gfx_rect_is_empty(&window->dirty_rect)) {
1255 (void) gfx_bitmap_render(window->bmp, &window->dirty_rect,
1256 &window->dpos);
1257 }
1258
1259 window->dirty_rect.p0.x = 0;
1260 window->dirty_rect.p0.y = 0;
1261 window->dirty_rect.p1.x = 0;
1262 window->dirty_rect.p1.y = 0;
1263}
1264
1265/** Window cursor get position callback
1266 *
1267 * @param arg Argument (ui_window_t *)
1268 * @param pos Place to store position
1269 */
1270static errno_t ui_window_cursor_get_pos(void *arg, gfx_coord2_t *pos)
1271{
1272 ui_window_t *window = (ui_window_t *) arg;
1273 gfx_coord2_t cpos;
1274 errno_t rc;
1275
1276 rc = gfx_cursor_get_pos(window->realgc, &cpos);
1277 if (rc != EOK)
1278 return rc;
1279
1280 pos->x = cpos.x - window->dpos.x;
1281 pos->y = cpos.y - window->dpos.y;
1282 return EOK;
1283}
1284
1285/** Window cursor set position callback
1286 *
1287 * @param arg Argument (ui_window_t *)
1288 * @param pos New position
1289 */
1290static errno_t ui_window_cursor_set_pos(void *arg, gfx_coord2_t *pos)
1291{
1292 ui_window_t *window = (ui_window_t *) arg;
1293 gfx_coord2_t cpos;
1294
1295 cpos.x = pos->x + window->dpos.x;
1296 cpos.y = pos->y + window->dpos.y;
1297
1298 return gfx_cursor_set_pos(window->realgc, &cpos);
1299}
1300
1301/** Window cursor set visibility callback
1302 *
1303 * @param arg Argument (ui_window_t *)
1304 * @param visible @c true iff cursor is to be made visible
1305 */
1306static errno_t ui_window_cursor_set_visible(void *arg, bool visible)
1307{
1308 ui_window_t *window = (ui_window_t *) arg;
1309
1310 return gfx_cursor_set_visible(window->realgc, visible);
1311}
1312
1313/** Application area invalidate callback
1314 *
1315 * @param arg Argument (ui_window_t *)
1316 * @param rect Rectangle to update
1317 */
1318static void ui_window_app_invalidate(void *arg, gfx_rect_t *rect)
1319{
1320 ui_window_t *window = (ui_window_t *) arg;
1321 gfx_rect_t arect;
1322
1323 ui_window_get_app_rect(window, &arect);
1324
1325 /* Render bitmap rectangle inside the application area */
1326 (void) gfx_bitmap_render(window->app_bmp, rect, &arect.p0);
1327 /*
1328 * TODO Update applications to call gfx_update(), then
1329 * we can defer update to ui_window_app_update().
1330 */
1331 (void) gfx_update(window->res->gc);
1332}
1333
1334/** Application area update callback
1335 *
1336 * @param arg Argument (ui_window_t *)
1337 */
1338static void ui_window_app_update(void *arg)
1339{
1340 ui_window_t *window = (ui_window_t *) arg;
1341
1342 /*
1343 * Not used since display is updated immediately
1344 * in ui_window_app_invalidate
1345 */
1346 (void) window;
1347}
1348
1349/** Window expose callback. */
1350static void ui_window_expose_cb(void *arg)
1351{
1352 ui_window_t *window = (ui_window_t *) arg;
1353
1354 ui_window_paint(window);
1355}
1356
1357/** @}
1358 */
Note: See TracBrowser for help on using the repository browser.