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

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

Popup windows event delivery is special

Popup windows don't get focus, yet they still receive events.

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