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

Last change on this file since 1bebc906 was 1bebc906, checked in by Jiri Svoboda <jiri@…>, 4 years ago

Allow setting initial window position (instead of moving the window)

To reduce display artifacts. We can create the menu popup windows
in the correct place from the start. The same goes for regular
windows with specific placement.

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