mirror of
https://github.com/kovidgoyal/kitty.git
synced 2024-09-11 14:45:31 +03:00
Rationalize mouse cursor shape handling
Now can use the full range of standard mouse cursor shapes similar to those supported by browsers via the CSS cursor property. Still needs to be fully implemented for cocoa backend.
This commit is contained in:
parent
a8a1571ed1
commit
4f1971c480
@ -50,6 +50,8 @@ Detailed list of changes
|
||||
|
||||
- A new mouse action ``mouse_selection word_and_line_from_point`` to select the current word under the mouse cursor and extend to end of line (:pull:`6663`)
|
||||
|
||||
- Allow using the full range of standard mouse cursor shapes when customizing the mouse cursor
|
||||
|
||||
- macOS: When running the default shell with the login program fix :file:`~/.hushlogin` not being respected when opening windows not in the home directory (:iss:`6689`)
|
||||
|
||||
- ``kitten @ set-background-opacity`` - add a new ``--toggle`` flag to easily switch opacity between the specified value and the default (:iss:`6691`)
|
||||
|
@ -32,6 +32,9 @@ def main(args: List[str]=sys.argv) -> None:
|
||||
elif which == 'wcwidth':
|
||||
from gen.wcwidth import main
|
||||
main(args)
|
||||
elif which == 'cursors':
|
||||
from gen.cursors import main
|
||||
main(args)
|
||||
else:
|
||||
raise SystemExit(f'Unknown which: {which}')
|
||||
|
||||
|
103
gen/cursors.py
Executable file
103
gen/cursors.py
Executable file
@ -0,0 +1,103 @@
|
||||
#!/usr/bin/env python
|
||||
# License: GPLv3 Copyright: 2023, Kovid Goyal <kovid at kovidgoyal.net>
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
from typing import List
|
||||
|
||||
from .key_constants import patch_file
|
||||
|
||||
# References for these names:
|
||||
# CSS: https://developer.mozilla.org/en-US/docs/Web/CSS/cursor
|
||||
# XCursor: https://tronche.com/gui/x/xlib/appendix/b/ + Absolute chaos
|
||||
# Wayland: https://wayland.app/protocols/cursor-shape-v1
|
||||
# Cocoa: https://developer.apple.com/documentation/appkit/nscursor + secret apple selectors + SDL_cocoamouse.m
|
||||
|
||||
# kitty_names CSS_name XCursor_names Wayland_name Cocoa_name
|
||||
cursors = '''\
|
||||
arrow default default,!left_ptr default arrowCursor
|
||||
beam,text text text,!xterm,ibeam text IBeamCursor
|
||||
pointer,hand pointer pointing_hand,pointer,!hand2,hand pointer pointingHandCursor
|
||||
help help help,!question_arrow,whats_this help help:arrowCursor
|
||||
wait wait wait,!clock,watch wait busybutclickable:arrowCursor
|
||||
progress progress progress,half-busy,left_ptr_watch progress busybutclickable:arrowCursor
|
||||
crosshair crosshair crosshair,!tcross crosshair crosshairCursor
|
||||
vertical-text vertical-text vertical-text vertical-text IBeamCursorForVerticalLayout
|
||||
move move move,!fleur,pointer-move move move:openHandCursor
|
||||
|
||||
e-resize e-resize e-resize,!right_side e_resize resizeRightCursor
|
||||
ne-resize ne-resize ne-resize,!top_right_corner ne_resize resizenortheast:_windowResizeNorthEastSouthWestCursor
|
||||
nw-resize nw-resize nw-resize,!top_left_corner nw_resize resizenorthwest:_windowResizeNorthWestSouthEastCursor
|
||||
n-resize n-resize n-resize,!top_side n_resize resizeUpCursor
|
||||
se-resize se-resize se-resize,!bottom_right_corner se_resize resizesoutheast:_windowResizeNorthWestSouthEastCursor
|
||||
sw-resize sw-resize sw-resize,!bottom_left_corner sw_resize resizesouthwest:_windowResizeNorthEastSouthWestCursor
|
||||
s-resize s-resize s-resize,!bottom_side s_resize resizeDownCursor
|
||||
w-resize w-resize w-resize,!left_side w_resize resizeLeftCursor
|
||||
|
||||
ew-resize ew-resize ew-resize,!sb_h_double_arrow,split_h ew_resize resizeLeftRightCursor
|
||||
ns-resize ns-resize ns-resize,!sb_v_double_arrow,split_v ns_resize resizeUpDownCursor
|
||||
nesw-resize nesw-resize nesw-resize,size_bdiag,!sb_v_double_arrow nesw_resize _windowResizeNorthEastSouthWestCursor
|
||||
nwse-resize nwse-resize nwse-resize,size_fdiag,!sb_h_double_arrow nwse_resize _windowResizeNorthWestSouthEastCursor
|
||||
|
||||
zoom-in zoom-in zoom-in,zoom_in zoom_in zoomin:arrowCursor
|
||||
zoom-out zoom-out zoom-out,zoom_out zoom_out zoomout:arrowCursor
|
||||
|
||||
alias alias dnd-link alias dragLinkCursor
|
||||
copy copy dnd-copy copy dragCopyCursor
|
||||
not-allowed not-allowed not-allowed,forbidden,crossed_circle not_allowed operationNotAllowedCursor
|
||||
no-drop no-drop no-drop,dnd-no-drop no_drop operationNotAllowedCursor
|
||||
grab grab grab,openhand,!hand1 grab openHandCursor
|
||||
grabbing grabbing grabbing,closedhand,dnd-none grabbing closedHandCursor
|
||||
'''
|
||||
|
||||
|
||||
def main(args: List[str]=sys.argv) -> None:
|
||||
glfw_enum = []
|
||||
glfw_xc_map = {}
|
||||
glfw_xfont_map = []
|
||||
kitty_to_enum_map = {}
|
||||
enum_to_glfw_map = {}
|
||||
for line in cursors.splitlines():
|
||||
line = line.strip()
|
||||
if line:
|
||||
names_, css, xc_, wayland, cocoa = line.split()
|
||||
names, xc = names_.split(','), xc_.split(',')
|
||||
base = css.replace('-', '_').upper()
|
||||
glfw_name = 'GLFW_' + base + '_CURSOR'
|
||||
enum_name = base + '_POINTER'
|
||||
enum_to_glfw_map[enum_name] = glfw_name
|
||||
for n in names:
|
||||
kitty_to_enum_map[n] = enum_name
|
||||
glfw_enum.append(glfw_name)
|
||||
glfw_xc_map[glfw_name] = ', '.join(f'''"{x.replace('!', '')}"''' for x in xc)
|
||||
for x in xc:
|
||||
if x.startswith('!'):
|
||||
glfw_xfont_map.append(f"case {glfw_name}: return set_cursor_from_font(cursor, {'XC_' + x[1:]});")
|
||||
break
|
||||
else:
|
||||
items = tuple('"' + x.replace('!', '') + '"' for x in xc)
|
||||
glfw_xfont_map.append(f'case {glfw_name}: return try_cursor_names(cursor, {len(items)}, {", ".join(items)});')
|
||||
|
||||
glfw_enum.append('GLFW_INVALID_CURSOR')
|
||||
patch_file('glfw/glfw3.h', 'mouse cursor shapes', '\n'.join(f' {x},' for x in glfw_enum))
|
||||
patch_file('glfw/wl_window.c', 'glfw to xc mapping', '\n'.join(f' C({g}, {x});' for g, x in glfw_xc_map.items()))
|
||||
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),
|
||||
start_marker='# ', end_marker='',
|
||||
)
|
||||
patch_file('kitty/options/to-c.h', 'pointer shapes', '\n'.join(
|
||||
f' else if (strcmp(name, "{k}") == 0) return {v};' for k, v in kitty_to_enum_map.items()))
|
||||
patch_file('kitty/glfw.c', 'enum to glfw', '\n'.join(
|
||||
f' case {k}: set_glfw_mouse_cursor(w, {v}); break;' for k, v in enum_to_glfw_map.items()))
|
||||
patch_file('kitty/glfw.c', 'name to glfw', '\n'.join(
|
||||
f' if (strcmp(name, "{k}") == 0) return {enum_to_glfw_map[v]};' for k, v in kitty_to_enum_map.items()))
|
||||
subprocess.check_call(['glfw/glfw.py'])
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import runpy
|
||||
m = runpy.run_path(os.path.dirname(os.path.abspath(__file__)))
|
||||
m['main']([sys.executable, 'cursors'])
|
37
glfw/glfw3.h
vendored
37
glfw/glfw3.h
vendored
@ -1099,17 +1099,38 @@ typedef enum {
|
||||
* @{ */
|
||||
|
||||
typedef enum {
|
||||
GLFW_ARROW_CURSOR,
|
||||
GLFW_IBEAM_CURSOR,
|
||||
/* start mouse cursor shapes (auto generated by gen-key-constants.py do not edit) */
|
||||
GLFW_DEFAULT_CURSOR,
|
||||
GLFW_TEXT_CURSOR,
|
||||
GLFW_POINTER_CURSOR,
|
||||
GLFW_HELP_CURSOR,
|
||||
GLFW_WAIT_CURSOR,
|
||||
GLFW_PROGRESS_CURSOR,
|
||||
GLFW_CROSSHAIR_CURSOR,
|
||||
GLFW_HAND_CURSOR,
|
||||
GLFW_HRESIZE_CURSOR,
|
||||
GLFW_VRESIZE_CURSOR,
|
||||
GLFW_NW_RESIZE_CURSOR,
|
||||
GLFW_VERTICAL_TEXT_CURSOR,
|
||||
GLFW_MOVE_CURSOR,
|
||||
GLFW_E_RESIZE_CURSOR,
|
||||
GLFW_NE_RESIZE_CURSOR,
|
||||
GLFW_SW_RESIZE_CURSOR,
|
||||
GLFW_NW_RESIZE_CURSOR,
|
||||
GLFW_N_RESIZE_CURSOR,
|
||||
GLFW_SE_RESIZE_CURSOR,
|
||||
GLFW_INVALID_CURSOR
|
||||
GLFW_SW_RESIZE_CURSOR,
|
||||
GLFW_S_RESIZE_CURSOR,
|
||||
GLFW_W_RESIZE_CURSOR,
|
||||
GLFW_EW_RESIZE_CURSOR,
|
||||
GLFW_NS_RESIZE_CURSOR,
|
||||
GLFW_NESW_RESIZE_CURSOR,
|
||||
GLFW_NWSE_RESIZE_CURSOR,
|
||||
GLFW_ZOOM_IN_CURSOR,
|
||||
GLFW_ZOOM_OUT_CURSOR,
|
||||
GLFW_ALIAS_CURSOR,
|
||||
GLFW_COPY_CURSOR,
|
||||
GLFW_NOT_ALLOWED_CURSOR,
|
||||
GLFW_NO_DROP_CURSOR,
|
||||
GLFW_GRAB_CURSOR,
|
||||
GLFW_GRABBING_CURSOR,
|
||||
GLFW_INVALID_CURSOR,
|
||||
/* end mouse cursor shapes */
|
||||
} GLFWCursorShape;
|
||||
/*! @} */
|
||||
|
||||
|
12
glfw/wl_init.c
vendored
12
glfw/wl_init.c
vendored
@ -177,7 +177,7 @@ static void pointerHandleMotion(void* data UNUSED,
|
||||
wl_fixed_t sy)
|
||||
{
|
||||
_GLFWwindow* window = _glfw.wl.pointerFocus;
|
||||
GLFWCursorShape cursorShape = GLFW_ARROW_CURSOR;
|
||||
GLFWCursorShape cursorShape = GLFW_DEFAULT_CURSOR;
|
||||
|
||||
if (!window)
|
||||
return;
|
||||
@ -197,21 +197,21 @@ static void pointerHandleMotion(void* data UNUSED,
|
||||
return;
|
||||
case TOP_DECORATION:
|
||||
if (y < window->wl.decorations.metrics.width)
|
||||
cursorShape = GLFW_VRESIZE_CURSOR;
|
||||
cursorShape = GLFW_N_RESIZE_CURSOR;
|
||||
else
|
||||
cursorShape = GLFW_ARROW_CURSOR;
|
||||
cursorShape = GLFW_DEFAULT_CURSOR;
|
||||
break;
|
||||
case LEFT_DECORATION:
|
||||
if (y < window->wl.decorations.metrics.width)
|
||||
cursorShape = GLFW_NW_RESIZE_CURSOR;
|
||||
else
|
||||
cursorShape = GLFW_HRESIZE_CURSOR;
|
||||
cursorShape = GLFW_W_RESIZE_CURSOR;
|
||||
break;
|
||||
case RIGHT_DECORATION:
|
||||
if (y < window->wl.decorations.metrics.width)
|
||||
cursorShape = GLFW_NE_RESIZE_CURSOR;
|
||||
else
|
||||
cursorShape = GLFW_HRESIZE_CURSOR;
|
||||
cursorShape = GLFW_E_RESIZE_CURSOR;
|
||||
break;
|
||||
case BOTTOM_DECORATION:
|
||||
if (x < window->wl.decorations.metrics.width)
|
||||
@ -219,7 +219,7 @@ static void pointerHandleMotion(void* data UNUSED,
|
||||
else if (x > window->wl.width + window->wl.decorations.metrics.width)
|
||||
cursorShape = GLFW_SE_RESIZE_CURSOR;
|
||||
else
|
||||
cursorShape = GLFW_VRESIZE_CURSOR;
|
||||
cursorShape = GLFW_S_RESIZE_CURSOR;
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
|
43
glfw/wl_window.c
vendored
43
glfw/wl_window.c
vendored
@ -154,7 +154,7 @@ static struct wl_buffer* createShmBuffer(const GLFWimage* image, bool is_opaque,
|
||||
|
||||
static void
|
||||
setCursorImage(_GLFWwindow* window, bool on_theme_change) {
|
||||
_GLFWcursorWayland defaultCursor = {.shape = GLFW_ARROW_CURSOR};
|
||||
_GLFWcursorWayland defaultCursor = {.shape = GLFW_DEFAULT_CURSOR};
|
||||
_GLFWcursorWayland* cursorWayland = window->cursor ? &window->cursor->wl : &defaultCursor;
|
||||
struct wl_cursor_image* image = NULL;
|
||||
struct wl_buffer* buffer = NULL;
|
||||
@ -831,16 +831,37 @@ struct wl_cursor* _glfwLoadCursor(GLFWCursorShape shape, struct wl_cursor_theme*
|
||||
struct wl_cursor* ans = NULL;
|
||||
switch (shape)
|
||||
{
|
||||
C(GLFW_ARROW_CURSOR, "left_ptr", "arrow", "default")
|
||||
C(GLFW_IBEAM_CURSOR, "xterm", "ibeam", "text")
|
||||
C(GLFW_CROSSHAIR_CURSOR, "crosshair", "cross")
|
||||
C(GLFW_HAND_CURSOR, "hand2", "grab", "grabbing", "closedhand")
|
||||
C(GLFW_HRESIZE_CURSOR, "sb_h_double_arrow", "h_double_arrow", "col-resize")
|
||||
C(GLFW_VRESIZE_CURSOR, "sb_v_double_arrow", "v_double_arrow", "row-resize")
|
||||
C(GLFW_NW_RESIZE_CURSOR, "top_left_corner", "nw-resize")
|
||||
C(GLFW_NE_RESIZE_CURSOR, "top_right_corner", "ne-resize")
|
||||
C(GLFW_SW_RESIZE_CURSOR, "bottom_left_corner", "sw-resize")
|
||||
C(GLFW_SE_RESIZE_CURSOR, "bottom_right_corner", "se-resize")
|
||||
/* start glfw to xc mapping (auto generated by gen-key-constants.py do not edit) */
|
||||
C(GLFW_DEFAULT_CURSOR, "default", "left_ptr");
|
||||
C(GLFW_TEXT_CURSOR, "text", "xterm", "ibeam");
|
||||
C(GLFW_POINTER_CURSOR, "pointing_hand", "pointer", "hand2", "hand");
|
||||
C(GLFW_HELP_CURSOR, "help", "question_arrow", "whats_this");
|
||||
C(GLFW_WAIT_CURSOR, "wait", "clock", "watch");
|
||||
C(GLFW_PROGRESS_CURSOR, "progress", "half-busy", "left_ptr_watch");
|
||||
C(GLFW_CROSSHAIR_CURSOR, "crosshair", "tcross");
|
||||
C(GLFW_VERTICAL_TEXT_CURSOR, "vertical-text");
|
||||
C(GLFW_MOVE_CURSOR, "move", "fleur", "pointer-move");
|
||||
C(GLFW_E_RESIZE_CURSOR, "e-resize", "right_side");
|
||||
C(GLFW_NE_RESIZE_CURSOR, "ne-resize", "top_right_corner");
|
||||
C(GLFW_NW_RESIZE_CURSOR, "nw-resize", "top_left_corner");
|
||||
C(GLFW_N_RESIZE_CURSOR, "n-resize", "top_side");
|
||||
C(GLFW_SE_RESIZE_CURSOR, "se-resize", "bottom_right_corner");
|
||||
C(GLFW_SW_RESIZE_CURSOR, "sw-resize", "bottom_left_corner");
|
||||
C(GLFW_S_RESIZE_CURSOR, "s-resize", "bottom_side");
|
||||
C(GLFW_W_RESIZE_CURSOR, "w-resize", "left_side");
|
||||
C(GLFW_EW_RESIZE_CURSOR, "ew-resize", "sb_h_double_arrow", "split_h");
|
||||
C(GLFW_NS_RESIZE_CURSOR, "ns-resize", "sb_v_double_arrow", "split_v");
|
||||
C(GLFW_NESW_RESIZE_CURSOR, "nesw-resize", "size_bdiag", "sb_v_double_arrow");
|
||||
C(GLFW_NWSE_RESIZE_CURSOR, "nwse-resize", "size_fdiag", "sb_h_double_arrow");
|
||||
C(GLFW_ZOOM_IN_CURSOR, "zoom-in", "zoom_in");
|
||||
C(GLFW_ZOOM_OUT_CURSOR, "zoom-out", "zoom_out");
|
||||
C(GLFW_ALIAS_CURSOR, "dnd-link");
|
||||
C(GLFW_COPY_CURSOR, "dnd-copy");
|
||||
C(GLFW_NOT_ALLOWED_CURSOR, "not-allowed", "forbidden", "crossed_circle");
|
||||
C(GLFW_NO_DROP_CURSOR, "no-drop", "dnd-no-drop");
|
||||
C(GLFW_GRAB_CURSOR, "grab", "openhand", "hand1");
|
||||
C(GLFW_GRABBING_CURSOR, "grabbing", "closedhand", "dnd-none");
|
||||
/* end glfw to xc mapping */
|
||||
case GLFW_INVALID_CURSOR:
|
||||
break;
|
||||
}
|
||||
|
86
glfw/x11_window.c
vendored
86
glfw/x11_window.c
vendored
@ -2811,37 +2811,77 @@ int _glfwPlatformCreateCursor(_GLFWcursor* cursor,
|
||||
return true;
|
||||
}
|
||||
|
||||
int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, GLFWCursorShape shape)
|
||||
{
|
||||
int native = 0;
|
||||
#define C(name, val) case name: native = val; break;
|
||||
switch(shape) {
|
||||
C(GLFW_ARROW_CURSOR, XC_left_ptr);
|
||||
C(GLFW_IBEAM_CURSOR, XC_xterm);
|
||||
C(GLFW_CROSSHAIR_CURSOR, XC_crosshair);
|
||||
C(GLFW_HAND_CURSOR, XC_hand2);
|
||||
C(GLFW_HRESIZE_CURSOR, XC_sb_h_double_arrow);
|
||||
C(GLFW_VRESIZE_CURSOR, XC_sb_v_double_arrow);
|
||||
C(GLFW_NW_RESIZE_CURSOR, XC_top_left_corner);
|
||||
C(GLFW_NE_RESIZE_CURSOR, XC_top_right_corner);
|
||||
C(GLFW_SW_RESIZE_CURSOR, XC_bottom_left_corner);
|
||||
C(GLFW_SE_RESIZE_CURSOR, XC_bottom_right_corner);
|
||||
case GLFW_INVALID_CURSOR:
|
||||
return false;
|
||||
}
|
||||
#undef C
|
||||
|
||||
static int
|
||||
set_cursor_from_font(_GLFWcursor* cursor, int native) {
|
||||
cursor->x11.handle = XCreateFontCursor(_glfw.x11.display, native);
|
||||
if (!cursor->x11.handle)
|
||||
{
|
||||
if (!cursor->x11.handle) {
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"X11: Failed to create standard cursor");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
try_cursor_names(_GLFWcursor *cursor, int arg_count, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, arg_count);
|
||||
const char *first_name = "";
|
||||
for (int i = 0; i < arg_count; i++) {
|
||||
const char *name = va_arg(ap, const char *);
|
||||
first_name = name;
|
||||
cursor->x11.handle = XcursorLibraryLoadCursor(_glfw.x11.display, name);
|
||||
if (cursor->x11.handle) break;
|
||||
}
|
||||
va_end(ap);
|
||||
if (!cursor->x11.handle) {
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"X11: Failed to load standard cursor: %s with %d aliases via Xcursor library", first_name, arg_count);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, GLFWCursorShape shape)
|
||||
{
|
||||
switch(shape) {
|
||||
/* start glfw to xc mapping (auto generated by gen-key-constants.py do not edit) */
|
||||
case GLFW_DEFAULT_CURSOR: return set_cursor_from_font(cursor, XC_left_ptr);
|
||||
case GLFW_TEXT_CURSOR: return set_cursor_from_font(cursor, XC_xterm);
|
||||
case GLFW_POINTER_CURSOR: return set_cursor_from_font(cursor, XC_hand2);
|
||||
case GLFW_HELP_CURSOR: return set_cursor_from_font(cursor, XC_question_arrow);
|
||||
case GLFW_WAIT_CURSOR: return set_cursor_from_font(cursor, XC_clock);
|
||||
case GLFW_PROGRESS_CURSOR: return try_cursor_names(cursor, 3, "progress", "half-busy", "left_ptr_watch");
|
||||
case GLFW_CROSSHAIR_CURSOR: return set_cursor_from_font(cursor, XC_tcross);
|
||||
case GLFW_VERTICAL_TEXT_CURSOR: return try_cursor_names(cursor, 1, "vertical-text");
|
||||
case GLFW_MOVE_CURSOR: return set_cursor_from_font(cursor, XC_fleur);
|
||||
case GLFW_E_RESIZE_CURSOR: return set_cursor_from_font(cursor, XC_right_side);
|
||||
case GLFW_NE_RESIZE_CURSOR: return set_cursor_from_font(cursor, XC_top_right_corner);
|
||||
case GLFW_NW_RESIZE_CURSOR: return set_cursor_from_font(cursor, XC_top_left_corner);
|
||||
case GLFW_N_RESIZE_CURSOR: return set_cursor_from_font(cursor, XC_top_side);
|
||||
case GLFW_SE_RESIZE_CURSOR: return set_cursor_from_font(cursor, XC_bottom_right_corner);
|
||||
case GLFW_SW_RESIZE_CURSOR: return set_cursor_from_font(cursor, XC_bottom_left_corner);
|
||||
case GLFW_S_RESIZE_CURSOR: return set_cursor_from_font(cursor, XC_bottom_side);
|
||||
case GLFW_W_RESIZE_CURSOR: return set_cursor_from_font(cursor, XC_left_side);
|
||||
case GLFW_EW_RESIZE_CURSOR: return set_cursor_from_font(cursor, XC_sb_h_double_arrow);
|
||||
case GLFW_NS_RESIZE_CURSOR: return set_cursor_from_font(cursor, XC_sb_v_double_arrow);
|
||||
case GLFW_NESW_RESIZE_CURSOR: return set_cursor_from_font(cursor, XC_sb_v_double_arrow);
|
||||
case GLFW_NWSE_RESIZE_CURSOR: return set_cursor_from_font(cursor, XC_sb_h_double_arrow);
|
||||
case GLFW_ZOOM_IN_CURSOR: return try_cursor_names(cursor, 2, "zoom-in", "zoom_in");
|
||||
case GLFW_ZOOM_OUT_CURSOR: return try_cursor_names(cursor, 2, "zoom-out", "zoom_out");
|
||||
case GLFW_ALIAS_CURSOR: return try_cursor_names(cursor, 1, "dnd-link");
|
||||
case GLFW_COPY_CURSOR: return try_cursor_names(cursor, 1, "dnd-copy");
|
||||
case GLFW_NOT_ALLOWED_CURSOR: return try_cursor_names(cursor, 3, "not-allowed", "forbidden", "crossed_circle");
|
||||
case GLFW_NO_DROP_CURSOR: return try_cursor_names(cursor, 2, "no-drop", "dnd-no-drop");
|
||||
case GLFW_GRAB_CURSOR: return set_cursor_from_font(cursor, XC_hand1);
|
||||
case GLFW_GRABBING_CURSOR: return try_cursor_names(cursor, 3, "grabbing", "closedhand", "dnd-none");
|
||||
/* end glfw to xc mapping */
|
||||
case GLFW_INVALID_CURSOR: return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void _glfwPlatformDestroyCursor(_GLFWcursor* cursor)
|
||||
{
|
||||
if (cursor->x11.handle)
|
||||
|
@ -68,7 +68,40 @@ typedef enum { DISABLE_LIGATURES_NEVER, DISABLE_LIGATURES_CURSOR, DISABLE_LIGATU
|
||||
#define ERROR_PREFIX "[PARSE ERROR]"
|
||||
typedef enum MouseTrackingModes { NO_TRACKING, BUTTON_MODE, MOTION_MODE, ANY_MODE } MouseTrackingMode;
|
||||
typedef enum MouseTrackingProtocols { NORMAL_PROTOCOL, UTF8_PROTOCOL, SGR_PROTOCOL, URXVT_PROTOCOL, SGR_PIXEL_PROTOCOL} MouseTrackingProtocol;
|
||||
typedef enum MouseShapes { BEAM, HAND, ARROW } MouseShape;
|
||||
typedef enum MouseShapes {
|
||||
INVALID_POINTER,
|
||||
/* start mouse shapes (auto generated by gen-key-constants.py do not edit) */
|
||||
DEFAULT_POINTER,
|
||||
TEXT_POINTER,
|
||||
POINTER_POINTER,
|
||||
HELP_POINTER,
|
||||
WAIT_POINTER,
|
||||
PROGRESS_POINTER,
|
||||
CROSSHAIR_POINTER,
|
||||
VERTICAL_TEXT_POINTER,
|
||||
MOVE_POINTER,
|
||||
E_RESIZE_POINTER,
|
||||
NE_RESIZE_POINTER,
|
||||
NW_RESIZE_POINTER,
|
||||
N_RESIZE_POINTER,
|
||||
SE_RESIZE_POINTER,
|
||||
SW_RESIZE_POINTER,
|
||||
S_RESIZE_POINTER,
|
||||
W_RESIZE_POINTER,
|
||||
EW_RESIZE_POINTER,
|
||||
NS_RESIZE_POINTER,
|
||||
NESW_RESIZE_POINTER,
|
||||
NWSE_RESIZE_POINTER,
|
||||
ZOOM_IN_POINTER,
|
||||
ZOOM_OUT_POINTER,
|
||||
ALIAS_POINTER,
|
||||
COPY_POINTER,
|
||||
NOT_ALLOWED_POINTER,
|
||||
NO_DROP_POINTER,
|
||||
GRAB_POINTER,
|
||||
GRABBING_POINTER,
|
||||
/* end mouse shapes */
|
||||
} MouseShape;
|
||||
typedef enum { NONE, MENUBAR, WINDOW, ALL } WindowTitleIn;
|
||||
typedef enum { TILING, SCALED, MIRRORED, CLAMPED, CENTER_CLAMPED, CENTER_SCALED } BackgroundImageLayout;
|
||||
typedef struct ImageAnchorPosition {
|
||||
|
@ -43,7 +43,6 @@ IMPERATIVE_CLOSE_REQUESTED: int
|
||||
CLOSE_BEING_CONFIRMED: int
|
||||
ERROR_PREFIX: str
|
||||
GLSL_VERSION: int
|
||||
GLFW_IBEAM_CURSOR: int
|
||||
# start glfw functional keys (auto generated by gen-key-constants.py do not edit)
|
||||
GLFW_FKEY_ESCAPE: int
|
||||
GLFW_FKEY_ENTER: int
|
||||
@ -565,7 +564,7 @@ def set_default_window_icon(path: str) -> None:
|
||||
|
||||
|
||||
def set_custom_cursor(
|
||||
cursor_type: int,
|
||||
cursor_shape: str,
|
||||
images: Tuple[Tuple[bytes, int, int], ...],
|
||||
x: int = 0,
|
||||
y: int = 0
|
||||
|
37
kitty/glfw-wrapper.h
generated
37
kitty/glfw-wrapper.h
generated
@ -837,17 +837,38 @@ typedef enum {
|
||||
* @{ */
|
||||
|
||||
typedef enum {
|
||||
GLFW_ARROW_CURSOR,
|
||||
GLFW_IBEAM_CURSOR,
|
||||
/* start mouse cursor shapes (auto generated by gen-key-constants.py do not edit) */
|
||||
GLFW_DEFAULT_CURSOR,
|
||||
GLFW_TEXT_CURSOR,
|
||||
GLFW_POINTER_CURSOR,
|
||||
GLFW_HELP_CURSOR,
|
||||
GLFW_WAIT_CURSOR,
|
||||
GLFW_PROGRESS_CURSOR,
|
||||
GLFW_CROSSHAIR_CURSOR,
|
||||
GLFW_HAND_CURSOR,
|
||||
GLFW_HRESIZE_CURSOR,
|
||||
GLFW_VRESIZE_CURSOR,
|
||||
GLFW_NW_RESIZE_CURSOR,
|
||||
GLFW_VERTICAL_TEXT_CURSOR,
|
||||
GLFW_MOVE_CURSOR,
|
||||
GLFW_E_RESIZE_CURSOR,
|
||||
GLFW_NE_RESIZE_CURSOR,
|
||||
GLFW_SW_RESIZE_CURSOR,
|
||||
GLFW_NW_RESIZE_CURSOR,
|
||||
GLFW_N_RESIZE_CURSOR,
|
||||
GLFW_SE_RESIZE_CURSOR,
|
||||
GLFW_INVALID_CURSOR
|
||||
GLFW_SW_RESIZE_CURSOR,
|
||||
GLFW_S_RESIZE_CURSOR,
|
||||
GLFW_W_RESIZE_CURSOR,
|
||||
GLFW_EW_RESIZE_CURSOR,
|
||||
GLFW_NS_RESIZE_CURSOR,
|
||||
GLFW_NESW_RESIZE_CURSOR,
|
||||
GLFW_NWSE_RESIZE_CURSOR,
|
||||
GLFW_ZOOM_IN_CURSOR,
|
||||
GLFW_ZOOM_OUT_CURSOR,
|
||||
GLFW_ALIAS_CURSOR,
|
||||
GLFW_COPY_CURSOR,
|
||||
GLFW_NOT_ALLOWED_CURSOR,
|
||||
GLFW_NO_DROP_CURSOR,
|
||||
GLFW_GRAB_CURSOR,
|
||||
GLFW_GRABBING_CURSOR,
|
||||
GLFW_INVALID_CURSOR,
|
||||
/* end mouse cursor shapes */
|
||||
} GLFWCursorShape;
|
||||
/*! @} */
|
||||
|
||||
|
135
kitty/glfw.c
135
kitty/glfw.c
@ -33,7 +33,12 @@ extern size_t cocoa_get_workspace_ids(void *w, size_t *workspace_ids, size_t arr
|
||||
extern monotonic_t cocoa_cursor_blink_interval(void);
|
||||
|
||||
|
||||
static GLFWcursor *standard_cursor = NULL, *click_cursor = NULL, *arrow_cursor = NULL;
|
||||
typedef struct mouse_cursor {
|
||||
GLFWcursor *glfw;
|
||||
bool initialized, is_custom;
|
||||
} mouse_cursor;
|
||||
|
||||
static mouse_cursor cursors[GLFW_INVALID_CURSOR+1] = {0};
|
||||
|
||||
static void set_os_window_dpi(OSWindow *w);
|
||||
|
||||
@ -675,20 +680,52 @@ draw_single_ascii_char(const char ch, size_t *result_width, size_t *result_heigh
|
||||
#endif
|
||||
// }}}
|
||||
|
||||
static void
|
||||
set_glfw_mouse_cursor(GLFWwindow *w, GLFWCursorShape shape) {
|
||||
if (!cursors[shape].initialized) {
|
||||
cursors[shape].initialized = true;
|
||||
cursors[shape].glfw = glfwCreateStandardCursor(shape);
|
||||
}
|
||||
if (cursors[shape].glfw) glfwSetCursor(w, cursors[shape].glfw);
|
||||
}
|
||||
|
||||
void
|
||||
set_mouse_cursor(MouseShape type) {
|
||||
if (global_state.callback_os_window) {
|
||||
GLFWwindow *w = (GLFWwindow*)global_state.callback_os_window->handle;
|
||||
switch(type) {
|
||||
case HAND:
|
||||
glfwSetCursor(w, click_cursor);
|
||||
break;
|
||||
case ARROW:
|
||||
glfwSetCursor(w, arrow_cursor);
|
||||
break;
|
||||
default:
|
||||
glfwSetCursor(w, standard_cursor);
|
||||
break;
|
||||
case INVALID_POINTER: break;
|
||||
/* start enum to glfw (auto generated by gen-key-constants.py do not edit) */
|
||||
case DEFAULT_POINTER: set_glfw_mouse_cursor(w, GLFW_DEFAULT_CURSOR); break;
|
||||
case TEXT_POINTER: set_glfw_mouse_cursor(w, GLFW_TEXT_CURSOR); break;
|
||||
case POINTER_POINTER: set_glfw_mouse_cursor(w, GLFW_POINTER_CURSOR); break;
|
||||
case HELP_POINTER: set_glfw_mouse_cursor(w, GLFW_HELP_CURSOR); break;
|
||||
case WAIT_POINTER: set_glfw_mouse_cursor(w, GLFW_WAIT_CURSOR); break;
|
||||
case PROGRESS_POINTER: set_glfw_mouse_cursor(w, GLFW_PROGRESS_CURSOR); break;
|
||||
case CROSSHAIR_POINTER: set_glfw_mouse_cursor(w, GLFW_CROSSHAIR_CURSOR); break;
|
||||
case VERTICAL_TEXT_POINTER: set_glfw_mouse_cursor(w, GLFW_VERTICAL_TEXT_CURSOR); break;
|
||||
case MOVE_POINTER: set_glfw_mouse_cursor(w, GLFW_MOVE_CURSOR); break;
|
||||
case E_RESIZE_POINTER: set_glfw_mouse_cursor(w, GLFW_E_RESIZE_CURSOR); break;
|
||||
case NE_RESIZE_POINTER: set_glfw_mouse_cursor(w, GLFW_NE_RESIZE_CURSOR); break;
|
||||
case NW_RESIZE_POINTER: set_glfw_mouse_cursor(w, GLFW_NW_RESIZE_CURSOR); break;
|
||||
case N_RESIZE_POINTER: set_glfw_mouse_cursor(w, GLFW_N_RESIZE_CURSOR); break;
|
||||
case SE_RESIZE_POINTER: set_glfw_mouse_cursor(w, GLFW_SE_RESIZE_CURSOR); break;
|
||||
case SW_RESIZE_POINTER: set_glfw_mouse_cursor(w, GLFW_SW_RESIZE_CURSOR); break;
|
||||
case S_RESIZE_POINTER: set_glfw_mouse_cursor(w, GLFW_S_RESIZE_CURSOR); break;
|
||||
case W_RESIZE_POINTER: set_glfw_mouse_cursor(w, GLFW_W_RESIZE_CURSOR); break;
|
||||
case EW_RESIZE_POINTER: set_glfw_mouse_cursor(w, GLFW_EW_RESIZE_CURSOR); break;
|
||||
case NS_RESIZE_POINTER: set_glfw_mouse_cursor(w, GLFW_NS_RESIZE_CURSOR); break;
|
||||
case NESW_RESIZE_POINTER: set_glfw_mouse_cursor(w, GLFW_NESW_RESIZE_CURSOR); break;
|
||||
case NWSE_RESIZE_POINTER: set_glfw_mouse_cursor(w, GLFW_NWSE_RESIZE_CURSOR); break;
|
||||
case ZOOM_IN_POINTER: set_glfw_mouse_cursor(w, GLFW_ZOOM_IN_CURSOR); break;
|
||||
case ZOOM_OUT_POINTER: set_glfw_mouse_cursor(w, GLFW_ZOOM_OUT_CURSOR); break;
|
||||
case ALIAS_POINTER: set_glfw_mouse_cursor(w, GLFW_ALIAS_CURSOR); break;
|
||||
case COPY_POINTER: set_glfw_mouse_cursor(w, GLFW_COPY_CURSOR); break;
|
||||
case NOT_ALLOWED_POINTER: set_glfw_mouse_cursor(w, GLFW_NOT_ALLOWED_CURSOR); break;
|
||||
case NO_DROP_POINTER: set_glfw_mouse_cursor(w, GLFW_NO_DROP_CURSOR); break;
|
||||
case GRAB_POINTER: set_glfw_mouse_cursor(w, GLFW_GRAB_CURSOR); break;
|
||||
case GRABBING_POINTER: set_glfw_mouse_cursor(w, GLFW_GRABBING_CURSOR); break;
|
||||
/* end enum to glfw */
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1090,13 +1127,6 @@ create_os_window(PyObject UNUSED *self, PyObject *args, PyObject *kw) {
|
||||
PyObject *ret = PyObject_CallFunction(load_programs, "O", is_semi_transparent ? Py_True : Py_False);
|
||||
if (ret == NULL) return NULL;
|
||||
Py_DECREF(ret);
|
||||
#define CC(dest, shape) {\
|
||||
if (!dest##_cursor) { \
|
||||
dest##_cursor = glfwCreateStandardCursor(GLFW_##shape##_CURSOR); \
|
||||
if (dest##_cursor == NULL) { log_error("Failed to create the %s mouse cursor, using default cursor.", #shape); } \
|
||||
}}
|
||||
CC(standard, IBEAM); CC(click, HAND); CC(arrow, ARROW);
|
||||
#undef CC
|
||||
get_platform_dependent_config_values(glfw_window);
|
||||
is_first_window = false;
|
||||
}
|
||||
@ -1121,7 +1151,7 @@ create_os_window(PyObject UNUSED *self, PyObject *args, PyObject *kw) {
|
||||
#endif
|
||||
send_prerendered_sprites_for_window(w);
|
||||
if (logo.pixels && logo.width && logo.height) glfwSetWindowIcon(glfw_window, 1, &logo);
|
||||
glfwSetCursor(glfw_window, standard_cursor);
|
||||
set_glfw_mouse_cursor(glfw_window, GLFW_TEXT_CURSOR);
|
||||
update_os_window_viewport(w, false);
|
||||
glfwSetWindowPosCallback(glfw_window, window_pos_callback);
|
||||
// missing size callback
|
||||
@ -1310,6 +1340,12 @@ glfw_init(PyObject UNUSED *self, PyObject *args) {
|
||||
|
||||
static PyObject*
|
||||
glfw_terminate(PYNOARG) {
|
||||
for (size_t i = 0; i < arraysz(cursors); i++) {
|
||||
if (cursors[i].is_custom && cursors[i].glfw) {
|
||||
glfwDestroyCursor(cursors[i].glfw);
|
||||
cursors[i] = (mouse_cursor){0};
|
||||
}
|
||||
}
|
||||
glfwTerminate();
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
@ -1692,13 +1728,51 @@ cocoa_window_id(PyObject UNUSED *self, PyObject *os_wid) {
|
||||
#endif
|
||||
}
|
||||
|
||||
static GLFWCursorShape
|
||||
pointer_name_to_glfw_name(const char *name) {
|
||||
/* start name to glfw (auto generated by gen-key-constants.py do not edit) */
|
||||
if (strcmp(name, "arrow") == 0) return GLFW_DEFAULT_CURSOR;
|
||||
if (strcmp(name, "beam") == 0) return GLFW_TEXT_CURSOR;
|
||||
if (strcmp(name, "text") == 0) return GLFW_TEXT_CURSOR;
|
||||
if (strcmp(name, "pointer") == 0) return GLFW_POINTER_CURSOR;
|
||||
if (strcmp(name, "hand") == 0) return GLFW_POINTER_CURSOR;
|
||||
if (strcmp(name, "help") == 0) return GLFW_HELP_CURSOR;
|
||||
if (strcmp(name, "wait") == 0) return GLFW_WAIT_CURSOR;
|
||||
if (strcmp(name, "progress") == 0) return GLFW_PROGRESS_CURSOR;
|
||||
if (strcmp(name, "crosshair") == 0) return GLFW_CROSSHAIR_CURSOR;
|
||||
if (strcmp(name, "vertical-text") == 0) return GLFW_VERTICAL_TEXT_CURSOR;
|
||||
if (strcmp(name, "move") == 0) return GLFW_MOVE_CURSOR;
|
||||
if (strcmp(name, "e-resize") == 0) return GLFW_E_RESIZE_CURSOR;
|
||||
if (strcmp(name, "ne-resize") == 0) return GLFW_NE_RESIZE_CURSOR;
|
||||
if (strcmp(name, "nw-resize") == 0) return GLFW_NW_RESIZE_CURSOR;
|
||||
if (strcmp(name, "n-resize") == 0) return GLFW_N_RESIZE_CURSOR;
|
||||
if (strcmp(name, "se-resize") == 0) return GLFW_SE_RESIZE_CURSOR;
|
||||
if (strcmp(name, "sw-resize") == 0) return GLFW_SW_RESIZE_CURSOR;
|
||||
if (strcmp(name, "s-resize") == 0) return GLFW_S_RESIZE_CURSOR;
|
||||
if (strcmp(name, "w-resize") == 0) return GLFW_W_RESIZE_CURSOR;
|
||||
if (strcmp(name, "ew-resize") == 0) return GLFW_EW_RESIZE_CURSOR;
|
||||
if (strcmp(name, "ns-resize") == 0) return GLFW_NS_RESIZE_CURSOR;
|
||||
if (strcmp(name, "nesw-resize") == 0) return GLFW_NESW_RESIZE_CURSOR;
|
||||
if (strcmp(name, "nwse-resize") == 0) return GLFW_NWSE_RESIZE_CURSOR;
|
||||
if (strcmp(name, "zoom-in") == 0) return GLFW_ZOOM_IN_CURSOR;
|
||||
if (strcmp(name, "zoom-out") == 0) return GLFW_ZOOM_OUT_CURSOR;
|
||||
if (strcmp(name, "alias") == 0) return GLFW_ALIAS_CURSOR;
|
||||
if (strcmp(name, "copy") == 0) return GLFW_COPY_CURSOR;
|
||||
if (strcmp(name, "not-allowed") == 0) return GLFW_NOT_ALLOWED_CURSOR;
|
||||
if (strcmp(name, "no-drop") == 0) return GLFW_NO_DROP_CURSOR;
|
||||
if (strcmp(name, "grab") == 0) return GLFW_GRAB_CURSOR;
|
||||
if (strcmp(name, "grabbing") == 0) return GLFW_GRABBING_CURSOR;
|
||||
/* end name to glfw */
|
||||
return GLFW_INVALID_CURSOR;
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
set_custom_cursor(PyObject *self UNUSED, PyObject *args) {
|
||||
int shape;
|
||||
int x=0, y=0;
|
||||
Py_ssize_t sz;
|
||||
PyObject *images;
|
||||
if (!PyArg_ParseTuple(args, "iO!|ii", &shape, &PyTuple_Type, &images, &x, &y)) return NULL;
|
||||
const char *shape;
|
||||
if (!PyArg_ParseTuple(args, "sO!|ii", &shape, &PyTuple_Type, &images, &x, &y)) return NULL;
|
||||
static GLFWimage gimages[16] = {{0}};
|
||||
size_t count = MIN((size_t)PyTuple_GET_SIZE(images), arraysz(gimages));
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
@ -1708,20 +1782,14 @@ set_custom_cursor(PyObject *self UNUSED, PyObject *args) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
#define CASE(which, dest) {\
|
||||
case which: \
|
||||
dest = glfwCreateCursor(gimages, x, y, count); \
|
||||
if (dest == NULL) { PyErr_SetString(PyExc_ValueError, "Failed to create custom cursor"); return NULL; } \
|
||||
break; \
|
||||
}
|
||||
switch(shape) {
|
||||
CASE(GLFW_IBEAM_CURSOR, standard_cursor);
|
||||
CASE(GLFW_HAND_CURSOR, click_cursor);
|
||||
CASE(GLFW_ARROW_CURSOR, arrow_cursor);
|
||||
default:
|
||||
PyErr_SetString(PyExc_ValueError, "Unknown cursor shape");
|
||||
return NULL;
|
||||
GLFWCursorShape gshape = pointer_name_to_glfw_name(shape);
|
||||
if (gshape == GLFW_INVALID_CURSOR) { PyErr_Format(PyExc_KeyError, "Unknown pointer shape: %s", shape); return NULL; }
|
||||
GLFWcursor *c = glfwCreateCursor(gimages, x, y, count);
|
||||
if (c == NULL) { PyErr_SetString(PyExc_ValueError, "Failed to create custom cursor from specified images"); return NULL; }
|
||||
if (cursors[gshape].initialized && cursors[gshape].is_custom && cursors[gshape].glfw) {
|
||||
glfwDestroyCursor(cursors[gshape].glfw);
|
||||
}
|
||||
cursors[gshape].initialized = true; cursors[gshape].is_custom = true; cursors[gshape].glfw = c;
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
@ -2002,7 +2070,6 @@ init_glfw(PyObject *m) {
|
||||
ADDC(GLFW_PRESS);
|
||||
ADDC(GLFW_REPEAT);
|
||||
ADDC(true); ADDC(false);
|
||||
ADDC(GLFW_IBEAM_CURSOR); ADDC(GLFW_HAND_CURSOR); ADDC(GLFW_ARROW_CURSOR);
|
||||
ADDC(GLFW_PRIMARY_SELECTION); ADDC(GLFW_CLIPBOARD);
|
||||
|
||||
/* start glfw functional keys (auto generated by gen-key-constants.py do not edit) */
|
||||
|
@ -30,7 +30,6 @@
|
||||
website_url,
|
||||
)
|
||||
from .fast_data_types import (
|
||||
GLFW_IBEAM_CURSOR,
|
||||
GLFW_MOD_ALT,
|
||||
GLFW_MOD_SHIFT,
|
||||
SingleKey,
|
||||
@ -76,7 +75,7 @@ def set_custom_ibeam_cursor() -> None:
|
||||
rgba_data2, width2, height2 = load_png_data(data)
|
||||
images = (rgba_data, width, height), (rgba_data2, width2, height2)
|
||||
try:
|
||||
set_custom_cursor(GLFW_IBEAM_CURSOR, images, 4, 8)
|
||||
set_custom_cursor("beam", images, 4, 8)
|
||||
except Exception as e:
|
||||
log_error(f'Failed to set custom beam cursor with error: {e}')
|
||||
|
||||
|
@ -17,7 +17,7 @@
|
||||
|
||||
extern PyTypeObject Screen_Type;
|
||||
|
||||
static MouseShape mouse_cursor_shape = BEAM;
|
||||
static MouseShape mouse_cursor_shape = TEXT_POINTER;
|
||||
typedef enum MouseActions { PRESS, RELEASE, DRAG, MOVE } MouseAction;
|
||||
#define debug(...) if (OPT(debug_keyboard)) printf(__VA_ARGS__);
|
||||
|
||||
@ -288,8 +288,8 @@ do_drag_scroll(Window *w, bool upwards) {
|
||||
if (screen->linebuf == screen->main_linebuf) {
|
||||
screen_history_scroll(screen, SCROLL_LINE, upwards);
|
||||
update_drag(w);
|
||||
if (mouse_cursor_shape != ARROW) {
|
||||
mouse_cursor_shape = ARROW;
|
||||
if (mouse_cursor_shape != DEFAULT_POINTER) {
|
||||
mouse_cursor_shape = DEFAULT_POINTER;
|
||||
set_mouse_cursor(mouse_cursor_shape);
|
||||
}
|
||||
return true;
|
||||
@ -347,7 +347,7 @@ detect_url(Screen *screen, unsigned int x, unsigned int y) {
|
||||
int hid = screen_detect_url(screen, x, y);
|
||||
screen->current_hyperlink_under_mouse.id = 0;
|
||||
if (hid != 0) {
|
||||
mouse_cursor_shape = HAND;
|
||||
mouse_cursor_shape = POINTER_POINTER;
|
||||
if (hid > 0) {
|
||||
screen->current_hyperlink_under_mouse.id = (hyperlink_id_type)hid;
|
||||
screen->current_hyperlink_under_mouse.x = x;
|
||||
@ -655,7 +655,7 @@ focus_in_event(void) {
|
||||
// Ensure that no URL is highlighted and the mouse cursor is in default shape
|
||||
bool in_tab_bar;
|
||||
unsigned int window_idx = 0;
|
||||
mouse_cursor_shape = BEAM;
|
||||
mouse_cursor_shape = TEXT_POINTER;
|
||||
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);
|
||||
@ -817,7 +817,7 @@ mouse_event(const int button, int modifiers, int action) {
|
||||
}
|
||||
w = window_for_event(&window_idx, &in_tab_bar);
|
||||
if (in_tab_bar) {
|
||||
mouse_cursor_shape = HAND;
|
||||
mouse_cursor_shape = POINTER_POINTER;
|
||||
handle_tab_bar_mouse(button, modifiers, action);
|
||||
debug("handled by tab bar\n");
|
||||
} else if (w) {
|
||||
|
@ -588,27 +588,61 @@
|
||||
'''
|
||||
)
|
||||
|
||||
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',
|
||||
'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=('arrow', 'beam', 'hand'), ctype='pointer_shape',
|
||||
choices=pointer_shape_names, ctype='pointer_shape',
|
||||
long_text='''
|
||||
The shape of the mouse pointer when the program running in the terminal grabs
|
||||
the mouse. Valid values are: :code:`arrow`, :code:`beam` and :code:`hand`.
|
||||
the mouse.
|
||||
'''
|
||||
)
|
||||
|
||||
opt('default_pointer_shape', 'beam',
|
||||
choices=('arrow', 'beam', 'hand'), ctype='pointer_shape',
|
||||
choices=pointer_shape_names, ctype='pointer_shape',
|
||||
long_text='''
|
||||
The default shape of the mouse pointer. Valid values are: :code:`arrow`,
|
||||
:code:`beam` and :code:`hand`.
|
||||
The default shape of the mouse pointer.
|
||||
'''
|
||||
)
|
||||
|
||||
opt('pointer_shape_when_dragging', 'beam',
|
||||
choices=('arrow', 'beam', 'hand'), ctype='pointer_shape',
|
||||
choices=pointer_shape_names, ctype='pointer_shape',
|
||||
long_text='''
|
||||
The default shape of the mouse pointer when dragging across text. Valid values
|
||||
are: :code:`arrow`, :code:`beam` and :code:`hand`.
|
||||
The default shape of the mouse pointer when dragging across text.
|
||||
'''
|
||||
)
|
||||
|
||||
|
6
kitty/options/parse.py
generated
6
kitty/options/parse.py
generated
@ -934,7 +934,7 @@ def default_pointer_shape(self, val: str, ans: typing.Dict[str, typing.Any]) ->
|
||||
raise ValueError(f"The value {val} is not a valid choice for default_pointer_shape")
|
||||
ans["default_pointer_shape"] = val
|
||||
|
||||
choices_for_default_pointer_shape = frozenset(('arrow', 'beam', 'hand'))
|
||||
choices_for_default_pointer_shape = frozenset(('arrow', 'beam', 'text', 'pointer', 'hand', 'help', 'wait', 'progress', 'crosshair', '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'))
|
||||
|
||||
def detect_urls(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
|
||||
ans['detect_urls'] = to_bool(val)
|
||||
@ -1140,7 +1140,7 @@ def pointer_shape_when_dragging(self, val: str, ans: typing.Dict[str, typing.Any
|
||||
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 = frozenset(('arrow', 'beam', 'hand'))
|
||||
choices_for_pointer_shape_when_dragging = frozenset(('arrow', 'beam', 'text', 'pointer', 'hand', 'help', 'wait', 'progress', 'crosshair', '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'))
|
||||
|
||||
def pointer_shape_when_grabbed(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
|
||||
val = val.lower()
|
||||
@ -1148,7 +1148,7 @@ def pointer_shape_when_grabbed(self, val: str, ans: typing.Dict[str, typing.Any]
|
||||
raise ValueError(f"The value {val} is not a valid choice for pointer_shape_when_grabbed")
|
||||
ans["pointer_shape_when_grabbed"] = val
|
||||
|
||||
choices_for_pointer_shape_when_grabbed = frozenset(('arrow', 'beam', 'hand'))
|
||||
choices_for_pointer_shape_when_grabbed = frozenset(('arrow', 'beam', 'text', 'pointer', 'hand', 'help', 'wait', 'progress', 'crosshair', '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'))
|
||||
|
||||
def remember_window_size(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
|
||||
ans['remember_window_size'] = to_bool(val)
|
||||
|
@ -133,13 +133,41 @@ modify_font(PyObject *mf, Options *opts) {
|
||||
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;
|
||||
if (!name) return TEXT_POINTER;
|
||||
/* start pointer shapes (auto generated by gen-key-constants.py do not edit) */
|
||||
else if (strcmp(name, "arrow") == 0) return DEFAULT_POINTER;
|
||||
else if (strcmp(name, "beam") == 0) return TEXT_POINTER;
|
||||
else if (strcmp(name, "text") == 0) return TEXT_POINTER;
|
||||
else if (strcmp(name, "pointer") == 0) return POINTER_POINTER;
|
||||
else if (strcmp(name, "hand") == 0) return POINTER_POINTER;
|
||||
else if (strcmp(name, "help") == 0) return HELP_POINTER;
|
||||
else if (strcmp(name, "wait") == 0) return WAIT_POINTER;
|
||||
else if (strcmp(name, "progress") == 0) return PROGRESS_POINTER;
|
||||
else if (strcmp(name, "crosshair") == 0) return CROSSHAIR_POINTER;
|
||||
else if (strcmp(name, "vertical-text") == 0) return VERTICAL_TEXT_POINTER;
|
||||
else if (strcmp(name, "move") == 0) return MOVE_POINTER;
|
||||
else if (strcmp(name, "e-resize") == 0) return E_RESIZE_POINTER;
|
||||
else if (strcmp(name, "ne-resize") == 0) return NE_RESIZE_POINTER;
|
||||
else if (strcmp(name, "nw-resize") == 0) return NW_RESIZE_POINTER;
|
||||
else if (strcmp(name, "n-resize") == 0) return N_RESIZE_POINTER;
|
||||
else if (strcmp(name, "se-resize") == 0) return SE_RESIZE_POINTER;
|
||||
else if (strcmp(name, "sw-resize") == 0) return SW_RESIZE_POINTER;
|
||||
else if (strcmp(name, "s-resize") == 0) return S_RESIZE_POINTER;
|
||||
else if (strcmp(name, "w-resize") == 0) return W_RESIZE_POINTER;
|
||||
else if (strcmp(name, "ew-resize") == 0) return EW_RESIZE_POINTER;
|
||||
else if (strcmp(name, "ns-resize") == 0) return NS_RESIZE_POINTER;
|
||||
else if (strcmp(name, "nesw-resize") == 0) return NESW_RESIZE_POINTER;
|
||||
else if (strcmp(name, "nwse-resize") == 0) return NWSE_RESIZE_POINTER;
|
||||
else if (strcmp(name, "zoom-in") == 0) return ZOOM_IN_POINTER;
|
||||
else if (strcmp(name, "zoom-out") == 0) return ZOOM_OUT_POINTER;
|
||||
else if (strcmp(name, "alias") == 0) return ALIAS_POINTER;
|
||||
else if (strcmp(name, "copy") == 0) return COPY_POINTER;
|
||||
else if (strcmp(name, "not-allowed") == 0) return NOT_ALLOWED_POINTER;
|
||||
else if (strcmp(name, "no-drop") == 0) return NO_DROP_POINTER;
|
||||
else if (strcmp(name, "grab") == 0) return GRAB_POINTER;
|
||||
else if (strcmp(name, "grabbing") == 0) return GRABBING_POINTER;
|
||||
/* end pointer shapes */
|
||||
return TEXT_POINTER;
|
||||
}
|
||||
|
||||
static int
|
||||
|
6
kitty/options/types.py
generated
6
kitty/options/types.py
generated
@ -17,13 +17,13 @@
|
||||
choices_for_allow_cloning = typing.Literal['yes', 'y', 'true', 'no', 'n', 'false', 'ask']
|
||||
choices_for_allow_remote_control = typing.Literal['password', 'socket-only', 'socket', 'no', 'n', 'false', 'yes', 'y', 'true']
|
||||
choices_for_background_image_layout = typing.Literal['mirror-tiled', 'scaled', 'tiled', 'clamped', 'centered', 'cscaled']
|
||||
choices_for_default_pointer_shape = typing.Literal['arrow', 'beam', 'hand']
|
||||
choices_for_default_pointer_shape = typing.Literal['arrow', 'beam', 'text', 'pointer', 'hand', 'help', 'wait', 'progress', 'crosshair', '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']
|
||||
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['center', 'top-left']
|
||||
choices_for_pointer_shape_when_dragging = typing.Literal['arrow', 'beam', 'hand']
|
||||
choices_for_pointer_shape_when_grabbed = typing.Literal['arrow', 'beam', 'hand']
|
||||
choices_for_pointer_shape_when_dragging = typing.Literal['arrow', 'beam', 'text', 'pointer', 'hand', 'help', 'wait', 'progress', 'crosshair', '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']
|
||||
choices_for_pointer_shape_when_grabbed = typing.Literal['arrow', 'beam', 'text', 'pointer', 'hand', 'help', 'wait', 'progress', 'crosshair', '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']
|
||||
choices_for_strip_trailing_spaces = typing.Literal['always', 'never', 'smart']
|
||||
choices_for_tab_bar_align = typing.Literal['left', 'center', 'right']
|
||||
choices_for_tab_bar_style = typing.Literal['fade', 'hidden', 'powerline', 'separator', 'slant', 'custom']
|
||||
|
Loading…
Reference in New Issue
Block a user