aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/sway/config.h1
-rw-r--r--include/sway/input/input-manager.h3
-rw-r--r--include/sway/input/seat.h18
-rw-r--r--sway/commands/bind.c5
-rw-r--r--sway/input/input-manager.c47
-rw-r--r--sway/input/keyboard.c41
-rw-r--r--sway/input/seat.c16
-rw-r--r--sway/sway.5.scd8
8 files changed, 129 insertions, 10 deletions
diff --git a/include/sway/config.h b/include/sway/config.h
index 5f02e44f..fdd65efd 100644
--- a/include/sway/config.h
+++ b/include/sway/config.h
@@ -40,6 +40,7 @@ enum binding_flags {
BINDING_TITLEBAR=16, // mouse only; trigger on container titlebar
BINDING_CODE=32, // keyboard only; convert keysyms into keycodes
BINDING_RELOAD=64, // switch only; (re)trigger binding on reload
+ BINDING_INHIBITED=128, // keyboard only: ignore shortcut inhibitor
};
/**
diff --git a/include/sway/input/input-manager.h b/include/sway/input/input-manager.h
index a5392c6b..410d17a8 100644
--- a/include/sway/input/input-manager.h
+++ b/include/sway/input/input-manager.h
@@ -2,6 +2,7 @@
#define _SWAY_INPUT_INPUT_MANAGER_H
#include <libinput.h>
#include <wlr/types/wlr_input_inhibitor.h>
+#include <wlr/types/wlr_keyboard_shortcuts_inhibit_v1.h>
#include <wlr/types/wlr_virtual_keyboard_v1.h>
#include <wlr/types/wlr_virtual_pointer_v1.h>
#include "sway/server.h"
@@ -20,12 +21,14 @@ struct sway_input_manager {
struct wl_list seats;
struct wlr_input_inhibit_manager *inhibit;
+ struct wlr_keyboard_shortcuts_inhibit_manager_v1 *keyboard_shortcuts_inhibit;
struct wlr_virtual_keyboard_manager_v1 *virtual_keyboard;
struct wlr_virtual_pointer_manager_v1 *virtual_pointer;
struct wl_listener new_input;
struct wl_listener inhibit_activate;
struct wl_listener inhibit_deactivate;
+ struct wl_listener keyboard_shortcuts_inhibit_new_inhibitor;
struct wl_listener virtual_keyboard_new;
struct wl_listener virtual_pointer_new;
};
diff --git a/include/sway/input/seat.h b/include/sway/input/seat.h
index 9c3028c5..49b9d09b 100644
--- a/include/sway/input/seat.h
+++ b/include/sway/input/seat.h
@@ -1,6 +1,7 @@
#ifndef _SWAY_INPUT_SEAT_H
#define _SWAY_INPUT_SEAT_H
+#include <wlr/types/wlr_keyboard_shortcuts_inhibit_v1.h>
#include <wlr/types/wlr_layer_shell_v1.h>
#include <wlr/types/wlr_seat.h>
#include <wlr/util/edges.h>
@@ -94,6 +95,8 @@ struct sway_seat {
struct wl_list devices; // sway_seat_device::link
struct wl_list keyboard_groups; // sway_keyboard_group::link
+ struct wl_list keyboard_shortcuts_inhibitors;
+ // sway_keyboard_shortcuts_inhibitor::link
struct wl_list link; // input_manager::seats
};
@@ -104,6 +107,14 @@ struct sway_pointer_constraint {
struct wl_listener destroy;
};
+struct sway_keyboard_shortcuts_inhibitor {
+ struct wlr_keyboard_shortcuts_inhibitor_v1 *inhibitor;
+
+ struct wl_listener destroy;
+
+ struct wl_list link; // sway_seat::keyboard_shortcuts_inhibitors
+};
+
struct sway_seat *seat_create(const char *seat_name);
void seat_destroy(struct sway_seat *seat);
@@ -269,4 +280,11 @@ void seatop_render(struct sway_seat *seat, struct sway_output *output,
bool seatop_allows_set_cursor(struct sway_seat *seat);
+/**
+ * Returns the keyboard shortcuts inhibitor that applies to the currently
+ * focused surface of a seat or NULL if none exists.
+ */
+struct sway_keyboard_shortcuts_inhibitor *
+keyboard_shortcuts_inhibitor_get_for_focused_surface(const struct sway_seat *seat);
+
#endif
diff --git a/sway/commands/bind.c b/sway/commands/bind.c
index 5ec89982..0ddee742 100644
--- a/sway/commands/bind.c
+++ b/sway/commands/bind.c
@@ -72,7 +72,8 @@ static bool binding_key_compare(struct sway_binding *binding_a,
}
uint32_t conflict_generating_flags = BINDING_RELEASE | BINDING_BORDER
- | BINDING_CONTENTS | BINDING_TITLEBAR | BINDING_LOCKED;
+ | BINDING_CONTENTS | BINDING_TITLEBAR | BINDING_LOCKED
+ | BINDING_INHIBITED;
if ((binding_a->flags & conflict_generating_flags) !=
(binding_b->flags & conflict_generating_flags)) {
return false;
@@ -354,6 +355,8 @@ static struct cmd_results *cmd_bindsym_or_bindcode(int argc, char **argv,
binding->flags |= BINDING_RELEASE;
} else if (strcmp("--locked", argv[0]) == 0) {
binding->flags |= BINDING_LOCKED;
+ } else if (strcmp("--inhibited", argv[0]) == 0) {
+ binding->flags |= BINDING_INHIBITED;
} else if (strcmp("--whole-window", argv[0]) == 0) {
binding->flags |= BINDING_BORDER | BINDING_CONTENTS | BINDING_TITLEBAR;
} else if (strcmp("--border", argv[0]) == 0) {
diff --git a/sway/input/input-manager.c b/sway/input/input-manager.c
index 4cc07fe6..af0f5afa 100644
--- a/sway/input/input-manager.c
+++ b/sway/input/input-manager.c
@@ -296,6 +296,46 @@ static void handle_inhibit_deactivate(struct wl_listener *listener, void *data)
}
}
+static void handle_keyboard_shortcuts_inhibitor_destroy(
+ struct wl_listener *listener, void *data) {
+ struct sway_keyboard_shortcuts_inhibitor *sway_inhibitor =
+ wl_container_of(listener, sway_inhibitor, destroy);
+
+ sway_log(SWAY_DEBUG, "Removing keyboard shortcuts inhibitor");
+
+ // sway_seat::keyboard_shortcuts_inhibitors
+ wl_list_remove(&sway_inhibitor->link);
+ wl_list_remove(&sway_inhibitor->destroy.link);
+ free(sway_inhibitor);
+}
+
+static void handle_keyboard_shortcuts_inhibit_new_inhibitor(
+ struct wl_listener *listener, void *data) {
+ struct sway_input_manager *input_manager =
+ wl_container_of(listener, input_manager,
+ keyboard_shortcuts_inhibit_new_inhibitor);
+ struct wlr_keyboard_shortcuts_inhibitor_v1 *inhibitor = data;
+
+ sway_log(SWAY_DEBUG, "Adding keyboard shortcuts inhibitor");
+
+ struct sway_keyboard_shortcuts_inhibitor *sway_inhibitor =
+ calloc(1, sizeof(struct sway_keyboard_shortcuts_inhibitor));
+ if (!sway_assert(sway_inhibitor, "could not allocate keyboard "
+ "shortcuts inhibitor")) {
+ return;
+ }
+ sway_inhibitor->inhibitor = inhibitor;
+
+ sway_inhibitor->destroy.notify = handle_keyboard_shortcuts_inhibitor_destroy;
+ wl_signal_add(&inhibitor->events.destroy, &sway_inhibitor->destroy);
+
+ // attach inhibitor to the seat it applies to
+ struct sway_seat *seat = inhibitor->seat->data;
+ wl_list_insert(&seat->keyboard_shortcuts_inhibitors, &sway_inhibitor->link);
+
+ wlr_keyboard_shortcuts_inhibitor_v1_activate(inhibitor);
+}
+
void handle_virtual_keyboard(struct wl_listener *listener, void *data) {
struct sway_input_manager *input_manager =
wl_container_of(listener, input_manager, virtual_keyboard_new);
@@ -397,6 +437,13 @@ struct sway_input_manager *input_manager_create(struct sway_server *server) {
wl_signal_add(&input->inhibit->events.deactivate,
&input->inhibit_deactivate);
+ input->keyboard_shortcuts_inhibit =
+ wlr_keyboard_shortcuts_inhibit_v1_create(server->wl_display);
+ input->keyboard_shortcuts_inhibit_new_inhibitor.notify =
+ handle_keyboard_shortcuts_inhibit_new_inhibitor;
+ wl_signal_add(&input->keyboard_shortcuts_inhibit->events.new_inhibitor,
+ &input->keyboard_shortcuts_inhibit_new_inhibitor);
+
return input;
}
diff --git a/sway/input/keyboard.c b/sway/input/keyboard.c
index 2cfcd126..9c5f190e 100644
--- a/sway/input/keyboard.c
+++ b/sway/input/keyboard.c
@@ -150,16 +150,18 @@ static bool update_shortcut_state(struct sway_shortcut_state *state,
*/
static void get_active_binding(const struct sway_shortcut_state *state,
list_t *bindings, struct sway_binding **current_binding,
- uint32_t modifiers, bool release, bool locked, const char *input,
- bool exact_input, xkb_layout_index_t group) {
+ uint32_t modifiers, bool release, bool locked, bool inhibited,
+ const char *input, bool exact_input, xkb_layout_index_t group) {
for (int i = 0; i < bindings->length; ++i) {
struct sway_binding *binding = bindings->items[i];
bool binding_locked = (binding->flags & BINDING_LOCKED) != 0;
+ bool binding_inhibited = (binding->flags & BINDING_INHIBITED) != 0;
bool binding_release = binding->flags & BINDING_RELEASE;
if (modifiers ^ binding->modifiers ||
release != binding_release ||
locked > binding_locked ||
+ inhibited > binding_inhibited ||
(binding->group != XKB_LAYOUT_INVALID &&
binding->group != group) ||
(strcmp(binding->input, input) != 0 &&
@@ -195,6 +197,8 @@ static void get_active_binding(const struct sway_shortcut_state *state,
bool current_locked =
((*current_binding)->flags & BINDING_LOCKED) != 0;
+ bool current_inhibited =
+ ((*current_binding)->flags & BINDING_INHIBITED) != 0;
bool current_input = strcmp((*current_binding)->input, input) == 0;
bool current_group_set =
(*current_binding)->group != XKB_LAYOUT_INVALID;
@@ -203,6 +207,7 @@ static void get_active_binding(const struct sway_shortcut_state *state,
if (current_input == binding_input
&& current_locked == binding_locked
+ && current_inhibited == binding_inhibited
&& current_group_set == binding_group_set) {
sway_log(SWAY_DEBUG,
"Encountered conflicting bindings %d and %d",
@@ -224,11 +229,21 @@ static void get_active_binding(const struct sway_shortcut_state *state,
current_locked == locked) {
continue; // Prefer correct lock state for matching input+group
}
+
+ if (current_input == binding_input &&
+ current_group_set == binding_group_set &&
+ current_locked == binding_locked &&
+ current_inhibited == inhibited) {
+ // Prefer correct inhibition state for matching
+ // input+group+locked
+ continue;
+ }
}
*current_binding = binding;
if (strcmp((*current_binding)->input, input) == 0 &&
(((*current_binding)->flags & BINDING_LOCKED) == locked) &&
+ (((*current_binding)->flags & BINDING_INHIBITED) == inhibited) &&
(*current_binding)->group == group) {
return; // If a perfect match is found, quit searching
}
@@ -328,6 +343,9 @@ static void handle_key_event(struct sway_keyboard *keyboard,
bool exact_identifier = wlr_device->keyboard->group != NULL;
seat_idle_notify_activity(seat, IDLE_SOURCE_KEYBOARD);
bool input_inhibited = seat->exclusive_client != NULL;
+ struct sway_keyboard_shortcuts_inhibitor *sway_inhibitor =
+ keyboard_shortcuts_inhibitor_get_for_focused_surface(seat);
+ bool shortcuts_inhibited = sway_inhibitor && sway_inhibitor->inhibitor->active;
// Identify new keycode, raw keysym(s), and translated keysym(s)
xkb_keycode_t keycode = event->keycode + 8;
@@ -364,15 +382,18 @@ static void handle_key_event(struct sway_keyboard *keyboard,
struct sway_binding *binding_released = NULL;
get_active_binding(&keyboard->state_keycodes,
config->current_mode->keycode_bindings, &binding_released,
- code_modifiers, true, input_inhibited, device_identifier,
+ code_modifiers, true, input_inhibited,
+ shortcuts_inhibited, device_identifier,
exact_identifier, keyboard->effective_layout);
get_active_binding(&keyboard->state_keysyms_raw,
config->current_mode->keysym_bindings, &binding_released,
- raw_modifiers, true, input_inhibited, device_identifier,
+ raw_modifiers, true, input_inhibited,
+ shortcuts_inhibited, device_identifier,
exact_identifier, keyboard->effective_layout);
get_active_binding(&keyboard->state_keysyms_translated,
config->current_mode->keysym_bindings, &binding_released,
- translated_modifiers, true, input_inhibited, device_identifier,
+ translated_modifiers, true, input_inhibited,
+ shortcuts_inhibited, device_identifier,
exact_identifier, keyboard->effective_layout);
// Execute stored release binding once no longer active
@@ -393,17 +414,19 @@ static void handle_key_event(struct sway_keyboard *keyboard,
if (event->state == WLR_KEY_PRESSED) {
get_active_binding(&keyboard->state_keycodes,
config->current_mode->keycode_bindings, &binding,
- code_modifiers, false, input_inhibited, device_identifier,
+ code_modifiers, false, input_inhibited,
+ shortcuts_inhibited, device_identifier,
exact_identifier, keyboard->effective_layout);
get_active_binding(&keyboard->state_keysyms_raw,
config->current_mode->keysym_bindings, &binding,
- raw_modifiers, false, input_inhibited, device_identifier,
+ raw_modifiers, false, input_inhibited,
+ shortcuts_inhibited, device_identifier,
exact_identifier, keyboard->effective_layout);
get_active_binding(&keyboard->state_keysyms_translated,
config->current_mode->keysym_bindings, &binding,
translated_modifiers, false, input_inhibited,
- device_identifier, exact_identifier,
- keyboard->effective_layout);
+ shortcuts_inhibited, device_identifier,
+ exact_identifier, keyboard->effective_layout);
}
// Set up (or clear) keyboard repeat for a pressed binding. Since the
diff --git a/sway/input/seat.c b/sway/input/seat.c
index 371de56e..6739c163 100644
--- a/sway/input/seat.c
+++ b/sway/input/seat.c
@@ -557,6 +557,7 @@ struct sway_seat *seat_create(const char *seat_name) {
handle_request_set_primary_selection;
wl_list_init(&seat->keyboard_groups);
+ wl_list_init(&seat->keyboard_shortcuts_inhibitors);
wl_list_insert(&server.input->seats, &seat->link);
@@ -1473,3 +1474,18 @@ void seatop_render(struct sway_seat *seat, struct sway_output *output,
bool seatop_allows_set_cursor(struct sway_seat *seat) {
return seat->seatop_impl->allow_set_cursor;
}
+
+struct sway_keyboard_shortcuts_inhibitor *
+keyboard_shortcuts_inhibitor_get_for_focused_surface(
+ const struct sway_seat *seat) {
+ struct wlr_surface *focused_surface =
+ seat->wlr_seat->keyboard_state.focused_surface;
+ struct sway_keyboard_shortcuts_inhibitor *sway_inhibitor = NULL;
+ wl_list_for_each(sway_inhibitor, &seat->keyboard_shortcuts_inhibitors, link) {
+ if (sway_inhibitor->inhibitor->surface == focused_surface) {
+ return sway_inhibitor;
+ }
+ }
+
+ return NULL;
+}
diff --git a/sway/sway.5.scd b/sway/sway.5.scd
index b8b838ab..a2c74e70 100644
--- a/sway/sway.5.scd
+++ b/sway/sway.5.scd
@@ -374,6 +374,14 @@ runtime.
and one has both _--input-device_ and _--locked_ and the other has neither,
the former will be preferred even when unlocked.
+ Unless the flag _--inhibited_ is set, the command will not be run when
+ a keyboard shortcuts inhibitor is active for the currently focused
+ window. Such inhibitors are usually requested by remote desktop and
+ virtualization software to enable the user to send keyboard shortcuts
+ to the remote or virtual session. The _--inhibited_ flag allows to
+ define bindings which will be exempt from pass-through to such
+ software. The same preference logic as for _--locked_ applies.
+
Bindings to keysyms are layout-dependent. This can be changed with the
_--to-code_ flag. In this case, the keysyms will be translated into the
corresponding keycodes in the first configured layout.