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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since c8e2ac5 was c8e2ac5, checked in by Petr Koupy <petr.koupy@…>, 13 years ago

Fixed inconsistencies in calculation of bounding rectangle, ghost frame and client damage request.

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