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
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
[1bebc906]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 }
[b4b4dafe]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
[6af4b4f]139 *rgc = wnd;
[c8cf261]140 return EOK;
141error:
[946a666]142 if (wnd != NULL) {
143 if (wnd->bitmap != NULL)
144 gfx_bitmap_destroy(wnd->bitmap);
[6af4b4f]145 free(wnd);
[946a666]146 }
147
[c8cf261]148 return rc;
149}
150
[0e6e77f]151/** Destroy window.
[c8cf261]152 *
[0e6e77f]153 * @param wnd Window
[c8cf261]154 */
[da412547]155void ds_window_destroy(ds_window_t *wnd)
[c8cf261]156{
[cc90846]157 ds_display_t *disp;
158
159 disp = wnd->display;
160
[b3c185b6]161 ds_client_remove_window(wnd);
[fd777a2]162 ds_display_remove_window(wnd);
[cc90846]163
[dbef30f]164 mem_gc_delete(wnd->mgc);
165
[946a666]166 if (wnd->bitmap != NULL)
167 gfx_bitmap_destroy(wnd->bitmap);
[c8cf261]168
[6af4b4f]169 free(wnd);
[cc90846]170
171 (void) ds_display_paint(disp, NULL);
[c8cf261]172}
173
[1a1271d]174/** Bring window to top.
175 *
176 * @param wnd Window
177 */
[b5c7cee]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);
[2e0a2e7]184 (void) ds_display_paint(wnd->display, NULL);
[b5c7cee]185}
186
[6af4b4f]187/** Get generic graphic context from window.
[c8cf261]188 *
[6af4b4f]189 * @param wnd Window
[c8cf261]190 * @return Graphic context
191 */
[6af4b4f]192gfx_context_t *ds_window_get_ctx(ds_window_t *wnd)
[c8cf261]193{
[6af4b4f]194 return wnd->gc;
[c8cf261]195}
196
[2012fe0]197/** Paint a window using its backing bitmap.
[946a666]198 *
[2012fe0]199 * @param wnd Window to paint
200 * @param rect Display rectangle to paint to
[946a666]201 * @return EOK on success or an error code
202 */
[2012fe0]203errno_t ds_window_paint(ds_window_t *wnd, gfx_rect_t *rect)
[946a666]204{
[2012fe0]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 */
[01c2759]215 gfx_rect_clip(&srect, &wnd->rect, &crect);
[2012fe0]216 if (gfx_rect_is_empty(&crect))
217 return EOK;
218
219 brect = &srect;
220 } else {
221 brect = NULL;
222 }
223
[f5191b4]224 /* This can happen in unit tests */
225 if (wnd->bitmap == NULL)
226 return EOK;
227
[2012fe0]228 return gfx_bitmap_render(wnd->bitmap, brect, &wnd->dpos);
[946a666]229}
230
[6301a24f]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.
[a40ae0d]235 *
236 * @param wnd Window
[6301a24f]237 * @param rect Place to store preview rectangle
[a40ae0d]238 */
[6301a24f]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)
[a40ae0d]268{
[6301a24f]269 errno_t rc;
[1b443cc0]270 gfx_color_t *color;
[6301a24f]271 gfx_rect_t prect;
[a65b0c8]272 gfx_rect_t dr;
273 gfx_rect_t pr;
[6301a24f]274 gfx_context_t *gc;
[1b443cc0]275
[6301a24f]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 }
[a40ae0d]285
[1b443cc0]286 rc = gfx_color_new_rgb_i16(0xffff, 0xffff, 0xffff, &color);
287 if (rc != EOK)
[6301a24f]288 return rc;
[1b443cc0]289
[84e74ea]290 gc = ds_display_get_gc(wnd->display);
[1b443cc0]291 if (gc != NULL) {
292 gfx_set_color(gc, color);
[a65b0c8]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
[1b443cc0]328 }
329
330 gfx_color_delete(color);
[6301a24f]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);
[a40ae0d]412}
413
414/** Finish moving a window by mouse drag.
415 *
416 * @param wnd Window
[76a02db]417 * @param pos Position where mouse button was released
[a40ae0d]418 */
[76a02db]419static void ds_window_finish_move(ds_window_t *wnd, gfx_coord2_t *pos)
[a40ae0d]420{
421 gfx_coord2_t dmove;
422 gfx_coord2_t nwpos;
[6301a24f]423 gfx_rect_t old_rect;
[a40ae0d]424
425 log_msg(LOG_DEFAULT, LVL_DEBUG, "ds_window_finish_move (%d, %d)",
[76a02db]426 (int) pos->x, (int) pos->y);
[a40ae0d]427
[5f483be]428 assert(wnd->state == dsw_moving);
[a2e104e]429
[76a02db]430 gfx_coord2_subtract(pos, &wnd->orig_pos, &dmove);
[a40ae0d]431 gfx_coord2_add(&wnd->dpos, &dmove, &nwpos);
[6301a24f]432
433 ds_window_get_preview_rect(wnd, &old_rect);
434
[a40ae0d]435 wnd->dpos = nwpos;
436 wnd->state = dsw_idle;
[946a666]437
[2012fe0]438 (void) ds_display_paint(wnd->display, NULL);
[a40ae0d]439}
440
441/** Update window position when moving by mouse drag.
442 *
443 * @param wnd Window
[76a02db]444 * @param pos Current mouse position
[a40ae0d]445 */
[76a02db]446static void ds_window_update_move(ds_window_t *wnd, gfx_coord2_t *pos)
[a40ae0d]447{
448 gfx_coord2_t dmove;
449 gfx_coord2_t nwpos;
[6301a24f]450 gfx_rect_t old_rect;
[a40ae0d]451
452 log_msg(LOG_DEFAULT, LVL_DEBUG, "ds_window_update_move (%d, %d)",
[76a02db]453 (int) pos->x, (int) pos->y);
[a40ae0d]454
[5f483be]455 assert(wnd->state == dsw_moving);
[a2e104e]456
[76a02db]457 gfx_coord2_subtract(pos, &wnd->orig_pos, &dmove);
[a40ae0d]458 gfx_coord2_add(&wnd->dpos, &dmove, &nwpos);
[c79545e]459
[6301a24f]460 ds_window_get_preview_rect(wnd, &old_rect);
461 wnd->preview_pos = nwpos;
[a40ae0d]462
[6301a24f]463 (void) ds_window_repaint_preview(wnd, &old_rect);
[a40ae0d]464}
465
[76a02db]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{
[9901f267]475 ds_seat_t *seat;
476 display_stock_cursor_t ctype;
477
[76a02db]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;
[71eff34]487 wnd->preview_rect = wnd->rect;
[9901f267]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]);
[6301a24f]493
494 (void) ds_window_repaint_preview(wnd, NULL);
[76a02db]495}
496
[e022819]497/** Finish resizing a window by mouse drag.
498 *
499 * @param wnd Window
[76a02db]500 * @param pos Position where mouse button was released
[e022819]501 */
[76a02db]502static void ds_window_finish_resize(ds_window_t *wnd, gfx_coord2_t *pos)
[e022819]503{
504 gfx_coord2_t dresize;
505 gfx_rect_t nrect;
[9901f267]506 ds_seat_t *seat;
[e022819]507
508 log_msg(LOG_DEFAULT, LVL_DEBUG, "ds_window_finish_resize (%d, %d)",
[76a02db]509 (int) pos->x, (int) pos->y);
[e022819]510
[5f483be]511 assert(wnd->state == dsw_resizing);
[76a02db]512 gfx_coord2_subtract(pos, &wnd->orig_pos, &dresize);
[e022819]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);
[9901f267]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);
[6301a24f]523
524 (void) ds_display_paint(wnd->display, NULL);
[e022819]525}
526
527/** Update window position when resizing by mouse drag.
528 *
529 * @param wnd Window
[76a02db]530 * @param pos Current mouse position
[e022819]531 */
[76a02db]532static void ds_window_update_resize(ds_window_t *wnd, gfx_coord2_t *pos)
[e022819]533{
534 gfx_coord2_t dresize;
535 gfx_rect_t nrect;
[6301a24f]536 gfx_rect_t old_rect;
[e022819]537
538 log_msg(LOG_DEFAULT, LVL_DEBUG, "ds_window_update_resize (%d, %d)",
[76a02db]539 (int) pos->x, (int) pos->y);
[e022819]540
[5f483be]541 assert(wnd->state == dsw_resizing);
[e022819]542
[76a02db]543 gfx_coord2_subtract(pos, &wnd->orig_pos, &dresize);
[e022819]544 ds_window_calc_resize(wnd, &dresize, &nrect);
545
[6301a24f]546 ds_window_get_preview_rect(wnd, &old_rect);
547 wnd->preview_rect = nrect;
548 (void) ds_window_repaint_preview(wnd, &old_rect);
[e022819]549}
550
[338d0935]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
[a40ae0d]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{
[f7fb2b21]580 pos_event_t tevent;
[a2e104e]581 gfx_coord2_t pos;
582 gfx_rect_t drect;
583 bool inside;
[f7fb2b21]584
[a40ae0d]585 log_msg(LOG_DEFAULT, LVL_DEBUG,
[78445be8]586 "ds_window_post_pos_event type=%d pos=%d,%d", event->type,
[a40ae0d]587 (int) event->hpos, (int) event->vpos);
588
[a2e104e]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);
[a40ae0d]593
[5f483be]594 if (event->type == POS_PRESS && event->btn_num == 2 && inside) {
[76a02db]595 ds_window_start_move(wnd, &pos);
[5f483be]596 return EOK;
597 }
[a40ae0d]598
[e022819]599 if (event->type == POS_RELEASE) {
[5f483be]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 }
[e022819]609 }
[a2e104e]610
[e022819]611 if (event->type == POS_UPDATE) {
[5f483be]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 }
[e022819]621 }
[a40ae0d]622
[f7fb2b21]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);
[a40ae0d]629}
630
[b0a94854]631/** Post focus event to window.
632 *
633 * @param wnd Window
634 */
635errno_t ds_window_post_focus_event(ds_window_t *wnd)
636{
[78445be8]637 log_msg(LOG_DEFAULT, LVL_DEBUG, "ds_window_post_focus_event");
[b0a94854]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{
[78445be8]648 log_msg(LOG_DEFAULT, LVL_DEBUG, "ds_window_post_unfocus_event");
[b0a94854]649
650 return ds_client_post_unfocus_event(wnd->client, wnd);
651}
652
[e022819]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{
[76a02db]662 gfx_coord2_t orig_pos;
663
[e022819]664 log_msg(LOG_DEFAULT, LVL_DEBUG, "ds_window_move_req (%d, %d)",
665 (int) pos->x, (int) pos->y);
666
[76a02db]667 gfx_coord2_add(&wnd->dpos, pos, &orig_pos);
668 ds_window_start_move(wnd, &orig_pos);
[e022819]669}
670
[0680854]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
[6baab83]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
[e022819]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{
[76a02db]701 gfx_coord2_t orig_pos;
702
[195b7b3]703 log_msg(LOG_DEFAULT, LVL_DEBUG, "ds_window_resize_req (%d, %d, %d)",
[e022819]704 (int) rsztype, (int) pos->x, (int) pos->y);
705
[76a02db]706 gfx_coord2_add(&wnd->dpos, pos, &orig_pos);
707 ds_window_start_resize(wnd, rsztype, &orig_pos);
[e022819]708}
709
[0680854]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
[84e74ea]726 dgc = ds_display_get_gc(wnd->display);
[0680854]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;
[dbef30f]753
754 /* Point memory GC to the new bitmap */
755 mem_gc_retarget(wnd->mgc, nrect, &alloc);
[0680854]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
[e022819]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{
[9b502dd]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 }
[e022819]804}
805
[9242ad9]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
[2ab8ab3]822/** Window memory GC invalidate callback.
[dbef30f]823 *
[2ab8ab3]824 * This is called by the window's memory GC when a rectangle is modified.
[dbef30f]825 */
[2ab8ab3]826static void ds_window_invalidate_cb(void *arg, gfx_rect_t *rect)
[dbef30f]827{
828 ds_window_t *wnd = (ds_window_t *)arg;
829 gfx_rect_t drect;
830
831 /* Repaint the corresponding part of the display */
[d74a2b8]832
[dbef30f]833 gfx_rect_translate(&wnd->dpos, rect, &drect);
[d74a2b8]834 ds_display_lock(wnd->display);
[dbef30f]835 (void) ds_display_paint(wnd->display, &drect);
[d74a2b8]836 ds_display_unlock(wnd->display);
[dbef30f]837}
838
[2ab8ab3]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
[c8cf261]850/** @}
851 */
Note: See TracBrowser for help on using the repository browser.