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

serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since ab3bfc1 was 7896f23, checked in by Jiri Svoboda <jiri@…>, 4 years ago

Do not delete window→gc when destroying window

In all cases this is handled elsewhere: memory GC - destroying it
earlier, window GC - destroyed along with window later, console GC -
shared by all windows and destroyed along with UI. Deleting window→gc
here leads to a double free and heap corruption (only with server-side
rendering).

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