Implement the keyboard shortcuts inhibitor protocol
parent
1ca82ce2e2
commit
4fc5eb6d06
|
@ -0,0 +1,23 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#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*);
|
|
@ -69,6 +69,7 @@ sources = [
|
||||||
'src/vnc.c',
|
'src/vnc.c',
|
||||||
'src/strlcpy.c',
|
'src/strlcpy.c',
|
||||||
'src/evdev-to-qnum.c',
|
'src/evdev-to-qnum.c',
|
||||||
|
'src/inhibitor.c',
|
||||||
]
|
]
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
|
|
@ -0,0 +1,143 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<protocol name="keyboard_shortcuts_inhibit_unstable_v1">
|
||||||
|
|
||||||
|
<copyright>
|
||||||
|
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.
|
||||||
|
</copyright>
|
||||||
|
|
||||||
|
<description summary="Protocol for inhibiting the compositor keyboard shortcuts">
|
||||||
|
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.
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<interface name="zwp_keyboard_shortcuts_inhibit_manager_v1" version="1">
|
||||||
|
<description summary="context object for keyboard grab_manager">
|
||||||
|
A global interface used for inhibiting the compositor keyboard shortcuts.
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<request name="destroy" type="destructor">
|
||||||
|
<description summary="destroy the keyboard shortcuts inhibitor object">
|
||||||
|
Destroy the keyboard shortcuts inhibitor manager.
|
||||||
|
</description>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<request name="inhibit_shortcuts">
|
||||||
|
<description summary="create a new keyboard shortcuts inhibitor object">
|
||||||
|
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.
|
||||||
|
</description>
|
||||||
|
<arg name="id" type="new_id" interface="zwp_keyboard_shortcuts_inhibitor_v1"/>
|
||||||
|
<arg name="surface" type="object" interface="wl_surface"
|
||||||
|
summary="the surface that inhibits the keyboard shortcuts behavior"/>
|
||||||
|
<arg name="seat" type="object" interface="wl_seat"
|
||||||
|
summary="the wl_seat for which keyboard shortcuts should be disabled"/>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<enum name="error">
|
||||||
|
<entry name="already_inhibited"
|
||||||
|
value="0"
|
||||||
|
summary="the shortcuts are already inhibited for this surface"/>
|
||||||
|
</enum>
|
||||||
|
</interface>
|
||||||
|
|
||||||
|
<interface name="zwp_keyboard_shortcuts_inhibitor_v1" version="1">
|
||||||
|
<description summary="context object for keyboard shortcuts inhibitor">
|
||||||
|
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.
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<request name="destroy" type="destructor">
|
||||||
|
<description summary="destroy the keyboard shortcuts inhibitor object">
|
||||||
|
Remove the keyboard shortcuts inhibitor from the associated wl_surface.
|
||||||
|
</description>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<event name="active">
|
||||||
|
<description summary="shortcuts are inhibited">
|
||||||
|
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.
|
||||||
|
</description>
|
||||||
|
</event>
|
||||||
|
|
||||||
|
<event name="inactive">
|
||||||
|
<description summary="shortcuts are restored">
|
||||||
|
This event indicates that the shortcuts inhibitor is inactive,
|
||||||
|
normal shortcuts processing is restored by the compositor.
|
||||||
|
</description>
|
||||||
|
</event>
|
||||||
|
</interface>
|
||||||
|
</protocol>
|
|
@ -15,6 +15,7 @@ wayland_scanner_client = generator(
|
||||||
|
|
||||||
client_protocols = [
|
client_protocols = [
|
||||||
'xdg-shell.xml',
|
'xdg-shell.xml',
|
||||||
|
'keyboard-shortcuts-inhibit-unstable-v1.xml',
|
||||||
]
|
]
|
||||||
|
|
||||||
client_protos_src = []
|
client_protos_src = []
|
||||||
|
|
|
@ -0,0 +1,68 @@
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "inhibitor.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
19
src/main.c
19
src/main.c
|
@ -29,6 +29,7 @@
|
||||||
#include <wayland-client.h>
|
#include <wayland-client.h>
|
||||||
#include <xkbcommon/xkbcommon.h>
|
#include <xkbcommon/xkbcommon.h>
|
||||||
|
|
||||||
|
#include "inhibitor.h"
|
||||||
#include "pixman.h"
|
#include "pixman.h"
|
||||||
#include "xdg-shell.h"
|
#include "xdg-shell.h"
|
||||||
#include "shm.h"
|
#include "shm.h"
|
||||||
|
@ -61,8 +62,10 @@ struct wl_compositor* wl_compositor = NULL;
|
||||||
struct wl_shm* wl_shm = NULL;
|
struct wl_shm* wl_shm = NULL;
|
||||||
static struct xdg_wm_base* xdg_wm_base;
|
static struct xdg_wm_base* xdg_wm_base;
|
||||||
static struct wl_list seats;
|
static struct wl_list seats;
|
||||||
|
static struct zwp_keyboard_shortcuts_inhibit_manager_v1* keyboard_shortcuts_inhibitor;
|
||||||
struct pointer_collection* pointers;
|
struct pointer_collection* pointers;
|
||||||
struct keyboard_collection* keyboards;
|
struct keyboard_collection* keyboards;
|
||||||
|
struct shortcuts_inhibitor* inhibitor;
|
||||||
|
|
||||||
static enum wl_shm_format wl_shm_format;
|
static enum wl_shm_format wl_shm_format;
|
||||||
static bool have_format = false;
|
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);
|
xdg_wm_base = wl_registry_bind(registry, id, &xdg_wm_base_interface, 1);
|
||||||
} else if (strcmp(interface, "wl_shm") == 0) {
|
} else if (strcmp(interface, "wl_shm") == 0) {
|
||||||
wl_shm = wl_registry_bind(registry, id, &wl_shm_interface, 1);
|
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) {
|
} else if (strcmp(interface, "wl_seat") == 0) {
|
||||||
struct wl_seat* wl_seat;
|
struct wl_seat* wl_seat;
|
||||||
wl_seat = wl_registry_bind(registry, id, &wl_seat_interface, 5);
|
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;
|
struct window* w = data;
|
||||||
xdg_surface_ack_configure(surface, serial);
|
xdg_surface_ack_configure(surface, serial);
|
||||||
window_configure(w);
|
window_configure(w);
|
||||||
|
inhibitor_init(inhibitor, w->wl_surface, seat_first(&seats)->wl_seat);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct xdg_surface_listener xdg_surface_listener = {
|
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
|
// TODO handle multiple symbols
|
||||||
xkb_keysym_t symbol = xkb_state_key_get_one_sym(keyboard->state, key);
|
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];
|
char name[256];
|
||||||
xkb_keysym_get_name(symbol, name, sizeof(name));
|
xkb_keysym_get_name(symbol, name, sizeof(name));
|
||||||
|
|
||||||
|
|
|
@ -22,12 +22,14 @@
|
||||||
#include <wayland-cursor.h>
|
#include <wayland-cursor.h>
|
||||||
#include <linux/input-event-codes.h>
|
#include <linux/input-event-codes.h>
|
||||||
|
|
||||||
|
#include "inhibitor.h"
|
||||||
#include "pointer.h"
|
#include "pointer.h"
|
||||||
|
|
||||||
#define STEP_SIZE 15.0
|
#define STEP_SIZE 15.0
|
||||||
|
|
||||||
extern struct wl_shm* wl_shm;
|
extern struct wl_shm* wl_shm;
|
||||||
extern struct wl_compositor* wl_compositor;
|
extern struct wl_compositor* wl_compositor;
|
||||||
|
extern struct shortcuts_inhibitor* inhibitor;
|
||||||
|
|
||||||
static struct wl_cursor_theme* pointer_load_cursor_theme(void)
|
static struct wl_cursor_theme* pointer_load_cursor_theme(void)
|
||||||
{
|
{
|
||||||
|
@ -69,6 +71,7 @@ void pointer_destroy(struct pointer* self)
|
||||||
if (self->cursor_theme)
|
if (self->cursor_theme)
|
||||||
wl_cursor_theme_destroy(self->cursor_theme);
|
wl_cursor_theme_destroy(self->cursor_theme);
|
||||||
wl_surface_destroy(self->cursor_surface);
|
wl_surface_destroy(self->cursor_surface);
|
||||||
|
inhibitor_destroy(inhibitor);
|
||||||
free(self);
|
free(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -162,6 +165,7 @@ static void pointer_enter(void* data, struct wl_pointer* wl_pointer,
|
||||||
pointer->serial = serial;
|
pointer->serial = serial;
|
||||||
|
|
||||||
pointer_update_cursor(pointer);
|
pointer_update_cursor(pointer);
|
||||||
|
inhibitor_inhibit(inhibitor);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pointer_leave(void* data, struct wl_pointer* wl_pointer,
|
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);
|
assert(pointer);
|
||||||
|
|
||||||
pointer->serial = serial;
|
pointer->serial = serial;
|
||||||
|
inhibitor_release(inhibitor);
|
||||||
// Do nothing?
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pointer_motion(void* data, struct wl_pointer* wl_pointer,
|
static void pointer_motion(void* data, struct wl_pointer* wl_pointer,
|
||||||
|
|
Loading…
Reference in New Issue