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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since da680b4b was 984a9ba, checked in by Martin Decky <martin@…>, 7 years ago

do not expose the call capability handler from the async framework

Keep the call capability handler encapsulated within the async framework
and do not expose it explicitly via its API. Use the pointer to
ipc_call_t as the sole object identifying an IPC call in the code that
uses the async framework.

This plugs a major leak in the abstraction and also simplifies both the
async framework (slightly) and all IPC servers.

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