diff --git a/include/inhibitor.h b/include/inhibitor.h new file mode 100644 index 0000000..983926e --- /dev/null +++ b/include/inhibitor.h @@ -0,0 +1,23 @@ +#pragma once + +#include + +#include "keyboard-shortcuts-inhibit-unstable-v1.h" + +struct shortcuts_inhibitor { + //TODO add the inhibitor toggle key to the struct ? + struct zwp_keyboard_shortcuts_inhibit_manager_v1* manager; + struct zwp_keyboard_shortcuts_inhibitor_v1* inhibitor; + + struct wl_surface* surface; + struct wl_seat* seat; +}; + +struct shortcuts_inhibitor* inhibitor_new(struct zwp_keyboard_shortcuts_inhibit_manager_v1*); +void inhibitor_destroy(struct shortcuts_inhibitor*); +bool inhibitor_init(struct shortcuts_inhibitor*, struct wl_surface*, struct wl_seat*); + +bool inhibitor_is_inhibited(const struct shortcuts_inhibitor*); +void inhibitor_inhibit(struct shortcuts_inhibitor*); +void inhibitor_release(struct shortcuts_inhibitor*); +void inhibitor_toggle(struct shortcuts_inhibitor*); diff --git a/meson.build b/meson.build index 91fe9fc..e9e0009 100644 --- a/meson.build +++ b/meson.build @@ -69,6 +69,7 @@ sources = [ 'src/vnc.c', 'src/strlcpy.c', 'src/evdev-to-qnum.c', + 'src/inhibitor.c', ] dependencies = [ diff --git a/protocols/keyboard-shortcuts-inhibit-unstable-v1.xml b/protocols/keyboard-shortcuts-inhibit-unstable-v1.xml new file mode 100644 index 0000000..2774876 --- /dev/null +++ b/protocols/keyboard-shortcuts-inhibit-unstable-v1.xml @@ -0,0 +1,143 @@ + + + + + Copyright © 2017 Red Hat Inc. + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice (including the next + paragraph) shall be included in all copies or substantial portions of the + Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + + + + This protocol specifies a way for a client to request the compositor + to ignore its own keyboard shortcuts for a given seat, so that all + key events from that seat get forwarded to a surface. + + Warning! The protocol described in this file is experimental and + backward incompatible changes may be made. Backward compatible + changes may be added together with the corresponding interface + version bump. + Backward incompatible changes are done by bumping the version + number in the protocol and interface names and resetting the + interface version. Once the protocol is to be declared stable, + the 'z' prefix and the version number in the protocol and + interface names are removed and the interface version number is + reset. + + + + + A global interface used for inhibiting the compositor keyboard shortcuts. + + + + + Destroy the keyboard shortcuts inhibitor manager. + + + + + + Create a new keyboard shortcuts inhibitor object associated with + the given surface for the given seat. + + If shortcuts are already inhibited for the specified seat and surface, + a protocol error "already_inhibited" is raised by the compositor. + + + + + + + + + + + + + + A keyboard shortcuts inhibitor instructs the compositor to ignore + its own keyboard shortcuts when the associated surface has keyboard + focus. As a result, when the surface has keyboard focus on the given + seat, it will receive all key events originating from the specified + seat, even those which would normally be caught by the compositor for + its own shortcuts. + + The Wayland compositor is however under no obligation to disable + all of its shortcuts, and may keep some special key combo for its own + use, including but not limited to one allowing the user to forcibly + restore normal keyboard events routing in the case of an unwilling + client. The compositor may also use the same key combo to reactivate + an existing shortcut inhibitor that was previously deactivated on + user request. + + When the compositor restores its own keyboard shortcuts, an + "inactive" event is emitted to notify the client that the keyboard + shortcuts inhibitor is not effectively active for the surface and + seat any more, and the client should not expect to receive all + keyboard events. + + When the keyboard shortcuts inhibitor is inactive, the client has + no way to forcibly reactivate the keyboard shortcuts inhibitor. + + The user can chose to re-enable a previously deactivated keyboard + shortcuts inhibitor using any mechanism the compositor may offer, + in which case the compositor will send an "active" event to notify + the client. + + If the surface is destroyed, unmapped, or loses the seat's keyboard + focus, the keyboard shortcuts inhibitor becomes irrelevant and the + compositor will restore its own keyboard shortcuts but no "inactive" + event is emitted in this case. + + + + + Remove the keyboard shortcuts inhibitor from the associated wl_surface. + + + + + + This event indicates that the shortcut inhibitor is active. + + The compositor sends this event every time compositor shortcuts + are inhibited on behalf of the surface. When active, the client + may receive input events normally reserved by the compositor + (see zwp_keyboard_shortcuts_inhibitor_v1). + + This occurs typically when the initial request "inhibit_shortcuts" + first becomes active or when the user instructs the compositor to + re-enable and existing shortcuts inhibitor using any mechanism + offered by the compositor. + + + + + + This event indicates that the shortcuts inhibitor is inactive, + normal shortcuts processing is restored by the compositor. + + + + diff --git a/protocols/meson.build b/protocols/meson.build index d400ee4..300184c 100644 --- a/protocols/meson.build +++ b/protocols/meson.build @@ -15,6 +15,7 @@ wayland_scanner_client = generator( client_protocols = [ 'xdg-shell.xml', + 'keyboard-shortcuts-inhibit-unstable-v1.xml', ] client_protos_src = [] diff --git a/src/inhibitor.c b/src/inhibitor.c new file mode 100644 index 0000000..64f75e9 --- /dev/null +++ b/src/inhibitor.c @@ -0,0 +1,68 @@ +#include + +#include "inhibitor.h" +#include + +struct shortcuts_inhibitor* inhibitor_new(struct zwp_keyboard_shortcuts_inhibit_manager_v1* manager) +{ + struct shortcuts_inhibitor* self = calloc(1, sizeof(*self)); + if (!self) + return NULL; + + self->manager = manager; + self->inhibitor = NULL; + self->surface = NULL; + self->seat = NULL; + return self; +} + +bool inhibitor_init(struct shortcuts_inhibitor* self, struct wl_surface* surface, + struct wl_seat* seat) +{ + if ( self->surface != NULL || self->seat != NULL) + return false; + + self->surface = surface; + self->seat = seat; + return true; +} + +void inhibitor_destroy(struct shortcuts_inhibitor* self) +{ + if (self->inhibitor) + zwp_keyboard_shortcuts_inhibitor_v1_destroy(self->inhibitor); + if (self->manager) + zwp_keyboard_shortcuts_inhibit_manager_v1_destroy(self->manager); +} + +bool inhibitor_is_inhibited(const struct shortcuts_inhibitor* self) +{ + return self->inhibitor != NULL; +} + +void inhibitor_inhibit(struct shortcuts_inhibitor* self) +{ + // The compositor does not support the wlr shortcuts inhibitor protocol + if (self->manager == NULL) + return; + if (!inhibitor_is_inhibited(self)) + self->inhibitor = zwp_keyboard_shortcuts_inhibit_manager_v1_inhibit_shortcuts( + self->manager, self->surface, self->seat); +} + +void inhibitor_release(struct shortcuts_inhibitor* self) +{ + if (inhibitor_is_inhibited(self)) { + zwp_keyboard_shortcuts_inhibitor_v1_destroy(self->inhibitor); + self->inhibitor = NULL; + } +} + +void inhibitor_toggle(struct shortcuts_inhibitor* self) +{ + if (inhibitor_is_inhibited(self)) { + inhibitor_release(self); + } else { + inhibitor_inhibit(self); + } +} diff --git a/src/main.c b/src/main.c index 859692d..69ff68f 100644 --- a/src/main.c +++ b/src/main.c @@ -29,6 +29,7 @@ #include #include +#include "inhibitor.h" #include "pixman.h" #include "xdg-shell.h" #include "shm.h" @@ -61,8 +62,10 @@ struct wl_compositor* wl_compositor = NULL; struct wl_shm* wl_shm = NULL; static struct xdg_wm_base* xdg_wm_base; static struct wl_list seats; +static struct zwp_keyboard_shortcuts_inhibit_manager_v1* keyboard_shortcuts_inhibitor; struct pointer_collection* pointers; struct keyboard_collection* keyboards; +struct shortcuts_inhibitor* inhibitor; static enum wl_shm_format wl_shm_format; static bool have_format = false; @@ -103,6 +106,10 @@ static void registry_add(void* data, struct wl_registry* registry, uint32_t id, xdg_wm_base = wl_registry_bind(registry, id, &xdg_wm_base_interface, 1); } else if (strcmp(interface, "wl_shm") == 0) { wl_shm = wl_registry_bind(registry, id, &wl_shm_interface, 1); + } else if (strcmp(interface, zwp_keyboard_shortcuts_inhibit_manager_v1_interface.name) == 0) { + keyboard_shortcuts_inhibitor = wl_registry_bind(registry, id, + &zwp_keyboard_shortcuts_inhibit_manager_v1_interface, 1); + inhibitor = inhibitor_new(keyboard_shortcuts_inhibitor); } else if (strcmp(interface, "wl_seat") == 0) { struct wl_seat* wl_seat; wl_seat = wl_registry_bind(registry, id, &wl_seat_interface, 5); @@ -312,6 +319,7 @@ static void xdg_surface_configure(void* data, struct xdg_surface* surface, struct window* w = data; xdg_surface_ack_configure(surface, serial); window_configure(w); + inhibitor_init(inhibitor, w->wl_surface, seat_first(&seats)->wl_seat); } static const struct xdg_surface_listener xdg_surface_listener = { @@ -436,6 +444,17 @@ void on_keyboard_event(struct keyboard_collection* collection, // TODO handle multiple symbols xkb_keysym_t symbol = xkb_state_key_get_one_sym(keyboard->state, key); + if (symbol == XKB_KEY_F12) { + if (!is_pressed) { + inhibitor_toggle(inhibitor); + } + return; + } + + if (inhibitor->manager != NULL && !inhibitor_is_inhibited(inhibitor)) { + return; + } + char name[256]; xkb_keysym_get_name(symbol, name, sizeof(name)); diff --git a/src/pointer.c b/src/pointer.c index bbfb5a4..722251b 100644 --- a/src/pointer.c +++ b/src/pointer.c @@ -22,12 +22,14 @@ #include #include +#include "inhibitor.h" #include "pointer.h" #define STEP_SIZE 15.0 extern struct wl_shm* wl_shm; extern struct wl_compositor* wl_compositor; +extern struct shortcuts_inhibitor* inhibitor; static struct wl_cursor_theme* pointer_load_cursor_theme(void) { @@ -69,6 +71,7 @@ void pointer_destroy(struct pointer* self) if (self->cursor_theme) wl_cursor_theme_destroy(self->cursor_theme); wl_surface_destroy(self->cursor_surface); + inhibitor_destroy(inhibitor); free(self); } @@ -162,6 +165,7 @@ static void pointer_enter(void* data, struct wl_pointer* wl_pointer, pointer->serial = serial; pointer_update_cursor(pointer); + inhibitor_inhibit(inhibitor); } static void pointer_leave(void* data, struct wl_pointer* wl_pointer, @@ -173,8 +177,7 @@ static void pointer_leave(void* data, struct wl_pointer* wl_pointer, assert(pointer); pointer->serial = serial; - - // Do nothing? + inhibitor_release(inhibitor); } static void pointer_motion(void* data, struct wl_pointer* wl_pointer,