From 0f11aa037ad8765abf66e0c90052f9e4c37d56db Mon Sep 17 00:00:00 2001 From: Michael Weiser Date: Thu, 12 Mar 2020 22:10:04 +0100 Subject: [PATCH] commands: Add per-view shortcuts_inhibitor command Add a separate per-view shortcuts_inhibitor command that can be used with criteria to override the per-seat defaults. This allows to e.g. disable shortcuts inhibiting globally but enable it for specific, known-good virtualization and remote desktop software or, alternatively, to blacklist that one slightly broken piece of software that just doesn't seem to get it right but insists on trying. Add a flag to sway_view and handling logic in the input manager that respects that flag if configured but falls back to per-seat config otherwise. Add the actual command but with just enable and disable subcommands since there's no value in duplicating the per-seat activate/deactivate/toggle logic here. Split the inhibitor retrieval helper in two so we can use the backend half in the command to retrieve inhibitors for a specific surface and not just the currently focused one. Extend the manual page with documentation of the command and references to its per-seat sibling and usefulness with criteria. Signed-off-by: Michael Weiser --- include/sway/commands.h | 1 + include/sway/input/seat.h | 8 +++++ include/sway/tree/view.h | 2 ++ sway/commands.c | 1 + sway/commands/shortcuts_inhibitor.c | 49 +++++++++++++++++++++++++++++ sway/input/input-manager.c | 22 ++++++++++--- sway/input/seat.c | 16 +++++++--- sway/meson.build | 1 + sway/sway.5.scd | 11 +++++++ sway/tree/view.c | 1 + 10 files changed, 103 insertions(+), 9 deletions(-) create mode 100644 sway/commands/shortcuts_inhibitor.c diff --git a/include/sway/commands.h b/include/sway/commands.h index 3fde0893..4a2f8c20 100644 --- a/include/sway/commands.h +++ b/include/sway/commands.h @@ -164,6 +164,7 @@ sway_cmd cmd_resize; sway_cmd cmd_scratchpad; sway_cmd cmd_seamless_mouse; sway_cmd cmd_set; +sway_cmd cmd_shortcuts_inhibitor; sway_cmd cmd_show_marks; sway_cmd cmd_smart_borders; sway_cmd cmd_smart_gaps; diff --git a/include/sway/input/seat.h b/include/sway/input/seat.h index fa232aa2..6a46fa91 100644 --- a/include/sway/input/seat.h +++ b/include/sway/input/seat.h @@ -294,6 +294,14 @@ 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 given surface + * or NULL if none exists. + */ +struct sway_keyboard_shortcuts_inhibitor * +keyboard_shortcuts_inhibitor_get_for_surface(const struct sway_seat *seat, + const struct wlr_surface *surface); + /** * Returns the keyboard shortcuts inhibitor that applies to the currently * focused surface of a seat or NULL if none exists. diff --git a/include/sway/tree/view.h b/include/sway/tree/view.h index 4d3532d2..9230f456 100644 --- a/include/sway/tree/view.h +++ b/include/sway/tree/view.h @@ -110,6 +110,8 @@ struct sway_view { struct wl_listener surface_new_subsurface; int max_render_time; // In milliseconds + + enum seat_config_shortcuts_inhibit shortcuts_inhibit; }; struct sway_xdg_shell_view { diff --git a/sway/commands.c b/sway/commands.c index 6a56ff5a..afe05b26 100644 --- a/sway/commands.c +++ b/sway/commands.c @@ -127,6 +127,7 @@ static struct cmd_handler command_handlers[] = { { "rename", cmd_rename }, { "resize", cmd_resize }, { "scratchpad", cmd_scratchpad }, + { "shortcuts_inhibitor", cmd_shortcuts_inhibitor }, { "split", cmd_split }, { "splith", cmd_splith }, { "splitt", cmd_splitt }, diff --git a/sway/commands/shortcuts_inhibitor.c b/sway/commands/shortcuts_inhibitor.c new file mode 100644 index 00000000..ffa1a5c9 --- /dev/null +++ b/sway/commands/shortcuts_inhibitor.c @@ -0,0 +1,49 @@ +#include +#include "log.h" +#include "sway/commands.h" +#include "sway/config.h" +#include "sway/input/seat.h" +#include "sway/tree/container.h" +#include "sway/tree/view.h" + +struct cmd_results *cmd_shortcuts_inhibitor(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "shortcuts_inhibitor", EXPECTED_EQUAL_TO, 1))) { + return error; + } + + struct sway_container *con = config->handler_context.container; + if (!con || !con->view) { + return cmd_results_new(CMD_INVALID, + "Only views can have shortcuts inhibitors"); + } + + struct sway_view *view = con->view; + if (strcmp(argv[0], "enable") == 0) { + view->shortcuts_inhibit = SHORTCUTS_INHIBIT_ENABLE; + } else if (strcmp(argv[0], "disable") == 0) { + view->shortcuts_inhibit = SHORTCUTS_INHIBIT_DISABLE; + + struct sway_seat *seat = NULL; + wl_list_for_each(seat, &server.input->seats, link) { + struct sway_keyboard_shortcuts_inhibitor *sway_inhibitor = + keyboard_shortcuts_inhibitor_get_for_surface( + seat, view->surface); + if (!sway_inhibitor) { + continue; + } + + wlr_keyboard_shortcuts_inhibitor_v1_deactivate( + sway_inhibitor->inhibitor); + sway_log(SWAY_DEBUG, "Deactivated keyboard shortcuts " + "inhibitor for seat %s on view", + seat->wlr_seat->name); + + } + } else { + return cmd_results_new(CMD_INVALID, + "Expected `shortcuts_inhibitor enable|disable`"); + } + + return cmd_results_new(CMD_SUCCESS, NULL); +} diff --git a/sway/input/input-manager.c b/sway/input/input-manager.c index 243f860b..dc07cbf0 100644 --- a/sway/input/input-manager.c +++ b/sway/input/input-manager.c @@ -15,6 +15,7 @@ #include "sway/input/cursor.h" #include "sway/ipc-server.h" #include "sway/server.h" +#include "sway/tree/view.h" #include "stringop.h" #include "list.h" #include "log.h" @@ -333,12 +334,25 @@ static void handle_keyboard_shortcuts_inhibit_new_inhibitor( struct sway_seat *seat = inhibitor->seat->data; wl_list_insert(&seat->keyboard_shortcuts_inhibitors, &sway_inhibitor->link); - struct seat_config *config = seat_get_config(seat); - if (!config) { - config = seat_get_config_by_name("*"); + // per-view, seat-agnostic config via criteria + struct sway_view *view = view_from_wlr_surface(inhibitor->surface); + enum seat_config_shortcuts_inhibit inhibit = SHORTCUTS_INHIBIT_DEFAULT; + if (view) { + inhibit = view->shortcuts_inhibit; } - if (config && config->shortcuts_inhibit == SHORTCUTS_INHIBIT_DISABLE) { + if (inhibit == SHORTCUTS_INHIBIT_DEFAULT) { + struct seat_config *config = seat_get_config(seat); + if (!config) { + config = seat_get_config_by_name("*"); + } + + if (config) { + inhibit = config->shortcuts_inhibit; + } + } + + if (inhibit == SHORTCUTS_INHIBIT_DISABLE) { /** * Here we deny to honour the inhibitor by never sending the * activate signal. We can not, however, destroy the inhibitor diff --git a/sway/input/seat.c b/sway/input/seat.c index aa46940d..a4e06c57 100644 --- a/sway/input/seat.c +++ b/sway/input/seat.c @@ -1499,16 +1499,22 @@ bool seatop_allows_set_cursor(struct sway_seat *seat) { } 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; +keyboard_shortcuts_inhibitor_get_for_surface( + const struct sway_seat *seat, + const struct wlr_surface *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) { + if (sway_inhibitor->inhibitor->surface == surface) { return sway_inhibitor; } } return NULL; } + +struct sway_keyboard_shortcuts_inhibitor * +keyboard_shortcuts_inhibitor_get_for_focused_surface( + const struct sway_seat *seat) { + return keyboard_shortcuts_inhibitor_get_for_surface(seat, + seat->wlr_seat->keyboard_state.focused_surface); +} diff --git a/sway/meson.build b/sway/meson.build index 226e6458..d71846a4 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -99,6 +99,7 @@ sway_sources = files( 'commands/seat/xcursor_theme.c', 'commands/set.c', 'commands/show_marks.c', + 'commands/shortcuts_inhibitor.c', 'commands/smart_borders.c', 'commands/smart_gaps.c', 'commands/split.c', diff --git a/sway/sway.5.scd b/sway/sway.5.scd index febf749f..9e42d897 100644 --- a/sway/sway.5.scd +++ b/sway/sway.5.scd @@ -304,6 +304,17 @@ set|plus|minus Shows a window from the scratchpad. Repeatedly using this command will cycle through the windows in the scratchpad. +*shortcuts inhibitor* enable|disable + Enables or disables the ability of clients to inhibit keyboard + shortcuts for a view. This is primarily useful for virtualization and + remote desktop software. It affects either the currently focused view + or a set of views selected by criteria. Subcommand _disable_ + additionally deactivates any active inhibitors for the given view(s). + Criteria are particularly useful with the *for_window* command to + configure a class of views differently from the per-seat defaults + established by the *seat* subcommand of the same name. See + *sway-input*(5) for more ways to affect inhibitors. + *split* vertical|v|horizontal|h|toggle|t Splits the current container, vertically or horizontally. When _toggle_ is specified, the current container is split opposite to the parent diff --git a/sway/tree/view.c b/sway/tree/view.c index de1e936a..2b4b6c09 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c @@ -36,6 +36,7 @@ void view_init(struct sway_view *view, enum sway_view_type type, view->impl = impl; view->executed_criteria = create_list(); view->allow_request_urgent = true; + view->shortcuts_inhibit = SHORTCUTS_INHIBIT_DEFAULT; wl_signal_init(&view->events.unmap); }