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

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

Change the correct pointer's shape when resizing window

The request to resize a window originates from the client. The display
server forces the cursor to a double-arrow shape regardless of whether
it is over the window or not, until the resize is done. This is to
make sure the cursor keeps that shape even if it moves outside of
the current boundaries of the window. With multiple pointers we need
to know which one to change. This is done by passing the pos_id from
button press event that starts the resize all the way to
ds_window_start_resize(). Then it needs to be stored in the window
structure for use when it is time to restore the cursor.

  • Property mode set to 100644
File size: 33.4 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 *);
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 */
976static void wd_move(ui_wdecor_t *wdecor, void *arg, gfx_coord2_t *pos)
977{
978 ui_window_t *window = (ui_window_t *) arg;
979
980 if (window->dwindow != NULL)
981 (void) display_window_move_req(window->dwindow, pos);
982}
983
984/** Window decoration requested window resize.
985 *
986 * @param wdecor Window decoration
987 * @param arg Argument (window)
988 * @param rsztype Resize type
989 * @param pos Position where the button was pressed
990 * @param pos_id Positioning device ID
991 */
992static void wd_resize(ui_wdecor_t *wdecor, void *arg,
993 ui_wdecor_rsztype_t rsztype, gfx_coord2_t *pos, sysarg_t pos_id)
994{
995 ui_window_t *window = (ui_window_t *) arg;
996
997 if (window->dwindow != NULL) {
998 (void) display_window_resize_req(window->dwindow, rsztype,
999 pos, pos_id);
1000 }
1001}
1002
1003/** Get display stock cursor from UI stock cursor.
1004 *
1005 * @param cursor UI stock cursor
1006 * @return Display stock cursor
1007 */
1008display_stock_cursor_t wnd_dcursor_from_cursor(ui_stock_cursor_t cursor)
1009{
1010 display_stock_cursor_t dcursor;
1011
1012 dcursor = dcurs_arrow;
1013
1014 switch (cursor) {
1015 case ui_curs_arrow:
1016 dcursor = dcurs_arrow;
1017 break;
1018 case ui_curs_size_ud:
1019 dcursor = dcurs_size_ud;
1020 break;
1021 case ui_curs_size_lr:
1022 dcursor = dcurs_size_lr;
1023 break;
1024 case ui_curs_size_uldr:
1025 dcursor = dcurs_size_uldr;
1026 break;
1027 case ui_curs_size_urdl:
1028 dcursor = dcurs_size_urdl;
1029 break;
1030 case ui_curs_ibeam:
1031 dcursor = dcurs_ibeam;
1032 break;
1033 }
1034
1035 return dcursor;
1036}
1037
1038/** Window decoration requested changing cursor.
1039 *
1040 * @param wdecor Window decoration
1041 * @param arg Argument (window)
1042 * @param cursor Cursor to set
1043 */
1044static void wd_set_cursor(ui_wdecor_t *wdecor, void *arg,
1045 ui_stock_cursor_t cursor)
1046{
1047 ui_window_t *window = (ui_window_t *) arg;
1048 display_stock_cursor_t dcursor;
1049
1050 if (cursor == window->cursor)
1051 return;
1052
1053 dcursor = wnd_dcursor_from_cursor(cursor);
1054
1055 if (window->dwindow != NULL)
1056 (void) display_window_set_cursor(window->dwindow, dcursor);
1057
1058 window->cursor = cursor;
1059}
1060
1061/** Send window minimize event.
1062 *
1063 * @param window Window
1064 */
1065void ui_window_send_minimize(ui_window_t *window)
1066{
1067 if (window->cb != NULL && window->cb->maximize != NULL)
1068 window->cb->minimize(window, window->arg);
1069 else
1070 ui_window_def_minimize(window);
1071}
1072
1073/** Send window maximize event.
1074 *
1075 * @param window Window
1076 */
1077void ui_window_send_maximize(ui_window_t *window)
1078{
1079 if (window->cb != NULL && window->cb->maximize != NULL)
1080 window->cb->maximize(window, window->arg);
1081 else
1082 ui_window_def_maximize(window);
1083}
1084
1085/** Send window unmaximize event.
1086 *
1087 * @param window Window
1088 */
1089void ui_window_send_unmaximize(ui_window_t *window)
1090{
1091 if (window->cb != NULL && window->cb->unmaximize != NULL)
1092 window->cb->unmaximize(window, window->arg);
1093 else
1094 ui_window_def_unmaximize(window);
1095}
1096
1097/** Send window close event.
1098 *
1099 * @param window Window
1100 */
1101void ui_window_send_close(ui_window_t *window)
1102{
1103 if (window->cb != NULL && window->cb->close != NULL)
1104 window->cb->close(window, window->arg);
1105}
1106
1107/** Send window focus event.
1108 *
1109 * @param window Window
1110 * @param nfocus New number of foci
1111 */
1112void ui_window_send_focus(ui_window_t *window, unsigned nfocus)
1113{
1114 if (window->cb != NULL && window->cb->focus != NULL)
1115 window->cb->focus(window, window->arg, nfocus);
1116}
1117
1118/** Send window keyboard event.
1119 *
1120 * @param window Window
1121 */
1122void ui_window_send_kbd(ui_window_t *window, kbd_event_t *kbd)
1123{
1124 if (window->cb != NULL && window->cb->kbd != NULL)
1125 window->cb->kbd(window, window->arg, kbd);
1126 else
1127 ui_window_def_kbd(window, kbd);
1128}
1129
1130/** Send window paint event.
1131 *
1132 * @param window Window
1133 */
1134errno_t ui_window_send_paint(ui_window_t *window)
1135{
1136 if (window->cb != NULL && window->cb->paint != NULL)
1137 return window->cb->paint(window, window->arg);
1138 else
1139 return ui_window_def_paint(window);
1140}
1141
1142/** Send window position event.
1143 *
1144 * @param window Window
1145 */
1146void ui_window_send_pos(ui_window_t *window, pos_event_t *pos)
1147{
1148 if (window->cb != NULL && window->cb->pos != NULL)
1149 window->cb->pos(window, window->arg, pos);
1150 else
1151 ui_window_def_pos(window, pos);
1152}
1153
1154/** Send window unfocus event.
1155 *
1156 * @param window Window
1157 * @param nfocus Number of remaining foci
1158 */
1159void ui_window_send_unfocus(ui_window_t *window, unsigned nfocus)
1160{
1161 if (window->cb != NULL && window->cb->unfocus != NULL)
1162 window->cb->unfocus(window, window->arg, nfocus);
1163 else
1164 return ui_window_def_unfocus(window, nfocus);
1165}
1166
1167/** Default window minimize routine.
1168 *
1169 * @param window Window
1170 * @return EOK on success or an error code
1171 */
1172errno_t ui_window_def_minimize(ui_window_t *window)
1173{
1174 errno_t rc;
1175
1176 if (window->dwindow != NULL) {
1177 rc = display_window_minimize(window->dwindow);
1178 if (rc != EOK)
1179 goto error;
1180 }
1181
1182 return EOK;
1183error:
1184 return rc;
1185}
1186
1187/** Default window maximize routine.
1188 *
1189 * @param window Window
1190 * @return EOK on success or an error code
1191 */
1192errno_t ui_window_def_maximize(ui_window_t *window)
1193{
1194 errno_t rc;
1195 gfx_rect_t old_rect;
1196 gfx_rect_t rect;
1197
1198 old_rect = window->rect;
1199
1200 if (window->dwindow != NULL) {
1201 rc = display_window_get_max_rect(window->dwindow, &rect);
1202 if (rc != EOK)
1203 return rc;
1204 } else {
1205 rect = window->ui->rect;
1206 }
1207
1208 ui_wdecor_set_maximized(window->wdecor, true);
1209
1210 rc = ui_window_size_change(window, &rect, ui_wsc_maximize);
1211 if (rc != EOK) {
1212 ui_wdecor_set_maximized(window->wdecor, false);
1213 return rc;
1214 }
1215
1216 window->normal_rect = old_rect;
1217 (void) ui_window_paint(window);
1218 return EOK;
1219}
1220
1221/** Default window unmaximize routine.
1222 *
1223 * @param window Window
1224 * @return EOK on success or an error code
1225 */
1226errno_t ui_window_def_unmaximize(ui_window_t *window)
1227{
1228 errno_t rc;
1229
1230 ui_wdecor_set_maximized(window->wdecor, false);
1231
1232 rc = ui_window_size_change(window, &window->normal_rect,
1233 ui_wsc_unmaximize);
1234 if (rc != EOK) {
1235 ui_wdecor_set_maximized(window->wdecor, true);
1236 printf("ui_window_size_change->error\n");
1237 return rc;
1238 }
1239
1240 (void) ui_window_paint(window);
1241 return EOK;
1242}
1243
1244/** Default window keyboard event routine.
1245 *
1246 * @param window Window
1247 * @return ui_claimed iff event was claimed
1248 */
1249ui_evclaim_t ui_window_def_kbd(ui_window_t *window, kbd_event_t *kbd)
1250{
1251 if (window->control != NULL)
1252 return ui_control_kbd_event(window->control, kbd);
1253
1254 return ui_unclaimed;
1255}
1256
1257/** Default window paint routine.
1258 *
1259 * @param window Window
1260 * @return EOK on success or an error code
1261 */
1262errno_t ui_window_def_paint(ui_window_t *window)
1263{
1264 gfx_rect_t app_rect;
1265 errno_t rc;
1266
1267 rc = gfx_set_color(window->gc, window->res->wnd_face_color);
1268 if (rc != EOK)
1269 return rc;
1270
1271 ui_window_get_app_rect(window, &app_rect);
1272
1273 rc = gfx_fill_rect(window->gc, &app_rect);
1274 if (rc != EOK)
1275 return rc;
1276
1277 if (window->control != NULL)
1278 return ui_control_paint(window->control);
1279
1280 rc = gfx_update(window->res->gc);
1281 if (rc != EOK)
1282 return rc;
1283
1284 return EOK;
1285}
1286
1287/** Default window position event routine.
1288 *
1289 * @param window Window
1290 */
1291void ui_window_def_pos(ui_window_t *window, pos_event_t *pos)
1292{
1293 if (window->control != NULL)
1294 ui_control_pos_event(window->control, pos);
1295}
1296
1297/** Default window unfocus routine.
1298 *
1299 * @param window Window
1300 * @param nfocus Number of remaining foci
1301 * @return EOK on success or an error code
1302 */
1303void ui_window_def_unfocus(ui_window_t *window, unsigned nfocus)
1304{
1305 if (window->control != NULL)
1306 ui_control_unfocus(window->control, nfocus);
1307}
1308
1309/** Window invalidate callback
1310 *
1311 * @param arg Argument (ui_window_t *)
1312 * @param rect Rectangle to update
1313 */
1314static void ui_window_invalidate(void *arg, gfx_rect_t *rect)
1315{
1316 ui_window_t *window = (ui_window_t *) arg;
1317 gfx_rect_t env;
1318
1319 gfx_rect_envelope(&window->dirty_rect, rect, &env);
1320 window->dirty_rect = env;
1321}
1322
1323/** Window update callback
1324 *
1325 * @param arg Argument (ui_window_t *)
1326 */
1327static void ui_window_update(void *arg)
1328{
1329 ui_window_t *window = (ui_window_t *) arg;
1330
1331 if (!gfx_rect_is_empty(&window->dirty_rect)) {
1332 (void) gfx_bitmap_render(window->bmp, &window->dirty_rect,
1333 &window->dpos);
1334 }
1335
1336 window->dirty_rect.p0.x = 0;
1337 window->dirty_rect.p0.y = 0;
1338 window->dirty_rect.p1.x = 0;
1339 window->dirty_rect.p1.y = 0;
1340}
1341
1342/** Window cursor get position callback
1343 *
1344 * @param arg Argument (ui_window_t *)
1345 * @param pos Place to store position
1346 */
1347static errno_t ui_window_cursor_get_pos(void *arg, gfx_coord2_t *pos)
1348{
1349 ui_window_t *window = (ui_window_t *) arg;
1350 gfx_coord2_t cpos;
1351 errno_t rc;
1352
1353 rc = gfx_cursor_get_pos(window->realgc, &cpos);
1354 if (rc != EOK)
1355 return rc;
1356
1357 pos->x = cpos.x - window->dpos.x;
1358 pos->y = cpos.y - window->dpos.y;
1359 return EOK;
1360}
1361
1362/** Window cursor set position callback
1363 *
1364 * @param arg Argument (ui_window_t *)
1365 * @param pos New position
1366 */
1367static errno_t ui_window_cursor_set_pos(void *arg, gfx_coord2_t *pos)
1368{
1369 ui_window_t *window = (ui_window_t *) arg;
1370 gfx_coord2_t cpos;
1371
1372 cpos.x = pos->x + window->dpos.x;
1373 cpos.y = pos->y + window->dpos.y;
1374
1375 return gfx_cursor_set_pos(window->realgc, &cpos);
1376}
1377
1378/** Window cursor set visibility callback
1379 *
1380 * @param arg Argument (ui_window_t *)
1381 * @param visible @c true iff cursor is to be made visible
1382 */
1383static errno_t ui_window_cursor_set_visible(void *arg, bool visible)
1384{
1385 ui_window_t *window = (ui_window_t *) arg;
1386
1387 return gfx_cursor_set_visible(window->realgc, visible);
1388}
1389
1390/** Application area invalidate callback
1391 *
1392 * @param arg Argument (ui_window_t *)
1393 * @param rect Rectangle to update
1394 */
1395static void ui_window_app_invalidate(void *arg, gfx_rect_t *rect)
1396{
1397 ui_window_t *window = (ui_window_t *) arg;
1398 gfx_rect_t arect;
1399
1400 ui_window_get_app_rect(window, &arect);
1401
1402 /* Render bitmap rectangle inside the application area */
1403 (void) gfx_bitmap_render(window->app_bmp, rect, &arect.p0);
1404 /*
1405 * TODO Update applications to call gfx_update(), then
1406 * we can defer update to ui_window_app_update().
1407 */
1408 (void) gfx_update(window->res->gc);
1409}
1410
1411/** Application area update callback
1412 *
1413 * @param arg Argument (ui_window_t *)
1414 */
1415static void ui_window_app_update(void *arg)
1416{
1417 ui_window_t *window = (ui_window_t *) arg;
1418
1419 /*
1420 * Not used since display is updated immediately
1421 * in ui_window_app_invalidate
1422 */
1423 (void) window;
1424}
1425
1426/** Window expose callback. */
1427static void ui_window_expose_cb(void *arg)
1428{
1429 ui_window_t *window = (ui_window_t *) arg;
1430
1431 ui_window_paint(window);
1432}
1433
1434/** @}
1435 */
Note: See TracBrowser for help on using the repository browser.