mirror of
https://github.com/swaywm/sway.git
synced 2026-04-28 06:46:26 -04:00
Implement seat subcommand hide_cursor_while_typing
This implements the following seat subcommand: `hide_cursor_while_typing <timeout>` If timeout is set to a positive value (of at least 100), the cursor will be hidden when typing and will not be unhidden until the timeout has expired after the last key has been released. This also changes the way cursor hiding/unhiding is managed to allow for both `hide_cursor` and `hide_cursor_while_typing` to be used in conjunction with each other for complex cursor hiding rules.
This commit is contained in:
parent
d9de5b8758
commit
f1654af50f
11 changed files with 161 additions and 33 deletions
|
|
@ -269,6 +269,7 @@ sway_cmd seat_cmd_attach;
|
||||||
sway_cmd seat_cmd_cursor;
|
sway_cmd seat_cmd_cursor;
|
||||||
sway_cmd seat_cmd_fallback;
|
sway_cmd seat_cmd_fallback;
|
||||||
sway_cmd seat_cmd_hide_cursor;
|
sway_cmd seat_cmd_hide_cursor;
|
||||||
|
sway_cmd seat_cmd_hide_cursor_while_typing;
|
||||||
sway_cmd seat_cmd_pointer_constraint;
|
sway_cmd seat_cmd_pointer_constraint;
|
||||||
|
|
||||||
sway_cmd cmd_ipc_cmd;
|
sway_cmd cmd_ipc_cmd;
|
||||||
|
|
|
||||||
|
|
@ -161,7 +161,8 @@ struct seat_config {
|
||||||
char *name;
|
char *name;
|
||||||
int fallback; // -1 means not set
|
int fallback; // -1 means not set
|
||||||
list_t *attachments; // list of seat_attachment configs
|
list_t *attachments; // list of seat_attachment configs
|
||||||
int hide_cursor_timeout;
|
int hide_cursor_timeout; // idle timeout
|
||||||
|
int hide_cursor_typing_timeout;
|
||||||
enum seat_config_allow_constrain allow_constrain;
|
enum seat_config_allow_constrain allow_constrain;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,12 @@
|
||||||
#define SWAY_SCROLL_LEFT KEY_MAX + 3
|
#define SWAY_SCROLL_LEFT KEY_MAX + 3
|
||||||
#define SWAY_SCROLL_RIGHT KEY_MAX + 4
|
#define SWAY_SCROLL_RIGHT KEY_MAX + 4
|
||||||
|
|
||||||
|
enum sway_cursor_hidden_reason {
|
||||||
|
CURSOR_VISIBLE = 0,
|
||||||
|
CURSOR_HIDDEN_IDLE = 1,
|
||||||
|
CURSOR_HIDDEN_TYPING = 2,
|
||||||
|
};
|
||||||
|
|
||||||
struct sway_cursor {
|
struct sway_cursor {
|
||||||
struct sway_seat *seat;
|
struct sway_seat *seat;
|
||||||
struct wlr_cursor *cursor;
|
struct wlr_cursor *cursor;
|
||||||
|
|
@ -49,8 +55,9 @@ struct sway_cursor {
|
||||||
|
|
||||||
struct wl_listener constraint_commit;
|
struct wl_listener constraint_commit;
|
||||||
|
|
||||||
struct wl_event_source *hide_source;
|
struct wl_event_source *hide_source; // idle
|
||||||
bool hidden;
|
struct wl_event_source *hide_source_typing;
|
||||||
|
uint32_t hidden; // bitfield of enum sway_cursor_hidden_reason
|
||||||
|
|
||||||
size_t pressed_button_count;
|
size_t pressed_button_count;
|
||||||
};
|
};
|
||||||
|
|
@ -73,8 +80,18 @@ void cursor_rebase(struct sway_cursor *cursor);
|
||||||
void cursor_rebase_all(void);
|
void cursor_rebase_all(void);
|
||||||
|
|
||||||
void cursor_handle_activity(struct sway_cursor *cursor);
|
void cursor_handle_activity(struct sway_cursor *cursor);
|
||||||
void cursor_unhide(struct sway_cursor *cursor);
|
|
||||||
int cursor_get_timeout(struct sway_cursor *cursor);
|
void cursor_hide(struct sway_cursor *cursor,
|
||||||
|
enum sway_cursor_hidden_reason reason);
|
||||||
|
|
||||||
|
// Removes the cursor hidden reason and if all reasons are removed, unhides the
|
||||||
|
// cursor. If CURSOR_VISIBLE is given as the reason, all reasons will be
|
||||||
|
// removed and the cursor will be unhidden.
|
||||||
|
void cursor_unhide(struct sway_cursor *cursor,
|
||||||
|
enum sway_cursor_hidden_reason reason);
|
||||||
|
|
||||||
|
int cursor_get_timeout(struct sway_cursor *cursor,
|
||||||
|
enum sway_cursor_hidden_reason reason);
|
||||||
|
|
||||||
void dispatch_cursor_button(struct sway_cursor *cursor,
|
void dispatch_cursor_button(struct sway_cursor *cursor,
|
||||||
struct wlr_input_device *device, uint32_t time_msec, uint32_t button,
|
struct wlr_input_device *device, uint32_t time_msec, uint32_t button,
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ static struct cmd_handler seat_handlers[] = {
|
||||||
{ "cursor", seat_cmd_cursor },
|
{ "cursor", seat_cmd_cursor },
|
||||||
{ "fallback", seat_cmd_fallback },
|
{ "fallback", seat_cmd_fallback },
|
||||||
{ "hide_cursor", seat_cmd_hide_cursor },
|
{ "hide_cursor", seat_cmd_hide_cursor },
|
||||||
|
{ "hide_cursor_while_typing", seat_cmd_hide_cursor_while_typing },
|
||||||
{ "pointer_constraint", seat_cmd_pointer_constraint },
|
{ "pointer_constraint", seat_cmd_pointer_constraint },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
29
sway/commands/seat/hide_cursor_while_typing.c
Normal file
29
sway/commands/seat/hide_cursor_while_typing.c
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
#define _POSIX_C_SOURCE 200809L
|
||||||
|
#include <string.h>
|
||||||
|
#include "sway/commands.h"
|
||||||
|
#include "sway/config.h"
|
||||||
|
#include "sway/input/seat.h"
|
||||||
|
#include "stringop.h"
|
||||||
|
|
||||||
|
struct cmd_results *seat_cmd_hide_cursor_while_typing(int argc, char **argv) {
|
||||||
|
struct cmd_results *error =
|
||||||
|
checkarg(argc, "hide_cursor_while_typing", EXPECTED_EQUAL_TO, 1);
|
||||||
|
if (error) {
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
if (!config->handler_context.seat_config) {
|
||||||
|
return cmd_results_new(CMD_FAILURE, "No seat defined");
|
||||||
|
}
|
||||||
|
|
||||||
|
char *end;
|
||||||
|
int timeout = strtol(argv[0], &end, 10);
|
||||||
|
if (*end) {
|
||||||
|
return cmd_results_new(CMD_INVALID, "Expected an integer timeout");
|
||||||
|
}
|
||||||
|
if (timeout < 100 && timeout != 0) {
|
||||||
|
timeout = 100;
|
||||||
|
}
|
||||||
|
config->handler_context.seat_config->hide_cursor_typing_timeout = timeout;
|
||||||
|
|
||||||
|
return cmd_results_new(CMD_SUCCESS, NULL);
|
||||||
|
}
|
||||||
|
|
@ -26,6 +26,7 @@ struct seat_config *new_seat_config(const char* name) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
seat->hide_cursor_timeout = -1;
|
seat->hide_cursor_timeout = -1;
|
||||||
|
seat->hide_cursor_typing_timeout = -1;
|
||||||
seat->allow_constrain = CONSTRAIN_DEFAULT;
|
seat->allow_constrain = CONSTRAIN_DEFAULT;
|
||||||
|
|
||||||
return seat;
|
return seat;
|
||||||
|
|
@ -144,6 +145,10 @@ void merge_seat_config(struct seat_config *dest, struct seat_config *source) {
|
||||||
dest->hide_cursor_timeout = source->hide_cursor_timeout;
|
dest->hide_cursor_timeout = source->hide_cursor_timeout;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (source->hide_cursor_typing_timeout != -1) {
|
||||||
|
dest->hide_cursor_typing_timeout = source->hide_cursor_typing_timeout;
|
||||||
|
}
|
||||||
|
|
||||||
if (source->allow_constrain != CONSTRAIN_DEFAULT) {
|
if (source->allow_constrain != CONSTRAIN_DEFAULT) {
|
||||||
dest->allow_constrain = source->allow_constrain;
|
dest->allow_constrain = source->allow_constrain;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -176,18 +176,48 @@ void cursor_rebase_all(void) {
|
||||||
|
|
||||||
static int hide_notify(void *data) {
|
static int hide_notify(void *data) {
|
||||||
struct sway_cursor *cursor = data;
|
struct sway_cursor *cursor = data;
|
||||||
wlr_cursor_set_image(cursor->cursor, NULL, 0, 0, 0, 0, 0, 0);
|
cursor_hide(cursor, CURSOR_HIDDEN_IDLE);
|
||||||
cursor->hidden = true;
|
|
||||||
wlr_seat_pointer_clear_focus(cursor->seat->wlr_seat);
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int cursor_get_timeout(struct sway_cursor *cursor){
|
void cursor_hide(struct sway_cursor *cursor,
|
||||||
|
enum sway_cursor_hidden_reason reason) {
|
||||||
|
if (!sway_assert(reason != CURSOR_VISIBLE,
|
||||||
|
"Cannot hide cursor for reason CURSOR_VISIBLE")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (cursor->hidden == CURSOR_VISIBLE) {
|
||||||
|
wlr_cursor_set_image(cursor->cursor, NULL, 0, 0, 0, 0, 0, 0);
|
||||||
|
cursor->hidden |= reason;
|
||||||
|
wlr_seat_pointer_clear_focus(cursor->seat->wlr_seat);
|
||||||
|
} else {
|
||||||
|
cursor->hidden |= reason;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int cursor_get_timeout(struct sway_cursor *cursor,
|
||||||
|
enum sway_cursor_hidden_reason reason) {
|
||||||
struct seat_config *sc = seat_get_config(cursor->seat);
|
struct seat_config *sc = seat_get_config(cursor->seat);
|
||||||
if (!sc) {
|
if (!sc) {
|
||||||
sc = seat_get_config_by_name("*");
|
sc = seat_get_config_by_name("*");
|
||||||
}
|
}
|
||||||
int timeout = sc ? sc->hide_cursor_timeout : 0;
|
int timeout = 0;
|
||||||
|
switch (reason) {
|
||||||
|
case CURSOR_VISIBLE:
|
||||||
|
sway_assert(false, "There should not be attempt to retrieve the "
|
||||||
|
"timeout for CURSOR_VISIBLE");
|
||||||
|
break;
|
||||||
|
case CURSOR_HIDDEN_IDLE:
|
||||||
|
if (sc) {
|
||||||
|
timeout = sc->hide_cursor_timeout;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CURSOR_HIDDEN_TYPING:
|
||||||
|
if (sc) {
|
||||||
|
timeout = sc->hide_cursor_typing_timeout;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
if (timeout < 0) {
|
if (timeout < 0) {
|
||||||
timeout = 0;
|
timeout = 0;
|
||||||
}
|
}
|
||||||
|
|
@ -195,17 +225,31 @@ int cursor_get_timeout(struct sway_cursor *cursor){
|
||||||
}
|
}
|
||||||
|
|
||||||
void cursor_handle_activity(struct sway_cursor *cursor) {
|
void cursor_handle_activity(struct sway_cursor *cursor) {
|
||||||
wl_event_source_timer_update(
|
wl_event_source_timer_update(cursor->hide_source,
|
||||||
cursor->hide_source, cursor_get_timeout(cursor));
|
cursor_get_timeout(cursor, CURSOR_HIDDEN_IDLE));
|
||||||
|
|
||||||
wlr_idle_notify_activity(server.idle, cursor->seat->wlr_seat);
|
wlr_idle_notify_activity(server.idle, cursor->seat->wlr_seat);
|
||||||
if (cursor->hidden) {
|
if ((cursor->hidden & CURSOR_HIDDEN_IDLE) != 0) {
|
||||||
cursor_unhide(cursor);
|
cursor_unhide(cursor, CURSOR_HIDDEN_IDLE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void cursor_unhide(struct sway_cursor *cursor) {
|
static int handle_typing_unhide(void *data) {
|
||||||
cursor->hidden = false;
|
struct sway_cursor *cursor = data;
|
||||||
|
if ((cursor->hidden & CURSOR_HIDDEN_TYPING) != 0) {
|
||||||
|
cursor_unhide(cursor, CURSOR_HIDDEN_TYPING);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cursor_unhide(struct sway_cursor *cursor,
|
||||||
|
enum sway_cursor_hidden_reason reason) {
|
||||||
|
if (reason == CURSOR_VISIBLE) {
|
||||||
|
cursor->hidden = CURSOR_VISIBLE;
|
||||||
|
} else {
|
||||||
|
cursor->hidden &= ~reason;
|
||||||
|
}
|
||||||
|
if (cursor->hidden == CURSOR_VISIBLE) {
|
||||||
if (cursor->image_surface) {
|
if (cursor->image_surface) {
|
||||||
cursor_set_image_surface(cursor,
|
cursor_set_image_surface(cursor,
|
||||||
cursor->image_surface,
|
cursor->image_surface,
|
||||||
|
|
@ -218,6 +262,7 @@ void cursor_unhide(struct sway_cursor *cursor) {
|
||||||
cursor_set_image(cursor, image, cursor->image_client);
|
cursor_set_image(cursor, image, cursor->image_client);
|
||||||
}
|
}
|
||||||
cursor_rebase(cursor);
|
cursor_rebase(cursor);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cursor_motion(struct sway_cursor *cursor, uint32_t time_msec,
|
static void cursor_motion(struct sway_cursor *cursor, uint32_t time_msec,
|
||||||
|
|
@ -587,7 +632,7 @@ void cursor_set_image(struct sway_cursor *cursor, const char *image,
|
||||||
cursor->hotspot_x = cursor->hotspot_y = 0;
|
cursor->hotspot_x = cursor->hotspot_y = 0;
|
||||||
cursor->image_client = client;
|
cursor->image_client = client;
|
||||||
|
|
||||||
if (cursor->hidden) {
|
if (cursor->hidden != CURSOR_VISIBLE) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -612,7 +657,7 @@ void cursor_set_image_surface(struct sway_cursor *cursor,
|
||||||
cursor->hotspot_y = hotspot_y;
|
cursor->hotspot_y = hotspot_y;
|
||||||
cursor->image_client = client;
|
cursor->image_client = client;
|
||||||
|
|
||||||
if (cursor->hidden) {
|
if (cursor->hidden != CURSOR_VISIBLE) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -625,6 +670,7 @@ void sway_cursor_destroy(struct sway_cursor *cursor) {
|
||||||
}
|
}
|
||||||
|
|
||||||
wl_event_source_remove(cursor->hide_source);
|
wl_event_source_remove(cursor->hide_source);
|
||||||
|
wl_event_source_remove(cursor->hide_source_typing);
|
||||||
|
|
||||||
wl_list_remove(&cursor->motion.link);
|
wl_list_remove(&cursor->motion.link);
|
||||||
wl_list_remove(&cursor->motion_absolute.link);
|
wl_list_remove(&cursor->motion_absolute.link);
|
||||||
|
|
@ -664,6 +710,8 @@ struct sway_cursor *sway_cursor_create(struct sway_seat *seat) {
|
||||||
|
|
||||||
cursor->hide_source = wl_event_loop_add_timer(server.wl_event_loop,
|
cursor->hide_source = wl_event_loop_add_timer(server.wl_event_loop,
|
||||||
hide_notify, cursor);
|
hide_notify, cursor);
|
||||||
|
cursor->hide_source_typing = wl_event_loop_add_timer(server.wl_event_loop,
|
||||||
|
handle_typing_unhide, cursor);
|
||||||
|
|
||||||
// input events
|
// input events
|
||||||
wl_signal_add(&wlr_cursor->events.motion, &cursor->motion);
|
wl_signal_add(&wlr_cursor->events.motion, &cursor->motion);
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@
|
||||||
#include "sway/commands.h"
|
#include "sway/commands.h"
|
||||||
#include "sway/desktop/transaction.h"
|
#include "sway/desktop/transaction.h"
|
||||||
#include "sway/input/input-manager.h"
|
#include "sway/input/input-manager.h"
|
||||||
|
#include "sway/input/cursor.h"
|
||||||
#include "sway/input/keyboard.h"
|
#include "sway/input/keyboard.h"
|
||||||
#include "sway/input/seat.h"
|
#include "sway/input/seat.h"
|
||||||
#include "sway/ipc-server.h"
|
#include "sway/ipc-server.h"
|
||||||
|
|
@ -396,6 +397,19 @@ static void handle_keyboard_key(struct wl_listener *listener, void *data) {
|
||||||
event->keycode, event->state);
|
event->keycode, event->state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle hiding the cursor while typing
|
||||||
|
int timeout = cursor_get_timeout(seat->cursor, CURSOR_HIDDEN_TYPING);
|
||||||
|
if (timeout > 0) {
|
||||||
|
if (event->state == WLR_KEY_PRESSED) {
|
||||||
|
cursor_hide(seat->cursor, CURSOR_HIDDEN_TYPING);
|
||||||
|
wl_event_source_timer_update(seat->cursor->hide_source_typing, 0);
|
||||||
|
} else if (event->state == WLR_KEY_RELEASED
|
||||||
|
&& keyboard->state_keycodes.npressed == 0) {
|
||||||
|
wl_event_source_timer_update(seat->cursor->hide_source_typing,
|
||||||
|
timeout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
transaction_commit_dirty();
|
transaction_commit_dirty();
|
||||||
|
|
||||||
free(device_identifier);
|
free(device_identifier);
|
||||||
|
|
|
||||||
|
|
@ -507,6 +507,7 @@ static void seat_reset_input_config(struct sway_seat *seat,
|
||||||
sway_device->input_device->identifier);
|
sway_device->input_device->identifier);
|
||||||
wlr_cursor_map_input_to_output(seat->cursor->cursor,
|
wlr_cursor_map_input_to_output(seat->cursor->cursor,
|
||||||
sway_device->input_device->wlr_device, NULL);
|
sway_device->input_device->wlr_device, NULL);
|
||||||
|
cursor_unhide(seat->cursor, CURSOR_VISIBLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void seat_apply_input_config(struct sway_seat *seat,
|
static void seat_apply_input_config(struct sway_seat *seat,
|
||||||
|
|
@ -1207,9 +1208,10 @@ void seat_consider_warp_to_focus(struct sway_seat *seat) {
|
||||||
} else {
|
} else {
|
||||||
cursor_warp_to_workspace(seat->cursor, focus->sway_workspace);
|
cursor_warp_to_workspace(seat->cursor, focus->sway_workspace);
|
||||||
}
|
}
|
||||||
if (seat->cursor->hidden){
|
if (seat->cursor->hidden != CURSOR_VISIBLE) {
|
||||||
cursor_unhide(seat->cursor);
|
cursor_unhide(seat->cursor, CURSOR_VISIBLE);
|
||||||
wl_event_source_timer_update(seat->cursor->hide_source, cursor_get_timeout(seat->cursor));
|
wl_event_source_timer_update(seat->cursor->hide_source,
|
||||||
|
cursor_get_timeout(seat->cursor, CURSOR_HIDDEN_IDLE));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -86,6 +86,7 @@ sway_sources = files(
|
||||||
'commands/seat/cursor.c',
|
'commands/seat/cursor.c',
|
||||||
'commands/seat/fallback.c',
|
'commands/seat/fallback.c',
|
||||||
'commands/seat/hide_cursor.c',
|
'commands/seat/hide_cursor.c',
|
||||||
|
'commands/seat/hide_cursor_while_typing.c',
|
||||||
'commands/seat/pointer_constraint.c',
|
'commands/seat/pointer_constraint.c',
|
||||||
'commands/set.c',
|
'commands/set.c',
|
||||||
'commands/show_marks.c',
|
'commands/show_marks.c',
|
||||||
|
|
|
||||||
|
|
@ -184,7 +184,16 @@ correct seat.
|
||||||
Hides the cursor image after the specified _timeout_ (in milliseconds)
|
Hides the cursor image after the specified _timeout_ (in milliseconds)
|
||||||
has elapsed with no activity on that cursor. A timeout of 0 (default)
|
has elapsed with no activity on that cursor. A timeout of 0 (default)
|
||||||
disables hiding the cursor. The minimal timeout is 100 and any value less
|
disables hiding the cursor. The minimal timeout is 100 and any value less
|
||||||
than that (aside from 0), will be increased to 100.
|
than that (aside from 0), will be increased to 100. This may be used in
|
||||||
|
conjunction with _hide_cursor_while_typing_ to have complex cursor hiding
|
||||||
|
rules.
|
||||||
|
|
||||||
|
*seat* <name> hide_cursor_while_typing <timeout>
|
||||||
|
Hides the cursor image while typing. The cursor image will be hidden until
|
||||||
|
the timeout expires after the last key is released. A timeout of 0
|
||||||
|
(default) disables hiding the cursor. The minimal timeout is 100 and any
|
||||||
|
value less than that (aside from 0), will be increased to 100. This may be
|
||||||
|
used in conjunction with _hide_cursor_ to have complex cursor hiding rules
|
||||||
|
|
||||||
*seat* <name> pointer_constraint enable|disable|escape
|
*seat* <name> pointer_constraint enable|disable|escape
|
||||||
Enables or disables the ability for clients to capture the cursor (enabled
|
Enables or disables the ability for clients to capture the cursor (enabled
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue