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

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

Adjust message verbosity levels in display server

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