From 4e48d550efba98ebecf4b60045004e52c585c52d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Thu, 9 Jul 2020 09:52:11 +0200 Subject: [PATCH] multi-seat: improve handling of multiple (mouse) pointers * xcursor always set for all pointers * xcursor sometimes not updated when it should be * mouse grabbed state wasn't per seat, but global (i.e. "does at least one seat enable mouse grabbing") * selection enabled state wasn't per seat --- input.c | 71 ++++++++++++++++++++++++++++------------------------- render.c | 34 ++++++++++++------------- render.h | 2 +- selection.c | 4 +-- selection.h | 2 +- terminal.c | 55 ++++++++++++++++++----------------------- terminal.h | 15 +++++++++-- wayland.h | 4 +-- 8 files changed, 97 insertions(+), 90 deletions(-) diff --git a/input.c b/input.c index 1caf46b3..f0024a0d 100644 --- a/input.c +++ b/input.c @@ -817,14 +817,14 @@ is_bottom_right(const struct terminal *term, int x, int y) static const char * xcursor_for_csd_border(struct terminal *term, int x, int y) { - if (is_top_left(term, x, y)) return "top_left_corner"; - else if (is_top_right(term, x, y)) return "top_right_corner"; - else if (is_bottom_left(term, x, y)) return "bottom_left_corner"; - else if (is_bottom_right(term, x, y)) return "bottom_right_corner"; - else if (term->active_surface == TERM_SURF_BORDER_LEFT) return "left_side"; - else if (term->active_surface == TERM_SURF_BORDER_RIGHT) return "right_side"; - else if (term->active_surface == TERM_SURF_BORDER_TOP) return "top_side"; - else if (term->active_surface == TERM_SURF_BORDER_BOTTOM) return"bottom_side"; + if (is_top_left(term, x, y)) return XCURSOR_TOP_LEFT_CORNER; + else if (is_top_right(term, x, y)) return XCURSOR_TOP_RIGHT_CORNER; + else if (is_bottom_left(term, x, y)) return XCURSOR_BOTTOM_LEFT_CORNER; + else if (is_bottom_right(term, x, y)) return XCURSOR_BOTTOM_RIGHT_CORNER; + else if (term->active_surface == TERM_SURF_BORDER_LEFT) return XCURSOR_LEFT_SIDE; + else if (term->active_surface == TERM_SURF_BORDER_RIGHT) return XCURSOR_RIGHT_SIDE; + else if (term->active_surface == TERM_SURF_BORDER_TOP) return XCURSOR_TOP_SIDE; + else if (term->active_surface == TERM_SURF_BORDER_BOTTOM) return XCURSOR_BOTTOM_SIDE; else { assert(false); return NULL; @@ -862,23 +862,20 @@ wl_pointer_enter(void *data, struct wl_pointer *wl_pointer, case TERM_SURF_SEARCH: case TERM_SURF_TITLE: - term->xcursor = "left_ptr"; - render_xcursor_set(seat, term); + render_xcursor_set(seat, term, XCURSOR_LEFT_PTR); break; case TERM_SURF_BORDER_LEFT: case TERM_SURF_BORDER_RIGHT: case TERM_SURF_BORDER_TOP: case TERM_SURF_BORDER_BOTTOM: - term->xcursor = xcursor_for_csd_border(term, x, y); - render_xcursor_set(seat, term); + render_xcursor_set(seat, term, xcursor_for_csd_border(term, x, y)); break; case TERM_SURF_BUTTON_MINIMIZE: case TERM_SURF_BUTTON_MAXIMIZE: case TERM_SURF_BUTTON_CLOSE: - term->xcursor = "left_ptr"; - render_xcursor_set(seat, term); + render_xcursor_set(seat, term, XCURSOR_LEFT_PTR); render_refresh_csd(term); break; @@ -903,7 +900,7 @@ wl_pointer_leave(void *data, struct wl_pointer *wl_pointer, /* A cursor frame callback may never be called if the pointer leaves our surface */ wl_callback_destroy(seat->pointer.xcursor_callback); seat->pointer.xcursor_callback = NULL; - seat->pointer.pending_terminal = NULL; + seat->pointer.xcursor_pending = false; seat->pointer.xcursor = NULL; } @@ -995,8 +992,7 @@ wl_pointer_motion(void *data, struct wl_pointer *wl_pointer, case TERM_SURF_BORDER_RIGHT: case TERM_SURF_BORDER_TOP: case TERM_SURF_BORDER_BOTTOM: - term->xcursor = xcursor_for_csd_border(term, x, y); - render_xcursor_set(seat, term); + render_xcursor_set(seat, term, xcursor_for_csd_border(term, x, y)); break; case TERM_SURF_GRID: { @@ -1021,9 +1017,11 @@ wl_pointer_motion(void *data, struct wl_pointer *wl_pointer, if (update_selection && !update_selection_early) selection_update(term, col, row); - term_mouse_motion( - term, seat->mouse.button, seat->mouse.row, seat->mouse.col, - seat->kbd.shift, seat->kbd.alt, seat->kbd.ctrl); + if (!term_mouse_grabbed(term, seat)) { + term_mouse_motion( + term, seat->mouse.button, seat->mouse.row, seat->mouse.col, + seat->kbd.shift, seat->kbd.alt, seat->kbd.ctrl); + } break; } } @@ -1190,7 +1188,7 @@ wl_pointer_button(void *data, struct wl_pointer *wl_pointer, if (button == BTN_LEFT && seat->mouse.count <= 3) { selection_cancel(term); - if (selection_enabled(term)) { + if (selection_enabled(term, seat)) { switch (seat->mouse.count) { case 1: selection_start( @@ -1212,7 +1210,7 @@ wl_pointer_button(void *data, struct wl_pointer *wl_pointer, } else if (button == BTN_RIGHT && seat->mouse.count == 1) { - if (selection_enabled(term)) { + if (selection_enabled(term, seat)) { selection_extend( seat, term, seat->mouse.col, seat->mouse.row, serial); } @@ -1238,9 +1236,11 @@ wl_pointer_button(void *data, struct wl_pointer *wl_pointer, } } - term_mouse_down( - term, button, seat->mouse.row, seat->mouse.col, - seat->kbd.shift, seat->kbd.alt, seat->kbd.ctrl); + if (!term_mouse_grabbed(term, seat)) { + term_mouse_down( + term, button, seat->mouse.row, seat->mouse.col, + seat->kbd.shift, seat->kbd.alt, seat->kbd.ctrl); + } break; } @@ -1248,9 +1248,11 @@ wl_pointer_button(void *data, struct wl_pointer *wl_pointer, if (button == BTN_LEFT && term->selection.end.col != -1) selection_finalize(seat, term, serial); - term_mouse_up( - term, button, seat->mouse.row, seat->mouse.col, - seat->kbd.shift, seat->kbd.alt, seat->kbd.ctrl); + if (!term_mouse_grabbed(term, seat)) { + term_mouse_up( + term, button, seat->mouse.row, seat->mouse.col, + seat->kbd.shift, seat->kbd.alt, seat->kbd.ctrl); + } break; } break; @@ -1298,15 +1300,16 @@ mouse_scroll(struct seat *seat, int amount) keyboard_key(seat, NULL, seat->input_serial, 0, key - 8, XKB_KEY_DOWN); keyboard_key(seat, NULL, seat->input_serial, 0, key - 8, XKB_KEY_UP); } else { - for (int i = 0; i < amount; i++) { - term_mouse_down( + if (!term_mouse_grabbed(term, seat)) { + for (int i = 0; i < amount; i++) { + term_mouse_down( + term, button, seat->mouse.row, seat->mouse.col, + seat->kbd.shift, seat->kbd.alt, seat->kbd.ctrl); + } + term_mouse_up( term, button, seat->mouse.row, seat->mouse.col, seat->kbd.shift, seat->kbd.alt, seat->kbd.ctrl); } - term_mouse_up( - term, button, seat->mouse.row, seat->mouse.col, - seat->kbd.shift, seat->kbd.alt, seat->kbd.ctrl); - scrollback(term, amount); } } diff --git a/render.c b/render.c index 8fb0fd6f..603f9c2d 100644 --- a/render.c +++ b/render.c @@ -1946,22 +1946,22 @@ static const struct wl_callback_listener xcursor_listener = { }; static void -render_xcursor_update(struct seat *seat, const struct terminal *term) +render_xcursor_update(struct seat *seat) { /* If called from a frame callback, we may no longer have mouse focus */ - if (seat->mouse_focus != term) + if (!seat->mouse_focus) return; - seat->pointer.cursor = wl_cursor_theme_get_cursor(seat->pointer.theme, term->xcursor); + seat->pointer.cursor = wl_cursor_theme_get_cursor( + seat->pointer.theme, seat->pointer.xcursor); + if (seat->pointer.cursor == NULL) { LOG_ERR("%s: failed to load xcursor pointer '%s'", - seat->pointer.theme_name, term->xcursor); + seat->pointer.theme_name, seat->pointer.xcursor); return; } - seat->pointer.xcursor = term->xcursor; - - const int scale = term->scale; + const int scale = seat->pointer.scale; struct wl_cursor_image *image = seat->pointer.cursor->images[0]; wl_surface_attach( @@ -1993,9 +1993,9 @@ xcursor_callback(void *data, struct wl_callback *wl_callback, uint32_t callback_ wl_callback_destroy(wl_callback); seat->pointer.xcursor_callback = NULL; - if (seat->pointer.pending_terminal != NULL) { - render_xcursor_update(seat, seat->pointer.pending_terminal); - seat->pointer.pending_terminal = NULL; + if (seat->pointer.xcursor_pending) { + render_xcursor_update(seat); + seat->pointer.xcursor_pending = false; } } @@ -2061,10 +2061,10 @@ fdm_hook_refresh_pending_terminals(struct fdm *fdm, void *data) } tll_foreach(wayl->seats, it) { - if (it->item.pointer.pending_terminal != NULL) { + if (it->item.pointer.xcursor_pending) { if (it->item.pointer.xcursor_callback == NULL) { - render_xcursor_update(&it->item, it->item.pointer.pending_terminal); - it->item.pointer.pending_terminal = NULL; + render_xcursor_update(&it->item); + it->item.pointer.xcursor_pending = false; } else { /* Frame callback will call render_xcursor_update() */ } @@ -2099,14 +2099,13 @@ render_refresh_search(struct terminal *term) } bool -render_xcursor_set(struct seat *seat, struct terminal *term) +render_xcursor_set(struct seat *seat, struct terminal *term, const char *xcursor) { if (seat->pointer.theme == NULL) return false; if (seat->mouse_focus == NULL) { seat->pointer.xcursor = NULL; - seat->pointer.pending_terminal = NULL; return true; } @@ -2115,10 +2114,11 @@ render_xcursor_set(struct seat *seat, struct terminal *term) return true; } - if (seat->pointer.xcursor == term->xcursor) + if (seat->pointer.xcursor == xcursor) return true; /* FDM hook takes care of actual rendering */ - seat->pointer.pending_terminal = term; + seat->pointer.xcursor_pending = true; + seat->pointer.xcursor = xcursor; return true; } diff --git a/render.h b/render.h index 4640145b..05c79322 100644 --- a/render.h +++ b/render.h @@ -16,7 +16,7 @@ void render_refresh(struct terminal *term); void render_refresh_csd(struct terminal *term); void render_refresh_search(struct terminal *term); void render_refresh_title(struct terminal *term); -bool render_xcursor_set(struct seat *seat, struct terminal *term); +bool render_xcursor_set(struct seat *seat, struct terminal *term, const char *xcursor); struct render_worker_context { int my_id; diff --git a/selection.c b/selection.c index 2c8176dd..f097e37b 100644 --- a/selection.c +++ b/selection.c @@ -21,11 +21,11 @@ #include "vt.h" bool -selection_enabled(const struct terminal *term) +selection_enabled(const struct terminal *term, struct seat *seat) { return term->mouse_tracking == MOUSE_NONE || - term_mouse_grabbed(term) || + term_mouse_grabbed(term, seat) || term->is_searching; } diff --git a/selection.h b/selection.h index e049f182..52b0f1a3 100644 --- a/selection.h +++ b/selection.h @@ -8,7 +8,7 @@ extern const struct wl_data_device_listener data_device_listener; extern const struct zwp_primary_selection_device_v1_listener primary_selection_device_listener; -bool selection_enabled(const struct terminal *term); +bool selection_enabled(const struct terminal *term, struct seat *seat); void selection_start( struct terminal *term, int col, int row, enum selection_kind kind); void selection_update(struct terminal *term, int col, int row); diff --git a/terminal.c b/terminal.c index 96c83644..1e7ddabe 100644 --- a/terminal.c +++ b/terminal.c @@ -34,9 +34,17 @@ #define PTMX_TIMING 0 -static const char *const XCURSOR_LEFT_PTR = "left_ptr"; -static const char *const XCURSOR_TEXT = "text"; -//static const char *const XCURSOR_HAND2 = "hand2"; +const char *const XCURSOR_LEFT_PTR = "left_ptr"; +const char *const XCURSOR_TEXT = "text"; +//const char *const XCURSOR_HAND2 = "hand2"; +const char *const XCURSOR_TOP_LEFT_CORNER = "top_left_corner"; +const char *const XCURSOR_TOP_RIGHT_CORNER = "top_right_corner"; +const char *const XCURSOR_BOTTOM_LEFT_CORNER = "bottom_left_corner"; +const char *const XCURSOR_BOTTOM_RIGHT_CORNER = "bottom_right_corner"; +const char *const XCURSOR_LEFT_SIDE = "left_side"; +const char *const XCURSOR_RIGHT_SIDE = "right_side"; +const char *const XCURSOR_TOP_SIDE = "top_side"; +const char *const XCURSOR_BOTTOM_SIDE = "bottom_side"; bool term_to_slave(struct terminal *term, const void *_data, size_t len) @@ -889,7 +897,6 @@ term_init(const struct config *conf, struct fdm *fdm, struct reaper *reaper, .text = conf->cursor.color.text, .cursor = conf->cursor.color.cursor, }, - .xcursor = "text", .selection = { .start = {-1, -1}, .end = {-1, -1}, @@ -2068,31 +2075,20 @@ report_mouse_motion(struct terminal *term, int encoded_button, int row, int col) } bool -term_mouse_grabbed(const struct terminal *term) +term_mouse_grabbed(const struct terminal *term, struct seat *seat) { /* * Mouse is grabbed by us, regardless of whether mouse tracking has been enabled or not. */ - tll_foreach(term->wl->seats, it) { - const struct seat *seat = &it->item; - - if (seat->kbd_focus == term && - seat->kbd.shift && - !seat->kbd.alt && /*!seat->kbd.ctrl &&*/ !seat->kbd.meta) - { - return true; - } - } - return false; + return seat->kbd_focus == term && + seat->kbd.shift && + !seat->kbd.alt && /*!seat->kbd.ctrl &&*/ !seat->kbd.meta; } void term_mouse_down(struct terminal *term, int button, int row, int col, bool _shift, bool _alt, bool _ctrl) { - if (term_mouse_grabbed(term)) - return; - /* Map libevent button event code to X button number */ int xbutton = linux_mouse_button_to_x(button); if (xbutton == -1) @@ -2131,9 +2127,6 @@ void term_mouse_up(struct terminal *term, int button, int row, int col, bool _shift, bool _alt, bool _ctrl) { - if (term_mouse_grabbed(term)) - return; - /* Map libevent button event code to X button number */ int xbutton = linux_mouse_button_to_x(button); if (xbutton == -1) @@ -2176,9 +2169,6 @@ void term_mouse_motion(struct terminal *term, int button, int row, int col, bool _shift, bool _alt, bool _ctrl) { - if (term_mouse_grabbed(term)) - return; - int encoded = 0; if (button != 0) { @@ -2225,13 +2215,16 @@ term_mouse_motion(struct terminal *term, int button, int row, int col, void term_xcursor_update(struct terminal *term) { - term->xcursor = - term->is_searching ? XCURSOR_LEFT_PTR : /* TODO: something different? */ - selection_enabled(term) ? XCURSOR_TEXT : - XCURSOR_LEFT_PTR; + tll_foreach(term->wl->seats, it) { + struct seat *seat = &it->item; - tll_foreach(term->wl->seats, it) - render_xcursor_set(&it->item, term); + const char *xcursor + = term->is_searching ? XCURSOR_LEFT_PTR : /* TODO: something different? */ + selection_enabled(term, seat) ? XCURSOR_TEXT : + XCURSOR_LEFT_PTR; + + render_xcursor_set(seat, term, xcursor); + } } void diff --git a/terminal.h b/terminal.h index 604511da..8316795f 100644 --- a/terminal.h +++ b/terminal.h @@ -305,7 +305,6 @@ struct terminal { uint32_t text; uint32_t cursor; } cursor_color; - const char *xcursor; struct { enum selection_kind kind; @@ -439,6 +438,18 @@ struct terminal { char *cwd; }; +extern const char *const XCURSOR_LEFT_PTR; +extern const char *const XCURSOR_TEXT; +//extern const char *const XCURSOR_HAND2; +extern const char *const XCURSOR_TOP_LEFT_CORNER; +extern const char *const XCURSOR_TOP_RIGHT_CORNER; +extern const char *const XCURSOR_BOTTOM_LEFT_CORNER; +extern const char *const XCURSOR_BOTTOM_RIGHT_CORNER; +extern const char *const XCURSOR_LEFT_SIDE; +extern const char *const XCURSOR_RIGHT_SIDE; +extern const char *const XCURSOR_TOP_SIDE; +extern const char *const XCURSOR_BOTTOM_SIDE; + struct config; struct terminal *term_init( const struct config *conf, struct fdm *fdm, struct reaper *reaper, @@ -518,7 +529,7 @@ void term_mouse_up( void term_mouse_motion( struct terminal *term, int button, int row, int col, bool shift, bool alt, bool ctrl); -bool term_mouse_grabbed(const struct terminal *term); +bool term_mouse_grabbed(const struct terminal *term, struct seat *seat); void term_xcursor_update(struct terminal *term); void term_set_window_title(struct terminal *term, const char *title); diff --git a/wayland.h b/wayland.h index 489f485d..f703883e 100644 --- a/wayland.h +++ b/wayland.h @@ -148,10 +148,10 @@ struct seat { int size; int scale; char *theme_name; - const char *xcursor; - const struct terminal *pending_terminal; + const char *xcursor; struct wl_callback *xcursor_callback; + bool xcursor_pending; } pointer; struct {