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

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

Implement bitmap color key to allow transparent cursor background

This seems to be the simplest solution of them all. It will work
on any bit depth except 1 bit per pixel (monochrome), where we would
need to extend the bitmap with a bit mask instead.

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