From ac448bd42be8cf8e46cadd7e1a209491e33b1693 Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Wed, 23 Jul 2014 15:33:03 +0200 Subject: [PATCH] seat: Listen for ClutterDeviceManager signals in order to update capabilities The capability flags are determined from the device types of the slave devices that are currently attached. This also happens whenever a device is added or removed, so the capabilities are kept up to date, and clients know about these. On VT switch, all slave devices are temporarily removed, so the cascade of signals will make the seat end up with capabililities=0 while input is suspended. https://bugzilla.gnome.org/show_bug.cgi?id=733563 --- src/wayland/meta-wayland-seat.c | 134 +++++++++++++++++++++++++++++--- src/wayland/meta-wayland-seat.h | 3 + 2 files changed, 127 insertions(+), 10 deletions(-) diff --git a/src/wayland/meta-wayland-seat.c b/src/wayland/meta-wayland-seat.c index 3f12cca32..9aaf51650 100644 --- a/src/wayland/meta-wayland-seat.c +++ b/src/wayland/meta-wayland-seat.c @@ -27,6 +27,9 @@ #include "meta-wayland-versions.h" #include "meta-wayland-data-device.h" +#define CAPABILITY_ENABLED(prev, cur, capability) ((cur & (capability)) && !(prev & (capability))) +#define CAPABILITY_DISABLED(prev, cur, capability) ((prev & (capability)) && !(cur & (capability))) + static void unbind_resource (struct wl_resource *resource) { @@ -86,27 +89,136 @@ bind_seat (struct wl_client *client, wl_resource_set_implementation (resource, &seat_interface, seat, unbind_resource); wl_list_insert (&seat->base_resource_list, wl_resource_get_link (resource)); - wl_seat_send_capabilities (resource, - WL_SEAT_CAPABILITY_POINTER | - WL_SEAT_CAPABILITY_KEYBOARD | - WL_SEAT_CAPABILITY_TOUCH); + wl_seat_send_capabilities (resource, seat->capabilities); if (version >= WL_SEAT_NAME_SINCE_VERSION) wl_seat_send_name (resource, "seat0"); } +static uint32_t +lookup_device_capabilities (ClutterDeviceManager *device_manager) +{ + const GSList *devices, *l; + uint32_t capabilities = 0; + + devices = clutter_device_manager_peek_devices (device_manager); + + for (l = devices; l; l = l->next) + { + ClutterInputDeviceType device_type; + + /* Only look for physical devices, master devices have rather generic + * keyboard/pointer device types, which is not truly representative of + * the slave devices connected to them. + */ + if (clutter_input_device_get_device_mode (l->data) == CLUTTER_INPUT_MODE_MASTER) + continue; + + device_type = clutter_input_device_get_device_type (l->data); + + switch (device_type) + { + case CLUTTER_POINTER_DEVICE: + capabilities |= WL_SEAT_CAPABILITY_POINTER; + break; + case CLUTTER_KEYBOARD_DEVICE: + capabilities |= WL_SEAT_CAPABILITY_KEYBOARD; + break; + case CLUTTER_TOUCHSCREEN_DEVICE: + capabilities |= WL_SEAT_CAPABILITY_TOUCH; + break; + default: + g_debug ("Ignoring device '%s' with unhandled type %d", + clutter_input_device_get_device_name (l->data), + device_type); + break; + } + } + + return capabilities; +} + +static void +meta_wayland_seat_set_capabilities (MetaWaylandSeat *seat, + uint32_t flags) +{ + struct wl_resource *resource; + uint32_t prev_flags; + + prev_flags = seat->capabilities; + + if (prev_flags == flags) + return; + + seat->capabilities = flags; + + if (CAPABILITY_ENABLED (prev_flags, flags, WL_SEAT_CAPABILITY_POINTER)) + meta_wayland_pointer_init (&seat->pointer, seat->wl_display); + else if (CAPABILITY_DISABLED (prev_flags, flags, WL_SEAT_CAPABILITY_POINTER)) + meta_wayland_pointer_release (&seat->pointer); + + if (CAPABILITY_ENABLED (prev_flags, flags, WL_SEAT_CAPABILITY_KEYBOARD)) + { + MetaDisplay *display; + + meta_wayland_keyboard_init (&seat->keyboard, seat->wl_display); + display = meta_get_display (); + + /* Post-initialization, ensure the input focus is in sync */ + if (display) + meta_display_sync_wayland_input_focus (display); + } + else if (CAPABILITY_DISABLED (prev_flags, flags, WL_SEAT_CAPABILITY_KEYBOARD)) + meta_wayland_keyboard_release (&seat->keyboard); + + if (CAPABILITY_ENABLED (prev_flags, flags, WL_SEAT_CAPABILITY_TOUCH)) + meta_wayland_touch_init (&seat->touch, seat->wl_display); + else if (CAPABILITY_DISABLED (prev_flags, flags, WL_SEAT_CAPABILITY_TOUCH)) + meta_wayland_touch_release (&seat->touch); + + /* Broadcast capability changes */ + wl_resource_for_each (resource, &seat->base_resource_list) + { + wl_seat_send_capabilities (resource, flags); + } +} + +static void +meta_wayland_seat_update_capabilities (MetaWaylandSeat *seat, + ClutterDeviceManager *device_manager) +{ + uint32_t capabilities; + + capabilities = lookup_device_capabilities (device_manager); + meta_wayland_seat_set_capabilities (seat, capabilities); +} + +static void +meta_wayland_seat_devices_updated (ClutterDeviceManager *device_manager, + ClutterInputDevice *input_device, + MetaWaylandSeat *seat) +{ + meta_wayland_seat_update_capabilities (seat, device_manager); +} + static MetaWaylandSeat * meta_wayland_seat_new (struct wl_display *display) { MetaWaylandSeat *seat = g_new0 (MetaWaylandSeat, 1); + ClutterDeviceManager *device_manager; wl_list_init (&seat->base_resource_list); + seat->wl_display = display; - meta_wayland_pointer_init (&seat->pointer, display); - meta_wayland_keyboard_init (&seat->keyboard, display); - meta_wayland_touch_init (&seat->touch, display); meta_wayland_data_device_init (&seat->data_device); + device_manager = clutter_device_manager_get_default (); + meta_wayland_seat_update_capabilities (seat, device_manager); + g_signal_connect (device_manager, "device-added", + G_CALLBACK (meta_wayland_seat_devices_updated), seat); + g_signal_connect (device_manager, "device-removed", + G_CALLBACK (meta_wayland_seat_devices_updated), seat); + wl_global_create (display, &wl_seat_interface, META_WL_SEAT_VERSION, seat, bind_seat); return seat; @@ -121,9 +233,11 @@ meta_wayland_seat_init (MetaWaylandCompositor *compositor) void meta_wayland_seat_free (MetaWaylandSeat *seat) { - meta_wayland_pointer_release (&seat->pointer); - meta_wayland_keyboard_release (&seat->keyboard); - meta_wayland_touch_release (&seat->touch); + ClutterDeviceManager *device_manager; + + device_manager = clutter_device_manager_get_default (); + g_signal_handlers_disconnect_by_data (device_manager, seat); + meta_wayland_seat_set_capabilities (seat, 0); g_slice_free (MetaWaylandSeat, seat); } diff --git a/src/wayland/meta-wayland-seat.h b/src/wayland/meta-wayland-seat.h index e9b52fb29..ee8e3d773 100644 --- a/src/wayland/meta-wayland-seat.h +++ b/src/wayland/meta-wayland-seat.h @@ -34,11 +34,14 @@ struct _MetaWaylandSeat { struct wl_list base_resource_list; + struct wl_display *wl_display; MetaWaylandPointer pointer; MetaWaylandKeyboard keyboard; MetaWaylandTouch touch; MetaWaylandDataDevice data_device; + + guint capabilities; }; void meta_wayland_seat_init (MetaWaylandCompositor *compositor);