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

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

Tab set control

This allows to expand the space available in a dialog window
using stacking, with individual tabs that can be activated
by clicking the handle.

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