1 /*
2  * Wayland Support
3  *
4  * Copyright (C) 2013 Intel Corporation
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License as
8  * published by the Free Software Foundation; either version 2 of the
9  * License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19  * 02111-1307, USA.
20  */
21 
22 #include "config.h"
23 
24 #include "wayland/meta-wayland-seat.h"
25 
26 #include "wayland/meta-wayland-data-device.h"
27 #include "wayland/meta-wayland-data-device-primary-legacy.h"
28 #include "wayland/meta-wayland-private.h"
29 #include "wayland/meta-wayland-tablet-seat.h"
30 #include "wayland/meta-wayland-versions.h"
31 
32 #define CAPABILITY_ENABLED(prev, cur, capability) ((cur & (capability)) && !(prev & (capability)))
33 #define CAPABILITY_DISABLED(prev, cur, capability) ((prev & (capability)) && !(cur & (capability)))
34 
35 static void
unbind_resource(struct wl_resource * resource)36 unbind_resource (struct wl_resource *resource)
37 {
38   wl_list_remove (wl_resource_get_link (resource));
39 }
40 
41 static void
seat_get_pointer(struct wl_client * client,struct wl_resource * resource,uint32_t id)42 seat_get_pointer (struct wl_client *client,
43                   struct wl_resource *resource,
44                   uint32_t id)
45 {
46   MetaWaylandSeat *seat = wl_resource_get_user_data (resource);
47   MetaWaylandPointer *pointer = seat->pointer;
48 
49   meta_wayland_pointer_create_new_resource (pointer, client, resource, id);
50 }
51 
52 static void
seat_get_keyboard(struct wl_client * client,struct wl_resource * resource,uint32_t id)53 seat_get_keyboard (struct wl_client *client,
54                    struct wl_resource *resource,
55                    uint32_t id)
56 {
57   MetaWaylandSeat *seat = wl_resource_get_user_data (resource);
58   MetaWaylandKeyboard *keyboard = seat->keyboard;
59 
60   meta_wayland_keyboard_create_new_resource (keyboard, client, resource, id);
61 }
62 
63 static void
seat_get_touch(struct wl_client * client,struct wl_resource * resource,uint32_t id)64 seat_get_touch (struct wl_client *client,
65                 struct wl_resource *resource,
66                 uint32_t id)
67 {
68   MetaWaylandSeat *seat = wl_resource_get_user_data (resource);
69   MetaWaylandTouch *touch = seat->touch;
70 
71   meta_wayland_touch_create_new_resource (touch, client, resource, id);
72 }
73 
74 static void
seat_release(struct wl_client * client,struct wl_resource * resource)75 seat_release (struct wl_client   *client,
76               struct wl_resource *resource)
77 {
78   wl_resource_destroy (resource);
79 }
80 
81 static const struct wl_seat_interface seat_interface = {
82   seat_get_pointer,
83   seat_get_keyboard,
84   seat_get_touch,
85   seat_release
86 };
87 
88 static void
bind_seat(struct wl_client * client,void * data,guint32 version,guint32 id)89 bind_seat (struct wl_client *client,
90            void *data,
91            guint32 version,
92            guint32 id)
93 {
94   MetaWaylandSeat *seat = data;
95   struct wl_resource *resource;
96 
97   resource = wl_resource_create (client, &wl_seat_interface, version, id);
98   wl_resource_set_implementation (resource, &seat_interface, seat, unbind_resource);
99   wl_list_insert (&seat->base_resource_list, wl_resource_get_link (resource));
100 
101   wl_seat_send_capabilities (resource, seat->capabilities);
102 
103   if (version >= WL_SEAT_NAME_SINCE_VERSION)
104     wl_seat_send_name (resource, "seat0");
105 }
106 
107 static uint32_t
lookup_device_capabilities(ClutterSeat * seat)108 lookup_device_capabilities (ClutterSeat *seat)
109 {
110   GList *devices, *l;
111   uint32_t capabilities = 0;
112 
113   devices = clutter_seat_list_devices (seat);
114 
115   for (l = devices; l; l = l->next)
116     {
117       ClutterInputDeviceType device_type;
118 
119       /* Only look for physical devices, logical devices have rather generic
120        * keyboard/pointer device types, which is not truly representative of
121        * the physical devices connected to them.
122        */
123       if (clutter_input_device_get_device_mode (l->data) == CLUTTER_INPUT_MODE_LOGICAL)
124         continue;
125 
126       device_type = clutter_input_device_get_device_type (l->data);
127 
128       switch (device_type)
129         {
130         case CLUTTER_TOUCHPAD_DEVICE:
131         case CLUTTER_POINTER_DEVICE:
132           capabilities |= WL_SEAT_CAPABILITY_POINTER;
133           break;
134         case CLUTTER_KEYBOARD_DEVICE:
135           capabilities |= WL_SEAT_CAPABILITY_KEYBOARD;
136           break;
137         case CLUTTER_TOUCHSCREEN_DEVICE:
138           capabilities |= WL_SEAT_CAPABILITY_TOUCH;
139           break;
140         default:
141           g_debug ("Ignoring device '%s' with unhandled type %d",
142                    clutter_input_device_get_device_name (l->data),
143                    device_type);
144           break;
145         }
146     }
147 
148   g_list_free (devices);
149 
150   return capabilities;
151 }
152 
153 static void
meta_wayland_seat_set_capabilities(MetaWaylandSeat * seat,uint32_t flags)154 meta_wayland_seat_set_capabilities (MetaWaylandSeat *seat,
155                                     uint32_t         flags)
156 {
157   struct wl_resource *resource;
158   uint32_t prev_flags;
159 
160   prev_flags = seat->capabilities;
161 
162   if (prev_flags == flags)
163     return;
164 
165   seat->capabilities = flags;
166 
167   if (CAPABILITY_ENABLED (prev_flags, flags, WL_SEAT_CAPABILITY_POINTER))
168     meta_wayland_pointer_enable (seat->pointer);
169   else if (CAPABILITY_DISABLED (prev_flags, flags, WL_SEAT_CAPABILITY_POINTER))
170     meta_wayland_pointer_disable (seat->pointer);
171 
172   if (CAPABILITY_ENABLED (prev_flags, flags, WL_SEAT_CAPABILITY_KEYBOARD))
173     {
174       MetaDisplay *display;
175 
176       meta_wayland_keyboard_enable (seat->keyboard);
177       display = meta_get_display ();
178 
179       /* Post-initialization, ensure the input focus is in sync */
180       if (display)
181         meta_display_sync_wayland_input_focus (display);
182     }
183   else if (CAPABILITY_DISABLED (prev_flags, flags, WL_SEAT_CAPABILITY_KEYBOARD))
184     meta_wayland_keyboard_disable (seat->keyboard);
185 
186   if (CAPABILITY_ENABLED (prev_flags, flags, WL_SEAT_CAPABILITY_TOUCH))
187     meta_wayland_touch_enable (seat->touch);
188   else if (CAPABILITY_DISABLED (prev_flags, flags, WL_SEAT_CAPABILITY_TOUCH))
189     meta_wayland_touch_disable (seat->touch);
190 
191   /* Broadcast capability changes */
192   wl_resource_for_each (resource, &seat->base_resource_list)
193     {
194       wl_seat_send_capabilities (resource, flags);
195     }
196 }
197 
198 static void
meta_wayland_seat_update_capabilities(MetaWaylandSeat * seat,ClutterSeat * clutter_seat)199 meta_wayland_seat_update_capabilities (MetaWaylandSeat *seat,
200 				       ClutterSeat     *clutter_seat)
201 {
202   uint32_t capabilities;
203 
204   capabilities = lookup_device_capabilities (clutter_seat);
205   meta_wayland_seat_set_capabilities (seat, capabilities);
206 }
207 
208 static void
meta_wayland_seat_devices_updated(ClutterSeat * clutter_seat,ClutterInputDevice * input_device,MetaWaylandSeat * seat)209 meta_wayland_seat_devices_updated (ClutterSeat        *clutter_seat,
210                                    ClutterInputDevice *input_device,
211                                    MetaWaylandSeat    *seat)
212 {
213   meta_wayland_seat_update_capabilities (seat, clutter_seat);
214 }
215 
216 static MetaWaylandSeat *
meta_wayland_seat_new(MetaWaylandCompositor * compositor,struct wl_display * display)217 meta_wayland_seat_new (MetaWaylandCompositor *compositor,
218                        struct wl_display     *display)
219 {
220   MetaWaylandSeat *seat = g_new0 (MetaWaylandSeat, 1);
221   ClutterSeat *clutter_seat;
222 
223   wl_list_init (&seat->base_resource_list);
224   seat->wl_display = display;
225 
226   seat->pointer = g_object_new (META_TYPE_WAYLAND_POINTER,
227                                 "seat", seat,
228                                 NULL);
229   seat->keyboard = g_object_new (META_TYPE_WAYLAND_KEYBOARD,
230                                  "seat", seat,
231                                  NULL);
232   seat->touch = g_object_new (META_TYPE_WAYLAND_TOUCH,
233                               "seat", seat,
234                               NULL);
235 
236   seat->text_input = meta_wayland_text_input_new (seat);
237   seat->gtk_text_input = meta_wayland_gtk_text_input_new (seat);
238 
239   meta_wayland_data_device_init (&seat->data_device);
240   meta_wayland_data_device_primary_init (&seat->primary_data_device);
241   meta_wayland_data_device_primary_legacy_init (&seat->primary_legacy_data_device);
242 
243   clutter_seat = clutter_backend_get_default_seat (clutter_get_default_backend ());
244   meta_wayland_seat_update_capabilities (seat, clutter_seat);
245   g_signal_connect (clutter_seat, "device-added",
246                     G_CALLBACK (meta_wayland_seat_devices_updated), seat);
247   g_signal_connect (clutter_seat, "device-removed",
248                     G_CALLBACK (meta_wayland_seat_devices_updated), seat);
249 
250   wl_global_create (display, &wl_seat_interface, META_WL_SEAT_VERSION, seat, bind_seat);
251 
252   meta_wayland_tablet_manager_ensure_seat (compositor->tablet_manager, seat);
253 
254   return seat;
255 }
256 
257 void
meta_wayland_seat_init(MetaWaylandCompositor * compositor)258 meta_wayland_seat_init (MetaWaylandCompositor *compositor)
259 {
260   compositor->seat = meta_wayland_seat_new (compositor,
261                                             compositor->wayland_display);
262 }
263 
264 void
meta_wayland_seat_free(MetaWaylandSeat * seat)265 meta_wayland_seat_free (MetaWaylandSeat *seat)
266 {
267   ClutterSeat *clutter_seat;
268 
269   clutter_seat = clutter_backend_get_default_seat (clutter_get_default_backend ());
270   g_signal_handlers_disconnect_by_data (clutter_seat, seat);
271   meta_wayland_seat_set_capabilities (seat, 0);
272 
273   meta_wayland_pointer_disable (seat->pointer);
274   g_object_unref (seat->pointer);
275   meta_wayland_keyboard_disable (seat->keyboard);
276   g_object_unref (seat->keyboard);
277   meta_wayland_touch_disable (seat->touch);
278   g_object_unref (seat->touch);
279 
280   meta_wayland_gtk_text_input_destroy (seat->gtk_text_input);
281   meta_wayland_text_input_destroy (seat->text_input);
282 
283   g_free (seat);
284 }
285 
286 static gboolean
event_is_synthesized_crossing(const ClutterEvent * event)287 event_is_synthesized_crossing (const ClutterEvent *event)
288 {
289   ClutterInputDevice *device;
290 
291   if (event->type != CLUTTER_ENTER && event->type != CLUTTER_LEAVE)
292     return FALSE;
293 
294   device = clutter_event_get_source_device (event);
295   return clutter_input_device_get_device_mode (device) == CLUTTER_INPUT_MODE_LOGICAL;
296 }
297 
298 static gboolean
event_from_supported_hardware_device(MetaWaylandSeat * seat,const ClutterEvent * event)299 event_from_supported_hardware_device (MetaWaylandSeat    *seat,
300                                       const ClutterEvent *event)
301 {
302   ClutterInputDevice     *input_device;
303   ClutterInputMode        input_mode;
304   ClutterInputDeviceType  device_type;
305   gboolean                hardware_device = FALSE;
306   gboolean                supported_device = FALSE;
307 
308   input_device = clutter_event_get_source_device (event);
309 
310   if (input_device == NULL)
311     goto out;
312 
313   input_mode = clutter_input_device_get_device_mode (input_device);
314 
315   if (input_mode != CLUTTER_INPUT_MODE_PHYSICAL)
316     goto out;
317 
318   hardware_device = TRUE;
319 
320   device_type = clutter_input_device_get_device_type (input_device);
321 
322   switch (device_type)
323     {
324     case CLUTTER_TOUCHPAD_DEVICE:
325     case CLUTTER_POINTER_DEVICE:
326     case CLUTTER_KEYBOARD_DEVICE:
327     case CLUTTER_TOUCHSCREEN_DEVICE:
328       supported_device = TRUE;
329       break;
330 
331     default:
332       supported_device = FALSE;
333       break;
334     }
335 
336 out:
337   return hardware_device && supported_device;
338 }
339 
340 void
meta_wayland_seat_update(MetaWaylandSeat * seat,const ClutterEvent * event)341 meta_wayland_seat_update (MetaWaylandSeat    *seat,
342                           const ClutterEvent *event)
343 {
344   if (!(clutter_event_get_flags (event) & CLUTTER_EVENT_FLAG_INPUT_METHOD) &&
345       !event_from_supported_hardware_device (seat, event) &&
346       !event_is_synthesized_crossing (event))
347     return;
348 
349   switch (event->type)
350     {
351     case CLUTTER_MOTION:
352     case CLUTTER_BUTTON_PRESS:
353     case CLUTTER_BUTTON_RELEASE:
354     case CLUTTER_SCROLL:
355     case CLUTTER_ENTER:
356     case CLUTTER_LEAVE:
357       if (meta_wayland_seat_has_pointer (seat))
358         meta_wayland_pointer_update (seat->pointer, event);
359       break;
360 
361     case CLUTTER_KEY_PRESS:
362     case CLUTTER_KEY_RELEASE:
363       if (meta_wayland_seat_has_keyboard (seat))
364         meta_wayland_keyboard_update (seat->keyboard, (const ClutterKeyEvent *) event);
365       break;
366 
367     case CLUTTER_TOUCH_BEGIN:
368     case CLUTTER_TOUCH_UPDATE:
369     case CLUTTER_TOUCH_END:
370       if (meta_wayland_seat_has_touch (seat))
371         meta_wayland_touch_update (seat->touch, event);
372       break;
373 
374     default:
375       break;
376     }
377 }
378 
379 gboolean
meta_wayland_seat_handle_event(MetaWaylandSeat * seat,const ClutterEvent * event)380 meta_wayland_seat_handle_event (MetaWaylandSeat *seat,
381                                 const ClutterEvent *event)
382 {
383   if (!(clutter_event_get_flags (event) & CLUTTER_EVENT_FLAG_INPUT_METHOD) &&
384       !event_from_supported_hardware_device (seat, event))
385     return FALSE;
386 
387   if (event->type == CLUTTER_BUTTON_PRESS ||
388       event->type == CLUTTER_TOUCH_BEGIN)
389     {
390       meta_wayland_text_input_handle_event (seat->text_input, event);
391       meta_wayland_gtk_text_input_handle_event (seat->gtk_text_input,
392                                                 event);
393     }
394 
395   switch (event->type)
396     {
397     case CLUTTER_MOTION:
398     case CLUTTER_BUTTON_PRESS:
399     case CLUTTER_BUTTON_RELEASE:
400     case CLUTTER_SCROLL:
401     case CLUTTER_TOUCHPAD_SWIPE:
402     case CLUTTER_TOUCHPAD_PINCH:
403       if (meta_wayland_seat_has_pointer (seat))
404         return meta_wayland_pointer_handle_event (seat->pointer, event);
405 
406       break;
407     case CLUTTER_KEY_PRESS:
408     case CLUTTER_KEY_RELEASE:
409       if (meta_wayland_text_input_handle_event (seat->text_input, event))
410         return TRUE;
411 
412       if (meta_wayland_gtk_text_input_handle_event (seat->gtk_text_input,
413                                                     event))
414         return TRUE;
415 
416       if (meta_wayland_seat_has_keyboard (seat))
417         return meta_wayland_keyboard_handle_event (seat->keyboard,
418                                                    (const ClutterKeyEvent *) event);
419       break;
420     case CLUTTER_TOUCH_BEGIN:
421     case CLUTTER_TOUCH_UPDATE:
422     case CLUTTER_TOUCH_END:
423       if (meta_wayland_seat_has_touch (seat))
424         return meta_wayland_touch_handle_event (seat->touch, event);
425 
426       break;
427     case CLUTTER_IM_COMMIT:
428     case CLUTTER_IM_DELETE:
429     case CLUTTER_IM_PREEDIT:
430       if (meta_wayland_text_input_handle_event (seat->text_input, event))
431         return TRUE;
432       if (meta_wayland_gtk_text_input_handle_event (seat->gtk_text_input,
433                                                     event))
434         return TRUE;
435 
436       break;
437     default:
438       break;
439     }
440 
441   return FALSE;
442 }
443 
444 void
meta_wayland_seat_set_input_focus(MetaWaylandSeat * seat,MetaWaylandSurface * surface)445 meta_wayland_seat_set_input_focus (MetaWaylandSeat    *seat,
446                                    MetaWaylandSurface *surface)
447 {
448   MetaWaylandTabletSeat *tablet_seat;
449   MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default ();
450 
451   if (meta_wayland_seat_has_keyboard (seat))
452     {
453       meta_wayland_keyboard_set_focus (seat->keyboard, surface);
454       meta_wayland_data_device_set_keyboard_focus (&seat->data_device);
455       meta_wayland_data_device_primary_set_keyboard_focus (&seat->primary_data_device);
456       meta_wayland_data_device_primary_legacy_set_keyboard_focus (&seat->primary_legacy_data_device);
457     }
458 
459   tablet_seat = meta_wayland_tablet_manager_ensure_seat (compositor->tablet_manager, seat);
460   meta_wayland_tablet_seat_set_pad_focus (tablet_seat, surface);
461 
462   meta_wayland_text_input_set_focus (seat->text_input, surface);
463   meta_wayland_gtk_text_input_set_focus (seat->gtk_text_input, surface);
464 }
465 
466 gboolean
meta_wayland_seat_get_grab_info(MetaWaylandSeat * seat,MetaWaylandSurface * surface,uint32_t serial,gboolean require_pressed,gfloat * x,gfloat * y)467 meta_wayland_seat_get_grab_info (MetaWaylandSeat    *seat,
468                                  MetaWaylandSurface *surface,
469                                  uint32_t            serial,
470                                  gboolean            require_pressed,
471                                  gfloat             *x,
472                                  gfloat             *y)
473 {
474   MetaWaylandCompositor *compositor;
475   MetaWaylandTabletSeat *tablet_seat;
476   GList *tools, *l;
477 
478   compositor = meta_wayland_compositor_get_default ();
479   tablet_seat = meta_wayland_tablet_manager_ensure_seat (compositor->tablet_manager, seat);
480   tools = g_hash_table_get_values (tablet_seat->tools);
481 
482   if (meta_wayland_seat_has_touch (seat))
483     {
484       ClutterEventSequence *sequence;
485       sequence = meta_wayland_touch_find_grab_sequence (seat->touch,
486                                                         surface,
487                                                         serial);
488       if (sequence)
489         {
490           meta_wayland_touch_get_press_coords (seat->touch, sequence, x, y);
491           return TRUE;
492         }
493     }
494 
495   if (meta_wayland_seat_has_pointer (seat))
496     {
497       if ((!require_pressed || seat->pointer->button_count > 0) &&
498           meta_wayland_pointer_can_grab_surface (seat->pointer, surface, serial))
499         {
500           if (x)
501             *x = seat->pointer->grab_x;
502           if (y)
503             *y = seat->pointer->grab_y;
504 
505           return TRUE;
506         }
507     }
508 
509   for (l = tools; l; l = l->next)
510     {
511       MetaWaylandTabletTool *tool = l->data;
512 
513       if ((!require_pressed || tool->button_count > 0) &&
514           meta_wayland_tablet_tool_can_grab_surface (tool, surface, serial))
515         {
516           if (x)
517             *x = tool->grab_x;
518           if (y)
519             *y = tool->grab_y;
520 
521           return TRUE;
522         }
523     }
524 
525   return FALSE;
526 }
527 
528 gboolean
meta_wayland_seat_can_popup(MetaWaylandSeat * seat,uint32_t serial)529 meta_wayland_seat_can_popup (MetaWaylandSeat *seat,
530                              uint32_t         serial)
531 {
532   MetaWaylandCompositor *compositor;
533   MetaWaylandTabletSeat *tablet_seat;
534 
535   compositor = meta_wayland_compositor_get_default ();
536   tablet_seat =
537     meta_wayland_tablet_manager_ensure_seat (compositor->tablet_manager, seat);
538 
539   return (meta_wayland_pointer_can_popup (seat->pointer, serial) ||
540           meta_wayland_keyboard_can_popup (seat->keyboard, serial) ||
541           meta_wayland_touch_can_popup (seat->touch, serial) ||
542           meta_wayland_tablet_seat_can_popup (tablet_seat, serial));
543 }
544 
545 gboolean
meta_wayland_seat_has_keyboard(MetaWaylandSeat * seat)546 meta_wayland_seat_has_keyboard (MetaWaylandSeat *seat)
547 {
548   return (seat->capabilities & WL_SEAT_CAPABILITY_KEYBOARD) != 0;
549 }
550 
551 gboolean
meta_wayland_seat_has_pointer(MetaWaylandSeat * seat)552 meta_wayland_seat_has_pointer (MetaWaylandSeat *seat)
553 {
554   return (seat->capabilities & WL_SEAT_CAPABILITY_POINTER) != 0;
555 }
556 
557 gboolean
meta_wayland_seat_has_touch(MetaWaylandSeat * seat)558 meta_wayland_seat_has_touch (MetaWaylandSeat *seat)
559 {
560   return (seat->capabilities & WL_SEAT_CAPABILITY_TOUCH) != 0;
561 }
562