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

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

Maximizing/unmaximizing a window

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