input: inhibit mouse events to client when a binding has consumed it

This introduces a new state to a seat's mouse struct, 'consumed'. It
is set on a mouse *press* event that is claimed by a mouse binding.

It is cleared after a mouse *release* event.

While set, *no* mouse motion or button events are sent to the client
application.
This commit is contained in:
Daniel Eklöf 2020-08-22 13:35:36 +02:00
parent 11cb08f1b5
commit 3ddc17937f
No known key found for this signature in database
GPG key ID: 5BBD4992C116573F
3 changed files with 62 additions and 36 deletions

View file

@ -82,6 +82,8 @@
content (https://codeberg.org/dnkl/foot/issues/94). content (https://codeberg.org/dnkl/foot/issues/94).
* Extra newlines when copying empty cells * Extra newlines when copying empty cells
(https://codeberg.org/dnkl/foot/issues/97). (https://codeberg.org/dnkl/foot/issues/97).
* Mouse events from being sent to client application when a mouse
binding has consumed it.
### Security ### Security

95
input.c
View file

@ -76,7 +76,7 @@ pipe_closed:
return true; return true;
} }
static void static bool
execute_binding(struct seat *seat, struct terminal *term, execute_binding(struct seat *seat, struct terminal *term,
enum bind_action_normal action, char *const *pipe_argv, enum bind_action_normal action, char *const *pipe_argv,
uint32_t serial) uint32_t serial)
@ -85,52 +85,52 @@ execute_binding(struct seat *seat, struct terminal *term,
switch (action) { switch (action) {
case BIND_ACTION_NONE: case BIND_ACTION_NONE:
break; return true;
case BIND_ACTION_SCROLLBACK_UP: case BIND_ACTION_SCROLLBACK_UP:
cmd_scrollback_up(term, term->rows); cmd_scrollback_up(term, term->rows);
break; return true;
case BIND_ACTION_SCROLLBACK_DOWN: case BIND_ACTION_SCROLLBACK_DOWN:
cmd_scrollback_down(term, term->rows); cmd_scrollback_down(term, term->rows);
break; return true;
case BIND_ACTION_CLIPBOARD_COPY: case BIND_ACTION_CLIPBOARD_COPY:
selection_to_clipboard(seat, term, serial); selection_to_clipboard(seat, term, serial);
break; return true;
case BIND_ACTION_CLIPBOARD_PASTE: case BIND_ACTION_CLIPBOARD_PASTE:
selection_from_clipboard(seat, term, serial); selection_from_clipboard(seat, term, serial);
term_reset_view(term); term_reset_view(term);
break; return true;
case BIND_ACTION_PRIMARY_PASTE: case BIND_ACTION_PRIMARY_PASTE:
selection_from_primary(seat, term); selection_from_primary(seat, term);
break; return true;
case BIND_ACTION_SEARCH_START: case BIND_ACTION_SEARCH_START:
search_begin(term); search_begin(term);
break; return true;
case BIND_ACTION_FONT_SIZE_UP: case BIND_ACTION_FONT_SIZE_UP:
term_font_size_increase(term); term_font_size_increase(term);
break; return true;
case BIND_ACTION_FONT_SIZE_DOWN: case BIND_ACTION_FONT_SIZE_DOWN:
term_font_size_decrease(term); term_font_size_decrease(term);
break; return true;
case BIND_ACTION_FONT_SIZE_RESET: case BIND_ACTION_FONT_SIZE_RESET:
term_font_size_reset(term); term_font_size_reset(term);
break; return true;
case BIND_ACTION_SPAWN_TERMINAL: case BIND_ACTION_SPAWN_TERMINAL:
term_spawn_new(term); term_spawn_new(term);
break; return true;
case BIND_ACTION_MINIMIZE: case BIND_ACTION_MINIMIZE:
xdg_toplevel_set_minimized(term->window->xdg_toplevel); xdg_toplevel_set_minimized(term->window->xdg_toplevel);
break; return true;
case BIND_ACTION_MAXIMIZE: case BIND_ACTION_MAXIMIZE:
if (term->window->is_fullscreen) if (term->window->is_fullscreen)
@ -139,20 +139,20 @@ execute_binding(struct seat *seat, struct terminal *term,
xdg_toplevel_unset_maximized(term->window->xdg_toplevel); xdg_toplevel_unset_maximized(term->window->xdg_toplevel);
else else
xdg_toplevel_set_maximized(term->window->xdg_toplevel); xdg_toplevel_set_maximized(term->window->xdg_toplevel);
break; return true;
case BIND_ACTION_FULLSCREEN: case BIND_ACTION_FULLSCREEN:
if (term->window->is_fullscreen) if (term->window->is_fullscreen)
xdg_toplevel_unset_fullscreen(term->window->xdg_toplevel); xdg_toplevel_unset_fullscreen(term->window->xdg_toplevel);
else else
xdg_toplevel_set_fullscreen(term->window->xdg_toplevel, NULL); xdg_toplevel_set_fullscreen(term->window->xdg_toplevel, NULL);
break; return true;
case BIND_ACTION_PIPE_SCROLLBACK: case BIND_ACTION_PIPE_SCROLLBACK:
case BIND_ACTION_PIPE_VIEW: case BIND_ACTION_PIPE_VIEW:
case BIND_ACTION_PIPE_SELECTED: { case BIND_ACTION_PIPE_SELECTED: {
if (pipe_argv == NULL) if (pipe_argv == NULL)
break; return true;
struct pipe_context *ctx = NULL; struct pipe_context *ctx = NULL;
@ -240,9 +240,9 @@ execute_binding(struct seat *seat, struct terminal *term,
if (!fdm_add(term->fdm, pipe_fd[1], EPOLLOUT, &fdm_write_pipe, ctx)) if (!fdm_add(term->fdm, pipe_fd[1], EPOLLOUT, &fdm_write_pipe, ctx))
goto pipe_err; goto pipe_err;
break; return true;
pipe_err: pipe_err:
if (stdout_fd >= 0) if (stdout_fd >= 0)
close(stdout_fd); close(stdout_fd);
if (stderr_fd >= 0) if (stderr_fd >= 0)
@ -253,53 +253,62 @@ execute_binding(struct seat *seat, struct terminal *term,
close(pipe_fd[1]); close(pipe_fd[1]);
free(text); free(text);
free(ctx); free(ctx);
break; return true;
} }
case BIND_ACTION_SELECT_BEGIN: case BIND_ACTION_SELECT_BEGIN:
if (selection_enabled(term, seat) && cursor_is_on_grid) { if (selection_enabled(term, seat) && cursor_is_on_grid) {
selection_start( selection_start(
term, seat->mouse.col, seat->mouse.row, SELECTION_NORMAL); term, seat->mouse.col, seat->mouse.row, SELECTION_NORMAL);
return true;
} }
break; return false;
case BIND_ACTION_SELECT_BEGIN_BLOCK: case BIND_ACTION_SELECT_BEGIN_BLOCK:
if (selection_enabled(term, seat) && cursor_is_on_grid) { if (selection_enabled(term, seat) && cursor_is_on_grid) {
selection_start( selection_start(
term, seat->mouse.col, seat->mouse.row, SELECTION_BLOCK); term, seat->mouse.col, seat->mouse.row, SELECTION_BLOCK);
return true;
} }
break; return false;
case BIND_ACTION_SELECT_EXTEND: case BIND_ACTION_SELECT_EXTEND:
if (selection_enabled(term, seat) && cursor_is_on_grid) { if (selection_enabled(term, seat) && cursor_is_on_grid) {
selection_extend( selection_extend(
seat, term, seat->mouse.col, seat->mouse.row, serial); seat, term, seat->mouse.col, seat->mouse.row, serial);
return true;
} }
break; return false;
case BIND_ACTION_SELECT_WORD: case BIND_ACTION_SELECT_WORD:
if (selection_enabled(term, seat) && cursor_is_on_grid) { if (selection_enabled(term, seat) && cursor_is_on_grid) {
selection_mark_word( selection_mark_word(
seat, term, seat->mouse.col, seat->mouse.row, false, serial); seat, term, seat->mouse.col, seat->mouse.row, false, serial);
return true;
} }
break; return false;
case BIND_ACTION_SELECT_WORD_WS: case BIND_ACTION_SELECT_WORD_WS:
if (selection_enabled(term, seat) && cursor_is_on_grid) { if (selection_enabled(term, seat) && cursor_is_on_grid) {
selection_mark_word( selection_mark_word(
seat, term, seat->mouse.col, seat->mouse.row, true, serial); seat, term, seat->mouse.col, seat->mouse.row, true, serial);
return true;
} }
break; return false;
case BIND_ACTION_SELECT_ROW: case BIND_ACTION_SELECT_ROW:
if (selection_enabled(term, seat) && cursor_is_on_grid) if (selection_enabled(term, seat) && cursor_is_on_grid) {
selection_mark_row(seat, term, seat->mouse.row, serial); selection_mark_row(seat, term, seat->mouse.row, serial);
break; return true;
}
return false;
case BIND_ACTION_COUNT: case BIND_ACTION_COUNT:
assert(false); assert(false);
break; return false;
} }
return false;
} }
static xkb_mod_mask_t static xkb_mod_mask_t
@ -798,15 +807,15 @@ keyboard_key(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial,
/* Match symbol */ /* Match symbol */
if (it->item.bind.sym == sym) { if (it->item.bind.sym == sym) {
execute_binding(seat, term, it->item.action, it->item.pipe_argv, serial); if (execute_binding(seat, term, it->item.action, it->item.pipe_argv, serial))
goto maybe_repeat; goto maybe_repeat;
} }
/* Match raw key code */ /* Match raw key code */
tll_foreach(it->item.bind.key_codes, code) { tll_foreach(it->item.bind.key_codes, code) {
if (code->item == key) { if (code->item == key) {
execute_binding(seat, term, it->item.action, it->item.pipe_argv, serial); if (execute_binding(seat, term, it->item.action, it->item.pipe_argv, serial))
goto maybe_repeat; goto maybe_repeat;
} }
} }
} }
@ -1152,6 +1161,7 @@ wl_pointer_leave(void *data, struct wl_pointer *wl_pointer,
seat->mouse.x = seat->mouse.y = 0; seat->mouse.x = seat->mouse.y = 0;
seat->mouse.col = seat->mouse.row = 0; seat->mouse.col = seat->mouse.row = 0;
seat->mouse.button = seat->mouse.last_button = seat->mouse.count = 0; seat->mouse.button = seat->mouse.last_button = seat->mouse.count = 0;
seat->mouse.consumed = false;
memset(&seat->mouse.last_time, 0, sizeof(seat->mouse.last_time)); memset(&seat->mouse.last_time, 0, sizeof(seat->mouse.last_time));
seat->mouse.axis_aggregated = 0.0; seat->mouse.axis_aggregated = 0.0;
seat->mouse.have_discrete = false; seat->mouse.have_discrete = false;
@ -1302,7 +1312,8 @@ wl_pointer_motion(void *data, struct wl_pointer *wl_pointer,
} }
/* Send mouse event to client application */ /* Send mouse event to client application */
if (!term_mouse_grabbed(term, seat) && if (!seat->mouse.consumed &&
!term_mouse_grabbed(term, seat) &&
cursor_is_on_new_cell && cursor_is_on_grid) cursor_is_on_new_cell && cursor_is_on_grid)
{ {
assert(seat->mouse.col < term->cols); assert(seat->mouse.col < term->cols);
@ -1481,6 +1492,8 @@ wl_pointer_button(void *data, struct wl_pointer *wl_pointer,
switch (state) { switch (state) {
case WL_POINTER_BUTTON_STATE_PRESSED: { case WL_POINTER_BUTTON_STATE_PRESSED: {
assert(!seat->mouse.consumed);
if (seat->wl_keyboard != NULL) { if (seat->wl_keyboard != NULL) {
/* Seat has keyboard - use mouse bindings *with* modifiers */ /* Seat has keyboard - use mouse bindings *with* modifiers */
@ -1510,7 +1523,8 @@ wl_pointer_button(void *data, struct wl_pointer *wl_pointer,
continue; continue;
} }
execute_binding(seat, term, binding->action, NULL, serial); seat->mouse.consumed = execute_binding(
seat, term, binding->action, NULL, serial);
break; break;
} }
} }
@ -1536,12 +1550,16 @@ wl_pointer_button(void *data, struct wl_pointer *wl_pointer,
continue; continue;
} }
execute_binding(seat, term, binding->action, NULL, serial); seat->mouse.consumed = execute_binding(
seat, term, binding->action, NULL, serial);
break; break;
} }
} }
if (!term_mouse_grabbed(term, seat) && cursor_is_on_grid) { if (!seat->mouse.consumed &&
!term_mouse_grabbed(term, seat) &&
cursor_is_on_grid)
{
term_mouse_down( term_mouse_down(
term, button, seat->mouse.row, seat->mouse.col, term, button, seat->mouse.row, seat->mouse.col,
seat->kbd.shift, seat->kbd.alt, seat->kbd.ctrl); seat->kbd.shift, seat->kbd.alt, seat->kbd.ctrl);
@ -1552,11 +1570,16 @@ wl_pointer_button(void *data, struct wl_pointer *wl_pointer,
case WL_POINTER_BUTTON_STATE_RELEASED: case WL_POINTER_BUTTON_STATE_RELEASED:
selection_finalize(seat, term, serial); selection_finalize(seat, term, serial);
if (!term_mouse_grabbed(term, seat) && cursor_is_on_grid) { if (!seat->mouse.consumed &&
!term_mouse_grabbed(term, seat) &&
cursor_is_on_grid)
{
term_mouse_up( term_mouse_up(
term, button, seat->mouse.row, seat->mouse.col, term, button, seat->mouse.row, seat->mouse.col,
seat->kbd.shift, seat->kbd.alt, seat->kbd.ctrl); seat->kbd.shift, seat->kbd.alt, seat->kbd.ctrl);
} }
seat->mouse.consumed = false;
break; break;
} }
break; break;

View file

@ -178,6 +178,7 @@ struct seat {
int col; int col;
int row; int row;
int button; int button;
bool consumed; /* True if a button press was consumed - i.e. if a binding claimed it */
int count; int count;
int last_button; int last_button;