When dragging in rectangle select mode use a crosshair mouse cursor

This commit is contained in:
Kovid Goyal
2025-02-23 10:32:54 +05:30
parent 1effdd8078
commit 2a714928db
11 changed files with 77 additions and 61 deletions

View File

@@ -228,6 +228,8 @@ Detailed list of changes
- hints/unicode_input kittens: Do not lose keypresses that are sent very rapidly via an automation tool immediately after the kitten is launched (:iss:`7089`)
- When dragging in rectangle select mode use a crosshair mouse cursor configurable via :opt:`pointer_shape_when_dragging`
0.37.0 [2024-10-30]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@@ -118,7 +118,7 @@ def main(args: list[str]=sys.argv) -> None:
patch_file('glfw/x11_window.c', 'glfw to xc mapping', '\n'.join(f' {x}' for x in glfw_xfont_map))
patch_file('kitty/data-types.h', 'mouse shapes', '\n'.join(f' {x},' for x in enum_to_glfw_map))
patch_file(
'kitty/options/definition.py', 'pointer shape names', '\n'.join(f' {x!r},' for x in kitty_to_enum_map),
'kitty/options/utils.py', 'pointer shape names', '\n'.join(f' {x!r},' for x in kitty_to_enum_map),
start_marker='# ', end_marker='',
)
patch_file('kitty/options/to-c.h', 'pointer shapes', '\n'.join(

View File

@@ -263,9 +263,11 @@ cell_for_pos(Window *w, unsigned int *x, unsigned int *y, bool *in_left_half_of_
#define HANDLER(name) static void name(Window UNUSED *w, int UNUSED button, int UNUSED modifiers, unsigned int UNUSED window_idx)
static void
set_mouse_cursor_when_dragging(void) {
if (mouse_cursor_shape != OPT(pointer_shape_when_dragging)) {
mouse_cursor_shape = OPT(pointer_shape_when_dragging);
set_mouse_cursor_when_dragging(Screen *screen) {
MouseShape expected_shape = OPT(pointer_shape_when_dragging);
if (screen && screen->selections.count && screen->selections.items[0].rectangle_select) expected_shape = OPT(pointer_shape_when_dragging_rectangle);
if (mouse_cursor_shape != expected_shape) {
mouse_cursor_shape = expected_shape;
set_mouse_cursor(mouse_cursor_shape);
}
}
@@ -276,7 +278,7 @@ update_drag(Window *w) {
if (screen && screen->selections.in_progress) {
screen_update_selection(screen, w->mouse_pos.cell_x, w->mouse_pos.cell_y, w->mouse_pos.in_left_half_of_cell, (SelectionUpdate){0});
}
set_mouse_cursor_when_dragging();
set_mouse_cursor_when_dragging(screen);
}
static bool
@@ -759,7 +761,7 @@ mouse_selection(Window *w, int code, int button) {
extend_selection(w, false, false);
break;
}
set_mouse_cursor_when_dragging();
set_mouse_cursor_when_dragging(screen);
#undef S
}

View File

@@ -7,6 +7,7 @@ import string
from kitty.conf.types import Action, Definition
from kitty.constants import website_url
from kitty.options.utils import pointer_shape_names
definition = Definition(
'kitty',
@@ -679,43 +680,6 @@ mouse enters it.
'''
)
pointer_shape_names = (
# start pointer shape names (auto generated by gen-key-constants.py do not edit)
'arrow',
'beam',
'text',
'pointer',
'hand',
'help',
'wait',
'progress',
'crosshair',
'cell',
'vertical-text',
'move',
'e-resize',
'ne-resize',
'nw-resize',
'n-resize',
'se-resize',
'sw-resize',
's-resize',
'w-resize',
'ew-resize',
'ns-resize',
'nesw-resize',
'nwse-resize',
'zoom-in',
'zoom-out',
'alias',
'copy',
'not-allowed',
'no-drop',
'grab',
'grabbing',
# end pointer shape names
)
opt('pointer_shape_when_grabbed', 'arrow',
choices=pointer_shape_names, ctype='pointer_shape',
long_text='''
@@ -731,10 +695,9 @@ The default shape of the mouse pointer.
'''
)
opt('pointer_shape_when_dragging', 'beam',
choices=pointer_shape_names, ctype='pointer_shape',
long_text='''
The default shape of the mouse pointer when dragging across text.
opt('pointer_shape_when_dragging', 'beam crosshair', option_type='pointer_shape_when_dragging', ctype='!dragging_pointer_shape', long_text='''
The default shape of the mouse pointer when dragging across text. The optional second value
sets the shape when dragging in rectangular selection mode.
'''
)

13
kitty/options/parse.py generated
View File

@@ -16,9 +16,9 @@ from kitty.options.utils import (
edge_width, env, filter_notification, font_features, hide_window_decorations, macos_option_as_alt,
macos_titlebar_color, menu_map, modify_font, narrow_symbols, notify_on_cmd_finish,
optional_edge_width, parse_font_spec, parse_map, parse_mouse_map, paste_actions,
remote_control_password, resize_debounce_time, scrollback_lines, scrollback_pager_history_size,
shell_integration, store_multiple, symbol_map, tab_activity_symbol, tab_bar_edge,
tab_bar_margin_height, tab_bar_min_tabs, tab_fade, tab_font_style, tab_separator,
pointer_shape_when_dragging, remote_control_password, resize_debounce_time, scrollback_lines,
scrollback_pager_history_size, shell_integration, store_multiple, symbol_map, tab_activity_symbol,
tab_bar_edge, tab_bar_margin_height, tab_bar_min_tabs, tab_fade, tab_font_style, tab_separator,
tab_title_template, titlebar_color, to_cursor_shape, to_cursor_unfocused_shape, to_font_size,
to_layout_names, to_modifiers, transparent_background_colors, underline_exclusion, url_prefixes,
url_style, visual_bell_duration, visual_window_select_characters, window_border_width,
@@ -1158,12 +1158,7 @@ class Parser:
choices_for_placement_strategy = frozenset(('top-left', 'top', 'top-right', 'left', 'center', 'right', 'bottom-left', 'bottom', 'bottom-right'))
def pointer_shape_when_dragging(self, val: str, ans: dict[str, typing.Any]) -> None:
val = val.lower()
if val not in self.choices_for_pointer_shape_when_dragging:
raise ValueError(f"The value {val} is not a valid choice for pointer_shape_when_dragging")
ans["pointer_shape_when_dragging"] = val
choices_for_pointer_shape_when_dragging = choices_for_default_pointer_shape
ans['pointer_shape_when_dragging'] = pointer_shape_when_dragging(val)
def pointer_shape_when_grabbed(self, val: str, ans: dict[str, typing.Any]) -> None:
val = val.lower()

View File

@@ -501,7 +501,7 @@ convert_from_opts_default_pointer_shape(PyObject *py_opts, Options *opts) {
static void
convert_from_python_pointer_shape_when_dragging(PyObject *val, Options *opts) {
opts->pointer_shape_when_dragging = pointer_shape(val);
dragging_pointer_shape(val, opts);
}
static void

View File

@@ -300,6 +300,12 @@ pointer_shape(PyObject *shape_name) {
return TEXT_POINTER;
}
static inline void
dragging_pointer_shape(PyObject *parts, Options *opts) {
opts->pointer_shape_when_dragging = pointer_shape(PyTuple_GET_ITEM(parts, 0));
opts->pointer_shape_when_dragging_rectangle = pointer_shape(PyTuple_GET_ITEM(parts, 1));
}
static inline int
macos_colorspace(PyObject *csname) {
if (PyUnicode_CompareWithASCIIString(csname, "srgb") == 0) return 1;

View File

@@ -26,7 +26,6 @@ choices_for_linux_display_server = typing.Literal['auto', 'wayland', 'x11']
choices_for_macos_colorspace = typing.Literal['srgb', 'default', 'displayp3']
choices_for_macos_show_window_title_in = typing.Literal['all', 'menubar', 'none', 'window']
choices_for_placement_strategy = typing.Literal['top-left', 'top', 'top-right', 'left', 'center', 'right', 'bottom-left', 'bottom', 'bottom-right']
choices_for_pointer_shape_when_dragging = choices_for_default_pointer_shape
choices_for_pointer_shape_when_grabbed = choices_for_default_pointer_shape
choices_for_strip_trailing_spaces = typing.Literal['always', 'never', 'smart']
choices_for_tab_bar_align = typing.Literal['left', 'center', 'right']
@@ -572,7 +571,7 @@ class Options:
open_url_with: list[str] = ['default']
paste_actions: frozenset[str] = frozenset({'confirm', 'quote-urls-at-prompt'})
placement_strategy: choices_for_placement_strategy = 'center'
pointer_shape_when_dragging: choices_for_pointer_shape_when_dragging = 'beam'
pointer_shape_when_dragging: tuple[str, str] = ('beam', 'crosshair')
pointer_shape_when_grabbed: choices_for_pointer_shape_when_grabbed = 'arrow'
remember_window_size: bool = True
repaint_delay: int = 10

View File

@@ -1581,6 +1581,55 @@ def visual_bell_duration(spec: str) -> tuple[float, EasingFunction, EasingFuncti
return parse_animation(spec, interval=0.)
pointer_shape_names = (
# start pointer shape names (auto generated by gen-key-constants.py do not edit)
'arrow',
'beam',
'text',
'pointer',
'hand',
'help',
'wait',
'progress',
'crosshair',
'cell',
'vertical-text',
'move',
'e-resize',
'ne-resize',
'nw-resize',
'n-resize',
'se-resize',
'sw-resize',
's-resize',
'w-resize',
'ew-resize',
'ns-resize',
'nesw-resize',
'nwse-resize',
'zoom-in',
'zoom-out',
'alias',
'copy',
'not-allowed',
'no-drop',
'grab',
'grabbing',
# end pointer shape names
)
def pointer_shape_when_dragging(spec: str) -> tuple[str, str]:
parts = spec.split(maxsplit=1)
first = parts[0]
if first not in pointer_shape_names:
raise ValueError(f'{first} is not a valid pointer shape name')
second = parts[1] if len(parts) > 1 else first
if second not in pointer_shape_names:
raise ValueError(f'{second} is not a valid pointer shape name')
return first, second
def transparent_background_colors(spec: str) -> tuple[tuple[Color, float], ...]:
if not spec:
return ()

View File

@@ -90,7 +90,7 @@ typedef struct {
struct { monotonic_t on_end, on_pause; } resize_debounce_time;
MouseShape pointer_shape_when_grabbed;
MouseShape default_pointer_shape;
MouseShape pointer_shape_when_dragging;
MouseShape pointer_shape_when_dragging, pointer_shape_when_dragging_rectangle;
struct {
UrlPrefix *values;
size_t num, max_prefix_len;