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

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

Pass input device ID via display specification argument

This allows launcher to start applications in the correct seat,
meaning the correct seat's focus will be changed to the newly
created window.

  • Property mode set to 100644
File size: 33.8 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 * @return EOK on success, ENOMEM if out of memory
455 */
456void ui_window_add(ui_window_t *window, ui_control_t *control)
457{
458 assert(window->control == NULL);
459
460 window->control = control;
461 control->elemp = (void *) window;
462}
463
464/** Remove control from window.
465 *
466 * @param window Window
467 * @param control Control
468 */
469void ui_window_remove(ui_window_t *window, ui_control_t *control)
470{
471 assert(window->control == control);
472 assert((ui_window_t *) control->elemp == window);
473
474 window->control = NULL;
475 control->elemp = NULL;
476}
477
478/** Get active window (only valid in fullscreen mode).
479 *
480 * @param ui User interface
481 * @return Active window
482 */
483ui_window_t *ui_window_get_active(ui_t *ui)
484{
485 link_t *link;
486
487 link = list_last(&ui->windows);
488 if (link == NULL)
489 return NULL;
490
491 return list_get_instance(link, ui_window_t, lwindows);
492}
493
494/** Resize or (un)maximize window.
495 *
496 * @param window Window
497 * @param rect Rectangle
498 * @param scop Size change operation
499 *
500 * @return EOK on success or an error code
501 */
502errno_t ui_window_size_change(ui_window_t *window, gfx_rect_t *rect,
503 ui_wnd_sc_op_t scop)
504{
505 gfx_coord2_t offs;
506 gfx_rect_t nrect;
507 gfx_rect_t arect;
508 gfx_bitmap_t *app_bmp = NULL;
509 gfx_bitmap_t *win_bmp = NULL;
510 gfx_bitmap_params_t app_params;
511 gfx_bitmap_params_t win_params;
512 gfx_bitmap_alloc_t app_alloc;
513 gfx_bitmap_alloc_t win_alloc;
514 errno_t rc;
515
516 /*
517 * Move rect so that p0=0,0 - keep window's coordinate system origin
518 * locked to top-left corner of the window.
519 */
520 offs = rect->p0;
521 gfx_rect_rtranslate(&offs, rect, &nrect);
522
523 /* mgc != NULL iff client-side rendering */
524 if (window->mgc != NULL) {
525#ifdef CONFIG_WIN_DOUBLE_BUF
526 /*
527 * Create new window bitmap in advance. If direct mapping,
528 * will need do it after resizing the window.
529 */
530 assert(window->bmp != NULL);
531 gfx_bitmap_params_init(&win_params);
532 win_params.rect = nrect;
533
534 rc = gfx_bitmap_create(window->realgc, &win_params, NULL,
535 &win_bmp);
536 if (rc != EOK)
537 goto error;
538
539 rc = gfx_bitmap_get_alloc(win_bmp, &win_alloc);
540 if (rc != EOK)
541 goto error;
542#endif
543 }
544
545 /* Application area GC? */
546 if (window->app_gc != NULL) {
547 /* Resize application bitmap */
548 assert(window->app_bmp != NULL);
549
550 gfx_bitmap_params_init(&app_params);
551
552 /*
553 * The bitmap will have the same dimensions as the
554 * application rectangle, but start at 0,0.
555 */
556 ui_wdecor_app_from_rect(window->wdecor->style, &nrect, &arect);
557 gfx_rect_rtranslate(&arect.p0, &arect, &app_params.rect);
558
559 rc = gfx_bitmap_create(window->gc, &app_params, NULL,
560 &app_bmp);
561 if (rc != EOK)
562 goto error;
563
564 rc = gfx_bitmap_get_alloc(app_bmp, &app_alloc);
565 if (rc != EOK)
566 goto error;
567 }
568
569 /* dwindow can be NULL in case of unit tests or fullscreen mode */
570 if (window->dwindow != NULL) {
571 switch (scop) {
572 case ui_wsc_resize:
573 rc = display_window_resize(window->dwindow, &offs,
574 &nrect);
575 if (rc != EOK)
576 goto error;
577 break;
578 case ui_wsc_maximize:
579 rc = display_window_maximize(window->dwindow);
580 if (rc != EOK)
581 goto error;
582 break;
583 case ui_wsc_unmaximize:
584 rc = display_window_unmaximize(window->dwindow);
585 if (rc != EOK)
586 goto error;
587 break;
588 }
589 }
590
591 /* Client side rendering? */
592 if (window->mgc != NULL) {
593#ifndef CONFIG_WIN_DOUBLE_BUF
594 /* Window is resized, now we can map the window bitmap again */
595 gfx_bitmap_params_init(&win_params);
596 win_params.flags |= bmpf_direct_output;
597 win_params.rect = nrect;
598
599 rc = gfx_bitmap_create(window->realgc, &win_params, NULL,
600 &win_bmp);
601 if (rc != EOK)
602 goto error;
603
604 rc = gfx_bitmap_get_alloc(win_bmp, &win_alloc);
605 if (rc != EOK)
606 goto error;
607#endif
608 mem_gc_retarget(window->mgc, &win_params.rect, &win_alloc);
609
610 gfx_bitmap_destroy(window->bmp);
611 window->bmp = win_bmp;
612 }
613
614 window->rect = nrect;
615 ui_wdecor_set_rect(window->wdecor, &nrect);
616 ui_wdecor_paint(window->wdecor);
617 gfx_update(window->gc);
618
619 /* Application area GC? */
620 if (window->app_gc != NULL) {
621 mem_gc_retarget(window->app_mgc, &app_params.rect, &app_alloc);
622
623 gfx_bitmap_destroy(window->app_bmp);
624 window->app_bmp = app_bmp;
625 }
626
627 return EOK;
628error:
629 if (app_bmp != NULL)
630 gfx_bitmap_destroy(app_bmp);
631 if (win_bmp != NULL)
632 gfx_bitmap_destroy(win_bmp);
633 return rc;
634}
635
636/** Resize/move window.
637 *
638 * Resize window to the dimensions of @a rect. If @a rect.p0 is not 0,0,
639 * the top-left corner of the window will move on the screen accordingly.
640 *
641 * @param window Window
642 * @param rect Rectangle
643 *
644 * @return EOK on success or an error code
645 */
646errno_t ui_window_resize(ui_window_t *window, gfx_rect_t *rect)
647{
648 return ui_window_size_change(window, rect, ui_wsc_resize);
649}
650
651/** Set window callbacks.
652 *
653 * @param window Window
654 * @param cb Window callbacks
655 * @param arg Callback argument
656 */
657void ui_window_set_cb(ui_window_t *window, ui_window_cb_t *cb, void *arg)
658{
659 window->cb = cb;
660 window->arg = arg;
661}
662
663/** Change window caption.
664 *
665 * @param window Window
666 * @param caption New caption
667 *
668 * @return EOK on success or an error code
669 */
670errno_t ui_window_set_caption(ui_window_t *window, const char *caption)
671{
672 errno_t rc;
673
674 /* Set console caption if fullscreen window on console */
675 if (window->ui->console != NULL && window->placement ==
676 ui_wnd_place_full_screen) {
677 rc = console_set_caption(window->ui->console, caption);
678 if (rc != EOK)
679 return rc;
680 }
681
682 /* Set display window caption if running on display service */
683 if (window->dwindow != NULL) {
684 rc = display_window_set_caption(window->dwindow, caption);
685 if (rc != EOK)
686 return rc;
687 }
688
689 return ui_wdecor_set_caption(window->wdecor, caption);
690}
691
692/** Get window's containing UI.
693 *
694 * @param window Window
695 * @return Containing UI
696 */
697ui_t *ui_window_get_ui(ui_window_t *window)
698{
699 return window->ui;
700}
701
702/** Get UI resource from window.
703 *
704 * @param window Window
705 * @return UI resource
706 */
707ui_resource_t *ui_window_get_res(ui_window_t *window)
708{
709 return window->res;
710}
711
712/** Get window GC.
713 *
714 * @param window Window
715 * @return GC (relative to window)
716 */
717gfx_context_t *ui_window_get_gc(ui_window_t *window)
718{
719 return window->gc;
720}
721
722/** Get window position.
723 *
724 * @param window Window
725 * @param pos Place to store position
726 * @return EOK on success or an error code
727 */
728errno_t ui_window_get_pos(ui_window_t *window, gfx_coord2_t *pos)
729{
730 errno_t rc;
731
732 if (window->dwindow != NULL) {
733 rc = display_window_get_pos(window->dwindow, pos);
734 if (rc != EOK)
735 return rc;
736 } else {
737 *pos = window->dpos;
738 }
739
740 return EOK;
741}
742
743/** Get window application area GC
744 *
745 * @param window Window
746 * @param rgc Place to store GC (relative to application area)
747 * @return EOK on success or an error code
748 */
749errno_t ui_window_get_app_gc(ui_window_t *window, gfx_context_t **rgc)
750{
751 gfx_bitmap_params_t params;
752 gfx_bitmap_alloc_t alloc;
753 gfx_rect_t rect;
754 mem_gc_t *memgc;
755 errno_t rc;
756
757 if (window->app_gc == NULL) {
758 assert(window->app_bmp == NULL);
759
760 gfx_bitmap_params_init(&params);
761
762 /*
763 * The bitmap will have the same dimensions as the
764 * application rectangle, but start at 0,0.
765 */
766 ui_window_get_app_rect(window, &rect);
767 gfx_rect_rtranslate(&rect.p0, &rect, &params.rect);
768
769 rc = gfx_bitmap_create(window->gc, &params, NULL,
770 &window->app_bmp);
771 if (rc != EOK)
772 return rc;
773
774 rc = gfx_bitmap_get_alloc(window->app_bmp, &alloc);
775 if (rc != EOK) {
776 gfx_bitmap_destroy(window->app_bmp);
777 return rc;
778 }
779
780 rc = mem_gc_create(&params.rect, &alloc,
781 &ui_window_app_mem_gc_cb, (void *) window, &memgc);
782 if (rc != EOK) {
783 gfx_bitmap_destroy(window->app_bmp);
784 return rc;
785 }
786
787 window->app_mgc = memgc;
788 window->app_gc = mem_gc_get_ctx(memgc);
789 }
790
791 *rgc = window->app_gc;
792 return EOK;
793}
794
795/** Get window application rectangle
796 *
797 * @param window Window
798 * @param rect Place to store application rectangle
799 */
800void ui_window_get_app_rect(ui_window_t *window, gfx_rect_t *rect)
801{
802 ui_wdecor_geom_t geom;
803
804 ui_wdecor_get_geom(window->wdecor, &geom);
805 *rect = geom.app_area_rect;
806}
807
808/** Set cursor when pointer is hovering over a control.
809 *
810 * @param window Window
811 * @param cursor Cursor
812 */
813void ui_window_set_ctl_cursor(ui_window_t *window, ui_stock_cursor_t cursor)
814{
815 display_stock_cursor_t dcursor;
816
817 dcursor = wnd_dcursor_from_cursor(cursor);
818
819 if (window->dwindow != NULL)
820 (void) display_window_set_cursor(window->dwindow, dcursor);
821}
822
823/** Paint window
824 *
825 * @param window Window
826 * @return EOK on success or an error code
827 */
828errno_t ui_window_paint(ui_window_t *window)
829{
830 return ui_window_send_paint(window);
831}
832
833/** Handle window close event. */
834static void dwnd_close_event(void *arg)
835{
836 ui_window_t *window = (ui_window_t *) arg;
837 ui_t *ui = window->ui;
838
839 ui_lock(ui);
840 ui_window_send_close(window);
841 ui_unlock(ui);
842}
843
844/** Handle window focus event. */
845static void dwnd_focus_event(void *arg, unsigned nfocus)
846{
847 ui_window_t *window = (ui_window_t *) arg;
848 ui_t *ui = window->ui;
849
850 ui_lock(ui);
851 (void)nfocus;
852
853 if (window->wdecor != NULL) {
854 ui_wdecor_set_active(window->wdecor, true);
855 ui_wdecor_paint(window->wdecor);
856 }
857
858 ui_window_send_focus(window, nfocus);
859 ui_unlock(ui);
860}
861
862/** Handle window keyboard event */
863static void dwnd_kbd_event(void *arg, kbd_event_t *kbd_event)
864{
865 ui_window_t *window = (ui_window_t *) arg;
866 ui_t *ui = window->ui;
867
868 ui_lock(ui);
869 ui_window_send_kbd(window, kbd_event);
870 ui_unlock(ui);
871}
872
873/** Handle window position event */
874static void dwnd_pos_event(void *arg, pos_event_t *event)
875{
876 ui_window_t *window = (ui_window_t *) arg;
877 ui_t *ui = window->ui;
878 ui_evclaim_t claim;
879
880 /* Make sure we don't process events until fully initialized */
881 if (window->wdecor == NULL)
882 return;
883
884 ui_lock(ui);
885
886 claim = ui_wdecor_pos_event(window->wdecor, event);
887 if (claim == ui_claimed) {
888 ui_unlock(ui);
889 return;
890 }
891
892 ui_window_send_pos(window, event);
893 ui_unlock(ui);
894}
895
896/** Handle window resize event */
897static void dwnd_resize_event(void *arg, gfx_rect_t *rect)
898{
899 ui_window_t *window = (ui_window_t *) arg;
900 ui_t *ui = window->ui;
901
902 /* Make sure we don't process events until fully initialized */
903 if (window->wdecor == NULL)
904 return;
905
906 if ((window->wdecor->style & ui_wds_resizable) == 0)
907 return;
908
909 ui_lock(ui);
910 (void) ui_window_resize(window, rect);
911 (void) ui_window_paint(window);
912 ui_unlock(ui);
913}
914
915/** Handle window unfocus event. */
916static void dwnd_unfocus_event(void *arg, unsigned nfocus)
917{
918 ui_window_t *window = (ui_window_t *) arg;
919 ui_t *ui = window->ui;
920
921 ui_lock(ui);
922
923 if (window->wdecor != NULL && nfocus == 0) {
924 ui_wdecor_set_active(window->wdecor, false);
925 ui_wdecor_paint(window->wdecor);
926 }
927
928 ui_window_send_unfocus(window, nfocus);
929 ui_unlock(ui);
930}
931
932/** Window decoration requested window minimization.
933 *
934 * @param wdecor Window decoration
935 * @param arg Argument (window)
936 */
937static void wd_minimize(ui_wdecor_t *wdecor, void *arg)
938{
939 ui_window_t *window = (ui_window_t *) arg;
940
941 ui_window_send_minimize(window);
942}
943
944/** Window decoration requested window maximization.
945 *
946 * @param wdecor Window decoration
947 * @param arg Argument (window)
948 */
949static void wd_maximize(ui_wdecor_t *wdecor, void *arg)
950{
951 ui_window_t *window = (ui_window_t *) arg;
952
953 ui_window_send_maximize(window);
954}
955
956/** Window decoration requested window unmaximization.
957 *
958 * @param wdecor Window decoration
959 * @param arg Argument (window)
960 */
961static void wd_unmaximize(ui_wdecor_t *wdecor, void *arg)
962{
963 ui_window_t *window = (ui_window_t *) arg;
964
965 ui_window_send_unmaximize(window);
966}
967
968/** Window decoration requested window closure.
969 *
970 * @param wdecor Window decoration
971 * @param arg Argument (window)
972 */
973static void wd_close(ui_wdecor_t *wdecor, void *arg)
974{
975 ui_window_t *window = (ui_window_t *) arg;
976
977 ui_window_send_close(window);
978}
979
980/** Window decoration requested window move.
981 *
982 * @param wdecor Window decoration
983 * @param arg Argument (window)
984 * @param pos Position where the title bar was pressed
985 * @param pos_id Positioning device ID
986 */
987static void wd_move(ui_wdecor_t *wdecor, void *arg, gfx_coord2_t *pos,
988 sysarg_t pos_id)
989{
990 ui_window_t *window = (ui_window_t *) arg;
991
992 if (window->dwindow != NULL)
993 (void) display_window_move_req(window->dwindow, pos, pos_id);
994}
995
996/** Window decoration requested window resize.
997 *
998 * @param wdecor Window decoration
999 * @param arg Argument (window)
1000 * @param rsztype Resize type
1001 * @param pos Position where the button was pressed
1002 * @param pos_id Positioning device ID
1003 */
1004static void wd_resize(ui_wdecor_t *wdecor, void *arg,
1005 ui_wdecor_rsztype_t rsztype, gfx_coord2_t *pos, sysarg_t pos_id)
1006{
1007 ui_window_t *window = (ui_window_t *) arg;
1008
1009 if (window->dwindow != NULL) {
1010 (void) display_window_resize_req(window->dwindow, rsztype,
1011 pos, pos_id);
1012 }
1013}
1014
1015/** Get display stock cursor from UI stock cursor.
1016 *
1017 * @param cursor UI stock cursor
1018 * @return Display stock cursor
1019 */
1020display_stock_cursor_t wnd_dcursor_from_cursor(ui_stock_cursor_t cursor)
1021{
1022 display_stock_cursor_t dcursor;
1023
1024 dcursor = dcurs_arrow;
1025
1026 switch (cursor) {
1027 case ui_curs_arrow:
1028 dcursor = dcurs_arrow;
1029 break;
1030 case ui_curs_size_ud:
1031 dcursor = dcurs_size_ud;
1032 break;
1033 case ui_curs_size_lr:
1034 dcursor = dcurs_size_lr;
1035 break;
1036 case ui_curs_size_uldr:
1037 dcursor = dcurs_size_uldr;
1038 break;
1039 case ui_curs_size_urdl:
1040 dcursor = dcurs_size_urdl;
1041 break;
1042 case ui_curs_ibeam:
1043 dcursor = dcurs_ibeam;
1044 break;
1045 }
1046
1047 return dcursor;
1048}
1049
1050/** Window decoration requested changing cursor.
1051 *
1052 * @param wdecor Window decoration
1053 * @param arg Argument (window)
1054 * @param cursor Cursor to set
1055 */
1056static void wd_set_cursor(ui_wdecor_t *wdecor, void *arg,
1057 ui_stock_cursor_t cursor)
1058{
1059 ui_window_t *window = (ui_window_t *) arg;
1060 display_stock_cursor_t dcursor;
1061
1062 if (cursor == window->cursor)
1063 return;
1064
1065 dcursor = wnd_dcursor_from_cursor(cursor);
1066
1067 if (window->dwindow != NULL)
1068 (void) display_window_set_cursor(window->dwindow, dcursor);
1069
1070 window->cursor = cursor;
1071}
1072
1073/** Send window minimize event.
1074 *
1075 * @param window Window
1076 */
1077void ui_window_send_minimize(ui_window_t *window)
1078{
1079 if (window->cb != NULL && window->cb->maximize != NULL)
1080 window->cb->minimize(window, window->arg);
1081 else
1082 ui_window_def_minimize(window);
1083}
1084
1085/** Send window maximize event.
1086 *
1087 * @param window Window
1088 */
1089void ui_window_send_maximize(ui_window_t *window)
1090{
1091 if (window->cb != NULL && window->cb->maximize != NULL)
1092 window->cb->maximize(window, window->arg);
1093 else
1094 ui_window_def_maximize(window);
1095}
1096
1097/** Send window unmaximize event.
1098 *
1099 * @param window Window
1100 */
1101void ui_window_send_unmaximize(ui_window_t *window)
1102{
1103 if (window->cb != NULL && window->cb->unmaximize != NULL)
1104 window->cb->unmaximize(window, window->arg);
1105 else
1106 ui_window_def_unmaximize(window);
1107}
1108
1109/** Send window close event.
1110 *
1111 * @param window Window
1112 */
1113void ui_window_send_close(ui_window_t *window)
1114{
1115 if (window->cb != NULL && window->cb->close != NULL)
1116 window->cb->close(window, window->arg);
1117}
1118
1119/** Send window focus event.
1120 *
1121 * @param window Window
1122 * @param nfocus New number of foci
1123 */
1124void ui_window_send_focus(ui_window_t *window, unsigned nfocus)
1125{
1126 if (window->cb != NULL && window->cb->focus != NULL)
1127 window->cb->focus(window, window->arg, nfocus);
1128}
1129
1130/** Send window keyboard event.
1131 *
1132 * @param window Window
1133 */
1134void ui_window_send_kbd(ui_window_t *window, kbd_event_t *kbd)
1135{
1136 if (window->cb != NULL && window->cb->kbd != NULL)
1137 window->cb->kbd(window, window->arg, kbd);
1138 else
1139 ui_window_def_kbd(window, kbd);
1140}
1141
1142/** Send window paint event.
1143 *
1144 * @param window Window
1145 */
1146errno_t ui_window_send_paint(ui_window_t *window)
1147{
1148 if (window->cb != NULL && window->cb->paint != NULL)
1149 return window->cb->paint(window, window->arg);
1150 else
1151 return ui_window_def_paint(window);
1152}
1153
1154/** Send window position event.
1155 *
1156 * @param window Window
1157 */
1158void ui_window_send_pos(ui_window_t *window, pos_event_t *pos)
1159{
1160 if (window->cb != NULL && window->cb->pos != NULL)
1161 window->cb->pos(window, window->arg, pos);
1162 else
1163 ui_window_def_pos(window, pos);
1164}
1165
1166/** Send window unfocus event.
1167 *
1168 * @param window Window
1169 * @param nfocus Number of remaining foci
1170 */
1171void ui_window_send_unfocus(ui_window_t *window, unsigned nfocus)
1172{
1173 if (window->cb != NULL && window->cb->unfocus != NULL)
1174 window->cb->unfocus(window, window->arg, nfocus);
1175 else
1176 return ui_window_def_unfocus(window, nfocus);
1177}
1178
1179/** Default window minimize routine.
1180 *
1181 * @param window Window
1182 * @return EOK on success or an error code
1183 */
1184errno_t ui_window_def_minimize(ui_window_t *window)
1185{
1186 errno_t rc;
1187
1188 if (window->dwindow != NULL) {
1189 rc = display_window_minimize(window->dwindow);
1190 if (rc != EOK)
1191 goto error;
1192 }
1193
1194 return EOK;
1195error:
1196 return rc;
1197}
1198
1199/** Default window maximize routine.
1200 *
1201 * @param window Window
1202 * @return EOK on success or an error code
1203 */
1204errno_t ui_window_def_maximize(ui_window_t *window)
1205{
1206 errno_t rc;
1207 gfx_rect_t old_rect;
1208 gfx_rect_t rect;
1209
1210 old_rect = window->rect;
1211
1212 if (window->dwindow != NULL) {
1213 rc = display_window_get_max_rect(window->dwindow, &rect);
1214 if (rc != EOK)
1215 return rc;
1216 } else {
1217 rect = window->ui->rect;
1218 }
1219
1220 ui_wdecor_set_maximized(window->wdecor, true);
1221
1222 rc = ui_window_size_change(window, &rect, ui_wsc_maximize);
1223 if (rc != EOK) {
1224 ui_wdecor_set_maximized(window->wdecor, false);
1225 return rc;
1226 }
1227
1228 window->normal_rect = old_rect;
1229 (void) ui_window_paint(window);
1230 return EOK;
1231}
1232
1233/** Default window unmaximize routine.
1234 *
1235 * @param window Window
1236 * @return EOK on success or an error code
1237 */
1238errno_t ui_window_def_unmaximize(ui_window_t *window)
1239{
1240 errno_t rc;
1241
1242 ui_wdecor_set_maximized(window->wdecor, false);
1243
1244 rc = ui_window_size_change(window, &window->normal_rect,
1245 ui_wsc_unmaximize);
1246 if (rc != EOK) {
1247 ui_wdecor_set_maximized(window->wdecor, true);
1248 printf("ui_window_size_change->error\n");
1249 return rc;
1250 }
1251
1252 (void) ui_window_paint(window);
1253 return EOK;
1254}
1255
1256/** Default window keyboard event routine.
1257 *
1258 * @param window Window
1259 * @return ui_claimed iff event was claimed
1260 */
1261ui_evclaim_t ui_window_def_kbd(ui_window_t *window, kbd_event_t *kbd)
1262{
1263 if (window->control != NULL)
1264 return ui_control_kbd_event(window->control, kbd);
1265
1266 return ui_unclaimed;
1267}
1268
1269/** Default window paint routine.
1270 *
1271 * @param window Window
1272 * @return EOK on success or an error code
1273 */
1274errno_t ui_window_def_paint(ui_window_t *window)
1275{
1276 gfx_rect_t app_rect;
1277 errno_t rc;
1278
1279 rc = gfx_set_color(window->gc, window->res->wnd_face_color);
1280 if (rc != EOK)
1281 return rc;
1282
1283 ui_window_get_app_rect(window, &app_rect);
1284
1285 rc = gfx_fill_rect(window->gc, &app_rect);
1286 if (rc != EOK)
1287 return rc;
1288
1289 if (window->control != NULL)
1290 return ui_control_paint(window->control);
1291
1292 rc = gfx_update(window->res->gc);
1293 if (rc != EOK)
1294 return rc;
1295
1296 return EOK;
1297}
1298
1299/** Default window position event routine.
1300 *
1301 * @param window Window
1302 */
1303void ui_window_def_pos(ui_window_t *window, pos_event_t *pos)
1304{
1305 if (window->control != NULL)
1306 ui_control_pos_event(window->control, pos);
1307}
1308
1309/** Default window unfocus routine.
1310 *
1311 * @param window Window
1312 * @param nfocus Number of remaining foci
1313 * @return EOK on success or an error code
1314 */
1315void ui_window_def_unfocus(ui_window_t *window, unsigned nfocus)
1316{
1317 if (window->control != NULL)
1318 ui_control_unfocus(window->control, nfocus);
1319}
1320
1321/** Window invalidate callback
1322 *
1323 * @param arg Argument (ui_window_t *)
1324 * @param rect Rectangle to update
1325 */
1326static void ui_window_invalidate(void *arg, gfx_rect_t *rect)
1327{
1328 ui_window_t *window = (ui_window_t *) arg;
1329 gfx_rect_t env;
1330
1331 gfx_rect_envelope(&window->dirty_rect, rect, &env);
1332 window->dirty_rect = env;
1333}
1334
1335/** Window update callback
1336 *
1337 * @param arg Argument (ui_window_t *)
1338 */
1339static void ui_window_update(void *arg)
1340{
1341 ui_window_t *window = (ui_window_t *) arg;
1342
1343 if (!gfx_rect_is_empty(&window->dirty_rect)) {
1344 (void) gfx_bitmap_render(window->bmp, &window->dirty_rect,
1345 &window->dpos);
1346 }
1347
1348 window->dirty_rect.p0.x = 0;
1349 window->dirty_rect.p0.y = 0;
1350 window->dirty_rect.p1.x = 0;
1351 window->dirty_rect.p1.y = 0;
1352}
1353
1354/** Window cursor get position callback
1355 *
1356 * @param arg Argument (ui_window_t *)
1357 * @param pos Place to store position
1358 */
1359static errno_t ui_window_cursor_get_pos(void *arg, gfx_coord2_t *pos)
1360{
1361 ui_window_t *window = (ui_window_t *) arg;
1362 gfx_coord2_t cpos;
1363 errno_t rc;
1364
1365 rc = gfx_cursor_get_pos(window->realgc, &cpos);
1366 if (rc != EOK)
1367 return rc;
1368
1369 pos->x = cpos.x - window->dpos.x;
1370 pos->y = cpos.y - window->dpos.y;
1371 return EOK;
1372}
1373
1374/** Window cursor set position callback
1375 *
1376 * @param arg Argument (ui_window_t *)
1377 * @param pos New position
1378 */
1379static errno_t ui_window_cursor_set_pos(void *arg, gfx_coord2_t *pos)
1380{
1381 ui_window_t *window = (ui_window_t *) arg;
1382 gfx_coord2_t cpos;
1383
1384 cpos.x = pos->x + window->dpos.x;
1385 cpos.y = pos->y + window->dpos.y;
1386
1387 return gfx_cursor_set_pos(window->realgc, &cpos);
1388}
1389
1390/** Window cursor set visibility callback
1391 *
1392 * @param arg Argument (ui_window_t *)
1393 * @param visible @c true iff cursor is to be made visible
1394 */
1395static errno_t ui_window_cursor_set_visible(void *arg, bool visible)
1396{
1397 ui_window_t *window = (ui_window_t *) arg;
1398
1399 return gfx_cursor_set_visible(window->realgc, visible);
1400}
1401
1402/** Application area invalidate callback
1403 *
1404 * @param arg Argument (ui_window_t *)
1405 * @param rect Rectangle to update
1406 */
1407static void ui_window_app_invalidate(void *arg, gfx_rect_t *rect)
1408{
1409 ui_window_t *window = (ui_window_t *) arg;
1410 gfx_rect_t arect;
1411
1412 ui_window_get_app_rect(window, &arect);
1413
1414 /* Render bitmap rectangle inside the application area */
1415 (void) gfx_bitmap_render(window->app_bmp, rect, &arect.p0);
1416 /*
1417 * TODO Update applications to call gfx_update(), then
1418 * we can defer update to ui_window_app_update().
1419 */
1420 (void) gfx_update(window->res->gc);
1421}
1422
1423/** Application area update callback
1424 *
1425 * @param arg Argument (ui_window_t *)
1426 */
1427static void ui_window_app_update(void *arg)
1428{
1429 ui_window_t *window = (ui_window_t *) arg;
1430
1431 /*
1432 * Not used since display is updated immediately
1433 * in ui_window_app_invalidate
1434 */
1435 (void) window;
1436}
1437
1438/** Window expose callback. */
1439static void ui_window_expose_cb(void *arg)
1440{
1441 ui_window_t *window = (ui_window_t *) arg;
1442
1443 ui_window_paint(window);
1444}
1445
1446/** @}
1447 */
Note: See TracBrowser for help on using the repository browser.