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:
Kovid Goyal 2023-10-15 09:05:05 +05:30
parent a8a1571ed1
commit 4f1971c480
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
17 changed files with 493 additions and 122 deletions

View File

@ -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`)

View File

@ -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
View 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
View File

@ -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
View File

@ -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
View File

@ -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
View File

@ -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)

View File

@ -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 {

View File

@ -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
View File

@ -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;
/*! @} */

View File

@ -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) */

View File

@ -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}')

View File

@ -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) {

View File

@ -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.
'''
)

View File

@ -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)

View File

@ -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

View File

@ -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']