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