diff --git a/include/sway/commands.h b/include/sway/commands.h index 5f249980..982125c1 100644 --- a/include/sway/commands.h +++ b/include/sway/commands.h @@ -285,6 +285,8 @@ sway_cmd seat_cmd_attach; sway_cmd seat_cmd_cursor; sway_cmd seat_cmd_fallback; sway_cmd seat_cmd_hide_cursor; +sway_cmd seat_cmd_idle_inhibit; +sway_cmd seat_cmd_idle_wake; sway_cmd seat_cmd_keyboard_grouping; sway_cmd seat_cmd_pointer_constraint; sway_cmd seat_cmd_xcursor_theme; diff --git a/include/sway/config.h b/include/sway/config.h index 9a00ccb5..3e3d2725 100644 --- a/include/sway/config.h +++ b/include/sway/config.h @@ -182,6 +182,15 @@ enum seat_keyboard_grouping { KEYBOARD_GROUP_KEYMAP }; +enum sway_input_idle_source { + IDLE_SOURCE_KEYBOARD = 1 << 0, + IDLE_SOURCE_POINTER = 1 << 1, + IDLE_SOURCE_TOUCH = 1 << 2, + IDLE_SOURCE_TABLET_PAD = 1 << 3, + IDLE_SOURCE_TABLET_TOOL = 1 << 4, + IDLE_SOURCE_SWITCH = 1 << 5, +}; + /** * Options for multiseat and other misc device configurations */ @@ -192,6 +201,7 @@ struct seat_config { int hide_cursor_timeout; enum seat_config_allow_constrain allow_constrain; enum seat_keyboard_grouping keyboard_grouping; + uint32_t idle_inhibit_sources, idle_wake_sources; struct { char *name; int size; diff --git a/include/sway/input/seat.h b/include/sway/input/seat.h index 32795b03..9c3028c5 100644 --- a/include/sway/input/seat.h +++ b/include/sway/input/seat.h @@ -4,6 +4,7 @@ #include #include #include +#include "sway/config.h" #include "sway/input/input-manager.h" struct sway_seat; @@ -80,6 +81,8 @@ struct sway_seat { uint32_t last_button_serial; + uint32_t idle_inhibit_sources, idle_wake_sources; + list_t *deferred_bindings; // struct sway_binding struct wl_listener focus_destroy; @@ -196,6 +199,9 @@ struct seat_config *seat_get_config(struct sway_seat *seat); struct seat_config *seat_get_config_by_name(const char *name); +void seat_idle_notify_activity(struct sway_seat *seat, + enum sway_input_idle_source source); + bool seat_is_input_allowed(struct sway_seat *seat, struct wlr_surface *surface); void drag_icon_update_position(struct sway_drag_icon *icon); diff --git a/sway/commands/seat.c b/sway/commands/seat.c index a2a3fbc4..eba28cac 100644 --- a/sway/commands/seat.c +++ b/sway/commands/seat.c @@ -18,6 +18,8 @@ static struct cmd_handler seat_handlers[] = { { "attach", seat_cmd_attach }, { "fallback", seat_cmd_fallback }, { "hide_cursor", seat_cmd_hide_cursor }, + { "idle_inhibit", seat_cmd_idle_inhibit }, + { "idle_wake", seat_cmd_idle_wake }, { "keyboard_grouping", seat_cmd_keyboard_grouping }, { "pointer_constraint", seat_cmd_pointer_constraint }, { "xcursor_theme", seat_cmd_xcursor_theme }, diff --git a/sway/commands/seat/idle.c b/sway/commands/seat/idle.c new file mode 100644 index 00000000..82428f2c --- /dev/null +++ b/sway/commands/seat/idle.c @@ -0,0 +1,73 @@ +#define _POSIX_C_SOURCE 200809L +#include +#include +#include +#include +#include "sway/commands.h" +#include "sway/config.h" +#include "sway/input/seat.h" + +static const struct { + const char *name; + uint32_t value; +} idle_source_strings[] = { + { "keyboard", IDLE_SOURCE_KEYBOARD }, + { "pointer", IDLE_SOURCE_POINTER }, + { "touch", IDLE_SOURCE_TOUCH }, + { "tablet_pad", IDLE_SOURCE_TABLET_PAD }, + { "tablet_tool", IDLE_SOURCE_TABLET_TOOL }, + { "switch", IDLE_SOURCE_SWITCH }, +}; + +static uint32_t parse_sources(int argc, char **argv) { + uint32_t sources = 0; + for (int i = 0; i < argc; ++i) { + uint32_t value = 0; + for (size_t j = 0; j < sizeof(idle_source_strings) + / sizeof(idle_source_strings[0]); ++j) { + if (strcasecmp(idle_source_strings[j].name, argv[i]) == 0) { + value = idle_source_strings[j].value; + break; + } + } + if (value == 0) { + return UINT32_MAX; + } + sources |= value; + } + return sources; +} + +struct cmd_results *seat_cmd_idle_inhibit(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "idle_inhibit", EXPECTED_AT_LEAST, 1))) { + return error; + } + if (!config->handler_context.seat_config) { + return cmd_results_new(CMD_FAILURE, "No seat defined"); + } + + uint32_t sources = parse_sources(argc, argv); + if (sources == UINT32_MAX) { + return cmd_results_new(CMD_FAILURE, "Invalid idle source"); + } + config->handler_context.seat_config->idle_inhibit_sources = sources; + return cmd_results_new(CMD_SUCCESS, NULL); +} + +struct cmd_results *seat_cmd_idle_wake(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "idle_wake", EXPECTED_AT_LEAST, 1))) { + return error; + } + if (!config->handler_context.seat_config) { + return cmd_results_new(CMD_FAILURE, "No seat defined"); + } + + uint32_t sources = parse_sources(argc, argv); + if (sources == UINT32_MAX) { + return cmd_results_new(CMD_FAILURE, "Invalid idle source"); + } + config->handler_context.seat_config->idle_wake_sources = sources; + return cmd_results_new(CMD_SUCCESS, NULL); +} diff --git a/sway/config/seat.c b/sway/config/seat.c index d2401162..6c916727 100644 --- a/sway/config/seat.c +++ b/sway/config/seat.c @@ -1,4 +1,5 @@ #define _POSIX_C_SOURCE 200809L +#include #include #include #include "sway/config.h" @@ -17,6 +18,8 @@ struct seat_config *new_seat_config(const char* name) { return NULL; } + seat->idle_inhibit_sources = seat->idle_wake_sources = UINT32_MAX; + seat->fallback = -1; seat->attachments = create_list(); if (!sway_assert(seat->attachments, @@ -160,6 +163,14 @@ void merge_seat_config(struct seat_config *dest, struct seat_config *source) { dest->xcursor_theme.name = strdup(source->xcursor_theme.name); dest->xcursor_theme.size = source->xcursor_theme.size; } + + if (source->idle_inhibit_sources != UINT32_MAX) { + dest->idle_inhibit_sources = source->idle_inhibit_sources; + } + + if (source->idle_wake_sources != UINT32_MAX) { + dest->idle_wake_sources = source->idle_wake_sources; + } } struct seat_config *copy_seat_config(struct seat_config *seat) { diff --git a/sway/input/cursor.c b/sway/input/cursor.c index 83b5212d..680fe39e 100644 --- a/sway/input/cursor.c +++ b/sway/input/cursor.c @@ -206,7 +206,7 @@ void cursor_handle_activity(struct sway_cursor *cursor) { wl_event_source_timer_update( cursor->hide_source, cursor_get_timeout(cursor)); - wlr_idle_notify_activity(server.idle, cursor->seat->wlr_seat); + seat_idle_notify_activity(cursor->seat, IDLE_SOURCE_POINTER); if (cursor->hidden) { cursor_unhide(cursor); } @@ -341,7 +341,7 @@ static void handle_cursor_frame(struct wl_listener *listener, void *data) { static void handle_touch_down(struct wl_listener *listener, void *data) { struct sway_cursor *cursor = wl_container_of(listener, cursor, touch_down); - wlr_idle_notify_activity(server.idle, cursor->seat->wlr_seat); + seat_idle_notify_activity(cursor->seat, IDLE_SOURCE_TOUCH); struct wlr_event_touch_down *event = data; struct sway_seat *seat = cursor->seat; @@ -372,7 +372,7 @@ static void handle_touch_down(struct wl_listener *listener, void *data) { static void handle_touch_up(struct wl_listener *listener, void *data) { struct sway_cursor *cursor = wl_container_of(listener, cursor, touch_up); - wlr_idle_notify_activity(server.idle, cursor->seat->wlr_seat); + seat_idle_notify_activity(cursor->seat, IDLE_SOURCE_TOUCH); struct wlr_event_touch_up *event = data; struct wlr_seat *seat = cursor->seat->wlr_seat; // TODO: fall back to cursor simulation if client has not bound to touch @@ -382,7 +382,7 @@ static void handle_touch_up(struct wl_listener *listener, void *data) { static void handle_touch_motion(struct wl_listener *listener, void *data) { struct sway_cursor *cursor = wl_container_of(listener, cursor, touch_motion); - wlr_idle_notify_activity(server.idle, cursor->seat->wlr_seat); + seat_idle_notify_activity(cursor->seat, IDLE_SOURCE_TOUCH); struct wlr_event_touch_motion *event = data; struct sway_seat *seat = cursor->seat; @@ -492,7 +492,7 @@ static void handle_tablet_tool_position(struct sway_cursor *cursor, static void handle_tool_axis(struct wl_listener *listener, void *data) { struct sway_cursor *cursor = wl_container_of(listener, cursor, tool_axis); - wlr_idle_notify_activity(server.idle, cursor->seat->wlr_seat); + seat_idle_notify_activity(cursor->seat, IDLE_SOURCE_TABLET_TOOL); struct wlr_event_tablet_tool_axis *event = data; struct sway_tablet_tool *sway_tool = event->tool->data; @@ -548,7 +548,7 @@ static void handle_tool_axis(struct wl_listener *listener, void *data) { static void handle_tool_tip(struct wl_listener *listener, void *data) { struct sway_cursor *cursor = wl_container_of(listener, cursor, tool_tip); - wlr_idle_notify_activity(server.idle, cursor->seat->wlr_seat); + seat_idle_notify_activity(cursor->seat, IDLE_SOURCE_TABLET_TOOL); struct wlr_event_tablet_tool_tip *event = data; struct sway_tablet_tool *sway_tool = event->tool->data; struct wlr_tablet_v2_tablet *tablet_v2 = sway_tool->tablet->tablet_v2; @@ -589,7 +589,7 @@ static struct sway_tablet *get_tablet_for_device(struct sway_cursor *cursor, static void handle_tool_proximity(struct wl_listener *listener, void *data) { struct sway_cursor *cursor = wl_container_of(listener, cursor, tool_proximity); - wlr_idle_notify_activity(server.idle, cursor->seat->wlr_seat); + seat_idle_notify_activity(cursor->seat, IDLE_SOURCE_TABLET_TOOL); struct wlr_event_tablet_tool_proximity *event = data; struct wlr_tablet_tool *tool = event->tool; @@ -619,7 +619,7 @@ static void handle_tool_proximity(struct wl_listener *listener, void *data) { static void handle_tool_button(struct wl_listener *listener, void *data) { struct sway_cursor *cursor = wl_container_of(listener, cursor, tool_button); - wlr_idle_notify_activity(server.idle, cursor->seat->wlr_seat); + seat_idle_notify_activity(cursor->seat, IDLE_SOURCE_TABLET_TOOL); struct wlr_event_tablet_tool_button *event = data; struct sway_tablet_tool *sway_tool = event->tool->data; struct wlr_tablet_v2_tablet *tablet_v2 = sway_tool->tablet->tablet_v2; diff --git a/sway/input/keyboard.c b/sway/input/keyboard.c index c4ce8246..1d55c165 100644 --- a/sway/input/keyboard.c +++ b/sway/input/keyboard.c @@ -326,7 +326,7 @@ static void handle_key_event(struct sway_keyboard *keyboard, keyboard->seat_device->input_device->wlr_device; char *device_identifier = input_device_get_identifier(wlr_device); bool exact_identifier = wlr_device->keyboard->group != NULL; - wlr_idle_notify_activity(server.idle, wlr_seat); + seat_idle_notify_activity(seat, IDLE_SOURCE_KEYBOARD); bool input_inhibited = seat->exclusive_client != NULL; // Identify new keycode, raw keysym(s), and translated keysym(s) diff --git a/sway/input/seat.c b/sway/input/seat.c index bc72ff0c..371de56e 100644 --- a/sway/input/seat.c +++ b/sway/input/seat.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -71,6 +72,25 @@ static void seat_node_destroy(struct sway_seat_node *seat_node) { free(seat_node); } +void seat_idle_notify_activity(struct sway_seat *seat, + enum sway_input_idle_source source) { + uint32_t mask = seat->idle_inhibit_sources; + struct wlr_idle_timeout *timeout; + int ntimers = 0, nidle = 0; + wl_list_for_each(timeout, &server.idle->idle_timers, link) { + ++ntimers; + if (timeout->idle_state) { + ++nidle; + } + } + if (nidle == ntimers) { + mask = seat->idle_wake_sources; + } + if ((source & mask) > 0) { + wlr_idle_notify_activity(server.idle, seat->wlr_seat); + } +} + /** * Activate all views within this container recursively. */ @@ -491,6 +511,14 @@ struct sway_seat *seat_create(const char *seat_name) { return NULL; } + seat->idle_inhibit_sources = seat->idle_wake_sources = + IDLE_SOURCE_KEYBOARD | + IDLE_SOURCE_POINTER | + IDLE_SOURCE_TOUCH | + IDLE_SOURCE_TABLET_PAD | + IDLE_SOURCE_TABLET_TOOL | + IDLE_SOURCE_SWITCH; + // init the focus stack wl_list_init(&seat->focus_stack); @@ -1325,6 +1353,9 @@ void seat_apply_config(struct sway_seat *seat, return; } + seat->idle_inhibit_sources = seat_config->idle_inhibit_sources; + seat->idle_wake_sources = seat_config->idle_wake_sources; + wl_list_for_each(seat_device, &seat->devices, link) { seat_configure_device(seat, seat_device->input_device); } diff --git a/sway/input/switch.c b/sway/input/switch.c index 72d1245f..b7c28df1 100644 --- a/sway/input/switch.c +++ b/sway/input/switch.c @@ -70,8 +70,8 @@ static void handle_switch_toggle(struct wl_listener *listener, void *data) { struct sway_switch *sway_switch = wl_container_of(listener, sway_switch, switch_toggle); struct wlr_event_switch_toggle *event = data; - struct wlr_seat* wlr_seat = sway_switch->seat_device->sway_seat->wlr_seat; - wlr_idle_notify_activity(server.idle, wlr_seat); + struct sway_seat *seat = sway_switch->seat_device->sway_seat; + seat_idle_notify_activity(seat, IDLE_SOURCE_SWITCH); struct wlr_input_device *wlr_device = sway_switch->seat_device->input_device->wlr_device; diff --git a/sway/meson.build b/sway/meson.build index 3e6e4da6..20fe02fb 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -91,6 +91,7 @@ sway_sources = files( 'commands/seat/cursor.c', 'commands/seat/fallback.c', 'commands/seat/hide_cursor.c', + 'commands/seat/idle.c', 'commands/seat/keyboard_grouping.c', 'commands/seat/pointer_constraint.c', 'commands/seat/xcursor_theme.c', diff --git a/sway/sway-input.5.scd b/sway/sway-input.5.scd index 5631293c..e1ae6781 100644 --- a/sway/sway-input.5.scd +++ b/sway/sway-input.5.scd @@ -218,6 +218,18 @@ correct seat. disables hiding the cursor. The minimal timeout is 100 and any value less than that (aside from 0), will be increased to 100. +*seat* idle_inhibit + Sets the set of input event sources which can prevent the seat from + becoming idle, as a space separated list of source names. Valid names are + "keyboard", "pointer", "touchpad", "touch", "tablet_pad", "tablet_tool", + and "switch". The default behavior is to prevent idle on any event. + +*seat* idle_wake + Sets the set of input event sources which can wake the seat from + its idle state, as a space separated list of source names. Valid names are + "keyboard", "pointer", "touchpad", "touch", "tablet pad", "tablet tool", + and "switch". The default behavior is to wake from idle on any event. + *seat* keyboard_grouping none|keymap Set how the keyboards in the seat are grouped together. Currently, there are two options. _none_ will disable all keyboard grouping. This will make