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

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

Display server needs to store window caption

Even though it does not use it itself, it needs to provide it to
window managers (e.g. Task bar). We need to be able to set caption
for a new window and to change it for an existing window.

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