summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarlos Garnacho <carlosg@gnome.org>2018-09-01 22:09:58 +0200
committerCarlos Garnacho <carlosg@gnome.org>2022-11-13 01:30:19 +0100
commit5375471edb2e54d0c933eb27351ab73fdec5bf1b (patch)
tree3fbeda90edd6a2c1402675a86836187f20d76a9b
parent7e838b1115f195ba4c7b06169ade3407d29c66d0 (diff)
downloadmutter-wip/carlosg/inputfd.tar.gz
wayland: Implement the "inputfd" wayland protocolswip/carlosg/inputfd
This allows lending control to applications of evdev devices, and withdrawing it with focus changes. Underneath, the device FD is revoked control through the EVIOCREVOKE ioctl, and closed. The newly focused client receives a brand new FD obtained through logind, which will be again revoked in a future focus change.
-rw-r--r--src/meson.build7
-rw-r--r--src/wayland/meta-wayland-inputfd-evdev-device.c307
-rw-r--r--src/wayland/meta-wayland-inputfd-evdev-device.h67
-rw-r--r--src/wayland/meta-wayland-inputfd-manager.c128
-rw-r--r--src/wayland/meta-wayland-inputfd-manager.h47
-rw-r--r--src/wayland/meta-wayland-inputfd-seat.c213
-rw-r--r--src/wayland/meta-wayland-inputfd-seat.h52
-rw-r--r--src/wayland/meta-wayland-private.h2
-rw-r--r--src/wayland/meta-wayland-seat.c17
-rw-r--r--src/wayland/meta-wayland-types.h4
-rw-r--r--src/wayland/meta-wayland-versions.h1
-rw-r--r--src/wayland/meta-wayland.c1
12 files changed, 845 insertions, 1 deletions
diff --git a/src/meson.build b/src/meson.build
index 6790efa16..24c354be0 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -600,6 +600,12 @@ if have_wayland
'wayland/meta-wayland-inhibit-shortcuts-dialog.c',
'wayland/meta-wayland-inhibit-shortcuts-dialog.h',
'wayland/meta-wayland-inhibit-shortcuts.h',
+ 'wayland/meta-wayland-inputfd-evdev-device.c',
+ 'wayland/meta-wayland-inputfd-evdev-device.h',
+ 'wayland/meta-wayland-inputfd-manager.c',
+ 'wayland/meta-wayland-inputfd-manager.h',
+ 'wayland/meta-wayland-inputfd-seat.c',
+ 'wayland/meta-wayland-inputfd-seat.h',
'wayland/meta-wayland-input-device.c',
'wayland/meta-wayland-input-device.h',
'wayland/meta-wayland-keyboard.c',
@@ -962,6 +968,7 @@ if have_wayland
# - protocol version (if stability is 'unstable')
wayland_protocols = [
['gtk-shell', 'private', ],
+ ['inputfd', 'staging', 'v1', ],
['keyboard-shortcuts-inhibit', 'unstable', 'v1', ],
['linux-dmabuf', 'unstable', 'v1', ],
['pointer-constraints', 'unstable', 'v1', ],
diff --git a/src/wayland/meta-wayland-inputfd-evdev-device.c b/src/wayland/meta-wayland-inputfd-evdev-device.c
new file mode 100644
index 000000000..1f5a21eea
--- /dev/null
+++ b/src/wayland/meta-wayland-inputfd-evdev-device.c
@@ -0,0 +1,307 @@
+/*
+ * Wayland Support
+ *
+ * Copyright (C) 2018 Red Hat
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Carlos Garnacho <carlosg@gnome.org>
+ */
+#include "config.h"
+
+#include <linux/input.h>
+#include <sys/ioctl.h>
+
+#include "backends/native/meta-backend-native.h"
+#include "compositor/meta-surface-actor-wayland.h"
+#include "inputfd-v1-server-protocol.h"
+#include "wayland/meta-wayland-inputfd-evdev-device.h"
+
+static void
+unbind_resource (struct wl_resource *resource)
+{
+ wl_list_remove (wl_resource_get_link (resource));
+}
+
+static void
+move_resources (struct wl_list *destination,
+ struct wl_list *source)
+{
+ wl_list_insert_list (destination, source);
+ wl_list_init (source);
+}
+
+static void
+move_resources_for_client (struct wl_list *destination,
+ struct wl_list *source,
+ struct wl_client *client)
+{
+ struct wl_resource *resource, *tmp;
+
+ wl_resource_for_each_safe (resource, tmp, source)
+ {
+ if (wl_resource_get_client (resource) == client)
+ {
+ wl_list_remove (wl_resource_get_link (resource));
+ wl_list_insert (destination, wl_resource_get_link (resource));
+ }
+ }
+}
+
+static void
+evdev_device_handle_focus_surface_destroy (struct wl_listener *listener,
+ void *data)
+{
+ MetaWaylandInputFdEvdevDevice *device = wl_container_of (listener, device,
+ focus_surface_listener);
+
+ meta_wayland_inputfd_evdev_device_set_focus (device, NULL);
+}
+
+static gboolean
+check_device_qualifies (GUdevDevice *device)
+{
+ const gchar *path = g_udev_device_get_device_file (device);
+
+ if (!path || !strstr (path, "/event"))
+ return FALSE;
+ if (!g_udev_device_get_property_as_boolean (device, "ID_INPUT_JOYSTICK"))
+ return FALSE;
+
+ return TRUE;
+}
+
+MetaWaylandInputFdEvdevDevice *
+meta_wayland_inputfd_evdev_device_new (MetaWaylandInputFdSeat *seat,
+ GUdevDevice *device)
+{
+ MetaWaylandInputFdEvdevDevice *evdev_device;
+ GUdevDevice *parent;
+
+ if (!check_device_qualifies (device))
+ return NULL;
+
+ parent = g_udev_device_get_parent (device);
+
+ evdev_device = g_slice_new0 (MetaWaylandInputFdEvdevDevice);
+ evdev_device->udev_device = g_object_ref (device);
+ wl_list_init (&evdev_device->resource_list);
+ wl_list_init (&evdev_device->focus_resource_list);
+ evdev_device->focus_surface_listener.notify =
+ evdev_device_handle_focus_surface_destroy;
+ evdev_device->fd = -1;
+
+ evdev_device->name =
+ g_udev_device_get_sysfs_attr (parent, "name");
+ evdev_device->vid =
+ strtol (g_udev_device_get_property (device, "ID_VENDOR_ID"),
+ NULL, 16);
+ evdev_device->pid =
+ strtol (g_udev_device_get_property (device, "ID_MODEL_ID"),
+ NULL, 16);
+
+ g_object_unref (parent);
+
+ return evdev_device;
+}
+
+void
+meta_wayland_inputfd_evdev_device_free (MetaWaylandInputFdEvdevDevice *evdev_device)
+{
+ struct wl_resource *resource, *next;
+
+ meta_wayland_inputfd_evdev_device_set_focus (evdev_device, NULL);
+
+ wl_resource_for_each_safe (resource, next, &evdev_device->resource_list)
+ {
+ wp_inputfd_device_evdev_v1_send_removed (resource);
+ wl_list_remove (wl_resource_get_link (resource));
+ wl_list_init (wl_resource_get_link (resource));
+ }
+
+ g_object_unref (evdev_device->udev_device);
+ g_slice_free (MetaWaylandInputFdEvdevDevice, evdev_device);
+}
+
+static void
+inputfd_device_evdev_destroy (struct wl_client *client,
+ struct wl_resource *resource)
+{
+ wl_resource_destroy (resource);
+}
+
+static const struct wp_inputfd_device_evdev_v1_interface inputfd_device_evdev_interface = {
+ inputfd_device_evdev_destroy,
+};
+
+struct wl_resource *
+meta_wayland_inputfd_evdev_device_create_new_resource (MetaWaylandInputFdEvdevDevice *device,
+ struct wl_client *client,
+ struct wl_resource *seat_resource,
+ uint32_t id)
+{
+ struct wl_resource *resource;
+
+ resource = wl_resource_create (client, &wp_inputfd_device_evdev_v1_interface,
+ wl_resource_get_version (seat_resource),
+ id);
+ wl_resource_set_implementation (resource, &inputfd_device_evdev_interface,
+ device, unbind_resource);
+ wl_resource_set_user_data (resource, device);
+ wl_list_insert (&device->resource_list, wl_resource_get_link (resource));
+
+ return resource;
+}
+
+void
+meta_wayland_inputfd_evdev_device_notify (MetaWaylandInputFdEvdevDevice *device,
+ struct wl_resource *resource)
+{
+ wp_inputfd_device_evdev_v1_send_name (resource, device->name);
+ wp_inputfd_device_evdev_v1_send_usb_id (resource, device->vid, device->pid);
+ wp_inputfd_device_evdev_v1_send_done (resource);
+}
+
+static void
+device_open_fd (MetaWaylandInputFdEvdevDevice *device)
+{
+#ifdef HAVE_NATIVE_BACKEND
+ MetaBackend *backend = meta_get_backend ();
+ MetaDevicePool *device_pool;
+ MetaDeviceFile *device_file;
+ const char *path;
+ g_autoptr (GError) error = NULL;
+
+ g_assert (device->fd == -1);
+ path = g_udev_device_get_device_file (device->udev_device);
+
+ if (!META_IS_BACKEND_NATIVE (backend))
+ return;
+
+ device_pool = meta_backend_native_get_device_pool (META_BACKEND_NATIVE (backend));
+
+ device_file = meta_device_pool_open (device_pool, path,
+ META_DEVICE_FILE_FLAG_TAKE_CONTROL,
+ &error);
+ if (error)
+ {
+ g_warning ("Could not open device file: %s", error->message);
+ device->fd = -1;
+ }
+ else
+ {
+ /* Take ownership on the device file, this must be fully closed
+ * and opened on focus changes, to ensure the device does not stay
+ * revoked.
+ */
+ device->device_file = device_file;
+ device->fd = meta_device_file_get_fd (device->device_file);
+ }
+#endif
+}
+
+static void
+device_close_fd (MetaWaylandInputFdEvdevDevice *device)
+{
+#ifdef HAVE_NATIVE_BACKEND
+ MetaBackend *backend = meta_get_backend ();
+
+ if (device->fd < 0)
+ return;
+
+ ioctl (device->fd, EVIOCREVOKE, NULL);
+
+ if (!META_IS_BACKEND_NATIVE (backend))
+ return;
+
+ g_clear_pointer (&device->device_file, meta_device_file_release);
+ device->fd = -1;
+#endif
+}
+
+static void
+meta_wayland_inputfd_evdev_device_broadcast_focus_in (MetaWaylandInputFdEvdevDevice *device,
+ MetaWaylandSurface *surface,
+ uint32_t serial)
+{
+ struct wl_resource *resource;
+
+ wl_resource_for_each (resource, &device->focus_resource_list)
+ {
+ wp_inputfd_device_evdev_v1_send_focus_in (resource,
+ serial,
+ device->fd,
+ surface->resource);
+ }
+}
+
+static void
+meta_wayland_inputfd_evdev_device_broadcast_focus_out (MetaWaylandInputFdEvdevDevice *device)
+{
+ struct wl_resource *resource;
+
+ wl_resource_for_each (resource, &device->focus_resource_list)
+ {
+ wp_inputfd_device_evdev_v1_send_focus_out (resource);
+ }
+}
+
+void
+meta_wayland_inputfd_evdev_device_set_focus (MetaWaylandInputFdEvdevDevice *device,
+ MetaWaylandSurface *surface)
+{
+ if (device->focus_surface == surface)
+ return;
+
+ if (device->focus_surface != NULL)
+ {
+ struct wl_list *focus_resources = &device->focus_resource_list;
+
+ if (!wl_list_empty (focus_resources))
+ {
+ meta_wayland_inputfd_evdev_device_broadcast_focus_out (device);
+ move_resources (&device->resource_list, &device->focus_resource_list);
+ }
+
+ wl_list_remove (&device->focus_surface_listener.link);
+ device->focus_surface = NULL;
+ device_close_fd (device);
+ }
+
+ if (surface != NULL)
+ device_open_fd (device);
+
+ if (surface != NULL && device->fd >= 0)
+ {
+ struct wl_client *client;
+
+ device->focus_surface = surface;
+ wl_resource_add_destroy_listener (device->focus_surface->resource,
+ &device->focus_surface_listener);
+
+ client = wl_resource_get_client (device->focus_surface->resource);
+ move_resources_for_client (&device->focus_resource_list,
+ &device->resource_list, client);
+
+ if (!wl_list_empty (&device->focus_resource_list))
+ {
+ struct wl_display *display = wl_client_get_display (client);
+ uint32_t serial = wl_display_next_serial (display);
+
+ meta_wayland_inputfd_evdev_device_broadcast_focus_in (device,
+ surface,
+ serial);
+ }
+ }
+}
diff --git a/src/wayland/meta-wayland-inputfd-evdev-device.h b/src/wayland/meta-wayland-inputfd-evdev-device.h
new file mode 100644
index 000000000..5fc4b3b09
--- /dev/null
+++ b/src/wayland/meta-wayland-inputfd-evdev-device.h
@@ -0,0 +1,67 @@
+/*
+ * Wayland Support
+ *
+ * Copyright (C) 2018 Red Hat
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Carlos Garnacho <carlosg@gnome.org>
+ */
+#ifndef META_WAYLAND_INPUTFD_EVDEV_DEVICE_H
+#define META_WAYLAND_INPUTFD_EVDEV_DEVICE_H
+
+#include <glib.h>
+#include <gudev/gudev.h>
+#include <wayland-server.h>
+
+#include "backends/native/meta-backend-native-private.h"
+#include "backends/native/meta-device-pool.h"
+#include "wayland/meta-wayland-types.h"
+
+struct _MetaWaylandInputFdEvdevDevice
+{
+ GUdevDevice *udev_device;
+
+ struct wl_list resource_list;
+ struct wl_list focus_resource_list;
+
+ MetaWaylandSurface *focus_surface;
+ struct wl_listener focus_surface_listener;
+
+ const gchar *name;
+ uint32_t vid;
+ uint32_t pid;
+
+ MetaDeviceFile *device_file;
+ int fd;
+};
+
+MetaWaylandInputFdEvdevDevice *
+ meta_wayland_inputfd_evdev_device_new (MetaWaylandInputFdSeat *seat,
+ GUdevDevice *device);
+void meta_wayland_inputfd_evdev_device_free (MetaWaylandInputFdEvdevDevice *evdev_device);
+
+
+struct wl_resource *
+ meta_wayland_inputfd_evdev_device_create_new_resource (MetaWaylandInputFdEvdevDevice *device,
+ struct wl_client *client,
+ struct wl_resource *seat_resource,
+ uint32_t id);
+void meta_wayland_inputfd_evdev_device_set_focus (MetaWaylandInputFdEvdevDevice *device,
+ MetaWaylandSurface *surface);
+
+void meta_wayland_inputfd_evdev_device_notify (MetaWaylandInputFdEvdevDevice *device,
+ struct wl_resource *resource);
+
+#endif /* META_WAYLAND_INPUTFD_EVDEV_DEVICE_H */
diff --git a/src/wayland/meta-wayland-inputfd-manager.c b/src/wayland/meta-wayland-inputfd-manager.c
new file mode 100644
index 000000000..db8709b63
--- /dev/null
+++ b/src/wayland/meta-wayland-inputfd-manager.c
@@ -0,0 +1,128 @@
+/*
+ * Wayland Support
+ *
+ * Copyright (C) 2018 Red Hat
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Carlos Garnacho <carlosg@gnome.org>
+ */
+#include "config.h"
+
+#include "inputfd-v1-server-protocol.h"
+#include "wayland/meta-wayland-inputfd-manager.h"
+#include "wayland/meta-wayland-inputfd-seat.h"
+#include "wayland/meta-wayland-private.h"
+
+static void
+unbind_resource (struct wl_resource *resource)
+{
+ wl_list_remove (wl_resource_get_link (resource));
+}
+
+static void
+inputfd_manager_get_seat_evdev (struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t id,
+ struct wl_resource *seat_resource)
+{
+ MetaWaylandInputFdManager *manager = wl_resource_get_user_data (resource);
+ MetaWaylandSeat *seat = wl_resource_get_user_data (seat_resource);
+ MetaWaylandInputFdSeat *inputfd_seat;
+
+ inputfd_seat = meta_wayland_inputfd_manager_ensure_seat (manager, seat);
+ meta_wayland_inputfd_seat_create_new_evdev_resource (inputfd_seat, client,
+ resource, id);
+}
+
+static void
+inputfd_manager_destroy (struct wl_client *client,
+ struct wl_resource *resource)
+{
+ wl_resource_destroy (resource);
+}
+
+static const struct wp_inputfd_manager_v1_interface inputfd_manager_interface = {
+ inputfd_manager_get_seat_evdev,
+ inputfd_manager_destroy
+};
+
+static void
+bind_inputfd_manager (struct wl_client *client,
+ void *data,
+ uint32_t version,
+ uint32_t id)
+{
+ MetaWaylandCompositor *compositor = data;
+ MetaWaylandInputFdManager *manager = compositor->inputfd_manager;
+ struct wl_resource *resource;
+
+ resource = wl_resource_create (client, &wp_inputfd_manager_v1_interface,
+ MIN (version, 1), id);
+ wl_resource_set_implementation (resource, &inputfd_manager_interface,
+ manager, unbind_resource);
+ wl_resource_set_user_data (resource, manager);
+ wl_list_insert (&manager->resource_list,
+ wl_resource_get_link (resource));
+}
+
+static MetaWaylandInputFdManager *
+meta_wayland_inputfd_manager_new (MetaWaylandCompositor *compositor)
+{
+ MetaWaylandInputFdManager *manager;
+
+ manager = g_slice_new0 (MetaWaylandInputFdManager);
+ manager->compositor = compositor;
+ manager->wl_display = compositor->wayland_display;
+ manager->seats = g_hash_table_new_full (NULL, NULL, NULL,
+ (GDestroyNotify) meta_wayland_inputfd_seat_free);
+ wl_list_init (&manager->resource_list);
+
+ wl_global_create (manager->wl_display,
+ &wp_inputfd_manager_v1_interface,
+ META_WP_INPUTFD_V1_VERSION,
+ compositor, bind_inputfd_manager);
+
+ return manager;
+}
+
+void
+meta_wayland_inputfd_manager_init (MetaWaylandCompositor *compositor)
+{
+ compositor->inputfd_manager = meta_wayland_inputfd_manager_new (compositor);
+}
+
+void
+meta_wayland_inputfd_manager_free (MetaWaylandInputFdManager *manager)
+{
+ g_hash_table_destroy (manager->seats);
+ g_slice_free (MetaWaylandInputFdManager, manager);
+}
+
+MetaWaylandInputFdSeat *
+meta_wayland_inputfd_manager_ensure_seat (MetaWaylandInputFdManager *manager,
+ MetaWaylandSeat *seat)
+{
+ MetaWaylandInputFdSeat *inputfd_seat;
+
+ inputfd_seat = g_hash_table_lookup (manager->seats, seat);
+
+ if (!inputfd_seat)
+ {
+ inputfd_seat = meta_wayland_inputfd_seat_new (manager, seat);
+ g_hash_table_insert (manager->seats, seat, inputfd_seat);
+ }
+
+ return inputfd_seat;
+}
diff --git a/src/wayland/meta-wayland-inputfd-manager.h b/src/wayland/meta-wayland-inputfd-manager.h
new file mode 100644
index 000000000..0fb41f145
--- /dev/null
+++ b/src/wayland/meta-wayland-inputfd-manager.h
@@ -0,0 +1,47 @@
+/*
+ * Wayland Support
+ *
+ * Copyright (C) 2018 Red Hat
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Carlos Garnacho <carlosg@gnome.org>
+ */
+
+#ifndef META_WAYLAND_INPUTFD_MANAGER_H
+#define META_WAYLAND_INPUTFD_MANAGER_H
+
+#include <wayland-server.h>
+
+#include <glib.h>
+
+#include "meta-wayland-types.h"
+
+struct _MetaWaylandInputFdManager
+{
+ MetaWaylandCompositor *compositor;
+ struct wl_display *wl_display;
+ struct wl_list resource_list;
+
+ GHashTable *seats;
+};
+
+void meta_wayland_inputfd_manager_init (MetaWaylandCompositor *compositor);
+void meta_wayland_inputfd_manager_free (MetaWaylandInputFdManager *manager);
+
+MetaWaylandInputFdSeat *
+ meta_wayland_inputfd_manager_ensure_seat (MetaWaylandInputFdManager *manager,
+ MetaWaylandSeat *seat);
+
+#endif /* META_WAYLAND_INPUTFD_MANAGER_H */
diff --git a/src/wayland/meta-wayland-inputfd-seat.c b/src/wayland/meta-wayland-inputfd-seat.c
new file mode 100644
index 000000000..bf78d0038
--- /dev/null
+++ b/src/wayland/meta-wayland-inputfd-seat.c
@@ -0,0 +1,213 @@
+/*
+ * Wayland Support
+ *
+ * Copyright (C) 2018 Red Hat
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Carlos Garnacho <carlosg@gnome.org>
+ */
+#include "config.h"
+
+#include "inputfd-v1-server-protocol.h"
+#include "wayland/meta-wayland-inputfd-seat.h"
+#include "wayland/meta-wayland-inputfd-evdev-device.h"
+#include "wayland/meta-wayland-seat.h"
+
+static void
+unbind_resource (struct wl_resource *resource)
+{
+ wl_list_remove (wl_resource_get_link (resource));
+}
+
+static void
+notify_evdev_device_added (MetaWaylandInputFdSeat *inputfd_seat,
+ MetaWaylandInputFdEvdevDevice *evdev_device,
+ struct wl_resource *seat_resource)
+{
+ MetaWaylandSurface *focus;
+ struct wl_resource *resource;
+ struct wl_client *client;
+
+ if (inputfd_seat->seat->keyboard)
+ focus = inputfd_seat->seat->keyboard->focus_surface;
+ else
+ focus = NULL;
+
+ client = wl_resource_get_client (seat_resource);
+ resource = meta_wayland_inputfd_evdev_device_create_new_resource (evdev_device,
+ client,
+ seat_resource,
+ 0);
+ wp_inputfd_seat_evdev_v1_send_device_added (seat_resource, resource);
+
+ meta_wayland_inputfd_evdev_device_notify (evdev_device, resource);
+
+ meta_wayland_inputfd_evdev_device_set_focus (evdev_device, focus);
+}
+
+static void
+broadcast_evdev_device_added (MetaWaylandInputFdSeat *seat,
+ MetaWaylandInputFdEvdevDevice *evdev_device)
+{
+ struct wl_resource *seat_resource;
+
+ wl_resource_for_each (seat_resource, &seat->evdev_seat_resources)
+ {
+ notify_evdev_device_added (seat, evdev_device, seat_resource);
+ }
+}
+
+static void
+check_add_device (MetaWaylandInputFdSeat *inputfd_seat,
+ GUdevDevice *device)
+{
+ MetaWaylandInputFdEvdevDevice *evdev_device;
+
+ evdev_device = meta_wayland_inputfd_evdev_device_new (inputfd_seat,
+ device);
+ if (evdev_device)
+ {
+ g_hash_table_insert (inputfd_seat->evdev_devices,
+ (gpointer) g_udev_device_get_sysfs_path (device),
+ evdev_device);
+ broadcast_evdev_device_added (inputfd_seat, evdev_device);
+ return;
+ }
+}
+
+static void
+remove_device (MetaWaylandInputFdSeat *inputfd_seat,
+ GUdevDevice *device)
+{
+ g_hash_table_remove (inputfd_seat->evdev_devices,
+ g_udev_device_get_sysfs_path (device));
+}
+
+static void
+udev_event_cb (GUdevClient *client,
+ char *action,
+ GUdevDevice *device,
+ MetaWaylandInputFdSeat *seat)
+{
+ if (g_strcmp0 (action, "add") == 0)
+ check_add_device (seat, device);
+ else if (g_strcmp0 (action, "remove") == 0)
+ remove_device (seat, device);
+}
+
+MetaWaylandInputFdSeat *
+meta_wayland_inputfd_seat_new (MetaWaylandInputFdManager *manager,
+ MetaWaylandSeat *seat)
+{
+ const char * const subsystems[] = { "input", NULL };
+ MetaWaylandInputFdSeat *inputfd_seat;
+ GList *devices;
+
+ inputfd_seat = g_slice_new0 (MetaWaylandInputFdSeat);
+ wl_list_init (&inputfd_seat->evdev_seat_resources);
+ inputfd_seat->seat = seat;
+ inputfd_seat->evdev_devices =
+ g_hash_table_new_full (g_str_hash, g_str_equal, NULL,
+ (GDestroyNotify) meta_wayland_inputfd_evdev_device_free);
+
+ inputfd_seat->udev_client = g_udev_client_new (subsystems);
+ g_signal_connect (inputfd_seat->udev_client, "uevent",
+ G_CALLBACK (udev_event_cb), inputfd_seat);
+
+ devices = g_udev_client_query_by_subsystem (inputfd_seat->udev_client,
+ subsystems[0]);
+ while (devices)
+ {
+ GUdevDevice *device = devices->data;
+
+ check_add_device (inputfd_seat, device);
+ g_object_unref (device);
+ devices = g_list_delete_link (devices, devices);
+ }
+
+ return inputfd_seat;
+}
+
+void
+meta_wayland_inputfd_seat_free (MetaWaylandInputFdSeat *inputfd_seat)
+{
+ g_hash_table_destroy (inputfd_seat->evdev_devices);
+
+ g_signal_handlers_disconnect_by_func (inputfd_seat->udev_client,
+ udev_event_cb, inputfd_seat);
+ g_object_unref (inputfd_seat->udev_client);
+
+ g_slice_free (MetaWaylandInputFdSeat, inputfd_seat);
+}
+
+static void
+notify_evdev_devices (MetaWaylandInputFdSeat *seat,
+ struct wl_resource *seat_resource)
+{
+ MetaWaylandInputFdEvdevDevice *device;
+ GHashTableIter iter;
+
+ g_hash_table_iter_init (&iter, seat->evdev_devices);
+
+ while (g_hash_table_iter_next (&iter, NULL, (void **) &device))
+ {
+ notify_evdev_device_added (seat, device, seat_resource);
+ }
+}
+
+static void
+inputfd_seat_evdev_destroy (struct wl_client *client,
+ struct wl_resource *resource)
+{
+ wl_resource_destroy (resource);
+}
+
+static const struct wp_inputfd_seat_evdev_v1_interface inputfd_seat_evdev_interface = {
+ inputfd_seat_evdev_destroy
+};
+
+struct wl_resource *
+meta_wayland_inputfd_seat_create_new_evdev_resource (MetaWaylandInputFdSeat *seat,
+ struct wl_client *client,
+ struct wl_resource *manager_resource,
+ uint32_t id)
+{
+ struct wl_resource *resource;
+
+ resource = wl_resource_create (client, &wp_inputfd_seat_evdev_v1_interface,
+ wl_resource_get_version (manager_resource),
+ id);
+ wl_resource_set_implementation (resource, &inputfd_seat_evdev_interface,
+ seat, unbind_resource);
+ wl_resource_set_user_data (resource, seat);
+ wl_list_insert (&seat->evdev_seat_resources, wl_resource_get_link (resource));
+
+ notify_evdev_devices (seat, resource);
+
+ return resource;
+}
+
+void
+meta_wayland_inputfd_seat_set_focus (MetaWaylandInputFdSeat *seat,
+ MetaWaylandSurface *surface)
+{
+ MetaWaylandInputFdEvdevDevice *device;
+ GHashTableIter iter;
+
+ g_hash_table_iter_init (&iter, seat->evdev_devices);
+
+ while (g_hash_table_iter_next (&iter, NULL, (void **) &device))
+ meta_wayland_inputfd_evdev_device_set_focus (device, surface);
+}
diff --git a/src/wayland/meta-wayland-inputfd-seat.h b/src/wayland/meta-wayland-inputfd-seat.h
new file mode 100644
index 000000000..b3c7229ab
--- /dev/null
+++ b/src/wayland/meta-wayland-inputfd-seat.h
@@ -0,0 +1,52 @@
+/*
+ * Wayland Support
+ *
+ * Copyright (C) 2018 Red Hat
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Carlos Garnacho <carlosg@gnome.org>
+ */
+#ifndef META_WAYLAND_INPUTFD_SEAT_H
+#define META_WAYLAND_INPUTFD_SEAT_H
+
+#include <glib.h>
+#include <gudev/gudev.h>
+#include <wayland-server.h>
+
+#include "meta-wayland-types.h"
+
+struct _MetaWaylandInputFdSeat
+{
+ GUdevClient *udev_client;
+ MetaWaylandSeat *seat;
+ struct wl_list evdev_seat_resources;
+ GHashTable *evdev_devices;
+};
+
+MetaWaylandInputFdSeat *
+ meta_wayland_inputfd_seat_new (MetaWaylandInputFdManager *manager,
+ MetaWaylandSeat *seat);
+void meta_wayland_inputfd_seat_free (MetaWaylandInputFdSeat *inputfd_seat);
+
+struct wl_resource *
+ meta_wayland_inputfd_seat_create_new_evdev_resource (MetaWaylandInputFdSeat *seat,
+ struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t id);
+
+void meta_wayland_inputfd_seat_set_focus (MetaWaylandInputFdSeat *seat,
+ MetaWaylandSurface *surface);
+
+#endif /* META_WAYLAND_INPUTFD_SEAT_H */
diff --git a/src/wayland/meta-wayland-private.h b/src/wayland/meta-wayland-private.h
index dc4dba4b4..022db23ae 100644
--- a/src/wayland/meta-wayland-private.h
+++ b/src/wayland/meta-wayland-private.h
@@ -26,6 +26,7 @@
#include "clutter/clutter.h"
#include "core/window-private.h"
#include "meta/meta-cursor-tracker.h"
+#include "wayland/meta-wayland-inputfd-manager.h"
#include "wayland/meta-wayland-pointer-gestures.h"
#include "wayland/meta-wayland-presentation-time-private.h"
#include "wayland/meta-wayland-seat.h"
@@ -95,6 +96,7 @@ struct _MetaWaylandCompositor
MetaWaylandSeat *seat;
MetaWaylandTabletManager *tablet_manager;
MetaWaylandActivation *activation;
+ MetaWaylandInputFdManager *inputfd_manager;
GHashTable *scheduled_surface_associations;
diff --git a/src/wayland/meta-wayland-seat.c b/src/wayland/meta-wayland-seat.c
index 4e0976920..35961932d 100644
--- a/src/wayland/meta-wayland-seat.c
+++ b/src/wayland/meta-wayland-seat.c
@@ -24,6 +24,7 @@
#include "wayland/meta-wayland-seat.h"
#include "wayland/meta-wayland-data-device.h"
+#include "wayland/meta-wayland-inputfd-seat.h"
#include "wayland/meta-wayland-private.h"
#include "wayland/meta-wayland-tablet-seat.h"
#include "wayland/meta-wayland-versions.h"
@@ -168,7 +169,16 @@ meta_wayland_seat_set_capabilities (MetaWaylandSeat *seat,
meta_display_sync_wayland_input_focus (display);
}
else if (CAPABILITY_DISABLED (prev_flags, flags, WL_SEAT_CAPABILITY_KEYBOARD))
- meta_wayland_keyboard_disable (seat->keyboard);
+ {
+ MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default ();
+ MetaWaylandInputFdSeat *inputfd_seat;
+
+ meta_wayland_keyboard_disable (seat->keyboard);
+
+ inputfd_seat = meta_wayland_inputfd_manager_ensure_seat (compositor->inputfd_manager,
+ seat);
+ meta_wayland_inputfd_seat_set_focus (inputfd_seat, NULL);
+ }
if (CAPABILITY_ENABLED (prev_flags, flags, WL_SEAT_CAPABILITY_TOUCH))
meta_wayland_touch_enable (seat->touch);
@@ -411,6 +421,7 @@ meta_wayland_seat_set_input_focus (MetaWaylandSeat *seat,
MetaWaylandSurface *surface)
{
MetaWaylandTabletSeat *tablet_seat;
+ MetaWaylandInputFdSeat *inputfd_seat;
MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default ();
if (meta_wayland_seat_has_keyboard (seat))
@@ -424,6 +435,10 @@ meta_wayland_seat_set_input_focus (MetaWaylandSeat *seat,
meta_wayland_tablet_seat_set_pad_focus (tablet_seat, surface);
meta_wayland_text_input_set_focus (seat->text_input, surface);
+
+ inputfd_seat = meta_wayland_inputfd_manager_ensure_seat (compositor->inputfd_manager,
+ seat);
+ meta_wayland_inputfd_seat_set_focus (inputfd_seat, surface);
}
gboolean
diff --git a/src/wayland/meta-wayland-types.h b/src/wayland/meta-wayland-types.h
index 2df2b5e2f..8f02a2eb7 100644
--- a/src/wayland/meta-wayland-types.h
+++ b/src/wayland/meta-wayland-types.h
@@ -66,4 +66,8 @@ typedef struct _MetaWaylandDmaBufManager MetaWaylandDmaBufManager;
typedef struct _MetaXWaylandManager MetaXWaylandManager;
+typedef struct _MetaWaylandInputFdManager MetaWaylandInputFdManager;
+typedef struct _MetaWaylandInputFdSeat MetaWaylandInputFdSeat;
+typedef struct _MetaWaylandInputFdEvdevDevice MetaWaylandInputFdEvdevDevice;
+
#endif
diff --git a/src/wayland/meta-wayland-versions.h b/src/wayland/meta-wayland-versions.h
index 254916f90..51b5f1480 100644
--- a/src/wayland/meta-wayland-versions.h
+++ b/src/wayland/meta-wayland-versions.h
@@ -55,5 +55,6 @@
#define META_WP_PRESENTATION_VERSION 1
#define META_XDG_ACTIVATION_V1_VERSION 1
#define META_WP_SINGLE_PIXEL_BUFFER_V1_VERSION 1
+#define META_WP_INPUTFD_V1_VERSION 1
#endif
diff --git a/src/wayland/meta-wayland.c b/src/wayland/meta-wayland.c
index 9d066b19c..03c9d1995 100644
--- a/src/wayland/meta-wayland.c
+++ b/src/wayland/meta-wayland.c
@@ -633,6 +633,7 @@ meta_wayland_compositor_new (MetaContext *context)
meta_wayland_text_input_init (compositor);
meta_wayland_init_presentation_time (compositor);
meta_wayland_activation_init (compositor);
+ meta_wayland_inputfd_manager_init (compositor);
/* Xwayland specific protocol, needs to be filtered out for all other clients */
if (meta_xwayland_grab_keyboard_init (compositor))