diff --git a/docs/changelog.rst b/docs/changelog.rst index c3742eb2d..96e963875 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -14,6 +14,10 @@ To update |kitty|, :doc:`follow the instructions `. - Document the kitty remote control protocol (:iss:`1646`) +- Add a new option :opt:`pointer_shape_when_grabbed` that allows you to control + the mouse pointer shape when the terminal programs grabs the pointer + (:iss:`1808`) + - Add an option :opt:`terminal_select_modifiers` to control which modifiers are used to override mouse selection even when a terminal application has grabbed the mouse (:iss:`1774`) diff --git a/kitty/config_data.py b/kitty/config_data.py index 76ed0ca3c..4dd961bd1 100644 --- a/kitty/config_data.py +++ b/kitty/config_data.py @@ -472,6 +472,10 @@ o('focus_follows_mouse', False, long_text=_(''' Set the active window to the window under the mouse when moving the mouse around''')) +o('pointer_shape_when_grabbed', 'arrow', option_type=choices('arrow', 'beam', 'hand'), long_text=(''' +The shape of the mouse pointer when the program running in the terminal grabs the mouse. +''')) + # }}} g('performance') # {{{ diff --git a/kitty/mouse.c b/kitty/mouse.c index 509635928..8079b2b1d 100644 --- a/kitty/mouse.c +++ b/kitty/mouse.c @@ -243,6 +243,11 @@ get_url_sentinel(Line *line, index_type url_start) { return sentinel; } +static inline void +set_mouse_cursor_for_screen(Screen *screen) { + mouse_cursor_shape = screen->modes.mouse_tracking_mode == NO_TRACKING ? BEAM : OPT(pointer_shape_when_grabbed); +} + static inline void detect_url(Screen *screen, unsigned int x, unsigned int y) { bool has_url = false; @@ -261,7 +266,7 @@ detect_url(Screen *screen, unsigned int x, unsigned int y) { extend_url(screen, line, &url_end, &y_extended, sentinel); screen_mark_url(screen, url_start, y, url_end, y_extended); } else { - mouse_cursor_shape = BEAM; + set_mouse_cursor_for_screen(screen); screen_mark_url(screen, 0, 0, 0, 0); } } @@ -491,9 +496,12 @@ focus_in_event() { bool in_tab_bar; unsigned int window_idx = 0; mouse_cursor_shape = BEAM; - set_mouse_cursor(BEAM); Window *w = window_for_event(&window_idx, &in_tab_bar); - if (w && w->render_data.screen) screen_mark_url(w->render_data.screen, 0, 0, 0, 0); + if (w && w->render_data.screen) { + screen_mark_url(w->render_data.screen, 0, 0, 0, 0); + set_mouse_cursor_for_screen(w->render_data.screen); + } + set_mouse_cursor(mouse_cursor_shape); } void diff --git a/kitty/state.c b/kitty/state.c index 83e6d5e87..f5f233d28 100644 --- a/kitty/state.c +++ b/kitty/state.c @@ -324,6 +324,18 @@ convert_mods(PyObject *obj) { return resolve_mods(PyLong_AsLong(obj)); } +static MouseShape +pointer_shape(PyObject *shape_name) { + const char *name = PyUnicode_AsUTF8(shape_name); + switch(name[0]) { + case 'a': return ARROW; + case 'h': return HAND; + case 'b': return BEAM; + default: break; + } + return BEAM; +} + static inline void set_special_keys(PyObject *dict) { dict_iter(dict) { @@ -410,6 +422,7 @@ PYWRAP1(set_options) { S(tab_bar_min_tabs, PyLong_AsUnsignedLong); S(disable_ligatures, PyLong_AsLong); S(resize_draw_strategy, PyLong_AsLong); + S(pointer_shape_when_grabbed, pointer_shape); GA(tab_bar_style); global_state.tab_bar_hidden = PyUnicode_CompareWithASCIIString(ret, "hidden") == 0 ? true: false; diff --git a/kitty/state.h b/kitty/state.h index f7f4ebf7a..162da143e 100644 --- a/kitty/state.h +++ b/kitty/state.h @@ -44,6 +44,7 @@ typedef struct { bool window_alert_on_bell; bool debug_keyboard; double resize_debounce_time; + MouseShape pointer_shape_when_grabbed; } Options; typedef struct {