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