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

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

Clickmatic

A class that periodically generates when held, after initial delay.
This is quite similar to the typematic feature found in PC keyboards.
We use it to automatically scroll when scrollbar button or through
is held.

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