source: mainline/uspace/srv/hid/display/window.c@ 7470d97

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

Client-side UI rendering

It is possible to turn on and off and if turned on, one can also
enable or disable window double buffering (currently both options
are build-time).

  • Property mode set to 100644
File size: 19.7 KB
Line 
1/*
2 * Copyright (c) 2019 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 display
30 * @{
31 */
32/**
33 * @file Display server window
34 */
35
36#include <gfx/bitmap.h>
37#include <gfx/color.h>
38#include <gfx/coord.h>
39#include <gfx/context.h>
40#include <gfx/render.h>
41#include <io/log.h>
42#include <io/pixelmap.h>
43#include <macros.h>
44#include <memgfx/memgc.h>
45#include <stdlib.h>
46#include "client.h"
47#include "display.h"
48#include "seat.h"
49#include "window.h"
50
51static void ds_window_invalidate_cb(void *, gfx_rect_t *);
52static void ds_window_update_cb(void *);
53static void ds_window_get_preview_rect(ds_window_t *, gfx_rect_t *);
54
55/** Create window.
56 *
57 * Create graphics context for rendering into a window.
58 *
59 * @param client Client owning the window
60 * @param params Window parameters
61 * @param rgc Place to store pointer to new GC.
62 *
63 * @return EOK on success or an error code
64 */
65errno_t ds_window_create(ds_client_t *client, display_wnd_params_t *params,
66 ds_window_t **rgc)
67{
68 ds_window_t *wnd = NULL;
69 gfx_context_t *dgc;
70 gfx_coord2_t dims;
71 gfx_bitmap_params_t bparams;
72 gfx_bitmap_alloc_t alloc;
73 errno_t rc;
74
75 wnd = calloc(1, sizeof(ds_window_t));
76 if (wnd == NULL) {
77 rc = ENOMEM;
78 goto error;
79 }
80
81 ds_client_add_window(client, wnd);
82 ds_display_add_window(client->display, wnd);
83
84 gfx_bitmap_params_init(&bparams);
85 bparams.rect = params->rect;
86
87 dgc = ds_display_get_gc(wnd->display);
88 if (dgc != NULL) {
89 rc = gfx_bitmap_create(dgc, &bparams, NULL, &wnd->bitmap);
90 if (rc != EOK)
91 goto error;
92
93 rc = gfx_bitmap_get_alloc(wnd->bitmap, &alloc);
94 if (rc != EOK)
95 goto error;
96
97 gfx_rect_dims(&params->rect, &dims);
98 wnd->pixelmap.width = dims.x;
99 wnd->pixelmap.height = dims.y;
100 wnd->pixelmap.data = alloc.pixels;
101 } else {
102 /* This is just for unit tests */
103 gfx_rect_dims(&params->rect, &dims);
104 alloc.pitch = dims.x * sizeof(uint32_t);
105 alloc.off0 = 0;
106 alloc.pixels = calloc(1, alloc.pitch * dims.y);
107 }
108
109 rc = mem_gc_create(&params->rect, &alloc, ds_window_invalidate_cb,
110 ds_window_update_cb, (void *)wnd, &wnd->mgc);
111 if (rc != EOK)
112 goto error;
113
114 wnd->rect = params->rect;
115 wnd->min_size = params->min_size;
116 wnd->gc = mem_gc_get_ctx(wnd->mgc);
117 wnd->cursor = wnd->display->cursor[dcurs_arrow];
118 *rgc = wnd;
119 return EOK;
120error:
121 if (wnd != NULL) {
122 if (wnd->bitmap != NULL)
123 gfx_bitmap_destroy(wnd->bitmap);
124 free(wnd);
125 }
126
127 return rc;
128}
129
130/** Destroy window.
131 *
132 * @param wnd Window
133 */
134void ds_window_destroy(ds_window_t *wnd)
135{
136 ds_display_t *disp;
137
138 disp = wnd->display;
139
140 ds_client_remove_window(wnd);
141 ds_display_remove_window(wnd);
142
143 mem_gc_delete(wnd->mgc);
144
145 if (wnd->bitmap != NULL)
146 gfx_bitmap_destroy(wnd->bitmap);
147
148 free(wnd);
149
150 (void) ds_display_paint(disp, NULL);
151}
152
153/** Bring window to top.
154 *
155 * @param wnd Window
156 */
157void ds_window_bring_to_top(ds_window_t *wnd)
158{
159 ds_display_t *disp = wnd->display;
160
161 ds_display_remove_window(wnd);
162 ds_display_add_window(disp, wnd);
163 (void) ds_display_paint(wnd->display, NULL);
164}
165
166/** Get generic graphic context from window.
167 *
168 * @param wnd Window
169 * @return Graphic context
170 */
171gfx_context_t *ds_window_get_ctx(ds_window_t *wnd)
172{
173 return wnd->gc;
174}
175
176/** Paint a window using its backing bitmap.
177 *
178 * @param wnd Window to paint
179 * @param rect Display rectangle to paint to
180 * @return EOK on success or an error code
181 */
182errno_t ds_window_paint(ds_window_t *wnd, gfx_rect_t *rect)
183{
184 gfx_rect_t srect;
185 gfx_rect_t *brect;
186 gfx_rect_t crect;
187
188 log_msg(LOG_DEFAULT, LVL_DEBUG, "ds_window_paint");
189
190 if (rect != NULL) {
191 gfx_rect_rtranslate(&wnd->dpos, rect, &srect);
192
193 /* Determine if we have anything to do */
194 gfx_rect_clip(&srect, &wnd->rect, &crect);
195 if (gfx_rect_is_empty(&crect))
196 return EOK;
197
198 brect = &srect;
199 } else {
200 brect = NULL;
201 }
202
203 /* This can happen in unit tests */
204 if (wnd->bitmap == NULL)
205 return EOK;
206
207 return gfx_bitmap_render(wnd->bitmap, brect, &wnd->dpos);
208}
209
210/** Get the preview rectangle for a window.
211 *
212 * Get the preview rectangle if the window is being resized or moved.
213 * If the window is not being resized or moved, return an empty rectangle.
214 *
215 * @param wnd Window
216 * @param rect Place to store preview rectangle
217 */
218static void ds_window_get_preview_rect(ds_window_t *wnd, gfx_rect_t *rect)
219{
220 switch (wnd->state) {
221 case dsw_idle:
222 break;
223 case dsw_moving:
224 gfx_rect_translate(&wnd->preview_pos, &wnd->rect, rect);
225 return;
226 case dsw_resizing:
227 gfx_rect_translate(&wnd->dpos, &wnd->preview_rect, rect);
228 return;
229 }
230
231 rect->p0.x = 0;
232 rect->p0.y = 0;
233 rect->p1.x = 0;
234 rect->p1.y = 0;
235}
236
237/** Paint window preview if the window is being moved or resized.
238 *
239 * If the window is not being resized or moved, take no action and return
240 * success.
241 *
242 * @param wnd Window for which to paint preview
243 * @param rect Clipping rectangle
244 * @return EOK on success or an error code
245 */
246errno_t ds_window_paint_preview(ds_window_t *wnd, gfx_rect_t *rect)
247{
248 errno_t rc;
249 gfx_color_t *color;
250 gfx_rect_t prect;
251 gfx_rect_t dr;
252 gfx_rect_t pr;
253 gfx_context_t *gc;
254
255 /*
256 * Get preview rectangle. If the window is not being resized/moved,
257 * we should get an empty rectangle.
258 */
259 ds_window_get_preview_rect(wnd, &prect);
260 if (gfx_rect_is_empty(&prect)) {
261 /* There is nothing to paint */
262 return EOK;
263 }
264
265 rc = gfx_color_new_rgb_i16(0xffff, 0xffff, 0xffff, &color);
266 if (rc != EOK)
267 return rc;
268
269 gc = ds_display_get_gc(wnd->display);
270 if (gc != NULL) {
271 gfx_set_color(gc, color);
272
273 /*
274 * TODO: Ideally we'd want XOR operation to make the preview
275 * frame visible on any background. If we wanted to get really
276 * fancy, we'd fill it with a pattern
277 */
278
279 pr.p0.x = prect.p0.x;
280 pr.p0.y = prect.p0.y;
281 pr.p1.x = prect.p1.x;
282 pr.p1.y = prect.p0.y + 1;
283 gfx_rect_clip(&pr, rect, &dr);
284 gfx_fill_rect(gc, &dr);
285
286 pr.p0.x = prect.p0.x;
287 pr.p0.y = prect.p1.y - 1;
288 pr.p1.x = prect.p1.x;
289 pr.p1.y = prect.p1.y;
290 gfx_rect_clip(&pr, rect, &dr);
291 gfx_fill_rect(gc, &dr);
292
293 pr.p0.x = prect.p0.x;
294 pr.p0.y = prect.p0.y;
295 pr.p1.x = prect.p0.x + 1;
296 pr.p1.y = prect.p1.y;
297 gfx_rect_clip(&pr, rect, &dr);
298 gfx_fill_rect(gc, &dr);
299
300 pr.p0.x = prect.p1.x - 1;
301 pr.p0.y = prect.p0.y;
302 pr.p1.x = prect.p1.x;
303 pr.p1.y = prect.p1.y;
304 gfx_rect_clip(&pr, rect, &dr);
305 gfx_fill_rect(gc, &dr);
306
307 }
308
309 gfx_color_delete(color);
310 return EOK;
311}
312
313/** Repaint window preview when resizing or moving.
314 *
315 * Repaint the window preview wich was previously at rectangle @a old_rect.
316 * The current preview rectangle is determined from window state. If
317 * the window did not previously have a preview, @a old_rect should point
318 * to an empty rectangle or be NULL. When window has finished
319 * moving or resizing, the preview will be cleared.
320 *
321 * @param wnd Window for which to paint preview
322 * @param rect Clipping rectangle
323 * @return EOK on success or an error code
324 */
325static errno_t ds_window_repaint_preview(ds_window_t *wnd, gfx_rect_t *old_rect)
326{
327 errno_t rc;
328 gfx_rect_t prect;
329 gfx_rect_t envelope;
330 bool oldr;
331 bool newr;
332
333 log_msg(LOG_DEFAULT, LVL_DEBUG, "ds_window_repaint_preview");
334
335 /*
336 * Get current preview rectangle. If the window is not being resized/moved,
337 * we should get an empty rectangle.
338 */
339 ds_window_get_preview_rect(wnd, &prect);
340
341 oldr = (old_rect != NULL) && !gfx_rect_is_empty(old_rect);
342 newr = !gfx_rect_is_empty(&prect);
343
344 if (oldr && newr && gfx_rect_is_incident(old_rect, &prect)) {
345 /*
346 * As an optimization, repaint both rectangles in a single
347 * operation.
348 */
349
350 gfx_rect_envelope(old_rect, &prect, &envelope);
351
352 rc = ds_display_paint(wnd->display, &envelope);
353 if (rc != EOK)
354 return rc;
355 } else {
356 /* Repaint each rectangle separately */
357 if (oldr) {
358 rc = ds_display_paint(wnd->display, old_rect);
359 if (rc != EOK)
360 return rc;
361 }
362
363 if (newr) {
364 rc = ds_display_paint(wnd->display, &prect);
365 if (rc != EOK)
366 return rc;
367 }
368 }
369
370 return EOK;
371}
372
373/** Start moving a window by mouse drag.
374 *
375 * @param wnd Window
376 * @param pos Position where mouse button was pressed
377 */
378static void ds_window_start_move(ds_window_t *wnd, gfx_coord2_t *pos)
379{
380 log_msg(LOG_DEFAULT, LVL_DEBUG, "ds_window_start_move (%d, %d)",
381 (int) pos->x, (int) pos->y);
382
383 if (wnd->state != dsw_idle)
384 return;
385
386 wnd->orig_pos = *pos;
387 wnd->state = dsw_moving;
388 wnd->preview_pos = wnd->dpos;
389
390 (void) ds_window_repaint_preview(wnd, NULL);
391}
392
393/** Finish moving a window by mouse drag.
394 *
395 * @param wnd Window
396 * @param pos Position where mouse button was released
397 */
398static void ds_window_finish_move(ds_window_t *wnd, gfx_coord2_t *pos)
399{
400 gfx_coord2_t dmove;
401 gfx_coord2_t nwpos;
402 gfx_rect_t old_rect;
403
404 log_msg(LOG_DEFAULT, LVL_DEBUG, "ds_window_finish_move (%d, %d)",
405 (int) pos->x, (int) pos->y);
406
407 assert(wnd->state == dsw_moving);
408
409 gfx_coord2_subtract(pos, &wnd->orig_pos, &dmove);
410 gfx_coord2_add(&wnd->dpos, &dmove, &nwpos);
411
412 ds_window_get_preview_rect(wnd, &old_rect);
413
414 wnd->dpos = nwpos;
415 wnd->state = dsw_idle;
416
417 (void) ds_display_paint(wnd->display, NULL);
418}
419
420/** Update window position when moving by mouse drag.
421 *
422 * @param wnd Window
423 * @param pos Current mouse position
424 */
425static void ds_window_update_move(ds_window_t *wnd, gfx_coord2_t *pos)
426{
427 gfx_coord2_t dmove;
428 gfx_coord2_t nwpos;
429 gfx_rect_t old_rect;
430
431 log_msg(LOG_DEFAULT, LVL_DEBUG, "ds_window_update_move (%d, %d)",
432 (int) pos->x, (int) pos->y);
433
434 assert(wnd->state == dsw_moving);
435
436 gfx_coord2_subtract(pos, &wnd->orig_pos, &dmove);
437 gfx_coord2_add(&wnd->dpos, &dmove, &nwpos);
438
439 ds_window_get_preview_rect(wnd, &old_rect);
440 wnd->preview_pos = nwpos;
441
442 (void) ds_window_repaint_preview(wnd, &old_rect);
443}
444
445/** Start resizing a window by mouse drag.
446 *
447 * @param wnd Window
448 * @param rsztype Resize type (which part of window is being dragged)
449 * @param pos Position where mouse button was pressed
450 */
451static void ds_window_start_resize(ds_window_t *wnd,
452 display_wnd_rsztype_t rsztype, gfx_coord2_t *pos)
453{
454 ds_seat_t *seat;
455 display_stock_cursor_t ctype;
456
457 log_msg(LOG_DEFAULT, LVL_DEBUG, "ds_window_start_resize (%d, %d)",
458 (int) pos->x, (int) pos->y);
459
460 if (wnd->state != dsw_idle)
461 return;
462
463 wnd->orig_pos = *pos;
464 wnd->state = dsw_resizing;
465 wnd->rsztype = rsztype;
466 wnd->preview_rect = wnd->rect;
467
468 // XXX Need client to tell us which seat started the resize!
469 seat = ds_display_first_seat(wnd->display);
470 ctype = display_cursor_from_wrsz(rsztype);
471 ds_seat_set_wm_cursor(seat, wnd->display->cursor[ctype]);
472
473 (void) ds_window_repaint_preview(wnd, NULL);
474}
475
476/** Finish resizing a window by mouse drag.
477 *
478 * @param wnd Window
479 * @param pos Position where mouse button was released
480 */
481static void ds_window_finish_resize(ds_window_t *wnd, gfx_coord2_t *pos)
482{
483 gfx_coord2_t dresize;
484 gfx_rect_t nrect;
485 ds_seat_t *seat;
486
487 log_msg(LOG_DEFAULT, LVL_DEBUG, "ds_window_finish_resize (%d, %d)",
488 (int) pos->x, (int) pos->y);
489
490 assert(wnd->state == dsw_resizing);
491 gfx_coord2_subtract(pos, &wnd->orig_pos, &dresize);
492
493 /* Compute new rectangle */
494 ds_window_calc_resize(wnd, &dresize, &nrect);
495
496 wnd->state = dsw_idle;
497 ds_client_post_resize_event(wnd->client, wnd, &nrect);
498
499 // XXX Need to know which seat started the resize!
500 seat = ds_display_first_seat(wnd->display);
501 ds_seat_set_wm_cursor(seat, NULL);
502
503 (void) ds_display_paint(wnd->display, NULL);
504}
505
506/** Update window position when resizing by mouse drag.
507 *
508 * @param wnd Window
509 * @param pos Current mouse position
510 */
511static void ds_window_update_resize(ds_window_t *wnd, gfx_coord2_t *pos)
512{
513 gfx_coord2_t dresize;
514 gfx_rect_t nrect;
515 gfx_rect_t old_rect;
516
517 log_msg(LOG_DEFAULT, LVL_DEBUG, "ds_window_update_resize (%d, %d)",
518 (int) pos->x, (int) pos->y);
519
520 assert(wnd->state == dsw_resizing);
521
522 gfx_coord2_subtract(pos, &wnd->orig_pos, &dresize);
523 ds_window_calc_resize(wnd, &dresize, &nrect);
524
525 ds_window_get_preview_rect(wnd, &old_rect);
526 wnd->preview_rect = nrect;
527 (void) ds_window_repaint_preview(wnd, &old_rect);
528}
529
530/** Post keyboard event to window.
531 *
532 * @param wnd Window
533 * @param event Event
534 *
535 * @return EOK on success or an error code
536 */
537errno_t ds_window_post_kbd_event(ds_window_t *wnd, kbd_event_t *event)
538{
539 bool alt_or_shift;
540
541 alt_or_shift = event->mods & (KM_SHIFT | KM_ALT);
542
543 if (event->type == KEY_PRESS && alt_or_shift && event->key == KC_F4) {
544 /* On Alt-F4 or Shift-F4 send close event to the window */
545 ds_client_post_close_event(wnd->client, wnd);
546 return EOK;
547 }
548
549 return ds_client_post_kbd_event(wnd->client, wnd, event);
550}
551
552/** Post position event to window.
553 *
554 * @param wnd Window
555 * @param event Position event
556 */
557errno_t ds_window_post_pos_event(ds_window_t *wnd, pos_event_t *event)
558{
559 pos_event_t tevent;
560 gfx_coord2_t pos;
561 gfx_rect_t drect;
562 bool inside;
563
564 log_msg(LOG_DEFAULT, LVL_DEBUG,
565 "ds_window_post_pos_event type=%d pos=%d,%d", event->type,
566 (int) event->hpos, (int) event->vpos);
567
568 pos.x = event->hpos;
569 pos.y = event->vpos;
570 gfx_rect_translate(&wnd->dpos, &wnd->rect, &drect);
571 inside = gfx_pix_inside_rect(&pos, &drect);
572
573 if (event->type == POS_PRESS && event->btn_num == 2 && inside) {
574 ds_window_start_move(wnd, &pos);
575 return EOK;
576 }
577
578 if (event->type == POS_RELEASE) {
579 if (wnd->state == dsw_moving) {
580 ds_window_finish_move(wnd, &pos);
581 return EOK;
582 }
583
584 if (wnd->state == dsw_resizing) {
585 ds_window_finish_resize(wnd, &pos);
586 return EOK;
587 }
588 }
589
590 if (event->type == POS_UPDATE) {
591 if (wnd->state == dsw_moving) {
592 ds_window_update_move(wnd, &pos);
593 return EOK;
594 }
595
596 if (wnd->state == dsw_resizing) {
597 ds_window_update_resize(wnd, &pos);
598 return EOK;
599 }
600 }
601
602 /* Transform event coordinates to window-local */
603 tevent = *event;
604 tevent.hpos -= wnd->dpos.x;
605 tevent.vpos -= wnd->dpos.y;
606
607 return ds_client_post_pos_event(wnd->client, wnd, &tevent);
608}
609
610/** Post focus event to window.
611 *
612 * @param wnd Window
613 */
614errno_t ds_window_post_focus_event(ds_window_t *wnd)
615{
616 log_msg(LOG_DEFAULT, LVL_DEBUG, "ds_window_post_focus_event");
617
618 return ds_client_post_focus_event(wnd->client, wnd);
619}
620
621/** Post unfocus event to window.
622 *
623 * @param wnd Window
624 */
625errno_t ds_window_post_unfocus_event(ds_window_t *wnd)
626{
627 log_msg(LOG_DEFAULT, LVL_DEBUG, "ds_window_post_unfocus_event");
628
629 return ds_client_post_unfocus_event(wnd->client, wnd);
630}
631
632/** Start moving a window, detected by client.
633 *
634 * @param wnd Window
635 * @param pos Position where the pointer was when the move started
636 * relative to the window
637 * @param event Button press event
638 */
639void ds_window_move_req(ds_window_t *wnd, gfx_coord2_t *pos)
640{
641 gfx_coord2_t orig_pos;
642
643 log_msg(LOG_DEFAULT, LVL_DEBUG, "ds_window_move_req (%d, %d)",
644 (int) pos->x, (int) pos->y);
645
646 gfx_coord2_add(&wnd->dpos, pos, &orig_pos);
647 ds_window_start_move(wnd, &orig_pos);
648}
649
650/** Move window.
651 *
652 * @param wnd Window
653 */
654void ds_window_move(ds_window_t *wnd, gfx_coord2_t *dpos)
655{
656 wnd->dpos = *dpos;
657 (void) ds_display_paint(wnd->display, NULL);
658}
659
660/** Start resizing a window, detected by client.
661 *
662 * @param wnd Window
663 * @param rsztype Resize type (which part of window is being dragged)
664 * @param pos Position where the pointer was when the resize started
665 * relative to the window
666 * @param event Button press event
667 */
668void ds_window_resize_req(ds_window_t *wnd, display_wnd_rsztype_t rsztype,
669 gfx_coord2_t *pos)
670{
671 gfx_coord2_t orig_pos;
672
673 log_msg(LOG_DEFAULT, LVL_DEBUG, "ds_window_resize_req (%d, %d, %d)",
674 (int) rsztype, (int) pos->x, (int) pos->y);
675
676 gfx_coord2_add(&wnd->dpos, pos, &orig_pos);
677 ds_window_start_resize(wnd, rsztype, &orig_pos);
678}
679
680/** Resize window.
681 *
682 * @param wnd Window
683 */
684errno_t ds_window_resize(ds_window_t *wnd, gfx_coord2_t *offs,
685 gfx_rect_t *nrect)
686{
687 gfx_context_t *dgc;
688 gfx_bitmap_params_t bparams;
689 gfx_bitmap_t *nbitmap;
690 pixelmap_t npixelmap;
691 gfx_coord2_t dims;
692 gfx_bitmap_alloc_t alloc;
693 gfx_coord2_t ndpos;
694 errno_t rc;
695
696 dgc = ds_display_get_gc(wnd->display);
697 if (dgc != NULL) {
698 gfx_bitmap_params_init(&bparams);
699 bparams.rect = *nrect;
700
701 rc = gfx_bitmap_create(dgc, &bparams, NULL, &nbitmap);
702 if (rc != EOK)
703 return ENOMEM;
704
705 rc = gfx_bitmap_get_alloc(nbitmap, &alloc);
706 if (rc != EOK) {
707 gfx_bitmap_destroy(nbitmap);
708 return ENOMEM;
709 }
710
711 gfx_rect_dims(nrect, &dims);
712 npixelmap.width = dims.x;
713 npixelmap.height = dims.y;
714 npixelmap.data = alloc.pixels;
715
716 /* TODO: Transfer contents within overlap */
717
718 if (wnd->bitmap != NULL)
719 gfx_bitmap_destroy(wnd->bitmap);
720
721 wnd->bitmap = nbitmap;
722 wnd->pixelmap = npixelmap;
723
724 /* Point memory GC to the new bitmap */
725 mem_gc_retarget(wnd->mgc, nrect, &alloc);
726 }
727
728 gfx_coord2_add(&wnd->dpos, offs, &ndpos);
729
730 wnd->dpos = ndpos;
731 wnd->rect = *nrect;
732
733 (void) ds_display_paint(wnd->display, NULL);
734 return EOK;
735}
736
737/** Compute new window rectangle after resize operation.
738 *
739 * @param wnd Window which is being resized (in dsw_resizing state and thus
740 * has rsztype set)
741 * @param dresize Amount by which to resize
742 * @param nrect Place to store new rectangle
743 */
744void ds_window_calc_resize(ds_window_t *wnd, gfx_coord2_t *dresize,
745 gfx_rect_t *nrect)
746{
747 if ((wnd->rsztype & display_wr_top) != 0) {
748 nrect->p0.y = min(wnd->rect.p0.y + dresize->y,
749 wnd->rect.p1.y - wnd->min_size.y);
750 } else {
751 nrect->p0.y = wnd->rect.p0.y;
752 }
753
754 if ((wnd->rsztype & display_wr_left) != 0) {
755 nrect->p0.x = min(wnd->rect.p0.x + dresize->x,
756 wnd->rect.p1.x - wnd->min_size.x);
757 } else {
758 nrect->p0.x = wnd->rect.p0.x;
759 }
760
761 if ((wnd->rsztype & display_wr_bottom) != 0) {
762 nrect->p1.y = max(wnd->rect.p1.y + dresize->y,
763 wnd->rect.p0.y + wnd->min_size.y);
764 } else {
765 nrect->p1.y = wnd->rect.p1.y;
766 }
767
768 if ((wnd->rsztype & display_wr_right) != 0) {
769 nrect->p1.x = max(wnd->rect.p1.x + dresize->x,
770 wnd->rect.p0.x + wnd->min_size.x);
771 } else {
772 nrect->p1.x = wnd->rect.p1.x;
773 }
774}
775
776/** Set window cursor.
777 *
778 * @param wnd Window
779 * @return EOK on success, EINVAL if @a cursor is invalid
780 */
781errno_t ds_window_set_cursor(ds_window_t *wnd, display_stock_cursor_t cursor)
782{
783 if (cursor >= dcurs_arrow &&
784 cursor < (display_stock_cursor_t) dcurs_limit) {
785 wnd->cursor = wnd->display->cursor[cursor];
786 return EOK;
787 } else {
788 return EINVAL;
789 }
790}
791
792/** Window memory GC invalidate callback.
793 *
794 * This is called by the window's memory GC when a rectangle is modified.
795 */
796static void ds_window_invalidate_cb(void *arg, gfx_rect_t *rect)
797{
798 ds_window_t *wnd = (ds_window_t *)arg;
799 gfx_rect_t drect;
800
801 /* Repaint the corresponding part of the display */
802
803 gfx_rect_translate(&wnd->dpos, rect, &drect);
804 ds_display_lock(wnd->display);
805 (void) ds_display_paint(wnd->display, &drect);
806 ds_display_unlock(wnd->display);
807}
808
809/** Window memory GC update callback.
810 *
811 * This is called by the window's memory GC when it is to be updated.
812 */
813static void ds_window_update_cb(void *arg)
814{
815 ds_window_t *wnd = (ds_window_t *)arg;
816
817 (void) wnd;
818}
819
820/** @}
821 */
Note: See TracBrowser for help on using the repository browser.