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

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

Deliver WM events for windows being added and removed

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