1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
|
#!/usr/bin/env python
# License: GPLv3 Copyright: 2023, Kovid Goyal <kovid at kovidgoyal.net>
import os
import subprocess
import sys
if __name__ == '__main__' and not __package__:
import __main__
__main__.__package__ = 'gen'
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from .key_constants import patch_file
# References for these names:
# CSS:choices_for_{option.name} 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
cell cell cell,!plus,!cross cell cell: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,size-bdiag nesw_resize _windowResizeNorthEastSouthWestCursor
nwse-resize nwse-resize nwse-resize,size_fdiag,size-fdiag 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 = []
css_names = []
glfw_xc_map = {}
glfw_xfont_map = []
kitty_to_enum_map = {}
enum_to_glfw_map = {}
enum_to_css_map = {}
glfw_cocoa_map = {}
glfw_css_map = {}
css_to_enum = {}
xc_to_enum = {}
glfw_wayland = {}
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
enum_to_css_map[enum_name] = css
glfw_css_map[glfw_name] = css
css_to_enum[css] = enum_name
css_names.append(css)
glfw_wayland[glfw_name] = 'WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_' + wayland.replace('-', '_').upper()
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)});')
for x in xc:
x = x.lstrip('!')
xc_to_enum[x] = enum_name
parts = cocoa.split(':', 1)
if len(parts) == 1:
if parts[0].startswith('_'):
glfw_cocoa_map[glfw_name] = f'U({glfw_name}, {parts[0]});'
else:
glfw_cocoa_map[glfw_name] = f'C({glfw_name}, {parts[0]});'
else:
glfw_cocoa_map[glfw_name] = f'S({glfw_name}, {parts[0]}, {parts[1]});'
for x, v in xc_to_enum.items():
if x not in css_to_enum:
css_to_enum[x] = v
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 wayland mapping', '\n'.join(f' C({g}, {x});' for g, x in glfw_wayland.items()))
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/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(
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()))
patch_file('kitty/glfw.c', 'glfw to css', '\n'.join(
f' case {g}: return "{c}";' for g, c in glfw_css_map.items()
))
patch_file('kitty/screen.c', 'enum to css', '\n'.join(
f' case {e}: ans = "{c}"; break;' for e, c in enum_to_css_map.items()))
patch_file('kitty/screen.c', 'css to enum', '\n'.join(
f' else if (strcmp("{c}", css_name) == 0) s = {e};' for c, e in css_to_enum.items()))
patch_file('glfw/cocoa_window.m', 'glfw to cocoa', '\n'.join(f' {x}' for x in glfw_cocoa_map.values()))
patch_file('docs/pointer-shapes.rst', 'list of shape css names', '\n'.join(
f'#. {x}' if x else '' for x in [''] + sorted(css_names) + ['']), start_marker='.. ', end_marker='')
patch_file('tools/tui/loop/mouse.go', 'pointer shape enum', '\n'.join(
f'\t{x} PointerShape = {i}' for i, x in enumerate(enum_to_glfw_map)), start_marker='// ', end_marker='')
patch_file('tools/tui/loop/mouse.go', 'pointer shape tostring', '\n'.join(
f'''\tcase {x}: return "{x.lower().rpartition('_')[0].replace('_', '-')}"''' for x in enum_to_glfw_map), start_marker='// ', end_marker='')
patch_file('tools/cmd/mouse_demo/main.go', 'all pointer shapes', '\n'.join(
f'\tloop.{x},' for x in enum_to_glfw_map), start_marker='// ', end_marker='')
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'])
|