diff --git a/include/sway/commands.h b/include/sway/commands.h index 7672a3fd..2877c370 100644 --- a/include/sway/commands.h +++ b/include/sway/commands.h @@ -153,6 +153,7 @@ sway_cmd cmd_new_window; sway_cmd cmd_no_focus; sway_cmd cmd_output; sway_cmd cmd_permit; +sway_cmd cmd_pointer_constraint; sway_cmd cmd_popup_during_fullscreen; sway_cmd cmd_reject; sway_cmd cmd_reload; diff --git a/include/sway/config.h b/include/sway/config.h index d5467a56..e63b9895 100644 --- a/include/sway/config.h +++ b/include/sway/config.h @@ -143,6 +143,7 @@ struct seat_config { int fallback; // -1 means not set list_t *attachments; // list of seat_attachment configs int hide_cursor_timeout; + bool allow_constrain; }; enum config_dpms { diff --git a/sway/commands.c b/sway/commands.c index dd994fa1..425897fb 100644 --- a/sway/commands.c +++ b/sway/commands.c @@ -81,6 +81,7 @@ static struct cmd_handler handlers[] = { { "no_focus", cmd_no_focus }, { "output", cmd_output }, { "popup_during_fullscreen", cmd_popup_during_fullscreen }, + { "pointer_constraint", cmd_pointer_constraint }, { "seat", cmd_seat }, { "set", cmd_set }, { "show_marks", cmd_show_marks }, diff --git a/sway/commands/pointer_constraint.c b/sway/commands/pointer_constraint.c new file mode 100644 index 00000000..2dda0776 --- /dev/null +++ b/sway/commands/pointer_constraint.c @@ -0,0 +1,51 @@ +#include +#include +#include "sway/commands.h" +#include "sway/config.h" +#include "sway/input/cursor.h" +#include "sway/input/seat.h" + +enum operation { + OP_ENABLE, + OP_DISABLE, + OP_ESCAPE, +}; + +// pointer_constraint [enable|disable|escape] +struct cmd_results *cmd_pointer_constraint(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "pointer_constraint", EXPECTED_EQUAL_TO, 1))) { + return error; + } + + enum operation op; + if (strcmp(argv[0], "enable") == 0) { + op = OP_ENABLE; + } else if (strcmp(argv[0], "disable") == 0) { + op = OP_DISABLE; + } else if (strcmp(argv[0], "escape") == 0) { + op = OP_ESCAPE; + } else { + return cmd_results_new(CMD_FAILURE, "Expected enable|disable|escape"); + } + + if (op == OP_ESCAPE && config->reading) { + return cmd_results_new(CMD_FAILURE, "Can only escape at runtime."); + } + + struct sway_cursor *cursor = config->handler_context.seat->cursor; + struct seat_config *seat_config = seat_get_config(cursor->seat); + switch (op) { + case OP_ENABLE: + seat_config->allow_constrain = true; + break; + case OP_DISABLE: + seat_config->allow_constrain = false; + /* fallthrough */ + case OP_ESCAPE: + sway_cursor_constrain(cursor, NULL); + break; + } + + return cmd_results_new(CMD_SUCCESS, NULL); +} diff --git a/sway/config/seat.c b/sway/config/seat.c index 92dc42e3..541c4f99 100644 --- a/sway/config/seat.c +++ b/sway/config/seat.c @@ -26,6 +26,7 @@ struct seat_config *new_seat_config(const char* name) { return NULL; } seat->hide_cursor_timeout = -1; + seat->allow_constrain = true; return seat; } diff --git a/sway/input/cursor.c b/sway/input/cursor.c index 78e2f695..14c62970 100644 --- a/sway/input/cursor.c +++ b/sway/input/cursor.c @@ -1454,6 +1454,11 @@ void handle_pointer_constraint(struct wl_listener *listener, void *data) { void sway_cursor_constrain(struct sway_cursor *cursor, struct wlr_pointer_constraint_v1 *constraint) { + struct seat_config *config = seat_get_config(cursor->seat); + if (!config->allow_constrain) { + return; + } + if (cursor->active_constraint == constraint) { return; } diff --git a/sway/meson.build b/sway/meson.build index 94d5abdb..b3837e21 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -75,6 +75,7 @@ sway_sources = files( 'commands/nop.c', 'commands/output.c', 'commands/popup_during_fullscreen.c', + 'commands/pointer_constraint.c', 'commands/reload.c', 'commands/rename.c', 'commands/resize.c', diff --git a/sway/sway.5.scd b/sway/sway.5.scd index 55de3c9c..e04c5fbf 100644 --- a/sway/sway.5.scd +++ b/sway/sway.5.scd @@ -539,6 +539,11 @@ The default colors are: \* may be used in lieu of a specific output name to configure all outputs. A list of output names may be obtained via *swaymsg -t get_outputs*. +*pointer_constraint* enable|disable|escape + Enables or disables the ability for clients to capture the cursor (enabled + by default). This is primarily useful for video games. The "escape" command + can be used at runtime to escape from a captured client. + *popup_during_fullscreen* smart|ignore|leave_fullscreen Determines what to do when a fullscreen view opens a dialog. If _smart_ (the default), the dialog will be displayed. If _ignore_, the