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

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

Need to lock display while updating window

This was causing flicker issues because updating window raced with other
rendering (e.g. painting mouse pointer or previewing window move).

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