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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 6769005 was 6769005, checked in by Jakub Jermar <jakub@…>, 7 years ago

Use user-defined labels instead of phone hashes

This commit changes the way how the async framework maps incomming calls
to connections. Instead of abusing the kernel addresses of attached
phones as identifiers, the IPC_M_CONNECT_TO_ME and IPC_M_CONNECT_ME_TO
messages allow the server to specify an arbitrary label which is
remembered in the connected phone and consequently imprinted on each
call which is routed through this phone.

The async framework uses the address of the connection structure as the
label. This removes the need for a connection hash table because each
incoming call already remembers the connection in its label.

To disambiguate this new label and the other user-defined label used for
answers, the call structure now has the request_label member for the
former and answer_label member for the latter.

This commit also moves the kernel definition of ipc_data_t to abi/ and
removes the uspace redefinition thereof. Finally, when forwarding the
IPC_M_CONNECT_TO_ME call, the phone capability and the kernel object
allocated in request_process are now correctly disposed of.

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