diff options
| -rw-r--r-- | include/sway/config.h | 1 | ||||
| -rw-r--r-- | include/sway/input/input-manager.h | 3 | ||||
| -rw-r--r-- | include/sway/input/seat.h | 18 | ||||
| -rw-r--r-- | sway/commands/bind.c | 5 | ||||
| -rw-r--r-- | sway/input/input-manager.c | 47 | ||||
| -rw-r--r-- | sway/input/keyboard.c | 41 | ||||
| -rw-r--r-- | sway/input/seat.c | 16 | ||||
| -rw-r--r-- | sway/sway.5.scd | 8 | 
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.  | 
