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

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

Add pos_id information to move request, too

This will become useful momentarily.

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