aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/wlr/types/wlr_keyboard_shortcuts_inhibit_v1.h85
-rw-r--r--protocol/meson.build1
-rw-r--r--types/meson.build1
-rw-r--r--types/wlr_keyboard_shortcuts_inhibit_v1.c227
4 files changed, 314 insertions, 0 deletions
diff --git a/include/wlr/types/wlr_keyboard_shortcuts_inhibit_v1.h b/include/wlr/types/wlr_keyboard_shortcuts_inhibit_v1.h
new file mode 100644
index 00000000..e212e0f4
--- /dev/null
+++ b/include/wlr/types/wlr_keyboard_shortcuts_inhibit_v1.h
@@ -0,0 +1,85 @@
+/*
+ * This an unstable interface of wlroots. No guarantees are made regarding the
+ * future consistency of this API.
+ */
+#ifndef WLR_USE_UNSTABLE
+#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features"
+#endif
+
+#ifndef WLR_TYPES_WLR_KEYBOARD_SHORTCUTS_INHIBIT_V1_H
+#define WLR_TYPES_WLR_KEYBOARD_SHORTCUTS_INHIBIT_V1_H
+
+#include <wayland-server-core.h>
+#include <wlr/types/wlr_seat.h>
+
+/* This interface permits clients to inhibit keyboard shortcut processing by
+ * the compositor.
+ *
+ * This allows clients to pass them on to e.g. remote desktops or virtual
+ * machine guests.
+ *
+ * Inhibitors are created for surfaces and seats. They should only be in effect
+ * while this surface has focus.
+ */
+
+struct wlr_keyboard_shortcuts_inhibit_manager_v1 {
+ // wlr_keyboard_shortcuts_inhibitor_v1::link
+ struct wl_list inhibitors;
+ struct wl_global *global;
+
+ struct wl_listener display_destroy;
+
+ struct {
+ struct wl_signal new_inhibitor; // wlr_keyboard_shortcuts_inhibitor_v1
+ struct wl_signal destroy;
+ } events;
+
+ void *data;
+};
+
+struct wlr_keyboard_shortcuts_inhibitor_v1 {
+ struct wlr_surface *surface;
+ struct wlr_seat *seat;
+ bool active;
+ struct wl_resource *resource;
+
+ struct wl_listener surface_destroy;
+ struct wl_listener seat_destroy;
+
+ // wlr_keyboard_shortcuts_inhibit_manager_v1::inhibitors
+ struct wl_list link;
+
+ struct {
+ struct wl_signal destroy;
+ } events;
+
+ void *data;
+};
+
+/*
+ * A compositor creating a manager will handle the new_inhibitor event and call
+ * wlr_keyboard_shortcuts_inhibitor_v1_activate() if it decides to honour the
+ * inhibitor. This will send the active event to the client, confirming
+ * activation of the inhibitor. From then on the compositor should respect the
+ * inhibitor until it calls wlr_keyboard_shortcuts_inhibitor_v1_deactivate() to
+ * suspend the inhibitor with an inactive event to the client or receives the
+ * destroy signal from wlroots, telling it that the inhibitor has been
+ * destroyed.
+ *
+ * Not sending the active event to the client is the only way under the
+ * protocol to let the client know that the compositor will not be honouring an
+ * inhibitor. It's the client's job to somehow deal with not receiving the
+ * event, i.e. not assume that shortcuts are inhibited and maybe destroy the
+ * pending and request a new inhibitor after a timeout.
+ */
+
+struct wlr_keyboard_shortcuts_inhibit_manager_v1 *
+wlr_keyboard_shortcuts_inhibit_v1_create(struct wl_display *display);
+
+void wlr_keyboard_shortcuts_inhibitor_v1_activate(
+ struct wlr_keyboard_shortcuts_inhibitor_v1 *inhibitor);
+
+void wlr_keyboard_shortcuts_inhibitor_v1_deactivate(
+ struct wlr_keyboard_shortcuts_inhibitor_v1 *inhibitor);
+
+#endif
diff --git a/protocol/meson.build b/protocol/meson.build
index f46b3d36..6275103a 100644
--- a/protocol/meson.build
+++ b/protocol/meson.build
@@ -17,6 +17,7 @@ protocols = {
# Unstable upstream protocols
'fullscreen-shell-unstable-v1': wl_protocol_dir / 'unstable/fullscreen-shell/fullscreen-shell-unstable-v1.xml',
'idle-inhibit-unstable-v1': wl_protocol_dir / 'unstable/idle-inhibit/idle-inhibit-unstable-v1.xml',
+ 'keyboard-shortcuts-inhibit-unstable-v1': wl_protocol_dir / 'unstable/keyboard-shortcuts-inhibit/keyboard-shortcuts-inhibit-unstable-v1.xml',
'linux-dmabuf-unstable-v1': wl_protocol_dir / 'unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml',
'pointer-constraints-unstable-v1': wl_protocol_dir / 'unstable/pointer-constraints/pointer-constraints-unstable-v1.xml',
'pointer-gestures-unstable-v1': wl_protocol_dir / 'unstable/pointer-gestures/pointer-gestures-unstable-v1.xml',
diff --git a/types/meson.build b/types/meson.build
index 1289b1f3..face4bdf 100644
--- a/types/meson.build
+++ b/types/meson.build
@@ -38,6 +38,7 @@ wlr_files += files(
'wlr_input_method_v2.c',
'wlr_keyboard.c',
'wlr_keyboard_group.c',
+ 'wlr_keyboard_shortcuts_inhibit_v1.c',
'wlr_layer_shell_v1.c',
'wlr_linux_dmabuf_v1.c',
'wlr_list.c',
diff --git a/types/wlr_keyboard_shortcuts_inhibit_v1.c b/types/wlr_keyboard_shortcuts_inhibit_v1.c
new file mode 100644
index 00000000..fe4e64b0
--- /dev/null
+++ b/types/wlr_keyboard_shortcuts_inhibit_v1.c
@@ -0,0 +1,227 @@
+#include <assert.h>
+#include <stdlib.h>
+#include <util/signal.h>
+#include <wlr/types/wlr_keyboard_shortcuts_inhibit_v1.h>
+#include "keyboard-shortcuts-inhibit-unstable-v1-protocol.h"
+
+static const struct zwp_keyboard_shortcuts_inhibit_manager_v1_interface
+ keyboard_shortcuts_inhibit_impl;
+
+static const struct zwp_keyboard_shortcuts_inhibitor_v1_interface
+ keyboard_shortcuts_inhibitor_impl;
+
+static struct wlr_keyboard_shortcuts_inhibit_manager_v1 *
+wlr_keyboard_shortcuts_inhibit_manager_v1_from_resource(
+ struct wl_resource *manager_resource) {
+ assert(wl_resource_instance_of(manager_resource,
+ &zwp_keyboard_shortcuts_inhibit_manager_v1_interface,
+ &keyboard_shortcuts_inhibit_impl));
+ return wl_resource_get_user_data(manager_resource);
+}
+
+static struct wlr_keyboard_shortcuts_inhibitor_v1 *
+wlr_keyboard_shortcuts_inhibitor_v1_from_resource(
+ struct wl_resource *inhibitor_resource) {
+ assert(wl_resource_instance_of(inhibitor_resource,
+ &zwp_keyboard_shortcuts_inhibitor_v1_interface,
+ &keyboard_shortcuts_inhibitor_impl));
+ return wl_resource_get_user_data(inhibitor_resource);
+}
+
+static void keyboard_shortcuts_inhibitor_v1_destroy(
+ struct wlr_keyboard_shortcuts_inhibitor_v1 *inhibitor) {
+ if (!inhibitor) {
+ return;
+ }
+
+ wlr_signal_emit_safe(&inhibitor->events.destroy, inhibitor);
+
+ wl_resource_set_user_data(inhibitor->resource, NULL);
+ wl_list_remove(&inhibitor->link);
+ wl_list_remove(&inhibitor->surface_destroy.link);
+ wl_list_remove(&inhibitor->seat_destroy.link);
+ free(inhibitor);
+}
+
+static void keyboard_shortcuts_inhibitor_v1_handle_resource_destroy(
+ struct wl_resource *inhibitor_resource) {
+ struct wlr_keyboard_shortcuts_inhibitor_v1 *inhibitor =
+ wlr_keyboard_shortcuts_inhibitor_v1_from_resource(
+ inhibitor_resource);
+ keyboard_shortcuts_inhibitor_v1_destroy(inhibitor);
+}
+
+static void keyboard_shortcuts_inhibitor_handle_surface_destroy(
+ struct wl_listener *listener, void *data) {
+ struct wlr_keyboard_shortcuts_inhibitor_v1 *inhibitor =
+ wl_container_of(listener, inhibitor, surface_destroy);
+
+ // be gracious and notify client that destruction of a referenced
+ // resource makes inhibitor moot
+ wlr_keyboard_shortcuts_inhibitor_v1_deactivate(inhibitor);
+ keyboard_shortcuts_inhibitor_v1_destroy(inhibitor);
+}
+
+static void keyboard_shortcuts_inhibitor_handle_seat_destroy(
+ struct wl_listener *listener, void *data) {
+ struct wlr_keyboard_shortcuts_inhibitor_v1 *inhibitor =
+ wl_container_of(listener, inhibitor, seat_destroy);
+ wlr_keyboard_shortcuts_inhibitor_v1_deactivate(inhibitor);
+ keyboard_shortcuts_inhibitor_v1_destroy(inhibitor);
+}
+
+static void keyboard_shortcuts_inhibitor_v1_handle_destroy(
+ struct wl_client *client,
+ struct wl_resource *inhibitor_resource) {
+ wl_resource_destroy(inhibitor_resource);
+}
+
+static const struct zwp_keyboard_shortcuts_inhibitor_v1_interface
+keyboard_shortcuts_inhibitor_impl = {
+ .destroy = keyboard_shortcuts_inhibitor_v1_handle_destroy,
+};
+
+static void manager_handle_inhibit_shortcuts(struct wl_client *client,
+ struct wl_resource *manager_resource, uint32_t id,
+ struct wl_resource *surface_resource,
+ struct wl_resource *seat_resource) {
+ struct wlr_surface *surface =
+ wlr_surface_from_resource(surface_resource);
+ struct wlr_seat_client *seat_client =
+ wlr_seat_client_from_resource(seat_resource);
+ struct wlr_keyboard_shortcuts_inhibit_manager_v1 *manager =
+ wlr_keyboard_shortcuts_inhibit_manager_v1_from_resource(
+ manager_resource);
+
+ struct wlr_seat *seat = seat_client->seat;
+ struct wlr_keyboard_shortcuts_inhibitor_v1 *existing_inhibitor;
+ wl_list_for_each(existing_inhibitor, &manager->inhibitors, link) {
+ if (existing_inhibitor->surface != surface ||
+ existing_inhibitor->seat != seat) {
+ continue;
+ }
+
+ wl_resource_post_error(manager_resource,
+ ZWP_KEYBOARD_SHORTCUTS_INHIBIT_MANAGER_V1_ERROR_ALREADY_INHIBITED,
+ "this surface already has keyboard shortcuts "
+ "inhibited on this seat");
+ return;
+ }
+
+ struct wlr_keyboard_shortcuts_inhibitor_v1 *inhibitor =
+ calloc(1, sizeof(struct wlr_keyboard_shortcuts_inhibitor_v1));
+ if (!inhibitor) {
+ wl_client_post_no_memory(client);
+ return;
+ }
+
+ uint32_t version = wl_resource_get_version(manager_resource);
+ struct wl_resource *inhibitor_resource = wl_resource_create(client,
+ &zwp_keyboard_shortcuts_inhibitor_v1_interface, version, id);
+ if (!inhibitor_resource) {
+ wl_client_post_no_memory(client);
+ free(inhibitor);
+ return;
+ }
+
+ inhibitor->resource = inhibitor_resource;
+ inhibitor->surface = surface;
+ inhibitor->seat = seat;
+ inhibitor->active = false;
+ wl_signal_init(&inhibitor->events.destroy);
+
+ inhibitor->surface_destroy.notify =
+ keyboard_shortcuts_inhibitor_handle_surface_destroy;
+ wl_signal_add(&surface->events.destroy, &inhibitor->surface_destroy);
+
+ inhibitor->seat_destroy.notify =
+ keyboard_shortcuts_inhibitor_handle_seat_destroy;
+ wl_signal_add(&seat->events.destroy, &inhibitor->seat_destroy);
+
+ wl_resource_set_implementation(inhibitor_resource,
+ &keyboard_shortcuts_inhibitor_impl, inhibitor,
+ keyboard_shortcuts_inhibitor_v1_handle_resource_destroy);
+
+ wl_list_insert(&manager->inhibitors, &inhibitor->link);
+ wlr_signal_emit_safe(&manager->events.new_inhibitor, inhibitor);
+}
+
+static void manager_handle_destroy(struct wl_client *client,
+ struct wl_resource *manager_resource) {
+ wl_resource_destroy(manager_resource);
+}
+
+static const struct zwp_keyboard_shortcuts_inhibit_manager_v1_interface
+keyboard_shortcuts_inhibit_impl = {
+ .destroy = manager_handle_destroy,
+ .inhibit_shortcuts = manager_handle_inhibit_shortcuts,
+};
+
+static void handle_display_destroy(struct wl_listener *listener, void *data) {
+ struct wlr_keyboard_shortcuts_inhibit_manager_v1 *manager =
+ wl_container_of(listener, manager, display_destroy);
+ wlr_signal_emit_safe(&manager->events.destroy, manager);
+ wl_list_remove(&manager->display_destroy.link);
+ wl_global_destroy(manager->global);
+ free(manager);
+}
+
+static void keyboard_shortcuts_inhibit_bind(struct wl_client *wl_client,
+ void *data, uint32_t version, uint32_t id) {
+ struct wlr_keyboard_shortcuts_inhibit_manager_v1 *manager = data;
+
+ struct wl_resource *manager_resource = wl_resource_create(wl_client,
+ &zwp_keyboard_shortcuts_inhibit_manager_v1_interface,
+ version, id);
+ if (!manager_resource) {
+ wl_client_post_no_memory(wl_client);
+ return;
+ }
+
+ wl_resource_set_implementation(manager_resource,
+ &keyboard_shortcuts_inhibit_impl, manager, NULL);
+}
+
+struct wlr_keyboard_shortcuts_inhibit_manager_v1 *
+wlr_keyboard_shortcuts_inhibit_v1_create(struct wl_display *display) {
+ struct wlr_keyboard_shortcuts_inhibit_manager_v1 *manager =
+ calloc(1, sizeof(struct wlr_keyboard_shortcuts_inhibit_manager_v1));
+ if (!manager) {
+ return NULL;
+ }
+
+ wl_list_init(&manager->inhibitors);
+ wl_signal_init(&manager->events.new_inhibitor);
+ wl_signal_init(&manager->events.destroy);
+
+ manager->global = wl_global_create(display,
+ &zwp_keyboard_shortcuts_inhibit_manager_v1_interface, 1,
+ manager, keyboard_shortcuts_inhibit_bind);
+ if (!manager->global) {
+ free(manager);
+ return NULL;
+ }
+
+ manager->display_destroy.notify = handle_display_destroy;
+ wl_display_add_destroy_listener(display, &manager->display_destroy);
+
+ return manager;
+}
+
+void wlr_keyboard_shortcuts_inhibitor_v1_activate(
+ struct wlr_keyboard_shortcuts_inhibitor_v1 *inhibitor) {
+ if (!inhibitor->active) {
+ zwp_keyboard_shortcuts_inhibitor_v1_send_active(
+ inhibitor->resource);
+ inhibitor->active = true;
+ }
+}
+
+void wlr_keyboard_shortcuts_inhibitor_v1_deactivate(
+ struct wlr_keyboard_shortcuts_inhibitor_v1 *inhibitor) {
+ if (inhibitor->active) {
+ zwp_keyboard_shortcuts_inhibitor_v1_send_inactive(
+ inhibitor->resource);
+ inhibitor->active = false;
+ }
+}