From 9321249b8dcec7ae7b9cf21b583e3cc16913fb27 Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Sat, 1 Sep 2018 22:09:58 +0200 Subject: [PATCH] wayland: Implement the "inputfd" wayland protocols This allows lending control to applications of evdev devices, and withdrawing it with focus. --- src/meson.build | 7 + .../meta-wayland-inputfd-evdev-device.c | 287 ++++++++++++++++++ .../meta-wayland-inputfd-evdev-device.h | 64 ++++ src/wayland/meta-wayland-inputfd-manager.c | 128 ++++++++ src/wayland/meta-wayland-inputfd-manager.h | 47 +++ src/wayland/meta-wayland-inputfd-seat.c | 201 ++++++++++++ src/wayland/meta-wayland-inputfd-seat.h | 51 ++++ src/wayland/meta-wayland-private.h | 2 + src/wayland/meta-wayland-seat.c | 17 +- src/wayland/meta-wayland-types.h | 4 + src/wayland/meta-wayland-versions.h | 1 + src/wayland/meta-wayland.c | 1 + 12 files changed, 809 insertions(+), 1 deletion(-) create mode 100644 src/wayland/meta-wayland-inputfd-evdev-device.c create mode 100644 src/wayland/meta-wayland-inputfd-evdev-device.h create mode 100644 src/wayland/meta-wayland-inputfd-manager.c create mode 100644 src/wayland/meta-wayland-inputfd-manager.h create mode 100644 src/wayland/meta-wayland-inputfd-seat.c create mode 100644 src/wayland/meta-wayland-inputfd-seat.h diff --git a/src/meson.build b/src/meson.build index 433f811d2..e8c7b44f6 100644 --- a/src/meson.build +++ b/src/meson.build @@ -533,6 +533,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', @@ -814,6 +820,7 @@ if have_wayland ['gtk-primary-selection', 'private', ], ['gtk-shell', 'private', ], ['gtk-text-input', 'private', ], + ['inputfd', 'unstable', '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..e211c8e24 --- /dev/null +++ b/src/wayland/meta-wayland-inputfd-evdev-device.c @@ -0,0 +1,287 @@ +/* + * 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 . + * + * Author: Carlos Garnacho + */ +#include "config.h" + +#include +#include + +#include "backends/native/meta-backend-native.h" +#include "compositor/meta-surface-actor-wayland.h" +#include "inputfd-unstable-v1-server-protocol.h" +#include "wayland/meta-wayland-inputfd-evdev-device.h" + +static void device_open_fd (MetaWaylandInputFdEvdevDevice *device); + +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) + { + zwp_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 zwp_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, &zwp_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) +{ + zwp_inputfd_device_evdev_v1_send_name (resource, device->name); + zwp_inputfd_device_evdev_v1_send_usb_id (resource, device->vid, device->pid); + zwp_inputfd_device_evdev_v1_send_done (resource); +} + +static void +device_open_fd (MetaWaylandInputFdEvdevDevice *device) +{ + MetaBackend *backend; + MetaLauncher *launcher; + const char *path; + + g_assert (device->fd == -1); + path = g_udev_device_get_device_file (device->udev_device); + + backend = meta_get_backend (); + if (!META_IS_BACKEND_NATIVE (backend)) + return; + + launcher = meta_backend_native_get_launcher (META_BACKEND_NATIVE (backend)); + device->fd = meta_launcher_open_restricted (launcher, path, NULL); +} + +static void +device_close_fd (MetaWaylandInputFdEvdevDevice *device) +{ + MetaBackend *backend; + MetaLauncher *launcher; + + ioctl(device->fd, EVIOCREVOKE, NULL); + + backend = meta_get_backend (); + if (!META_IS_BACKEND_NATIVE (backend)) + return; + + launcher = meta_backend_native_get_launcher (META_BACKEND_NATIVE (backend)); + meta_launcher_close_restricted (launcher, device->fd); + device->fd = -1; +} + +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) + { + zwp_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) + { + zwp_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..99a23f443 --- /dev/null +++ b/src/wayland/meta-wayland-inputfd-evdev-device.h @@ -0,0 +1,64 @@ +/* + * 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 . + * + * Author: Carlos Garnacho + */ +#ifndef META_WAYLAND_INPUTFD_EVDEV_DEVICE_H +#define META_WAYLAND_INPUTFD_EVDEV_DEVICE_H + +#include +#include +#include + +#include "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; + + 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..bc9188183 --- /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 . + * + * Author: Carlos Garnacho + */ +#include "config.h" + +#include "inputfd-unstable-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 zwp_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, &zwp_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, + &zwp_inputfd_manager_v1_interface, + META_ZWP_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 . + * + * Author: Carlos Garnacho + */ + +#ifndef META_WAYLAND_INPUTFD_MANAGER_H +#define META_WAYLAND_INPUTFD_MANAGER_H + +#include + +#include + +#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..2667c2a5a --- /dev/null +++ b/src/wayland/meta-wayland-inputfd-seat.c @@ -0,0 +1,201 @@ +/* + * 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 . + * + * Author: Carlos Garnacho + */ +#include "config.h" + +#include "inputfd-unstable-v1-server-protocol.h" +#include "wayland/meta-wayland-inputfd-seat.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 +notify_evdev_device_added (MetaWaylandInputFdSeat *seat, + MetaWaylandInputFdEvdevDevice *evdev_device, + struct wl_resource *seat_resource) +{ + struct wl_resource *resource; + struct wl_client *client; + + client = wl_resource_get_client (seat_resource); + resource = meta_wayland_inputfd_evdev_device_create_new_resource (evdev_device, + client, + seat_resource, + 0); + zwp_inputfd_seat_evdev_v1_send_device_added (seat_resource, resource); +} + +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->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 zwp_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, &zwp_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..f1ac95b12 --- /dev/null +++ b/src/wayland/meta-wayland-inputfd-seat.h @@ -0,0 +1,51 @@ +/* + * 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 . + * + * Author: Carlos Garnacho + */ +#ifndef META_WAYLAND_INPUTFD_SEAT_H +#define META_WAYLAND_INPUTFD_SEAT_H + +#include +#include +#include + +#include "meta-wayland-types.h" + +struct _MetaWaylandInputFdSeat +{ + GUdevClient *udev_client; + 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 727009b07..b00dd835c 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-seat.h" #include "wayland/meta-wayland-surface.h" @@ -85,6 +86,7 @@ struct _MetaWaylandCompositor MetaWaylandSeat *seat; MetaWaylandTabletManager *tablet_manager; + MetaWaylandInputFdManager *inputfd_manager; GHashTable *scheduled_surface_associations; }; diff --git a/src/wayland/meta-wayland-seat.c b/src/wayland/meta-wayland-seat.c index 3a76a1b5b..c0d86a4cb 100644 --- a/src/wayland/meta-wayland-seat.c +++ b/src/wayland/meta-wayland-seat.c @@ -25,6 +25,7 @@ #include "wayland/meta-wayland-data-device.h" #include "wayland/meta-wayland-data-device-primary-legacy.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" @@ -176,7 +177,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); @@ -428,6 +438,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)) @@ -443,6 +454,10 @@ meta_wayland_seat_set_input_focus (MetaWaylandSeat *seat, meta_wayland_text_input_set_focus (seat->text_input, surface); meta_wayland_gtk_text_input_set_focus (seat->gtk_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 00712ad1f..49ff81bbc 100644 --- a/src/wayland/meta-wayland-types.h +++ b/src/wayland/meta-wayland-types.h @@ -61,4 +61,8 @@ typedef struct _MetaWaylandWindowConfiguration MetaWaylandWindowConfiguration; typedef struct _MetaWaylandPointerClient MetaWaylandPointerClient; +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 2d6ce5ace..6db0a436a 100644 --- a/src/wayland/meta-wayland-versions.h +++ b/src/wayland/meta-wayland-versions.h @@ -55,5 +55,6 @@ #define META_GTK_TEXT_INPUT_VERSION 1 #define META_ZWP_TEXT_INPUT_V3_VERSION 1 #define META_WP_VIEWPORTER_VERSION 1 +#define META_ZWP_INPUTFD_V1_VERSION 1 #endif diff --git a/src/wayland/meta-wayland.c b/src/wayland/meta-wayland.c index e4b09cbfc..e81f1fa21 100644 --- a/src/wayland/meta-wayland.c +++ b/src/wayland/meta-wayland.c @@ -438,6 +438,7 @@ meta_wayland_compositor_setup (MetaWaylandCompositor *wayland_compositor) meta_wayland_surface_inhibit_shortcuts_dialog_init (); meta_wayland_text_input_init (compositor); meta_wayland_gtk_text_input_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))