From 0dd37f0a364fc36284dad17e8fb1345714261a4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Thu, 28 Nov 2019 19:35:47 +0100 Subject: [PATCH] terminal: use the 'text' xcursor pointer whenever selection is possible --- csi.c | 4 +++ input.c | 8 +++++- terminal.c | 14 ++++++++++ terminal.h | 2 ++ wayland.c | 77 +++++++++++++++++++++++++++++++----------------------- wayland.h | 3 +-- 6 files changed, 72 insertions(+), 36 deletions(-) diff --git a/csi.c b/csi.c index fbfac35d..a07267b1 100644 --- a/csi.c +++ b/csi.c @@ -875,14 +875,17 @@ csi_dispatch(struct terminal *term, uint8_t final) case 1000: term->mouse_tracking = MOUSE_CLICK; + term_xcursor_update(term); break; case 1002: term->mouse_tracking = MOUSE_DRAG; + term_xcursor_update(term); break; case 1003: term->mouse_tracking = MOUSE_MOTION; + term_xcursor_update(term); break; case 1004: @@ -1000,6 +1003,7 @@ csi_dispatch(struct terminal *term, uint8_t final) case 1002: /* MOUSE_BUTTON_EVENT */ case 1003: /* MOUSE_ANY_EVENT */ term->mouse_tracking = MOUSE_NONE; + term_xcursor_update(term); break; case 1005: /* MOUSE_UTF8 */ diff --git a/input.c b/input.c index 3a203f84..dc5ca77d 100644 --- a/input.c +++ b/input.c @@ -88,6 +88,7 @@ keyboard_enter(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, wayl->focused = wayl_terminal_from_surface(wayl, surface); assert(wayl->focused != NULL); term_focus_in(wayl->focused); + term_xcursor_update(wayl->focused); } static bool @@ -379,6 +380,8 @@ keyboard_modifiers(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, xkb_state_update_mask( wayl->kbd.xkb_state, mods_depressed, mods_latched, mods_locked, 0, 0, group); + bool old_shift = wayl->kbd.shift; + /* Update state of modifiers we're interrested in for e.g mouse events */ wayl->kbd.shift = xkb_state_mod_index_is_active( wayl->kbd.xkb_state, wayl->kbd.mod_shift, XKB_STATE_MODS_DEPRESSED); @@ -388,6 +391,9 @@ keyboard_modifiers(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, wayl->kbd.xkb_state, wayl->kbd.mod_ctrl, XKB_STATE_MODS_DEPRESSED); wayl->kbd.meta = xkb_state_mod_index_is_active( wayl->kbd.xkb_state, wayl->kbd.mod_meta, XKB_STATE_MODS_DEPRESSED); + + if (wayl->moused && old_shift != wayl->kbd.shift) + term_xcursor_update(wayl->moused); } static void @@ -431,7 +437,7 @@ wl_pointer_enter(void *data, struct wl_pointer *wl_pointer, wayl->mouse.col = x / term->cell_width; wayl->mouse.row = y / term->cell_height; - wayl_update_cursor_surface(wayl, term); + term_xcursor_update(term); } static void diff --git a/terminal.c b/terminal.c index 0cfbdb2e..22d19652 100644 --- a/terminal.c +++ b/terminal.c @@ -483,6 +483,7 @@ term_init(const struct config *conf, struct fdm *fdm, struct wayland *wayl, .text = conf->cursor.color.text, .cursor = conf->cursor.color.cursor, }, + .xcursor = "text", .selection = { .start = {-1, -1}, .end = {-1, -1}, @@ -1429,6 +1430,19 @@ term_mouse_motion(struct terminal *term, int button, int row, int col, } } +void +term_xcursor_update(struct terminal *term) +{ + const bool is_focused = term->wl->focused == term; + const char *new_cursor = + is_focused && selection_enabled(term) ? "text" : "left_ptr"; + + LOG_DBG("setting xcursor to '%s' for term=%p", new_cursor, term); + + term->xcursor = new_cursor; + wayl_cursor_set(term->wl, term); +} + void term_set_window_title(struct terminal *term, const char *title) { diff --git a/terminal.h b/terminal.h index bc43edeb..8e1ae4b7 100644 --- a/terminal.h +++ b/terminal.h @@ -240,6 +240,7 @@ struct terminal { uint32_t text; uint32_t cursor; } cursor_color; + const char *xcursor; struct { struct coord start; @@ -365,6 +366,7 @@ void term_mouse_up(struct terminal *term, int button, int row, int col, bool shift, bool alt, bool ctrl); void term_mouse_motion(struct terminal *term, int button, int row, int col, bool shift, bool alt, bool ctrl); +void term_xcursor_update(struct terminal *term); void term_set_window_title(struct terminal *term, const char *title); void term_flash(struct terminal *term, unsigned duration_ms); diff --git a/wayland.c b/wayland.c index c7720404..1a5cc5f9 100644 --- a/wayland.c +++ b/wayland.c @@ -28,6 +28,9 @@ #define min(x, y) ((x) < (y) ? (x) : (y)) #define max(x, y) ((x) > (y) ? (x) : (y)) +static bool wayl_reload_cursor_theme( + struct wayland *wayl, const struct terminal *term); + static void shm_format(void *data, struct wl_shm *wl_shm, uint32_t format) { @@ -792,7 +795,45 @@ wayl_win_destroy(struct wl_window *win) } bool -wayl_reload_cursor_theme(struct wayland *wayl, struct terminal *term) +wayl_cursor_set(struct wayland *wayl, const struct terminal *term) +{ + if (wayl->pointer.theme == NULL) + return false; + + if (wayl->moused != term) { + /* This terminal doesn't have mouse focus */ + return true; + } + + wayl->pointer.cursor = wl_cursor_theme_get_cursor(wayl->pointer.theme, term->xcursor); + if (wayl->pointer.cursor == NULL) { + LOG_ERR("%s: failed to load xcursor pointer '%s'", + wayl->pointer.theme_name, term->xcursor); + return false; + } + + const int scale = term->scale; + struct wl_cursor_image *image = wayl->pointer.cursor->images[0]; + + wl_surface_attach( + wayl->pointer.surface, wl_cursor_image_get_buffer(image), 0, 0); + + wl_pointer_set_cursor( + wayl->pointer.pointer, wayl->pointer.serial, + wayl->pointer.surface, + image->hotspot_x / scale, image->hotspot_y / scale); + + wl_surface_damage_buffer( + wayl->pointer.surface, 0, 0, INT32_MAX, INT32_MAX); + + wl_surface_set_buffer_scale(wayl->pointer.surface, scale); + wl_surface_commit(wayl->pointer.surface); + wl_display_roundtrip(wayl->display); + return true; +} + +static bool +wayl_reload_cursor_theme(struct wayland *wayl, const struct terminal *term) { if (wayl->pointer.size == 0) return true; @@ -808,45 +849,15 @@ wayl_reload_cursor_theme(struct wayland *wayl, struct terminal *term) wayl->pointer.theme = wl_cursor_theme_load( wayl->pointer.theme_name, wayl->pointer.size * term->scale, wayl->shm); + if (wayl->pointer.theme == NULL) { LOG_ERR("failed to load cursor theme"); return false; } - wayl->pointer.cursor = wl_cursor_theme_get_cursor( - wayl->pointer.theme, "left_ptr"); - assert(wayl->pointer.cursor != NULL); - wayl_update_cursor_surface(wayl, term); - - return true; + return wayl_cursor_set(wayl, term); } -void -wayl_update_cursor_surface(struct wayland *wayl, struct terminal *term) -{ - if (wayl->pointer.cursor == NULL) - return; - - const int scale = term->scale; - wl_surface_set_buffer_scale(wayl->pointer.surface, scale); - - struct wl_cursor_image *image = wayl->pointer.cursor->images[0]; - - wl_surface_attach( - wayl->pointer.surface, wl_cursor_image_get_buffer(image), 0, 0); - - wl_pointer_set_cursor( - wayl->pointer.pointer, wayl->pointer.serial, - wayl->pointer.surface, - image->hotspot_x / scale, image->hotspot_y / scale); - - wl_surface_damage_buffer( - wayl->pointer.surface, 0, 0, INT32_MAX, INT32_MAX); - - wl_surface_commit(wayl->pointer.surface); -} - - struct terminal * wayl_terminal_from_surface(struct wayland *wayl, struct wl_surface *surface) { diff --git a/wayland.h b/wayland.h index cbcedc1a..a5084d83 100644 --- a/wayland.h +++ b/wayland.h @@ -166,8 +166,7 @@ struct terminal *wayl_terminal_from_xdg_toplevel( struct wayland *wayl, struct xdg_toplevel *toplevel); /* TODO: pass something other than 'term'? Need scale... */ -bool wayl_reload_cursor_theme(struct wayland *wayl, struct terminal *term); -void wayl_update_cursor_surface(struct wayland *wayl, struct terminal *term); +bool wayl_cursor_set(struct wayland *wayl, const struct terminal *term); struct wl_window *wayl_win_init(struct wayland *wayl); void wayl_win_destroy(struct wl_window *win);