source: mainline/uspace/srv/hid/compositor/compositor.c@ f1380b7

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since f1380b7 was a35b458, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 7 years ago

style: Remove trailing whitespace on _all_ lines, including empty ones, for particular file types.

Command used: tools/srepl '\s\+$' '' -- *.c *.h *.py *.sh *.s *.S *.ag

Currently, whitespace on empty lines is very inconsistent.
There are two basic choices: Either remove the whitespace, or keep empty lines
indented to the level of surrounding code. The former is AFAICT more common,
and also much easier to do automatically.

Alternatively, we could write script for automatic indentation, and use that
instead. However, if such a script exists, it's possible to use the indented
style locally, by having the editor apply relevant conversions on load/save,
without affecting remote repository. IMO, it makes more sense to adopt
the simpler rule.

  • Property mode set to 100644
File size: 62.0 KB
Line 
1/*
2 * Copyright (c) 2012 Petr Koupy
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 compositor
30 * @{
31 */
32/** @file
33 */
34
35#include <stddef.h>
36#include <stdint.h>
37#include <stdbool.h>
38#include <errno.h>
39#include <str_error.h>
40#include <byteorder.h>
41#include <stdio.h>
42#include <libc.h>
43
44#include <align.h>
45#include <as.h>
46#include <stdlib.h>
47
48#include <atomic.h>
49#include <fibril_synch.h>
50#include <adt/prodcons.h>
51#include <adt/list.h>
52#include <io/input.h>
53#include <ipc/graph.h>
54#include <ipc/window.h>
55
56#include <async.h>
57#include <loc.h>
58#include <task.h>
59
60#include <io/keycode.h>
61#include <io/mode.h>
62#include <io/visualizer.h>
63#include <io/window.h>
64#include <io/console.h>
65
66#include <transform.h>
67#include <rectangle.h>
68#include <surface.h>
69#include <cursor.h>
70#include <source.h>
71#include <drawctx.h>
72#include <codec/tga.h>
73
74#include "compositor.h"
75
76#define NAME "compositor"
77#define NAMESPACE "comp"
78
79/* Until there is blitter support and some further optimizations, window
80 * animations are too slow to be practically usable. */
81#ifndef ANIMATE_WINDOW_TRANSFORMS
82#define ANIMATE_WINDOW_TRANSFORMS 0
83#endif
84
85static char *server_name;
86static sysarg_t coord_origin;
87static pixel_t bg_color;
88static filter_t filter = filter_bilinear;
89static unsigned int filter_index = 1;
90
91typedef struct {
92 link_t link;
93 atomic_t ref_cnt;
94 window_flags_t flags;
95 service_id_t in_dsid;
96 service_id_t out_dsid;
97 prodcons_t queue;
98 transform_t transform;
99 double dx;
100 double dy;
101 double fx;
102 double fy;
103 double angle;
104 uint8_t opacity;
105 surface_t *surface;
106} window_t;
107
108static service_id_t winreg_id;
109static sysarg_t window_id = 0;
110static FIBRIL_MUTEX_INITIALIZE(window_list_mtx);
111static LIST_INITIALIZE(window_list);
112static double scale_back_x;
113static double scale_back_y;
114
115typedef struct {
116 link_t link;
117 sysarg_t id;
118 uint8_t state;
119 desktop_point_t pos;
120 sysarg_t btn_num;
121 desktop_point_t btn_pos;
122 desktop_vector_t accum;
123 sysarg_t grab_flags;
124 bool pressed;
125 cursor_t cursor;
126 window_t ghost;
127 desktop_vector_t accum_ghost;
128} pointer_t;
129
130static sysarg_t pointer_id = 0;
131static FIBRIL_MUTEX_INITIALIZE(pointer_list_mtx);
132static LIST_INITIALIZE(pointer_list);
133
134typedef struct {
135 link_t link;
136 service_id_t dsid;
137 vslmode_t mode;
138 async_sess_t *sess;
139 desktop_point_t pos;
140 surface_t *surface;
141} viewport_t;
142
143static desktop_rect_t viewport_bound_rect;
144static FIBRIL_MUTEX_INITIALIZE(viewport_list_mtx);
145static LIST_INITIALIZE(viewport_list);
146
147static FIBRIL_MUTEX_INITIALIZE(discovery_mtx);
148
149/** Input server proxy */
150static input_t *input;
151static bool active = false;
152
153static errno_t comp_active(input_t *);
154static errno_t comp_deactive(input_t *);
155static errno_t comp_key_press(input_t *, kbd_event_type_t, keycode_t, keymod_t, wchar_t);
156static errno_t comp_mouse_move(input_t *, int, int);
157static errno_t comp_abs_move(input_t *, unsigned, unsigned, unsigned, unsigned);
158static errno_t comp_mouse_button(input_t *, int, int);
159
160static input_ev_ops_t input_ev_ops = {
161 .active = comp_active,
162 .deactive = comp_deactive,
163 .key = comp_key_press,
164 .move = comp_mouse_move,
165 .abs_move = comp_abs_move,
166 .button = comp_mouse_button
167};
168
169static pointer_t *input_pointer(input_t *input)
170{
171 return input->user;
172}
173
174static pointer_t *pointer_create(void)
175{
176 pointer_t *p = (pointer_t *) malloc(sizeof(pointer_t));
177 if (!p)
178 return NULL;
179
180 link_initialize(&p->link);
181 p->pos.x = coord_origin;
182 p->pos.y = coord_origin;
183 p->btn_num = 1;
184 p->btn_pos = p->pos;
185 p->accum.x = 0;
186 p->accum.y = 0;
187 p->grab_flags = GF_EMPTY;
188 p->pressed = false;
189 p->state = 0;
190 cursor_init(&p->cursor, CURSOR_DECODER_EMBEDDED, NULL);
191
192 /* Ghost window for transformation animation. */
193 transform_identity(&p->ghost.transform);
194 transform_translate(&p->ghost.transform, coord_origin, coord_origin);
195 p->ghost.dx = coord_origin;
196 p->ghost.dy = coord_origin;
197 p->ghost.fx = 1;
198 p->ghost.fy = 1;
199 p->ghost.angle = 0;
200 p->ghost.opacity = 255;
201 p->ghost.surface = NULL;
202 p->accum_ghost.x = 0;
203 p->accum_ghost.y = 0;
204
205 return p;
206}
207
208static void pointer_destroy(pointer_t *p)
209{
210 if (p) {
211 cursor_release(&p->cursor);
212 free(p);
213 }
214}
215
216static window_t *window_create(void)
217{
218 window_t *win = (window_t *) malloc(sizeof(window_t));
219 if (!win)
220 return NULL;
221
222 link_initialize(&win->link);
223 atomic_set(&win->ref_cnt, 0);
224 prodcons_initialize(&win->queue);
225 transform_identity(&win->transform);
226 transform_translate(&win->transform, coord_origin, coord_origin);
227 win->dx = coord_origin;
228 win->dy = coord_origin;
229 win->fx = 1;
230 win->fy = 1;
231 win->angle = 0;
232 win->opacity = 255;
233 win->surface = NULL;
234
235 return win;
236}
237
238static void window_destroy(window_t *win)
239{
240 if ((win) && (atomic_get(&win->ref_cnt) == 0)) {
241 while (!list_empty(&win->queue.list)) {
242 window_event_t *event = (window_event_t *) list_first(&win->queue.list);
243 list_remove(&event->link);
244 free(event);
245 }
246
247 if (win->surface)
248 surface_destroy(win->surface);
249
250 free(win);
251 }
252}
253
254static bool comp_coord_to_client(sysarg_t x_in, sysarg_t y_in, transform_t win_trans,
255 sysarg_t x_lim, sysarg_t y_lim, sysarg_t *x_out, sysarg_t *y_out)
256{
257 double x = x_in;
258 double y = y_in;
259 transform_invert(&win_trans);
260 transform_apply_affine(&win_trans, &x, &y);
261
262 /*
263 * Since client coordinate origin is (0, 0), it is necessary to check
264 * coordinates to avoid underflow. Moreover, it is convenient to also
265 * check against provided upper limits to determine whether the converted
266 * coordinates are within the client window.
267 */
268 if ((x < 0) || (y < 0))
269 return false;
270
271 (*x_out) = (sysarg_t) (x + 0.5);
272 (*y_out) = (sysarg_t) (y + 0.5);
273
274 if (((*x_out) >= x_lim) || ((*y_out) >= y_lim))
275 return false;
276
277 return true;
278}
279
280static void comp_coord_from_client(double x_in, double y_in, transform_t win_trans,
281 sysarg_t *x_out, sysarg_t *y_out)
282{
283 double x = x_in;
284 double y = y_in;
285 transform_apply_affine(&win_trans, &x, &y);
286
287 /*
288 * It is assumed that compositor coordinate origin is chosen in such way,
289 * that underflow/overflow here would be unlikely.
290 */
291 (*x_out) = (sysarg_t) (x + 0.5);
292 (*y_out) = (sysarg_t) (y + 0.5);
293}
294
295static void comp_coord_bounding_rect(double x_in, double y_in,
296 double w_in, double h_in, transform_t win_trans,
297 sysarg_t *x_out, sysarg_t *y_out, sysarg_t *w_out, sysarg_t *h_out)
298{
299 if ((w_in > 0) && (h_in > 0)) {
300 sysarg_t x[4];
301 sysarg_t y[4];
302
303 comp_coord_from_client(x_in, y_in, win_trans, &x[0], &y[0]);
304 comp_coord_from_client(x_in + w_in - 1, y_in, win_trans, &x[1], &y[1]);
305 comp_coord_from_client(x_in + w_in - 1, y_in + h_in - 1, win_trans, &x[2], &y[2]);
306 comp_coord_from_client(x_in, y_in + h_in - 1, win_trans, &x[3], &y[3]);
307
308 (*x_out) = x[0];
309 (*y_out) = y[0];
310 (*w_out) = x[0];
311 (*h_out) = y[0];
312
313 for (unsigned int i = 1; i < 4; ++i) {
314 (*x_out) = (x[i] < (*x_out)) ? x[i] : (*x_out);
315 (*y_out) = (y[i] < (*y_out)) ? y[i] : (*y_out);
316 (*w_out) = (x[i] > (*w_out)) ? x[i] : (*w_out);
317 (*h_out) = (y[i] > (*h_out)) ? y[i] : (*h_out);
318 }
319
320 (*w_out) = (*w_out) - (*x_out) + 1;
321 (*h_out) = (*h_out) - (*y_out) + 1;
322 } else {
323 (*x_out) = 0;
324 (*y_out) = 0;
325 (*w_out) = 0;
326 (*h_out) = 0;
327 }
328}
329
330static void comp_update_viewport_bound_rect(void)
331{
332 fibril_mutex_lock(&viewport_list_mtx);
333
334 sysarg_t x_res = coord_origin;
335 sysarg_t y_res = coord_origin;
336 sysarg_t w_res = 0;
337 sysarg_t h_res = 0;
338
339 if (!list_empty(&viewport_list)) {
340 viewport_t *vp = (viewport_t *) list_first(&viewport_list);
341 x_res = vp->pos.x;
342 y_res = vp->pos.y;
343 surface_get_resolution(vp->surface, &w_res, &h_res);
344 }
345
346 list_foreach(viewport_list, link, viewport_t, vp) {
347 sysarg_t w_vp, h_vp;
348 surface_get_resolution(vp->surface, &w_vp, &h_vp);
349 rectangle_union(x_res, y_res, w_res, h_res,
350 vp->pos.x, vp->pos.y, w_vp, h_vp,
351 &x_res, &y_res, &w_res, &h_res);
352 }
353
354 viewport_bound_rect.x = x_res;
355 viewport_bound_rect.y = y_res;
356 viewport_bound_rect.w = w_res;
357 viewport_bound_rect.h = h_res;
358
359 fibril_mutex_unlock(&viewport_list_mtx);
360}
361
362static void comp_restrict_pointers(void)
363{
364 comp_update_viewport_bound_rect();
365
366 fibril_mutex_lock(&pointer_list_mtx);
367
368 list_foreach(pointer_list, link, pointer_t, ptr) {
369 ptr->pos.x = ptr->pos.x > viewport_bound_rect.x ? ptr->pos.x : viewport_bound_rect.x;
370 ptr->pos.y = ptr->pos.y > viewport_bound_rect.y ? ptr->pos.y : viewport_bound_rect.y;
371 ptr->pos.x = ptr->pos.x < viewport_bound_rect.x + viewport_bound_rect.w ?
372 ptr->pos.x : viewport_bound_rect.x + viewport_bound_rect.w;
373 ptr->pos.y = ptr->pos.y < viewport_bound_rect.y + viewport_bound_rect.h ?
374 ptr->pos.y : viewport_bound_rect.y + viewport_bound_rect.h;
375 }
376
377 fibril_mutex_unlock(&pointer_list_mtx);
378}
379
380static void comp_damage(sysarg_t x_dmg_glob, sysarg_t y_dmg_glob,
381 sysarg_t w_dmg_glob, sysarg_t h_dmg_glob)
382{
383 fibril_mutex_lock(&viewport_list_mtx);
384 fibril_mutex_lock(&window_list_mtx);
385 fibril_mutex_lock(&pointer_list_mtx);
386
387 list_foreach(viewport_list, link, viewport_t, vp) {
388 /* Determine what part of the viewport must be updated. */
389 sysarg_t x_dmg_vp, y_dmg_vp, w_dmg_vp, h_dmg_vp;
390 surface_get_resolution(vp->surface, &w_dmg_vp, &h_dmg_vp);
391 bool isec_vp = rectangle_intersect(
392 x_dmg_glob, y_dmg_glob, w_dmg_glob, h_dmg_glob,
393 vp->pos.x, vp->pos.y, w_dmg_vp, h_dmg_vp,
394 &x_dmg_vp, &y_dmg_vp, &w_dmg_vp, &h_dmg_vp);
395
396 if (isec_vp) {
397
398 /* Paint background color. */
399 for (sysarg_t y = y_dmg_vp - vp->pos.y; y < y_dmg_vp - vp->pos.y + h_dmg_vp; ++y) {
400 pixel_t *dst = pixelmap_pixel_at(
401 surface_pixmap_access(vp->surface), x_dmg_vp - vp->pos.x, y);
402 sysarg_t count = w_dmg_vp;
403 while (count-- != 0) {
404 *dst++ = bg_color;
405 }
406 }
407 surface_add_damaged_region(vp->surface,
408 x_dmg_vp - vp->pos.x, y_dmg_vp - vp->pos.y, w_dmg_vp, h_dmg_vp);
409
410 transform_t transform;
411 source_t source;
412 drawctx_t context;
413
414 source_init(&source);
415 source_set_filter(&source, filter);
416 drawctx_init(&context, vp->surface);
417 drawctx_set_compose(&context, compose_over);
418 drawctx_set_source(&context, &source);
419
420 /* For each window. */
421 for (link_t *link = window_list.head.prev;
422 link != &window_list.head; link = link->prev) {
423
424 /* Determine what part of the window intersects with the
425 * updated area of the current viewport. */
426 window_t *win = list_get_instance(link, window_t, link);
427 if (!win->surface) {
428 continue;
429 }
430 sysarg_t x_dmg_win, y_dmg_win, w_dmg_win, h_dmg_win;
431 surface_get_resolution(win->surface, &w_dmg_win, &h_dmg_win);
432 comp_coord_bounding_rect(0, 0, w_dmg_win, h_dmg_win, win->transform,
433 &x_dmg_win, &y_dmg_win, &w_dmg_win, &h_dmg_win);
434 bool isec_win = rectangle_intersect(
435 x_dmg_vp, y_dmg_vp, w_dmg_vp, h_dmg_vp,
436 x_dmg_win, y_dmg_win, w_dmg_win, h_dmg_win,
437 &x_dmg_win, &y_dmg_win, &w_dmg_win, &h_dmg_win);
438
439 if (isec_win) {
440 /* Prepare conversion from global coordinates to viewport
441 * coordinates. */
442 transform = win->transform;
443 double_point_t pos;
444 pos.x = vp->pos.x;
445 pos.y = vp->pos.y;
446 transform_translate(&transform, -pos.x, -pos.y);
447
448 source_set_transform(&source, transform);
449 source_set_texture(&source, win->surface,
450 PIXELMAP_EXTEND_TRANSPARENT_SIDES);
451 source_set_alpha(&source, PIXEL(win->opacity, 0, 0, 0));
452
453 drawctx_transfer(&context,
454 x_dmg_win - vp->pos.x, y_dmg_win - vp->pos.y, w_dmg_win, h_dmg_win);
455 }
456 }
457
458 list_foreach(pointer_list, link, pointer_t, ptr) {
459 if (ptr->ghost.surface) {
460
461 sysarg_t x_bnd_ghost, y_bnd_ghost, w_bnd_ghost, h_bnd_ghost;
462 sysarg_t x_dmg_ghost, y_dmg_ghost, w_dmg_ghost, h_dmg_ghost;
463 surface_get_resolution(ptr->ghost.surface, &w_bnd_ghost, &h_bnd_ghost);
464 comp_coord_bounding_rect(0, 0, w_bnd_ghost, h_bnd_ghost, ptr->ghost.transform,
465 &x_bnd_ghost, &y_bnd_ghost, &w_bnd_ghost, &h_bnd_ghost);
466 bool isec_ghost = rectangle_intersect(
467 x_dmg_vp, y_dmg_vp, w_dmg_vp, h_dmg_vp,
468 x_bnd_ghost, y_bnd_ghost, w_bnd_ghost, h_bnd_ghost,
469 &x_dmg_ghost, &y_dmg_ghost, &w_dmg_ghost, &h_dmg_ghost);
470
471 if (isec_ghost) {
472 /* FIXME: Ghost is currently drawn based on the bounding
473 * rectangle of the window, which is sufficient as long
474 * as the windows can be rotated only by 90 degrees.
475 * For ghost to be compatible with arbitrary-angle
476 * rotation, it should be drawn as four lines adjusted
477 * by the transformation matrix. That would however
478 * require to equip libdraw with line drawing functionality. */
479
480 transform_t transform = ptr->ghost.transform;
481 double_point_t pos;
482 pos.x = vp->pos.x;
483 pos.y = vp->pos.y;
484 transform_translate(&transform, -pos.x, -pos.y);
485
486 pixel_t ghost_color;
487
488 if (y_bnd_ghost == y_dmg_ghost) {
489 for (sysarg_t x = x_dmg_ghost - vp->pos.x;
490 x < x_dmg_ghost - vp->pos.x + w_dmg_ghost; ++x) {
491 ghost_color = surface_get_pixel(vp->surface,
492 x, y_dmg_ghost - vp->pos.y);
493 surface_put_pixel(vp->surface,
494 x, y_dmg_ghost - vp->pos.y, INVERT(ghost_color));
495 }
496 }
497
498 if (y_bnd_ghost + h_bnd_ghost == y_dmg_ghost + h_dmg_ghost) {
499 for (sysarg_t x = x_dmg_ghost - vp->pos.x;
500 x < x_dmg_ghost - vp->pos.x + w_dmg_ghost; ++x) {
501 ghost_color = surface_get_pixel(vp->surface,
502 x, y_dmg_ghost - vp->pos.y + h_dmg_ghost - 1);
503 surface_put_pixel(vp->surface,
504 x, y_dmg_ghost - vp->pos.y + h_dmg_ghost - 1, INVERT(ghost_color));
505 }
506 }
507
508 if (x_bnd_ghost == x_dmg_ghost) {
509 for (sysarg_t y = y_dmg_ghost - vp->pos.y;
510 y < y_dmg_ghost - vp->pos.y + h_dmg_ghost; ++y) {
511 ghost_color = surface_get_pixel(vp->surface,
512 x_dmg_ghost - vp->pos.x, y);
513 surface_put_pixel(vp->surface,
514 x_dmg_ghost - vp->pos.x, y, INVERT(ghost_color));
515 }
516 }
517
518 if (x_bnd_ghost + w_bnd_ghost == x_dmg_ghost + w_dmg_ghost) {
519 for (sysarg_t y = y_dmg_ghost - vp->pos.y;
520 y < y_dmg_ghost - vp->pos.y + h_dmg_ghost; ++y) {
521 ghost_color = surface_get_pixel(vp->surface,
522 x_dmg_ghost - vp->pos.x + w_dmg_ghost - 1, y);
523 surface_put_pixel(vp->surface,
524 x_dmg_ghost - vp->pos.x + w_dmg_ghost - 1, y, INVERT(ghost_color));
525 }
526 }
527 }
528
529 }
530 }
531
532 list_foreach(pointer_list, link, pointer_t, ptr) {
533
534 /* Determine what part of the pointer intersects with the
535 * updated area of the current viewport. */
536 sysarg_t x_dmg_ptr, y_dmg_ptr, w_dmg_ptr, h_dmg_ptr;
537 surface_t *sf_ptr = ptr->cursor.states[ptr->state];
538 surface_get_resolution(sf_ptr, &w_dmg_ptr, &h_dmg_ptr);
539 bool isec_ptr = rectangle_intersect(
540 x_dmg_vp, y_dmg_vp, w_dmg_vp, h_dmg_vp,
541 ptr->pos.x, ptr->pos.y, w_dmg_ptr, h_dmg_ptr,
542 &x_dmg_ptr, &y_dmg_ptr, &w_dmg_ptr, &h_dmg_ptr);
543
544 if (isec_ptr) {
545 /* Pointer is currently painted directly by copying pixels.
546 * However, it is possible to draw the pointer similarly
547 * as window by using drawctx_transfer. It would allow
548 * more sophisticated control over drawing, but would also
549 * cost more regarding the performance. */
550
551 sysarg_t x_vp = x_dmg_ptr - vp->pos.x;
552 sysarg_t y_vp = y_dmg_ptr - vp->pos.y;
553 sysarg_t x_ptr = x_dmg_ptr - ptr->pos.x;
554 sysarg_t y_ptr = y_dmg_ptr - ptr->pos.y;
555
556 for (sysarg_t y = 0; y < h_dmg_ptr; ++y) {
557 pixel_t *src = pixelmap_pixel_at(
558 surface_pixmap_access(sf_ptr), x_ptr, y_ptr + y);
559 pixel_t *dst = pixelmap_pixel_at(
560 surface_pixmap_access(vp->surface), x_vp, y_vp + y);
561 sysarg_t count = w_dmg_ptr;
562 while (count-- != 0) {
563 *dst = (*src & 0xff000000) ? *src : *dst;
564 ++dst; ++src;
565 }
566 }
567 surface_add_damaged_region(vp->surface, x_vp, y_vp, w_dmg_ptr, h_dmg_ptr);
568 }
569
570 }
571 }
572 }
573
574 fibril_mutex_unlock(&pointer_list_mtx);
575 fibril_mutex_unlock(&window_list_mtx);
576
577 /* Notify visualizers about updated regions. */
578 if (active) {
579 list_foreach(viewport_list, link, viewport_t, vp) {
580 sysarg_t x_dmg_vp, y_dmg_vp, w_dmg_vp, h_dmg_vp;
581 surface_get_damaged_region(vp->surface, &x_dmg_vp, &y_dmg_vp, &w_dmg_vp, &h_dmg_vp);
582 surface_reset_damaged_region(vp->surface);
583 visualizer_update_damaged_region(vp->sess,
584 x_dmg_vp, y_dmg_vp, w_dmg_vp, h_dmg_vp, 0, 0);
585 }
586 }
587
588 fibril_mutex_unlock(&viewport_list_mtx);
589}
590
591static void comp_window_get_event(window_t *win, ipc_callid_t iid, ipc_call_t *icall)
592{
593 window_event_t *event = (window_event_t *) prodcons_consume(&win->queue);
594
595 ipc_callid_t callid;
596 size_t len;
597
598 if (!async_data_read_receive(&callid, &len)) {
599 async_answer_0(iid, EINVAL);
600 free(event);
601 return;
602 }
603
604 errno_t rc = async_data_read_finalize(callid, event, len);
605 if (rc != EOK) {
606 async_answer_0(iid, ENOMEM);
607 free(event);
608 return;
609 }
610
611 async_answer_0(iid, EOK);
612 free(event);
613}
614
615static void comp_window_damage(window_t *win, ipc_callid_t iid, ipc_call_t *icall)
616{
617 double x = IPC_GET_ARG1(*icall);
618 double y = IPC_GET_ARG2(*icall);
619 double width = IPC_GET_ARG3(*icall);
620 double height = IPC_GET_ARG4(*icall);
621
622 if ((width == 0) || (height == 0)) {
623 comp_damage(0, 0, UINT32_MAX, UINT32_MAX);
624 } else {
625 fibril_mutex_lock(&window_list_mtx);
626 sysarg_t x_dmg_glob, y_dmg_glob, w_dmg_glob, h_dmg_glob;
627 comp_coord_bounding_rect(x - 1, y - 1, width + 2, height + 2,
628 win->transform, &x_dmg_glob, &y_dmg_glob, &w_dmg_glob, &h_dmg_glob);
629 fibril_mutex_unlock(&window_list_mtx);
630 comp_damage(x_dmg_glob, y_dmg_glob, w_dmg_glob, h_dmg_glob);
631 }
632
633 async_answer_0(iid, EOK);
634}
635
636static void comp_window_grab(window_t *win, ipc_callid_t iid, ipc_call_t *icall)
637{
638 sysarg_t pos_id = IPC_GET_ARG1(*icall);
639 sysarg_t grab_flags = IPC_GET_ARG2(*icall);
640
641 /*
642 * Filter out resize grab flags if the window
643 * is not resizeable.
644 */
645 if ((win->flags & WINDOW_RESIZEABLE) != WINDOW_RESIZEABLE)
646 grab_flags &= ~(GF_RESIZE_X | GF_RESIZE_Y);
647
648 fibril_mutex_lock(&pointer_list_mtx);
649 list_foreach(pointer_list, link, pointer_t, pointer) {
650 if (pointer->id == pos_id) {
651 pointer->grab_flags = pointer->pressed ? grab_flags : GF_EMPTY;
652 // TODO change pointer->state according to grab_flags
653 break;
654 }
655 }
656 fibril_mutex_unlock(&pointer_list_mtx);
657
658 if ((grab_flags & GF_RESIZE_X) || (grab_flags & GF_RESIZE_Y)) {
659 scale_back_x = 1;
660 scale_back_y = 1;
661 }
662
663 async_answer_0(iid, EOK);
664}
665
666static void comp_recalc_transform(window_t *win)
667{
668 transform_t translate;
669 transform_identity(&translate);
670 transform_translate(&translate, win->dx, win->dy);
671
672 transform_t scale;
673 transform_identity(&scale);
674 if ((win->fx != 1) || (win->fy != 1))
675 transform_scale(&scale, win->fx, win->fy);
676
677 transform_t rotate;
678 transform_identity(&rotate);
679 if (win->angle != 0)
680 transform_rotate(&rotate, win->angle);
681
682 transform_t transform;
683 transform_t temp;
684 transform_identity(&transform);
685 temp = transform;
686 transform_product(&transform, &temp, &translate);
687 temp = transform;
688 transform_product(&transform, &temp, &rotate);
689 temp = transform;
690 transform_product(&transform, &temp, &scale);
691
692 win->transform = transform;
693}
694
695static void comp_window_resize(window_t *win, ipc_callid_t iid, ipc_call_t *icall)
696{
697 ipc_callid_t callid;
698 size_t size;
699 unsigned int flags;
700
701 /* Start sharing resized window with client. */
702 if (!async_share_out_receive(&callid, &size, &flags)) {
703 async_answer_0(iid, EINVAL);
704 return;
705 }
706
707 void *new_cell_storage;
708 errno_t rc = async_share_out_finalize(callid, &new_cell_storage);
709 if ((rc != EOK) || (new_cell_storage == AS_MAP_FAILED)) {
710 async_answer_0(iid, ENOMEM);
711 return;
712 }
713
714 /* Create new surface for the resized window. */
715 surface_t *new_surface = surface_create(IPC_GET_ARG3(*icall),
716 IPC_GET_ARG4(*icall), new_cell_storage, SURFACE_FLAG_SHARED);
717 if (!new_surface) {
718 as_area_destroy(new_cell_storage);
719 async_answer_0(iid, ENOMEM);
720 return;
721 }
722
723 sysarg_t offset_x = IPC_GET_ARG1(*icall);
724 sysarg_t offset_y = IPC_GET_ARG2(*icall);
725 window_placement_flags_t placement_flags =
726 (window_placement_flags_t) IPC_GET_ARG5(*icall);
727
728 comp_update_viewport_bound_rect();
729
730 /* Switch new surface with old surface and calculate damage. */
731 fibril_mutex_lock(&window_list_mtx);
732
733 sysarg_t old_width = 0;
734 sysarg_t old_height = 0;
735
736 if (win->surface) {
737 surface_get_resolution(win->surface, &old_width, &old_height);
738 surface_destroy(win->surface);
739 }
740
741 win->surface = new_surface;
742
743 sysarg_t new_width = 0;
744 sysarg_t new_height = 0;
745 surface_get_resolution(win->surface, &new_width, &new_height);
746
747 if (placement_flags & WINDOW_PLACEMENT_CENTER_X)
748 win->dx = viewport_bound_rect.x + viewport_bound_rect.w / 2 -
749 new_width / 2;
750
751 if (placement_flags & WINDOW_PLACEMENT_CENTER_Y)
752 win->dy = viewport_bound_rect.y + viewport_bound_rect.h / 2 -
753 new_height / 2;
754
755 if (placement_flags & WINDOW_PLACEMENT_LEFT)
756 win->dx = viewport_bound_rect.x;
757
758 if (placement_flags & WINDOW_PLACEMENT_TOP)
759 win->dy = viewport_bound_rect.y;
760
761 if (placement_flags & WINDOW_PLACEMENT_RIGHT)
762 win->dx = viewport_bound_rect.x + viewport_bound_rect.w -
763 new_width;
764
765 if (placement_flags & WINDOW_PLACEMENT_BOTTOM)
766 win->dy = viewport_bound_rect.y + viewport_bound_rect.h -
767 new_height;
768
769 if (placement_flags & WINDOW_PLACEMENT_ABSOLUTE_X)
770 win->dx = coord_origin + offset_x;
771
772 if (placement_flags & WINDOW_PLACEMENT_ABSOLUTE_Y)
773 win->dy = coord_origin + offset_y;
774
775 /* Transform the window and calculate damage. */
776 sysarg_t x1;
777 sysarg_t y1;
778 sysarg_t width1;
779 sysarg_t height1;
780
781 comp_coord_bounding_rect(0, 0, old_width, old_height, win->transform,
782 &x1, &y1, &width1, &height1);
783
784 comp_recalc_transform(win);
785
786 sysarg_t x2;
787 sysarg_t y2;
788 sysarg_t width2;
789 sysarg_t height2;
790
791 comp_coord_bounding_rect(0, 0, new_width, new_height, win->transform,
792 &x2, &y2, &width2, &height2);
793
794 sysarg_t x;
795 sysarg_t y;
796 sysarg_t width;
797 sysarg_t height;
798
799 rectangle_union(x1, y1, width1, height1, x2, y2, width2, height2,
800 &x, &y, &width, &height);
801
802 fibril_mutex_unlock(&window_list_mtx);
803
804 comp_damage(x, y, width, height);
805
806 async_answer_0(iid, EOK);
807}
808
809static void comp_post_event_win(window_event_t *event, window_t *target)
810{
811 fibril_mutex_lock(&window_list_mtx);
812
813 list_foreach(window_list, link, window_t, window) {
814 if (window == target) {
815 prodcons_produce(&window->queue, &event->link);
816 fibril_mutex_unlock(&window_list_mtx);
817 return;
818 }
819 }
820
821 fibril_mutex_unlock(&window_list_mtx);
822 free(event);
823}
824
825static void comp_post_event_top(window_event_t *event)
826{
827 fibril_mutex_lock(&window_list_mtx);
828
829 window_t *win = (window_t *) list_first(&window_list);
830 if (win)
831 prodcons_produce(&win->queue, &event->link);
832 else
833 free(event);
834
835 fibril_mutex_unlock(&window_list_mtx);
836}
837
838static void comp_window_close(window_t *win, ipc_callid_t iid, ipc_call_t *icall)
839{
840 /* Stop managing the window. */
841 fibril_mutex_lock(&window_list_mtx);
842 list_remove(&win->link);
843 window_t *win_focus = (window_t *) list_first(&window_list);
844 window_event_t *event_focus = (window_event_t *) malloc(sizeof(window_event_t));
845 if (event_focus) {
846 link_initialize(&event_focus->link);
847 event_focus->type = ET_WINDOW_FOCUS;
848 }
849 fibril_mutex_unlock(&window_list_mtx);
850
851 if (event_focus && win_focus) {
852 comp_post_event_win(event_focus, win_focus);
853 }
854
855 loc_service_unregister(win->in_dsid);
856 loc_service_unregister(win->out_dsid);
857
858 /* In case the client was killed, input fibril of the window might be
859 * still blocked on the condition within comp_window_get_event. */
860 window_event_t *event_dummy = (window_event_t *) malloc(sizeof(window_event_t));
861 if (event_dummy) {
862 link_initialize(&event_dummy->link);
863 prodcons_produce(&win->queue, &event_dummy->link);
864 }
865
866 /* Calculate damage. */
867 sysarg_t x = 0;
868 sysarg_t y = 0;
869 sysarg_t width = 0;
870 sysarg_t height = 0;
871 if (win->surface) {
872 surface_get_resolution(win->surface, &width, &height);
873 comp_coord_bounding_rect(
874 0, 0, width, height, win->transform, &x, &y, &width, &height);
875 }
876
877 comp_damage(x, y, width, height);
878 async_answer_0(iid, EOK);
879}
880
881static void comp_window_close_request(window_t *win, ipc_callid_t iid, ipc_call_t *icall)
882{
883 window_event_t *event = (window_event_t *) malloc(sizeof(window_event_t));
884 if (event == NULL) {
885 async_answer_0(iid, ENOMEM);
886 return;
887 }
888
889 link_initialize(&event->link);
890 event->type = ET_WINDOW_CLOSE;
891
892 prodcons_produce(&win->queue, &event->link);
893 async_answer_0(iid, EOK);
894}
895
896static void client_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
897{
898 ipc_call_t call;
899 ipc_callid_t callid;
900 service_id_t service_id = (service_id_t) IPC_GET_ARG2(*icall);
901
902 /* Allocate resources for new window and register it to the location service. */
903 if (service_id == winreg_id) {
904 async_answer_0(iid, EOK);
905
906 callid = async_get_call(&call);
907 if (IPC_GET_IMETHOD(call) == WINDOW_REGISTER) {
908 fibril_mutex_lock(&window_list_mtx);
909
910 window_t *win = window_create();
911 if (!win) {
912 async_answer_2(callid, ENOMEM, 0, 0);
913 fibril_mutex_unlock(&window_list_mtx);
914 return;
915 }
916
917 win->flags = IPC_GET_ARG1(call);
918
919 char name_in[LOC_NAME_MAXLEN + 1];
920 snprintf(name_in, LOC_NAME_MAXLEN, "%s%s/win%zuin", NAMESPACE,
921 server_name, window_id);
922
923 char name_out[LOC_NAME_MAXLEN + 1];
924 snprintf(name_out, LOC_NAME_MAXLEN, "%s%s/win%zuout", NAMESPACE,
925 server_name, window_id);
926
927 ++window_id;
928
929 if (loc_service_register(name_in, &win->in_dsid) != EOK) {
930 window_destroy(win);
931 async_answer_2(callid, EINVAL, 0, 0);
932 fibril_mutex_unlock(&window_list_mtx);
933 return;
934 }
935
936 if (loc_service_register(name_out, &win->out_dsid) != EOK) {
937 loc_service_unregister(win->in_dsid);
938 window_destroy(win);
939 async_answer_2(callid, EINVAL, 0, 0);
940 fibril_mutex_unlock(&window_list_mtx);
941 return;
942 }
943
944 window_t *win_unfocus = (window_t *) list_first(&window_list);
945 list_prepend(&win->link, &window_list);
946
947 window_event_t *event_unfocus = (window_event_t *) malloc(sizeof(window_event_t));
948 if (event_unfocus) {
949 link_initialize(&event_unfocus->link);
950 event_unfocus->type = ET_WINDOW_UNFOCUS;
951 }
952
953 async_answer_2(callid, EOK, win->in_dsid, win->out_dsid);
954 fibril_mutex_unlock(&window_list_mtx);
955
956 if (event_unfocus && win_unfocus) {
957 comp_post_event_win(event_unfocus, win_unfocus);
958 }
959
960 return;
961 } else {
962 async_answer_0(callid, EINVAL);
963 return;
964 }
965 }
966
967 /* Match the client with pre-allocated window. */
968 window_t *win = NULL;
969 fibril_mutex_lock(&window_list_mtx);
970 list_foreach(window_list, link, window_t, cur) {
971 if (cur->in_dsid == service_id || cur->out_dsid == service_id) {
972 win = cur;
973 break;
974 }
975 }
976 fibril_mutex_unlock(&window_list_mtx);
977
978 if (win) {
979 atomic_inc(&win->ref_cnt);
980 async_answer_0(iid, EOK);
981 } else {
982 async_answer_0(iid, EINVAL);
983 return;
984 }
985
986 /* Each client establishes two separate connections. */
987 if (win->in_dsid == service_id) {
988 while (true) {
989 callid = async_get_call(&call);
990
991 if (!IPC_GET_IMETHOD(call)) {
992 async_answer_0(callid, EOK);
993 atomic_dec(&win->ref_cnt);
994 window_destroy(win);
995 return;
996 }
997
998 switch (IPC_GET_IMETHOD(call)) {
999 case WINDOW_GET_EVENT:
1000 comp_window_get_event(win, callid, &call);
1001 break;
1002 default:
1003 async_answer_0(callid, EINVAL);
1004 }
1005 }
1006 } else if (win->out_dsid == service_id) {
1007 while (true) {
1008 callid = async_get_call(&call);
1009
1010 if (!IPC_GET_IMETHOD(call)) {
1011 comp_window_close(win, callid, &call);
1012 atomic_dec(&win->ref_cnt);
1013 window_destroy(win);
1014 return;
1015 }
1016
1017 switch (IPC_GET_IMETHOD(call)) {
1018 case WINDOW_DAMAGE:
1019 comp_window_damage(win, callid, &call);
1020 break;
1021 case WINDOW_GRAB:
1022 comp_window_grab(win, callid, &call);
1023 break;
1024 case WINDOW_RESIZE:
1025 comp_window_resize(win, callid, &call);
1026 break;
1027 case WINDOW_CLOSE:
1028 /*
1029 * Postpone the closing until the phone is hung up to cover
1030 * the case when the client is killed abruptly.
1031 */
1032 async_answer_0(callid, EOK);
1033 break;
1034 case WINDOW_CLOSE_REQUEST:
1035 comp_window_close_request(win, callid, &call);
1036 break;
1037 default:
1038 async_answer_0(callid, EINVAL);
1039 }
1040 }
1041 }
1042}
1043
1044static void comp_mode_change(viewport_t *vp, ipc_callid_t iid, ipc_call_t *icall)
1045{
1046 sysarg_t mode_idx = IPC_GET_ARG2(*icall);
1047 fibril_mutex_lock(&viewport_list_mtx);
1048
1049 /* Retrieve the mode that shall be set. */
1050 vslmode_t new_mode;
1051 errno_t rc = visualizer_get_mode(vp->sess, &new_mode, mode_idx);
1052 if (rc != EOK) {
1053 fibril_mutex_unlock(&viewport_list_mtx);
1054 async_answer_0(iid, EINVAL);
1055 return;
1056 }
1057
1058 /* Create surface with respect to the retrieved mode. */
1059 surface_t *new_surface = surface_create(new_mode.screen_width,
1060 new_mode.screen_height, NULL, SURFACE_FLAG_SHARED);
1061 if (!new_surface) {
1062 fibril_mutex_unlock(&viewport_list_mtx);
1063 async_answer_0(iid, ENOMEM);
1064 return;
1065 }
1066
1067 /* Try to set the mode and share out the surface. */
1068 rc = visualizer_set_mode(vp->sess,
1069 new_mode.index, new_mode.version, surface_direct_access(new_surface));
1070 if (rc != EOK) {
1071 surface_destroy(new_surface);
1072 fibril_mutex_unlock(&viewport_list_mtx);
1073 async_answer_0(iid, rc);
1074 return;
1075 }
1076
1077 /* Destroy old surface and update viewport. */
1078 surface_destroy(vp->surface);
1079 vp->mode = new_mode;
1080 vp->surface = new_surface;
1081
1082 fibril_mutex_unlock(&viewport_list_mtx);
1083 async_answer_0(iid, EOK);
1084
1085 comp_restrict_pointers();
1086 comp_damage(0, 0, UINT32_MAX, UINT32_MAX);
1087}
1088
1089static void viewport_destroy(viewport_t *vp)
1090{
1091 if (vp) {
1092 visualizer_yield(vp->sess);
1093 surface_destroy(vp->surface);
1094 async_hangup(vp->sess);
1095 free(vp);
1096 }
1097}
1098
1099#if 0
1100static void comp_shutdown(void)
1101{
1102 loc_service_unregister(winreg_id);
1103 input_disconnect();
1104
1105 /* Close all clients and their windows. */
1106 fibril_mutex_lock(&window_list_mtx);
1107 list_foreach(window_list, link, window_t, win) {
1108 window_event_t *event = (window_event_t *) malloc(sizeof(window_event_t));
1109 if (event) {
1110 link_initialize(&event->link);
1111 event->type = WINDOW_CLOSE;
1112 prodcons_produce(&win->queue, &event->link);
1113 }
1114 }
1115 fibril_mutex_unlock(&window_list_mtx);
1116
1117 async_answer_0(iid, EOK);
1118
1119 /* All fibrils of the compositor will terminate soon. */
1120}
1121#endif
1122
1123static void comp_visualizer_disconnect(viewport_t *vp, ipc_callid_t iid, ipc_call_t *icall)
1124{
1125 /* Release viewport resources. */
1126 fibril_mutex_lock(&viewport_list_mtx);
1127
1128 list_remove(&vp->link);
1129 viewport_destroy(vp);
1130
1131 fibril_mutex_unlock(&viewport_list_mtx);
1132
1133 async_answer_0(iid, EOK);
1134
1135 comp_restrict_pointers();
1136 comp_damage(0, 0, UINT32_MAX, UINT32_MAX);
1137}
1138
1139static void vsl_notifications(ipc_callid_t iid, ipc_call_t *icall, void *arg)
1140{
1141 viewport_t *vp = NULL;
1142 fibril_mutex_lock(&viewport_list_mtx);
1143 list_foreach(viewport_list, link, viewport_t, cur) {
1144 if (cur->dsid == (service_id_t) IPC_GET_ARG1(*icall)) {
1145 vp = cur;
1146 break;
1147 }
1148 }
1149 fibril_mutex_unlock(&viewport_list_mtx);
1150
1151 if (!vp)
1152 return;
1153
1154 /* Ignore parameters, the connection is already opened. */
1155 while (true) {
1156 ipc_call_t call;
1157 ipc_callid_t callid = async_get_call(&call);
1158
1159 if (!IPC_GET_IMETHOD(call)) {
1160 async_hangup(vp->sess);
1161 return;
1162 }
1163
1164 switch (IPC_GET_IMETHOD(call)) {
1165 case VISUALIZER_MODE_CHANGE:
1166 comp_mode_change(vp, callid, &call);
1167 break;
1168 case VISUALIZER_DISCONNECT:
1169 comp_visualizer_disconnect(vp, callid, &call);
1170 return;
1171 default:
1172 async_answer_0(callid, EINVAL);
1173 }
1174 }
1175}
1176
1177static async_sess_t *vsl_connect(service_id_t sid, const char *svc)
1178{
1179 errno_t rc;
1180 async_sess_t *sess;
1181
1182 sess = loc_service_connect(sid, INTERFACE_DDF, 0);
1183 if (sess == NULL) {
1184 printf("%s: Unable to connect to visualizer %s\n", NAME, svc);
1185 return NULL;
1186 }
1187
1188 async_exch_t *exch = async_exchange_begin(sess);
1189
1190 port_id_t port;
1191 rc = async_create_callback_port(exch, INTERFACE_VISUALIZER_CB, 0, 0,
1192 vsl_notifications, NULL, &port);
1193
1194 async_exchange_end(exch);
1195
1196 if (rc != EOK) {
1197 async_hangup(sess);
1198 printf("%s: Unable to create callback connection to service %s (%s)\n",
1199 NAME, svc, str_error(rc));
1200 return NULL;
1201 }
1202
1203 return sess;
1204}
1205
1206static viewport_t *viewport_create(service_id_t sid)
1207{
1208 errno_t rc;
1209 char *vsl_name = NULL;
1210 viewport_t *vp = NULL;
1211 bool claimed = false;
1212
1213 rc = loc_service_get_name(sid, &vsl_name);
1214 if (rc != EOK)
1215 goto error;
1216
1217 vp = (viewport_t *) calloc(1, sizeof(viewport_t));
1218 if (!vp)
1219 goto error;
1220
1221 link_initialize(&vp->link);
1222 vp->pos.x = coord_origin;
1223 vp->pos.y = coord_origin;
1224
1225 /* Establish output bidirectional connection. */
1226 vp->dsid = sid;
1227 vp->sess = vsl_connect(sid, vsl_name);
1228 if (vp->sess == NULL)
1229 goto error;
1230
1231 /* Claim the given visualizer. */
1232 rc = visualizer_claim(vp->sess, 0);
1233 if (rc != EOK) {
1234 printf("%s: Unable to claim visualizer (%s)\n", NAME, str_error(rc));
1235 goto error;
1236 }
1237
1238 claimed = true;
1239
1240 /* Retrieve the default mode. */
1241 rc = visualizer_get_default_mode(vp->sess, &vp->mode);
1242 if (rc != EOK) {
1243 printf("%s: Unable to retrieve mode (%s)\n", NAME, str_error(rc));
1244 goto error;
1245 }
1246
1247 /* Create surface with respect to the retrieved mode. */
1248 vp->surface = surface_create(vp->mode.screen_width, vp->mode.screen_height,
1249 NULL, SURFACE_FLAG_SHARED);
1250 if (vp->surface == NULL) {
1251 printf("%s: Unable to create surface (%s)\n", NAME, str_error(rc));
1252 goto error;
1253 }
1254
1255 /* Try to set the mode and share out the surface. */
1256 rc = visualizer_set_mode(vp->sess,
1257 vp->mode.index, vp->mode.version, surface_direct_access(vp->surface));
1258 if (rc != EOK) {
1259 printf("%s: Unable to set mode (%s)\n", NAME, str_error(rc));
1260 goto error;
1261 }
1262
1263 return vp;
1264error:
1265 if (claimed)
1266 visualizer_yield(vp->sess);
1267
1268 if (vp->sess != NULL)
1269 async_hangup(vp->sess);
1270
1271 free(vp);
1272 free(vsl_name);
1273 return NULL;
1274}
1275
1276static void comp_window_animate(pointer_t *pointer, window_t *win,
1277 sysarg_t *dmg_x, sysarg_t *dmg_y, sysarg_t *dmg_width, sysarg_t *dmg_height)
1278{
1279 /* window_list_mtx locked by caller */
1280 /* pointer_list_mtx locked by caller */
1281
1282 int dx = pointer->accum.x;
1283 int dy = pointer->accum.y;
1284 pointer->accum.x = 0;
1285 pointer->accum.y = 0;
1286
1287 bool move = (pointer->grab_flags & GF_MOVE_X) || (pointer->grab_flags & GF_MOVE_Y);
1288 bool scale = (pointer->grab_flags & GF_SCALE_X) || (pointer->grab_flags & GF_SCALE_Y);
1289 bool resize = (pointer->grab_flags & GF_RESIZE_X) || (pointer->grab_flags & GF_RESIZE_Y);
1290
1291 sysarg_t width, height;
1292 surface_get_resolution(win->surface, &width, &height);
1293
1294 if (move) {
1295 double cx = 0;
1296 double cy = 0;
1297
1298 if (pointer->grab_flags & GF_MOVE_X)
1299 cx = 1;
1300
1301 if (pointer->grab_flags & GF_MOVE_Y)
1302 cy = 1;
1303
1304 if (((scale) || (resize)) && (win->angle != 0)) {
1305 transform_t rotate;
1306 transform_identity(&rotate);
1307
1308 transform_rotate(&rotate, win->angle);
1309 transform_apply_linear(&rotate, &cx, &cy);
1310 }
1311
1312 cx = (cx < 0) ? (-1 * cx) : cx;
1313 cy = (cy < 0) ? (-1 * cy) : cy;
1314
1315 win->dx += (cx * dx);
1316 win->dy += (cy * dy);
1317 }
1318
1319 if ((scale) || (resize)) {
1320 double _dx = dx;
1321 double _dy = dy;
1322 if (win->angle != 0) {
1323 transform_t unrotate;
1324 transform_identity(&unrotate);
1325 transform_rotate(&unrotate, -win->angle);
1326 transform_apply_linear(&unrotate, &_dx, &_dy);
1327 }
1328 _dx = (pointer->grab_flags & GF_MOVE_X) ? -_dx : _dx;
1329 _dy = (pointer->grab_flags & GF_MOVE_Y) ? -_dy : _dy;
1330
1331 if ((pointer->grab_flags & GF_SCALE_X) || (pointer->grab_flags & GF_RESIZE_X)) {
1332 double fx = 1.0 + (_dx / ((width - 1) * win->fx));
1333 if (fx > 0) {
1334#if ANIMATE_WINDOW_TRANSFORMS == 0
1335 if (scale)
1336 win->fx *= fx;
1337#endif
1338#if ANIMATE_WINDOW_TRANSFORMS == 1
1339 win->fx *= fx;
1340#endif
1341 scale_back_x *= fx;
1342 }
1343 }
1344
1345 if ((pointer->grab_flags & GF_SCALE_Y) || (pointer->grab_flags & GF_RESIZE_Y)) {
1346 double fy = 1.0 + (_dy / ((height - 1) * win->fy));
1347 if (fy > 0) {
1348#if ANIMATE_WINDOW_TRANSFORMS == 0
1349 if (scale) win->fy *= fy;
1350#endif
1351#if ANIMATE_WINDOW_TRANSFORMS == 1
1352 win->fy *= fy;
1353#endif
1354 scale_back_y *= fy;
1355 }
1356 }
1357 }
1358
1359 sysarg_t x1, y1, width1, height1;
1360 sysarg_t x2, y2, width2, height2;
1361 comp_coord_bounding_rect(0, 0, width, height, win->transform,
1362 &x1, &y1, &width1, &height1);
1363 comp_recalc_transform(win);
1364 comp_coord_bounding_rect(0, 0, width, height, win->transform,
1365 &x2, &y2, &width2, &height2);
1366 rectangle_union(x1, y1, width1, height1, x2, y2, width2, height2,
1367 dmg_x, dmg_y, dmg_width, dmg_height);
1368}
1369
1370#if ANIMATE_WINDOW_TRANSFORMS == 0
1371static void comp_ghost_animate(pointer_t *pointer,
1372 desktop_rect_t *rect1, desktop_rect_t *rect2, desktop_rect_t *rect3, desktop_rect_t *rect4)
1373{
1374 /* window_list_mtx locked by caller */
1375 /* pointer_list_mtx locked by caller */
1376
1377 int dx = pointer->accum_ghost.x;
1378 int dy = pointer->accum_ghost.y;
1379 pointer->accum_ghost.x = 0;
1380 pointer->accum_ghost.y = 0;
1381
1382 bool move = (pointer->grab_flags & GF_MOVE_X) || (pointer->grab_flags & GF_MOVE_Y);
1383 bool scale = (pointer->grab_flags & GF_SCALE_X) || (pointer->grab_flags & GF_SCALE_Y);
1384 bool resize = (pointer->grab_flags & GF_RESIZE_X) || (pointer->grab_flags & GF_RESIZE_Y);
1385
1386 sysarg_t width, height;
1387 surface_get_resolution(pointer->ghost.surface, &width, &height);
1388
1389 if (move) {
1390 double cx = 0;
1391 double cy = 0;
1392 if (pointer->grab_flags & GF_MOVE_X) {
1393 cx = 1;
1394 }
1395 if (pointer->grab_flags & GF_MOVE_Y) {
1396 cy = 1;
1397 }
1398
1399 if (scale || resize) {
1400 transform_t rotate;
1401 transform_identity(&rotate);
1402 transform_rotate(&rotate, pointer->ghost.angle);
1403 transform_apply_linear(&rotate, &cx, &cy);
1404 }
1405
1406 cx = (cx < 0) ? (-1 * cx) : cx;
1407 cy = (cy < 0) ? (-1 * cy) : cy;
1408
1409 pointer->ghost.dx += (cx * dx);
1410 pointer->ghost.dy += (cy * dy);
1411 }
1412
1413 if (scale || resize) {
1414 double _dx = dx;
1415 double _dy = dy;
1416 transform_t unrotate;
1417 transform_identity(&unrotate);
1418 transform_rotate(&unrotate, -pointer->ghost.angle);
1419 transform_apply_linear(&unrotate, &_dx, &_dy);
1420 _dx = (pointer->grab_flags & GF_MOVE_X) ? -_dx : _dx;
1421 _dy = (pointer->grab_flags & GF_MOVE_Y) ? -_dy : _dy;
1422
1423 if ((pointer->grab_flags & GF_SCALE_X) || (pointer->grab_flags & GF_RESIZE_X)) {
1424 double fx = 1.0 + (_dx / ((width - 1) * pointer->ghost.fx));
1425 pointer->ghost.fx *= fx;
1426 }
1427
1428 if ((pointer->grab_flags & GF_SCALE_Y) || (pointer->grab_flags & GF_RESIZE_Y)) {
1429 double fy = 1.0 + (_dy / ((height - 1) * pointer->ghost.fy));
1430 pointer->ghost.fy *= fy;
1431 }
1432 }
1433
1434 sysarg_t x1, y1, width1, height1;
1435 sysarg_t x2, y2, width2, height2;
1436 comp_coord_bounding_rect(0, 0, width, height, pointer->ghost.transform,
1437 &x1, &y1, &width1, &height1);
1438 comp_recalc_transform(&pointer->ghost);
1439 comp_coord_bounding_rect(0, 0, width, height, pointer->ghost.transform,
1440 &x2, &y2, &width2, &height2);
1441
1442 sysarg_t x_u, y_u, w_u, h_u;
1443 rectangle_union(x1, y1, width1, height1, x2, y2, width2, height2,
1444 &x_u, &y_u, &w_u, &h_u);
1445
1446 sysarg_t x_i, y_i, w_i, h_i;
1447 rectangle_intersect(x1, y1, width1, height1, x2, y2, width2, height2,
1448 &x_i, &y_i, &w_i, &h_i);
1449
1450 if (w_i == 0 || h_i == 0) {
1451 rect1->x = x_u; rect2->x = 0; rect3->x = 0; rect4->x = 0;
1452 rect1->y = y_u; rect2->y = 0; rect3->y = 0; rect4->y = 0;
1453 rect1->w = w_u; rect2->w = 0; rect3->w = 0; rect4->w = 0;
1454 rect1->h = h_u; rect2->h = 0; rect3->h = 0; rect4->h = 0;
1455 } else {
1456 rect1->x = x_u;
1457 rect1->y = y_u;
1458 rect1->w = x_i - x_u + 1;
1459 rect1->h = h_u;
1460
1461 rect2->x = x_u;
1462 rect2->y = y_u;
1463 rect2->w = w_u;
1464 rect2->h = y_i - y_u + 1;
1465
1466 rect3->x = x_i + w_i - 1;
1467 rect3->y = y_u;
1468 rect3->w = w_u - w_i - x_i + x_u + 1;
1469 rect3->h = h_u;
1470
1471 rect4->x = x_u;
1472 rect4->y = y_i + h_i - 1;
1473 rect4->w = w_u;
1474 rect4->h = h_u - h_i - y_i + y_u + 1;
1475 }
1476}
1477#endif
1478
1479static errno_t comp_abs_move(input_t *input, unsigned x , unsigned y,
1480 unsigned max_x, unsigned max_y)
1481{
1482 /* XXX TODO Use absolute coordinates directly */
1483
1484 pointer_t *pointer = input_pointer(input);
1485
1486 sysarg_t width, height;
1487
1488 fibril_mutex_lock(&viewport_list_mtx);
1489 if (list_empty(&viewport_list)) {
1490 printf("No viewport found\n");
1491 fibril_mutex_unlock(&viewport_list_mtx);
1492 return EOK; /* XXX */
1493 }
1494 link_t *link = list_first(&viewport_list);
1495 viewport_t *vp = list_get_instance(link, viewport_t, link);
1496 surface_get_resolution(vp->surface, &width, &height);
1497 desktop_point_t vp_pos = vp->pos;
1498 fibril_mutex_unlock(&viewport_list_mtx);
1499
1500 desktop_point_t pos_in_viewport;
1501 pos_in_viewport.x = x * width / max_x;
1502 pos_in_viewport.y = y * height / max_y;
1503
1504 /* Calculate offset from pointer */
1505 fibril_mutex_lock(&pointer_list_mtx);
1506 desktop_vector_t delta;
1507 delta.x = (vp_pos.x + pos_in_viewport.x) - pointer->pos.x;
1508 delta.y = (vp_pos.y + pos_in_viewport.y) - pointer->pos.y;
1509 fibril_mutex_unlock(&pointer_list_mtx);
1510
1511 return comp_mouse_move(input, delta.x, delta.y);
1512}
1513
1514static errno_t comp_mouse_move(input_t *input, int dx, int dy)
1515{
1516 pointer_t *pointer = input_pointer(input);
1517
1518 comp_update_viewport_bound_rect();
1519
1520 /* Update pointer position. */
1521 fibril_mutex_lock(&pointer_list_mtx);
1522
1523 desktop_point_t old_pos = pointer->pos;
1524
1525 sysarg_t cursor_width;
1526 sysarg_t cursor_height;
1527 surface_get_resolution(pointer->cursor.states[pointer->state],
1528 &cursor_width, &cursor_height);
1529
1530 if (pointer->pos.x + dx < viewport_bound_rect.x)
1531 dx = -1 * (pointer->pos.x - viewport_bound_rect.x);
1532
1533 if (pointer->pos.y + dy < viewport_bound_rect.y)
1534 dy = -1 * (pointer->pos.y - viewport_bound_rect.y);
1535
1536 if (pointer->pos.x + dx > viewport_bound_rect.x + viewport_bound_rect.w)
1537 dx = (viewport_bound_rect.x + viewport_bound_rect.w - pointer->pos.x);
1538
1539 if (pointer->pos.y + dy > viewport_bound_rect.y + viewport_bound_rect.h)
1540 dy = (viewport_bound_rect.y + viewport_bound_rect.h - pointer->pos.y);
1541
1542 pointer->pos.x += dx;
1543 pointer->pos.y += dy;
1544 fibril_mutex_unlock(&pointer_list_mtx);
1545 comp_damage(old_pos.x, old_pos.y, cursor_width, cursor_height);
1546 comp_damage(old_pos.x + dx, old_pos.y + dy, cursor_width, cursor_height);
1547
1548 fibril_mutex_lock(&window_list_mtx);
1549 fibril_mutex_lock(&pointer_list_mtx);
1550 window_t *top = (window_t *) list_first(&window_list);
1551 if (top && top->surface) {
1552
1553 if (pointer->grab_flags == GF_EMPTY) {
1554 /* Notify top-level window about move event. */
1555 bool within_client = false;
1556 sysarg_t point_x, point_y;
1557 sysarg_t width, height;
1558 surface_get_resolution(top->surface, &width, &height);
1559 within_client = comp_coord_to_client(pointer->pos.x, pointer->pos.y,
1560 top->transform, width, height, &point_x, &point_y);
1561
1562 window_event_t *event = NULL;
1563 if (within_client) {
1564 event = (window_event_t *) malloc(sizeof(window_event_t));
1565 if (event) {
1566 link_initialize(&event->link);
1567 event->type = ET_POSITION_EVENT;
1568 event->data.pos.pos_id = pointer->id;
1569 event->data.pos.type = POS_UPDATE;
1570 event->data.pos.btn_num = pointer->btn_num;
1571 event->data.pos.hpos = point_x;
1572 event->data.pos.vpos = point_y;
1573 }
1574 }
1575
1576 fibril_mutex_unlock(&pointer_list_mtx);
1577 fibril_mutex_unlock(&window_list_mtx);
1578
1579 if (event) {
1580 comp_post_event_top(event);
1581 }
1582
1583 } else {
1584 /* Pointer is grabbed by top-level window action. */
1585 pointer->accum.x += dx;
1586 pointer->accum.y += dy;
1587 pointer->accum_ghost.x += dx;
1588 pointer->accum_ghost.y += dy;
1589#if ANIMATE_WINDOW_TRANSFORMS == 0
1590 if (pointer->ghost.surface == NULL) {
1591 pointer->ghost.surface = top->surface;
1592 pointer->ghost.dx = top->dx;
1593 pointer->ghost.dy = top->dy;
1594 pointer->ghost.fx = top->fx;
1595 pointer->ghost.fy = top->fy;
1596 pointer->ghost.angle = top->angle;
1597 pointer->ghost.transform = top->transform;
1598 }
1599 desktop_rect_t dmg_rect1, dmg_rect2, dmg_rect3, dmg_rect4;
1600 comp_ghost_animate(pointer, &dmg_rect1, &dmg_rect2, &dmg_rect3, &dmg_rect4);
1601#endif
1602#if ANIMATE_WINDOW_TRANSFORMS == 1
1603 sysarg_t x, y, width, height;
1604 comp_window_animate(pointer, top, &x, &y, &width, &height);
1605#endif
1606 fibril_mutex_unlock(&pointer_list_mtx);
1607 fibril_mutex_unlock(&window_list_mtx);
1608#if ANIMATE_WINDOW_TRANSFORMS == 0
1609 comp_damage(dmg_rect1.x, dmg_rect1.y, dmg_rect1.w, dmg_rect1.h);
1610 comp_damage(dmg_rect2.x, dmg_rect2.y, dmg_rect2.w, dmg_rect2.h);
1611 comp_damage(dmg_rect3.x, dmg_rect3.y, dmg_rect3.w, dmg_rect3.h);
1612 comp_damage(dmg_rect4.x, dmg_rect4.y, dmg_rect4.w, dmg_rect4.h);
1613#endif
1614#if ANIMATE_WINDOW_TRANSFORMS == 1
1615 comp_damage(x, y, width, height);
1616#endif
1617 }
1618 } else {
1619 fibril_mutex_unlock(&pointer_list_mtx);
1620 fibril_mutex_unlock(&window_list_mtx);
1621 }
1622
1623 return EOK;
1624}
1625
1626static errno_t comp_mouse_button(input_t *input, int bnum, int bpress)
1627{
1628 pointer_t *pointer = input_pointer(input);
1629
1630 fibril_mutex_lock(&window_list_mtx);
1631 fibril_mutex_lock(&pointer_list_mtx);
1632 window_t *win = NULL;
1633 sysarg_t point_x = 0;
1634 sysarg_t point_y = 0;
1635 sysarg_t width, height;
1636 bool within_client = false;
1637
1638 /* Determine the window which the mouse click belongs to. */
1639 list_foreach(window_list, link, window_t, cw) {
1640 win = cw;
1641 if (win->surface) {
1642 surface_get_resolution(win->surface, &width, &height);
1643 within_client = comp_coord_to_client(pointer->pos.x, pointer->pos.y,
1644 win->transform, width, height, &point_x, &point_y);
1645 }
1646 if (within_client) {
1647 break;
1648 }
1649 }
1650
1651 /* Check whether the window is top-level window. */
1652 window_t *top = (window_t *) list_first(&window_list);
1653 if (!win || !top) {
1654 fibril_mutex_unlock(&pointer_list_mtx);
1655 fibril_mutex_unlock(&window_list_mtx);
1656 return EOK;
1657 }
1658
1659 window_event_t *event_top = NULL;
1660 window_event_t *event_unfocus = NULL;
1661 window_t *win_unfocus = NULL;
1662 sysarg_t dmg_x, dmg_y;
1663 sysarg_t dmg_width = 0;
1664 sysarg_t dmg_height = 0;
1665
1666#if ANIMATE_WINDOW_TRANSFORMS == 0
1667 desktop_rect_t dmg_rect1, dmg_rect2, dmg_rect3, dmg_rect4;
1668#endif
1669
1670 if (bpress) {
1671 pointer->btn_pos = pointer->pos;
1672 pointer->btn_num = bnum;
1673 pointer->pressed = true;
1674
1675 /* Bring the window to the foreground. */
1676 if ((win != top) && within_client) {
1677 win_unfocus = (window_t *) list_first(&window_list);
1678 list_remove(&win->link);
1679 list_prepend(&win->link, &window_list);
1680 event_unfocus = (window_event_t *) malloc(sizeof(window_event_t));
1681 if (event_unfocus) {
1682 link_initialize(&event_unfocus->link);
1683 event_unfocus->type = ET_WINDOW_UNFOCUS;
1684 }
1685 comp_coord_bounding_rect(0, 0, width, height, win->transform,
1686 &dmg_x, &dmg_y, &dmg_width, &dmg_height);
1687 }
1688
1689 /* Notify top-level window about mouse press. */
1690 if (within_client) {
1691 event_top = (window_event_t *) malloc(sizeof(window_event_t));
1692 if (event_top) {
1693 link_initialize(&event_top->link);
1694 event_top->type = ET_POSITION_EVENT;
1695 event_top->data.pos.pos_id = pointer->id;
1696 event_top->data.pos.type = POS_PRESS;
1697 event_top->data.pos.btn_num = bnum;
1698 event_top->data.pos.hpos = point_x;
1699 event_top->data.pos.vpos = point_y;
1700 }
1701 pointer->grab_flags = GF_EMPTY;
1702 }
1703
1704 } else if (pointer->pressed && pointer->btn_num == (unsigned)bnum) {
1705 pointer->pressed = false;
1706
1707#if ANIMATE_WINDOW_TRANSFORMS == 0
1708 sysarg_t pre_x = 0;
1709 sysarg_t pre_y = 0;
1710 sysarg_t pre_width = 0;
1711 sysarg_t pre_height = 0;
1712
1713 if (pointer->grab_flags != GF_EMPTY) {
1714 if (pointer->ghost.surface) {
1715 comp_ghost_animate(pointer, &dmg_rect1, &dmg_rect2, &dmg_rect3, &dmg_rect4);
1716 pointer->ghost.surface = NULL;
1717 }
1718 comp_window_animate(pointer, top, &pre_x, &pre_y, &pre_width, &pre_height);
1719 dmg_x = pre_x;
1720 dmg_y = pre_y;
1721 dmg_width = pre_width;
1722 dmg_height = pre_height;
1723 }
1724#endif
1725
1726 if ((pointer->grab_flags & GF_RESIZE_X) || (pointer->grab_flags & GF_RESIZE_Y)) {
1727
1728 surface_get_resolution(top->surface, &width, &height);
1729#if ANIMATE_WINDOW_TRANSFORMS == 1
1730 top->fx *= (1.0 / scale_back_x);
1731 top->fy *= (1.0 / scale_back_y);
1732 comp_recalc_transform(top);
1733#endif
1734
1735 /* Commit proper resize action. */
1736 event_top = (window_event_t *) malloc(sizeof(window_event_t));
1737 if (event_top) {
1738 link_initialize(&event_top->link);
1739 event_top->type = ET_WINDOW_RESIZE;
1740
1741 event_top->data.resize.offset_x = 0;
1742 event_top->data.resize.offset_y = 0;
1743
1744 int dx = (int) (((double) width) * (scale_back_x - 1.0));
1745 int dy = (int) (((double) height) * (scale_back_y - 1.0));
1746
1747 if (pointer->grab_flags & GF_RESIZE_X)
1748 event_top->data.resize.width =
1749 ((((int) width) + dx) >= 0) ? (width + dx) : 0;
1750 else
1751 event_top->data.resize.width = width;
1752
1753 if (pointer->grab_flags & GF_RESIZE_Y)
1754 event_top->data.resize.height =
1755 ((((int) height) + dy) >= 0) ? (height + dy) : 0;
1756 else
1757 event_top->data.resize.height = height;
1758
1759 event_top->data.resize.placement_flags =
1760 WINDOW_PLACEMENT_ANY;
1761 }
1762
1763 pointer->grab_flags = GF_EMPTY;
1764
1765 } else if (within_client && (pointer->grab_flags == GF_EMPTY) && (top == win)) {
1766
1767 /* Notify top-level window about mouse release. */
1768 event_top = (window_event_t *) malloc(sizeof(window_event_t));
1769 if (event_top) {
1770 link_initialize(&event_top->link);
1771 event_top->type = ET_POSITION_EVENT;
1772 event_top->data.pos.pos_id = pointer->id;
1773 event_top->data.pos.type = POS_RELEASE;
1774 event_top->data.pos.btn_num = bnum;
1775 event_top->data.pos.hpos = point_x;
1776 event_top->data.pos.vpos = point_y;
1777 }
1778 pointer->grab_flags = GF_EMPTY;
1779
1780 } else {
1781 pointer->grab_flags = GF_EMPTY;
1782 }
1783
1784 }
1785
1786 fibril_mutex_unlock(&pointer_list_mtx);
1787 fibril_mutex_unlock(&window_list_mtx);
1788
1789#if ANIMATE_WINDOW_TRANSFORMS == 0
1790 comp_damage(dmg_rect1.x, dmg_rect1.y, dmg_rect1.w, dmg_rect1.h);
1791 comp_damage(dmg_rect2.x, dmg_rect2.y, dmg_rect2.w, dmg_rect2.h);
1792 comp_damage(dmg_rect3.x, dmg_rect3.y, dmg_rect3.w, dmg_rect3.h);
1793 comp_damage(dmg_rect4.x, dmg_rect4.y, dmg_rect4.w, dmg_rect4.h);
1794#endif
1795
1796 if (dmg_width > 0 && dmg_height > 0) {
1797 comp_damage(dmg_x, dmg_y, dmg_width, dmg_height);
1798 }
1799
1800 if (event_unfocus && win_unfocus) {
1801 comp_post_event_win(event_unfocus, win_unfocus);
1802 }
1803
1804 if (event_top) {
1805 comp_post_event_top(event_top);
1806 }
1807
1808 return EOK;
1809}
1810
1811static errno_t comp_active(input_t *input)
1812{
1813 active = true;
1814 comp_damage(0, 0, UINT32_MAX, UINT32_MAX);
1815
1816 return EOK;
1817}
1818
1819static errno_t comp_deactive(input_t *input)
1820{
1821 active = false;
1822 return EOK;
1823}
1824
1825static errno_t comp_key_press(input_t *input, kbd_event_type_t type, keycode_t key,
1826 keymod_t mods, wchar_t c)
1827{
1828 bool win_transform = (mods & KM_ALT) && (
1829 key == KC_W || key == KC_S || key == KC_A || key == KC_D ||
1830 key == KC_Q || key == KC_E || key == KC_R || key == KC_F);
1831 bool win_resize = (mods & KM_ALT) && (
1832 key == KC_T || key == KC_G || key == KC_B || key == KC_N);
1833 bool win_opacity = (mods & KM_ALT) && (
1834 key == KC_C || key == KC_V);
1835 bool win_close = (mods & KM_ALT) && (key == KC_X);
1836 bool win_switch = (mods & KM_ALT) && (key == KC_TAB);
1837 bool viewport_move = (mods & KM_ALT) && (
1838 key == KC_I || key == KC_K || key == KC_J || key == KC_L);
1839 bool viewport_change = (mods & KM_ALT) && (
1840 key == KC_O || key == KC_P);
1841 bool kconsole_switch = (key == KC_PAUSE) || (key == KC_BREAK);
1842 bool filter_switch = (mods & KM_ALT) && (key == KC_Y);
1843
1844 bool key_filter = (type == KEY_RELEASE) && (win_transform || win_resize ||
1845 win_opacity || win_close || win_switch || viewport_move ||
1846 viewport_change || kconsole_switch || filter_switch);
1847
1848 if (key_filter) {
1849 /* no-op */
1850 } else if (win_transform) {
1851 fibril_mutex_lock(&window_list_mtx);
1852 window_t *win = (window_t *) list_first(&window_list);
1853 if (win && win->surface) {
1854 switch (key) {
1855 case KC_W:
1856 win->dy += -20;
1857 break;
1858 case KC_S:
1859 win->dy += 20;
1860 break;
1861 case KC_A:
1862 win->dx += -20;
1863 break;
1864 case KC_D:
1865 win->dx += 20;
1866 break;
1867 case KC_Q:
1868 win->angle += 0.1;
1869 break;
1870 case KC_E:
1871 win->angle -= 0.1;
1872 break;
1873 case KC_R:
1874 win->fx *= 0.95;
1875 win->fy *= 0.95;
1876 break;
1877 case KC_F:
1878 win->fx *= 1.05;
1879 win->fy *= 1.05;
1880 break;
1881 default:
1882 break;
1883 }
1884
1885 /* Transform the window and calculate damage. */
1886 sysarg_t x, y, width, height;
1887 surface_get_resolution(win->surface, &width, &height);
1888 sysarg_t x1, y1, width1, height1;
1889 sysarg_t x2, y2, width2, height2;
1890 comp_coord_bounding_rect(0, 0, width, height, win->transform,
1891 &x1, &y1, &width1, &height1);
1892 comp_recalc_transform(win);
1893 comp_coord_bounding_rect(0, 0, width, height, win->transform,
1894 &x2, &y2, &width2, &height2);
1895 rectangle_union(x1, y1, width1, height1, x2, y2, width2, height2,
1896 &x, &y, &width, &height);
1897 fibril_mutex_unlock(&window_list_mtx);
1898
1899 comp_damage(x, y, width, height);
1900 } else {
1901 fibril_mutex_unlock(&window_list_mtx);
1902 }
1903 } else if (win_resize) {
1904 fibril_mutex_lock(&window_list_mtx);
1905 window_t *win = (window_t *) list_first(&window_list);
1906 if ((win) && (win->surface) && (win->flags & WINDOW_RESIZEABLE)) {
1907 window_event_t *event = (window_event_t *) malloc(sizeof(window_event_t));
1908 if (event == NULL) {
1909 fibril_mutex_unlock(&window_list_mtx);
1910 return ENOMEM;
1911 }
1912
1913 sysarg_t width, height;
1914 surface_get_resolution(win->surface, &width, &height);
1915
1916 link_initialize(&event->link);
1917 event->type = ET_WINDOW_RESIZE;
1918
1919 event->data.resize.offset_x = 0;
1920 event->data.resize.offset_y = 0;
1921
1922 switch (key) {
1923 case KC_T:
1924 event->data.resize.width = width;
1925 event->data.resize.height = (height >= 20) ? height - 20 : 0;
1926 break;
1927 case KC_G:
1928 event->data.resize.width = width;
1929 event->data.resize.height = height + 20;
1930 break;
1931 case KC_B:
1932 event->data.resize.width = (width >= 20) ? width - 20 : 0;;
1933 event->data.resize.height = height;
1934 break;
1935 case KC_N:
1936 event->data.resize.width = width + 20;
1937 event->data.resize.height = height;
1938 break;
1939 default:
1940 event->data.resize.width = 0;
1941 event->data.resize.height = 0;
1942 break;
1943 }
1944
1945 event->data.resize.placement_flags = WINDOW_PLACEMENT_ANY;
1946
1947 fibril_mutex_unlock(&window_list_mtx);
1948 comp_post_event_top(event);
1949 } else {
1950 fibril_mutex_unlock(&window_list_mtx);
1951 }
1952 } else if (win_opacity) {
1953 fibril_mutex_lock(&window_list_mtx);
1954 window_t *win = (window_t *) list_first(&window_list);
1955 if (win && win->surface) {
1956 switch (key) {
1957 case KC_C:
1958 if (win->opacity > 0) {
1959 win->opacity -= 5;
1960 }
1961 break;
1962 case KC_V:
1963 if (win->opacity < 255) {
1964 win->opacity += 5;
1965 }
1966 break;
1967 default:
1968 break;
1969 }
1970
1971 /* Calculate damage. */
1972 sysarg_t x, y, width, height;
1973 surface_get_resolution(win->surface, &width, &height);
1974 comp_coord_bounding_rect(0, 0, width, height, win->transform,
1975 &x, &y, &width, &height);
1976 fibril_mutex_unlock(&window_list_mtx);
1977
1978 comp_damage(x, y, width, height);
1979 } else {
1980 fibril_mutex_unlock(&window_list_mtx);
1981 }
1982 } else if (win_close) {
1983 window_event_t *event = (window_event_t *) malloc(sizeof(window_event_t));
1984 if (event == NULL)
1985 return ENOMEM;
1986
1987 link_initialize(&event->link);
1988 event->type = ET_WINDOW_CLOSE;
1989
1990 comp_post_event_top(event);
1991 } else if (win_switch) {
1992 fibril_mutex_lock(&window_list_mtx);
1993 if (!list_empty(&window_list)) {
1994 window_t *win1 = (window_t *) list_first(&window_list);
1995 list_remove(&win1->link);
1996 list_append(&win1->link, &window_list);
1997 window_t *win2 = (window_t *) list_first(&window_list);
1998
1999 window_event_t *event1 = (window_event_t *) malloc(sizeof(window_event_t));
2000 if (event1) {
2001 link_initialize(&event1->link);
2002 event1->type = ET_WINDOW_UNFOCUS;
2003 }
2004
2005 window_event_t *event2 = (window_event_t *) malloc(sizeof(window_event_t));
2006 if (event2) {
2007 link_initialize(&event2->link);
2008 event2->type = ET_WINDOW_FOCUS;
2009 }
2010
2011 sysarg_t x1 = 0;
2012 sysarg_t y1 = 0;
2013 sysarg_t width1 = 0;
2014 sysarg_t height1 = 0;
2015 if (win1->surface) {
2016 sysarg_t width, height;
2017 surface_get_resolution(win1->surface, &width, &height);
2018 comp_coord_bounding_rect(0, 0, width, height, win1->transform,
2019 &x1, &y1, &width1, &height1);
2020 }
2021
2022 sysarg_t x2 = 0;
2023 sysarg_t y2 = 0;
2024 sysarg_t width2 = 0;
2025 sysarg_t height2 = 0;
2026 if (win2->surface) {
2027 sysarg_t width, height;
2028 surface_get_resolution(win2->surface, &width, &height);
2029 comp_coord_bounding_rect(0, 0, width, height, win2->transform,
2030 &x2, &y2, &width2, &height2);
2031 }
2032
2033 sysarg_t x, y, width, height;
2034 rectangle_union(x1, y1, width1, height1, x2, y2, width2, height2,
2035 &x, &y, &width, &height);
2036
2037 fibril_mutex_unlock(&window_list_mtx);
2038
2039 if (event1 && win1) {
2040 comp_post_event_win(event1, win1);
2041 }
2042
2043 if (event2 && win2) {
2044 comp_post_event_win(event2, win2);
2045 }
2046
2047 comp_damage(x, y, width, height);
2048 } else {
2049 fibril_mutex_unlock(&window_list_mtx);
2050 }
2051 } else if (viewport_move) {
2052 fibril_mutex_lock(&viewport_list_mtx);
2053 viewport_t *vp = (viewport_t *) list_first(&viewport_list);
2054 if (vp) {
2055 switch (key) {
2056 case KC_I:
2057 vp->pos.x += 0;
2058 vp->pos.y += -20;
2059 break;
2060 case KC_K:
2061 vp->pos.x += 0;
2062 vp->pos.y += 20;
2063 break;
2064 case KC_J:
2065 vp->pos.x += -20;
2066 vp->pos.y += 0;
2067 break;
2068 case KC_L:
2069 vp->pos.x += 20;
2070 vp->pos.y += 0;
2071 break;
2072 default:
2073 vp->pos.x += 0;
2074 vp->pos.y += 0;
2075 break;
2076 }
2077
2078 sysarg_t x = vp->pos.x;
2079 sysarg_t y = vp->pos.y;
2080 sysarg_t width, height;
2081 surface_get_resolution(vp->surface, &width, &height);
2082 fibril_mutex_unlock(&viewport_list_mtx);
2083
2084 comp_restrict_pointers();
2085 comp_damage(x, y, width, height);
2086 } else {
2087 fibril_mutex_unlock(&viewport_list_mtx);
2088 }
2089 } else if (viewport_change) {
2090 fibril_mutex_lock(&viewport_list_mtx);
2091
2092 viewport_t *vp;
2093 switch (key) {
2094 case KC_O:
2095 vp = (viewport_t *) list_first(&viewport_list);
2096 if (vp) {
2097 list_remove(&vp->link);
2098 list_append(&vp->link, &viewport_list);
2099 }
2100 break;
2101 case KC_P:
2102 vp = (viewport_t *) list_last(&viewport_list);
2103 if (vp) {
2104 list_remove(&vp->link);
2105 list_prepend(&vp->link, &viewport_list);
2106 }
2107 break;
2108 default:
2109 break;
2110 }
2111
2112 fibril_mutex_unlock(&viewport_list_mtx);
2113 } else if (kconsole_switch) {
2114 if (console_kcon())
2115 active = false;
2116 } else if (filter_switch) {
2117 filter_index++;
2118 if (filter_index > 1)
2119 filter_index = 0;
2120 if (filter_index == 0) {
2121 filter = filter_nearest;
2122 }
2123 else {
2124 filter = filter_bilinear;
2125 }
2126 comp_damage(0, 0, UINT32_MAX, UINT32_MAX);
2127 } else {
2128 window_event_t *event = (window_event_t *) malloc(sizeof(window_event_t));
2129 if (event == NULL)
2130 return ENOMEM;
2131
2132 link_initialize(&event->link);
2133 event->type = ET_KEYBOARD_EVENT;
2134 event->data.kbd.type = type;
2135 event->data.kbd.key = key;
2136 event->data.kbd.mods = mods;
2137 event->data.kbd.c = c;
2138
2139 comp_post_event_top(event);
2140 }
2141
2142 return EOK;
2143}
2144
2145static errno_t input_connect(const char *svc)
2146{
2147 async_sess_t *sess;
2148 service_id_t dsid;
2149
2150 errno_t rc = loc_service_get_id(svc, &dsid, 0);
2151 if (rc != EOK) {
2152 printf("%s: Input service %s not found\n", NAME, svc);
2153 return rc;
2154 }
2155
2156 sess = loc_service_connect(dsid, INTERFACE_INPUT, 0);
2157 if (sess == NULL) {
2158 printf("%s: Unable to connect to input service %s\n", NAME,
2159 svc);
2160 return EIO;
2161 }
2162
2163 fibril_mutex_lock(&pointer_list_mtx);
2164 pointer_t *pointer = pointer_create();
2165 if (pointer != NULL) {
2166 pointer->id = pointer_id++;
2167 list_append(&pointer->link, &pointer_list);
2168 }
2169 fibril_mutex_unlock(&pointer_list_mtx);
2170
2171 if (pointer == NULL) {
2172 printf("%s: Cannot create pointer.\n", NAME);
2173 async_hangup(sess);
2174 return ENOMEM;
2175 }
2176
2177 rc = input_open(sess, &input_ev_ops, pointer, &input);
2178 if (rc != EOK) {
2179 async_hangup(sess);
2180 printf("%s: Unable to communicate with service %s (%s)\n",
2181 NAME, svc, str_error(rc));
2182 return rc;
2183 }
2184
2185 return EOK;
2186}
2187
2188static void input_disconnect(void)
2189{
2190 pointer_t *pointer = input->user;
2191 input_close(input);
2192 pointer_destroy(pointer);
2193}
2194
2195static void discover_viewports(void)
2196{
2197 fibril_mutex_lock(&discovery_mtx);
2198
2199 /* Create viewports and connect them to visualizers. */
2200 category_id_t cat_id;
2201 errno_t rc = loc_category_get_id("visualizer", &cat_id, IPC_FLAG_BLOCKING);
2202 if (rc != EOK)
2203 goto ret;
2204
2205 service_id_t *svcs;
2206 size_t svcs_cnt = 0;
2207 rc = loc_category_get_svcs(cat_id, &svcs, &svcs_cnt);
2208 if (rc != EOK)
2209 goto ret;
2210
2211 fibril_mutex_lock(&viewport_list_mtx);
2212 for (size_t i = 0; i < svcs_cnt; ++i) {
2213 bool exists = false;
2214 list_foreach(viewport_list, link, viewport_t, vp) {
2215 if (vp->dsid == svcs[i]) {
2216 exists = true;
2217 break;
2218 }
2219 }
2220
2221 if (exists)
2222 continue;
2223
2224 viewport_t *vp = viewport_create(svcs[i]);
2225 if (vp != NULL)
2226 list_append(&vp->link, &viewport_list);
2227 }
2228 fibril_mutex_unlock(&viewport_list_mtx);
2229
2230 if (!list_empty(&viewport_list))
2231 input_activate(input);
2232
2233ret:
2234 fibril_mutex_unlock(&discovery_mtx);
2235}
2236
2237static void category_change_cb(void)
2238{
2239 discover_viewports();
2240}
2241
2242static errno_t compositor_srv_init(char *input_svc, char *name)
2243{
2244 /* Coordinates of the central pixel. */
2245 coord_origin = UINT32_MAX / 4;
2246
2247 /* Color of the viewport background. Must be opaque. */
2248 bg_color = PIXEL(255, 69, 51, 103);
2249
2250 /* Register compositor server. */
2251 async_set_fallback_port_handler(client_connection, NULL);
2252
2253 errno_t rc = loc_server_register(NAME);
2254 if (rc != EOK) {
2255 printf("%s: Unable to register server (%s)\n", NAME, str_error(rc));
2256 return -1;
2257 }
2258
2259 server_name = name;
2260
2261 char svc[LOC_NAME_MAXLEN + 1];
2262 snprintf(svc, LOC_NAME_MAXLEN, "%s/%s", NAMESPACE, server_name);
2263
2264 service_id_t service_id;
2265 rc = loc_service_register(svc, &service_id);
2266 if (rc != EOK) {
2267 printf("%s: Unable to register service %s\n", NAME, svc);
2268 return rc;
2269 }
2270
2271 /* Prepare window registrator (entrypoint for clients). */
2272 char winreg[LOC_NAME_MAXLEN + 1];
2273 snprintf(winreg, LOC_NAME_MAXLEN, "%s%s/winreg", NAMESPACE, server_name);
2274 if (loc_service_register(winreg, &winreg_id) != EOK) {
2275 printf("%s: Unable to register service %s\n", NAME, winreg);
2276 return -1;
2277 }
2278
2279 /* Establish input bidirectional connection. */
2280 rc = input_connect(input_svc);
2281 if (rc != EOK) {
2282 printf("%s: Failed to connect to input service.\n", NAME);
2283 return rc;
2284 }
2285
2286 rc = loc_register_cat_change_cb(category_change_cb);
2287 if (rc != EOK) {
2288 printf("%s: Failed to register category change callback\n", NAME);
2289 input_disconnect();
2290 return rc;
2291 }
2292
2293 discover_viewports();
2294
2295 comp_restrict_pointers();
2296 comp_damage(0, 0, UINT32_MAX, UINT32_MAX);
2297
2298 return EOK;
2299}
2300
2301static void usage(char *name)
2302{
2303 printf("Usage: %s <input_dev> <server_name>\n", name);
2304}
2305
2306int main(int argc, char *argv[])
2307{
2308 if (argc < 3) {
2309 usage(argv[0]);
2310 return 1;
2311 }
2312
2313 printf("%s: HelenOS Compositor server\n", NAME);
2314
2315 errno_t rc = compositor_srv_init(argv[1], argv[2]);
2316 if (rc != EOK)
2317 return rc;
2318
2319 printf("%s: Accepting connections\n", NAME);
2320 task_retval(0);
2321 async_manager();
2322
2323 /* Never reached */
2324 return 0;
2325}
2326
2327/** @}
2328 */
Note: See TracBrowser for help on using the repository browser.