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

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

Add missing deallocations in error paths of ds_window_create()

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