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

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

add HelenOS logo to the launcher
(the grid layout widget currently creates uniform cells and ignores widget dimension hints, therefore the window needs to be so high and ugly)

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