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

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

Update window button when window caption changes

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