1 /*
2 * Clutter.
3 *
4 * An OpenGL based 'interactive canvas' library.
5 *
6 * Copyright (C) 2016 Red Hat Inc.
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
20 *
21 * Author: Jonas Ådahl <jadahl@gmail.com>
22 */
23
24 #ifdef HAVE_CONFIG_H
25 #include "clutter-build-config.h"
26 #endif
27
28 #include <glib-object.h>
29 #include <linux/input.h>
30
31 #include "clutter-private.h"
32 #include "clutter-virtual-input-device.h"
33 #include "evdev/clutter-input-device-evdev.h"
34 #include "evdev/clutter-seat-evdev.h"
35 #include "evdev/clutter-virtual-input-device-evdev.h"
36
37 enum
38 {
39 PROP_0,
40
41 PROP_SEAT,
42
43 PROP_LAST
44 };
45
46 static GParamSpec *obj_props[PROP_LAST];
47
48 struct _ClutterVirtualInputDeviceEvdev
49 {
50 ClutterVirtualInputDevice parent;
51
52 ClutterInputDevice *device;
53 ClutterSeatEvdev *seat;
54 int button_count[KEY_CNT];
55 };
56
57 G_DEFINE_TYPE (ClutterVirtualInputDeviceEvdev,
58 clutter_virtual_input_device_evdev,
59 CLUTTER_TYPE_VIRTUAL_INPUT_DEVICE)
60
61 typedef enum _EvdevButtonType
62 {
63 EVDEV_BUTTON_TYPE_NONE,
64 EVDEV_BUTTON_TYPE_KEY,
65 EVDEV_BUTTON_TYPE_BUTTON,
66 } EvdevButtonType;
67
68 static int
update_button_count(ClutterVirtualInputDeviceEvdev * virtual_evdev,uint32_t button,uint32_t state)69 update_button_count (ClutterVirtualInputDeviceEvdev *virtual_evdev,
70 uint32_t button,
71 uint32_t state)
72 {
73 if (state)
74 return ++virtual_evdev->button_count[button];
75 else
76 return --virtual_evdev->button_count[button];
77 }
78
79 static EvdevButtonType
get_button_type(uint16_t code)80 get_button_type (uint16_t code)
81 {
82 switch (code)
83 {
84 case BTN_TOOL_PEN:
85 case BTN_TOOL_RUBBER:
86 case BTN_TOOL_BRUSH:
87 case BTN_TOOL_PENCIL:
88 case BTN_TOOL_AIRBRUSH:
89 case BTN_TOOL_MOUSE:
90 case BTN_TOOL_LENS:
91 case BTN_TOOL_QUINTTAP:
92 case BTN_TOOL_DOUBLETAP:
93 case BTN_TOOL_TRIPLETAP:
94 case BTN_TOOL_QUADTAP:
95 case BTN_TOOL_FINGER:
96 case BTN_TOUCH:
97 return EVDEV_BUTTON_TYPE_NONE;
98 }
99
100 if (code >= KEY_ESC && code <= KEY_MICMUTE)
101 return EVDEV_BUTTON_TYPE_KEY;
102 if (code >= BTN_MISC && code <= BTN_GEAR_UP)
103 return EVDEV_BUTTON_TYPE_BUTTON;
104 if (code >= KEY_OK && code <= KEY_LIGHTS_TOGGLE)
105 return EVDEV_BUTTON_TYPE_KEY;
106 if (code >= BTN_DPAD_UP && code <= BTN_DPAD_RIGHT)
107 return EVDEV_BUTTON_TYPE_BUTTON;
108 if (code >= KEY_ALS_TOGGLE && code <= KEY_KBDINPUTASSIST_CANCEL)
109 return EVDEV_BUTTON_TYPE_KEY;
110 if (code >= BTN_TRIGGER_HAPPY && code <= BTN_TRIGGER_HAPPY40)
111 return EVDEV_BUTTON_TYPE_BUTTON;
112 return EVDEV_BUTTON_TYPE_NONE;
113 }
114
115 static void
release_pressed_buttons(ClutterVirtualInputDevice * virtual_device)116 release_pressed_buttons (ClutterVirtualInputDevice *virtual_device)
117 {
118 ClutterVirtualInputDeviceEvdev *virtual_evdev =
119 CLUTTER_VIRTUAL_INPUT_DEVICE_EVDEV (virtual_device);
120 int code;
121 uint64_t time_us;
122
123 time_us = g_get_monotonic_time ();
124
125 for (code = 0; code < G_N_ELEMENTS (virtual_evdev->button_count); code++)
126 {
127 if (virtual_evdev->button_count[code] == 0)
128 continue;
129
130 switch (get_button_type (code))
131 {
132 case EVDEV_BUTTON_TYPE_KEY:
133 clutter_virtual_input_device_notify_key (virtual_device,
134 time_us,
135 code,
136 CLUTTER_KEY_STATE_RELEASED);
137 break;
138 case EVDEV_BUTTON_TYPE_BUTTON:
139 clutter_virtual_input_device_notify_button (virtual_device,
140 time_us,
141 code,
142 CLUTTER_BUTTON_STATE_RELEASED);
143 break;
144 case EVDEV_BUTTON_TYPE_NONE:
145 g_assert_not_reached ();
146 }
147 }
148 }
149
150 static void
clutter_virtual_input_device_evdev_notify_relative_motion(ClutterVirtualInputDevice * virtual_device,uint64_t time_us,double dx,double dy)151 clutter_virtual_input_device_evdev_notify_relative_motion (ClutterVirtualInputDevice *virtual_device,
152 uint64_t time_us,
153 double dx,
154 double dy)
155 {
156 ClutterVirtualInputDeviceEvdev *virtual_evdev =
157 CLUTTER_VIRTUAL_INPUT_DEVICE_EVDEV (virtual_device);
158
159 if (time_us == CLUTTER_CURRENT_TIME)
160 time_us = g_get_monotonic_time ();
161
162 clutter_seat_evdev_notify_relative_motion (virtual_evdev->seat,
163 virtual_evdev->device,
164 time_us,
165 dx, dy,
166 dx, dy);
167 }
168
169 static void
clutter_virtual_input_device_evdev_notify_absolute_motion(ClutterVirtualInputDevice * virtual_device,uint64_t time_us,double x,double y)170 clutter_virtual_input_device_evdev_notify_absolute_motion (ClutterVirtualInputDevice *virtual_device,
171 uint64_t time_us,
172 double x,
173 double y)
174 {
175 ClutterVirtualInputDeviceEvdev *virtual_evdev =
176 CLUTTER_VIRTUAL_INPUT_DEVICE_EVDEV (virtual_device);
177
178 if (time_us == CLUTTER_CURRENT_TIME)
179 time_us = g_get_monotonic_time ();
180
181 clutter_seat_evdev_notify_absolute_motion (virtual_evdev->seat,
182 virtual_evdev->device,
183 time_us,
184 x, y,
185 NULL);
186 }
187
188 static void
clutter_virtual_input_device_evdev_notify_button(ClutterVirtualInputDevice * virtual_device,uint64_t time_us,uint32_t button,ClutterButtonState button_state)189 clutter_virtual_input_device_evdev_notify_button (ClutterVirtualInputDevice *virtual_device,
190 uint64_t time_us,
191 uint32_t button,
192 ClutterButtonState button_state)
193 {
194 ClutterVirtualInputDeviceEvdev *virtual_evdev =
195 CLUTTER_VIRTUAL_INPUT_DEVICE_EVDEV (virtual_device);
196 int button_count;
197
198 if (time_us == CLUTTER_CURRENT_TIME)
199 time_us = g_get_monotonic_time ();
200
201 if (get_button_type (button) != EVDEV_BUTTON_TYPE_BUTTON)
202 {
203 g_warning ("Unknown/invalid virtual device button 0x%x pressed",
204 button);
205 return;
206 }
207
208 button_count = update_button_count (virtual_evdev, button, button_state);
209 if (button_count < 0 || button_count > 1)
210 {
211 g_warning ("Received multiple virtual 0x%x button %s (ignoring)", button,
212 button_state == CLUTTER_BUTTON_STATE_PRESSED ? "presses" : "releases");
213 update_button_count (virtual_evdev, button, 1 - button_state);
214 return;
215 }
216
217 clutter_seat_evdev_notify_button (virtual_evdev->seat,
218 virtual_evdev->device,
219 time_us,
220 button,
221 button_state);
222 }
223
224 static void
clutter_virtual_input_device_evdev_notify_key(ClutterVirtualInputDevice * virtual_device,uint64_t time_us,uint32_t key,ClutterKeyState key_state)225 clutter_virtual_input_device_evdev_notify_key (ClutterVirtualInputDevice *virtual_device,
226 uint64_t time_us,
227 uint32_t key,
228 ClutterKeyState key_state)
229 {
230 ClutterVirtualInputDeviceEvdev *virtual_evdev =
231 CLUTTER_VIRTUAL_INPUT_DEVICE_EVDEV (virtual_device);
232 int key_count;
233
234 if (time_us == CLUTTER_CURRENT_TIME)
235 time_us = g_get_monotonic_time ();
236
237 if (get_button_type (key) != EVDEV_BUTTON_TYPE_KEY)
238 {
239 g_warning ("Unknown/invalid virtual device key 0x%x pressed\n", key);
240 return;
241 }
242
243 key_count = update_button_count (virtual_evdev, key, key_state);
244 if (key_count < 0 || key_count > 1)
245 {
246 g_warning ("Received multiple virtual 0x%x key %s (ignoring)", key,
247 key_state == CLUTTER_KEY_STATE_PRESSED ? "presses" : "releases");
248 update_button_count (virtual_evdev, key, 1 - key_state);
249 return;
250 }
251
252 clutter_seat_evdev_notify_key (virtual_evdev->seat,
253 virtual_evdev->device,
254 time_us,
255 key,
256 key_state,
257 TRUE);
258 }
259
260 static gboolean
pick_keycode_for_keyval_in_current_group(ClutterVirtualInputDevice * virtual_device,guint keyval,guint * keycode_out,guint * level_out)261 pick_keycode_for_keyval_in_current_group (ClutterVirtualInputDevice *virtual_device,
262 guint keyval,
263 guint *keycode_out,
264 guint *level_out)
265 {
266 ClutterVirtualInputDeviceEvdev *virtual_evdev =
267 CLUTTER_VIRTUAL_INPUT_DEVICE_EVDEV (virtual_device);
268 ClutterDeviceManager *manager;
269 struct xkb_keymap *xkb_keymap;
270 struct xkb_state *state;
271 guint keycode, layout;
272 xkb_keycode_t min_keycode, max_keycode;
273
274 manager = clutter_virtual_input_device_get_manager (virtual_device);
275 xkb_keymap = _clutter_device_manager_evdev_get_keymap (CLUTTER_DEVICE_MANAGER_EVDEV (manager));
276 state = virtual_evdev->seat->xkb;
277
278 layout = xkb_state_serialize_layout (state, XKB_STATE_LAYOUT_EFFECTIVE);
279 min_keycode = xkb_keymap_min_keycode (xkb_keymap);
280 max_keycode = xkb_keymap_max_keycode (xkb_keymap);
281 for (keycode = min_keycode; keycode < max_keycode; keycode++)
282 {
283 gint num_levels, level;
284 num_levels = xkb_keymap_num_levels_for_key (xkb_keymap, keycode, layout);
285 for (level = 0; level < num_levels; level++)
286 {
287 const xkb_keysym_t *syms;
288 gint num_syms, sym;
289 num_syms = xkb_keymap_key_get_syms_by_level (xkb_keymap, keycode, layout, level, &syms);
290 for (sym = 0; sym < num_syms; sym++)
291 {
292 if (syms[sym] == keyval)
293 {
294 *keycode_out = keycode;
295 if (level_out)
296 *level_out = level;
297 return TRUE;
298 }
299 }
300 }
301 }
302
303 return FALSE;
304 }
305
306 static void
apply_level_modifiers(ClutterVirtualInputDevice * virtual_device,uint64_t time_us,uint32_t level,uint32_t key_state)307 apply_level_modifiers (ClutterVirtualInputDevice *virtual_device,
308 uint64_t time_us,
309 uint32_t level,
310 uint32_t key_state)
311 {
312 ClutterVirtualInputDeviceEvdev *virtual_evdev =
313 CLUTTER_VIRTUAL_INPUT_DEVICE_EVDEV (virtual_device);
314 guint keysym, keycode, evcode;
315
316 if (level == 0)
317 return;
318
319 if (level == 1)
320 {
321 keysym = XKB_KEY_Shift_L;
322 }
323 else if (level == 2)
324 {
325 keysym = XKB_KEY_ISO_Level3_Shift;
326 }
327 else
328 {
329 g_warning ("Unhandled level: %d\n", level);
330 return;
331 }
332
333 if (!pick_keycode_for_keyval_in_current_group (virtual_device, keysym,
334 &keycode, NULL))
335 return;
336
337 clutter_input_device_keycode_to_evdev (virtual_evdev->device,
338 keycode, &evcode);
339 clutter_seat_evdev_notify_key (virtual_evdev->seat,
340 virtual_evdev->device,
341 time_us,
342 evcode,
343 key_state,
344 TRUE);
345 }
346
347 static void
clutter_virtual_input_device_evdev_notify_keyval(ClutterVirtualInputDevice * virtual_device,uint64_t time_us,uint32_t keyval,ClutterKeyState key_state)348 clutter_virtual_input_device_evdev_notify_keyval (ClutterVirtualInputDevice *virtual_device,
349 uint64_t time_us,
350 uint32_t keyval,
351 ClutterKeyState key_state)
352 {
353 ClutterVirtualInputDeviceEvdev *virtual_evdev =
354 CLUTTER_VIRTUAL_INPUT_DEVICE_EVDEV (virtual_device);
355 int key_count;
356 guint keycode = 0, level = 0, evcode = 0;
357
358 if (time_us == CLUTTER_CURRENT_TIME)
359 time_us = g_get_monotonic_time ();
360
361 if (!pick_keycode_for_keyval_in_current_group (virtual_device,
362 keyval, &keycode, &level))
363 {
364 g_warning ("No keycode found for keyval %x in current group", keyval);
365 return;
366 }
367
368 clutter_input_device_keycode_to_evdev (virtual_evdev->device,
369 keycode, &evcode);
370
371 if (get_button_type (evcode) != EVDEV_BUTTON_TYPE_KEY)
372 {
373 g_warning ("Unknown/invalid virtual device key 0x%x pressed\n", evcode);
374 return;
375 }
376
377 key_count = update_button_count (virtual_evdev, evcode, key_state);
378 if (key_count < 0 || key_count > 1)
379 {
380 g_warning ("Received multiple virtual 0x%x key %s (ignoring)", keycode,
381 key_state == CLUTTER_KEY_STATE_PRESSED ? "presses" : "releases");
382 update_button_count (virtual_evdev, evcode, 1 - key_state);
383 return;
384 }
385
386 if (key_state)
387 apply_level_modifiers (virtual_device, time_us, level, key_state);
388
389 clutter_seat_evdev_notify_key (virtual_evdev->seat,
390 virtual_evdev->device,
391 time_us,
392 evcode,
393 key_state,
394 TRUE);
395
396 if (!key_state)
397 apply_level_modifiers (virtual_device, time_us, level, key_state);
398 }
399
400 static void
direction_to_discrete(ClutterScrollDirection direction,double * discrete_dx,double * discrete_dy)401 direction_to_discrete (ClutterScrollDirection direction,
402 double *discrete_dx,
403 double *discrete_dy)
404 {
405 switch (direction)
406 {
407 case CLUTTER_SCROLL_UP:
408 *discrete_dx = 0.0;
409 *discrete_dy = -1.0;
410 break;
411 case CLUTTER_SCROLL_DOWN:
412 *discrete_dx = 0.0;
413 *discrete_dy = 1.0;
414 break;
415 case CLUTTER_SCROLL_LEFT:
416 *discrete_dx = -1.0;
417 *discrete_dy = 0.0;
418 break;
419 case CLUTTER_SCROLL_RIGHT:
420 *discrete_dx = 1.0;
421 *discrete_dy = 0.0;
422 break;
423 case CLUTTER_SCROLL_SMOOTH:
424 g_assert_not_reached ();
425 break;
426 }
427 }
428
429 static void
clutter_virtual_input_device_evdev_notify_discrete_scroll(ClutterVirtualInputDevice * virtual_device,uint64_t time_us,ClutterScrollDirection direction,ClutterScrollSource scroll_source)430 clutter_virtual_input_device_evdev_notify_discrete_scroll (ClutterVirtualInputDevice *virtual_device,
431 uint64_t time_us,
432 ClutterScrollDirection direction,
433 ClutterScrollSource scroll_source)
434 {
435 ClutterVirtualInputDeviceEvdev *virtual_evdev =
436 CLUTTER_VIRTUAL_INPUT_DEVICE_EVDEV (virtual_device);
437 double discrete_dx = 0.0, discrete_dy = 0.0;
438
439 if (time_us == CLUTTER_CURRENT_TIME)
440 time_us = g_get_monotonic_time ();
441
442 direction_to_discrete (direction, &discrete_dx, &discrete_dy);
443
444 clutter_seat_evdev_notify_discrete_scroll (virtual_evdev->seat,
445 virtual_evdev->device,
446 time_us,
447 discrete_dx, discrete_dy,
448 scroll_source);
449 }
450
451 static void
clutter_virtual_input_device_evdev_notify_scroll_continuous(ClutterVirtualInputDevice * virtual_device,uint64_t time_us,double dx,double dy,ClutterScrollSource scroll_source,ClutterScrollFinishFlags finish_flags)452 clutter_virtual_input_device_evdev_notify_scroll_continuous (ClutterVirtualInputDevice *virtual_device,
453 uint64_t time_us,
454 double dx,
455 double dy,
456 ClutterScrollSource scroll_source,
457 ClutterScrollFinishFlags finish_flags)
458 {
459 ClutterVirtualInputDeviceEvdev *virtual_evdev =
460 CLUTTER_VIRTUAL_INPUT_DEVICE_EVDEV (virtual_device);
461
462 if (time_us == CLUTTER_CURRENT_TIME)
463 time_us = g_get_monotonic_time ();
464
465 clutter_seat_evdev_notify_scroll_continuous (virtual_evdev->seat,
466 virtual_evdev->device,
467 time_us,
468 dx, dy,
469 scroll_source,
470 CLUTTER_SCROLL_FINISHED_NONE);
471 }
472
473 static void
clutter_virtual_input_device_evdev_notify_touch_down(ClutterVirtualInputDevice * virtual_device,uint64_t time_us,int device_slot,double x,double y)474 clutter_virtual_input_device_evdev_notify_touch_down (ClutterVirtualInputDevice *virtual_device,
475 uint64_t time_us,
476 int device_slot,
477 double x,
478 double y)
479 {
480 ClutterVirtualInputDeviceEvdev *virtual_evdev =
481 CLUTTER_VIRTUAL_INPUT_DEVICE_EVDEV (virtual_device);
482 ClutterInputDeviceEvdev *device_evdev =
483 CLUTTER_INPUT_DEVICE_EVDEV (virtual_evdev->device);
484 ClutterTouchState *touch_state;
485
486 if (time_us == CLUTTER_CURRENT_TIME)
487 time_us = g_get_monotonic_time ();
488
489 touch_state = clutter_input_device_evdev_acquire_touch_state (device_evdev,
490 device_slot);
491 if (!touch_state)
492 return;
493
494 touch_state->coords.x = x;
495 touch_state->coords.y = y;
496
497 clutter_seat_evdev_notify_touch_event (virtual_evdev->seat,
498 virtual_evdev->device,
499 CLUTTER_TOUCH_BEGIN,
500 time_us,
501 touch_state->seat_slot,
502 touch_state->coords.x,
503 touch_state->coords.y);
504 }
505
506 static void
clutter_virtual_input_device_evdev_notify_touch_motion(ClutterVirtualInputDevice * virtual_device,uint64_t time_us,int device_slot,double x,double y)507 clutter_virtual_input_device_evdev_notify_touch_motion (ClutterVirtualInputDevice *virtual_device,
508 uint64_t time_us,
509 int device_slot,
510 double x,
511 double y)
512 {
513 ClutterVirtualInputDeviceEvdev *virtual_evdev =
514 CLUTTER_VIRTUAL_INPUT_DEVICE_EVDEV (virtual_device);
515 ClutterInputDeviceEvdev *device_evdev =
516 CLUTTER_INPUT_DEVICE_EVDEV (virtual_evdev->device);
517 ClutterTouchState *touch_state;
518
519 if (time_us == CLUTTER_CURRENT_TIME)
520 time_us = g_get_monotonic_time ();
521
522 touch_state = clutter_input_device_evdev_lookup_touch_state (device_evdev,
523 device_slot);
524 if (!touch_state)
525 return;
526
527 touch_state->coords.x = x;
528 touch_state->coords.y = y;
529
530 clutter_seat_evdev_notify_touch_event (virtual_evdev->seat,
531 virtual_evdev->device,
532 CLUTTER_TOUCH_BEGIN,
533 time_us,
534 touch_state->seat_slot,
535 touch_state->coords.x,
536 touch_state->coords.y);
537 }
538
539 static void
clutter_virtual_input_device_evdev_notify_touch_up(ClutterVirtualInputDevice * virtual_device,uint64_t time_us,int device_slot)540 clutter_virtual_input_device_evdev_notify_touch_up (ClutterVirtualInputDevice *virtual_device,
541 uint64_t time_us,
542 int device_slot)
543 {
544 ClutterVirtualInputDeviceEvdev *virtual_evdev =
545 CLUTTER_VIRTUAL_INPUT_DEVICE_EVDEV (virtual_device);
546 ClutterInputDeviceEvdev *device_evdev =
547 CLUTTER_INPUT_DEVICE_EVDEV (virtual_evdev->device);
548 ClutterTouchState *touch_state;
549
550 if (time_us == CLUTTER_CURRENT_TIME)
551 time_us = g_get_monotonic_time ();
552
553 touch_state = clutter_input_device_evdev_lookup_touch_state (device_evdev,
554 device_slot);
555 if (!touch_state)
556 return;
557
558 clutter_seat_evdev_notify_touch_event (virtual_evdev->seat,
559 virtual_evdev->device,
560 CLUTTER_TOUCH_BEGIN,
561 time_us,
562 touch_state->seat_slot,
563 touch_state->coords.x,
564 touch_state->coords.y);
565
566 clutter_input_device_evdev_release_touch_state (device_evdev, touch_state);
567 }
568
569 static void
clutter_virtual_input_device_evdev_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)570 clutter_virtual_input_device_evdev_get_property (GObject *object,
571 guint prop_id,
572 GValue *value,
573 GParamSpec *pspec)
574 {
575 ClutterVirtualInputDeviceEvdev *virtual_evdev =
576 CLUTTER_VIRTUAL_INPUT_DEVICE_EVDEV (object);
577
578 switch (prop_id)
579 {
580 case PROP_SEAT:
581 g_value_set_pointer (value, virtual_evdev->seat);
582 break;
583 default:
584 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
585 break;
586 }
587 }
588
589 static void
clutter_virtual_input_device_evdev_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)590 clutter_virtual_input_device_evdev_set_property (GObject *object,
591 guint prop_id,
592 const GValue *value,
593 GParamSpec *pspec)
594 {
595 ClutterVirtualInputDeviceEvdev *virtual_evdev =
596 CLUTTER_VIRTUAL_INPUT_DEVICE_EVDEV (object);
597
598 switch (prop_id)
599 {
600 case PROP_SEAT:
601 virtual_evdev->seat = g_value_get_pointer (value);
602 break;
603 default:
604 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
605 break;
606 }
607 }
608
609 static void
clutter_virtual_input_device_evdev_constructed(GObject * object)610 clutter_virtual_input_device_evdev_constructed (GObject *object)
611 {
612 ClutterVirtualInputDevice *virtual_device =
613 CLUTTER_VIRTUAL_INPUT_DEVICE (object);
614 ClutterVirtualInputDeviceEvdev *virtual_evdev =
615 CLUTTER_VIRTUAL_INPUT_DEVICE_EVDEV (object);
616 ClutterDeviceManager *manager;
617 ClutterInputDeviceType device_type;
618 ClutterStage *stage;
619
620 manager = clutter_virtual_input_device_get_manager (virtual_device);
621 device_type = clutter_virtual_input_device_get_device_type (virtual_device);
622
623 virtual_evdev->device =
624 _clutter_input_device_evdev_new_virtual (manager,
625 virtual_evdev->seat,
626 device_type,
627 CLUTTER_INPUT_MODE_SLAVE);
628
629 stage = _clutter_device_manager_evdev_get_stage (CLUTTER_DEVICE_MANAGER_EVDEV (manager));
630 _clutter_input_device_set_stage (virtual_evdev->device, stage);
631 }
632
633 static void
clutter_virtual_input_device_evdev_finalize(GObject * object)634 clutter_virtual_input_device_evdev_finalize (GObject *object)
635 {
636 ClutterVirtualInputDevice *virtual_device =
637 CLUTTER_VIRTUAL_INPUT_DEVICE (object);
638 ClutterVirtualInputDeviceEvdev *virtual_evdev =
639 CLUTTER_VIRTUAL_INPUT_DEVICE_EVDEV (object);
640 GObjectClass *object_class;
641
642 release_pressed_buttons (virtual_device);
643 g_clear_object (&virtual_evdev->device);
644
645 object_class =
646 G_OBJECT_CLASS (clutter_virtual_input_device_evdev_parent_class);
647 object_class->finalize (object);
648 }
649
650 static void
clutter_virtual_input_device_evdev_init(ClutterVirtualInputDeviceEvdev * virtual_device_evdev)651 clutter_virtual_input_device_evdev_init (ClutterVirtualInputDeviceEvdev *virtual_device_evdev)
652 {
653 }
654
655 static void
clutter_virtual_input_device_evdev_class_init(ClutterVirtualInputDeviceEvdevClass * klass)656 clutter_virtual_input_device_evdev_class_init (ClutterVirtualInputDeviceEvdevClass *klass)
657 {
658 GObjectClass *object_class = G_OBJECT_CLASS (klass);
659 ClutterVirtualInputDeviceClass *virtual_input_device_class =
660 CLUTTER_VIRTUAL_INPUT_DEVICE_CLASS (klass);
661
662 object_class->get_property = clutter_virtual_input_device_evdev_get_property;
663 object_class->set_property = clutter_virtual_input_device_evdev_set_property;
664 object_class->constructed = clutter_virtual_input_device_evdev_constructed;
665 object_class->finalize = clutter_virtual_input_device_evdev_finalize;
666
667 virtual_input_device_class->notify_relative_motion = clutter_virtual_input_device_evdev_notify_relative_motion;
668 virtual_input_device_class->notify_absolute_motion = clutter_virtual_input_device_evdev_notify_absolute_motion;
669 virtual_input_device_class->notify_button = clutter_virtual_input_device_evdev_notify_button;
670 virtual_input_device_class->notify_key = clutter_virtual_input_device_evdev_notify_key;
671 virtual_input_device_class->notify_keyval = clutter_virtual_input_device_evdev_notify_keyval;
672 virtual_input_device_class->notify_discrete_scroll = clutter_virtual_input_device_evdev_notify_discrete_scroll;
673 virtual_input_device_class->notify_scroll_continuous = clutter_virtual_input_device_evdev_notify_scroll_continuous;
674 virtual_input_device_class->notify_touch_down = clutter_virtual_input_device_evdev_notify_touch_down;
675 virtual_input_device_class->notify_touch_motion = clutter_virtual_input_device_evdev_notify_touch_motion;
676 virtual_input_device_class->notify_touch_up = clutter_virtual_input_device_evdev_notify_touch_up;
677
678 obj_props[PROP_SEAT] = g_param_spec_pointer ("seat",
679 P_("ClutterSeatEvdev"),
680 P_("ClutterSeatEvdev"),
681 CLUTTER_PARAM_READWRITE |
682 G_PARAM_CONSTRUCT_ONLY);
683 g_object_class_install_properties (object_class, PROP_LAST, obj_props);
684 }
685