Compare commits

...

351 Commits

Author SHA1 Message Date
Kovid Goyal
804f72b31a Get monotonic.h to build on older linux distros 2019-11-27 09:55:00 +05:30
Kovid Goyal
e106dcc83b Dont use -Wfloat-conversion on old compilers 2019-11-27 09:27:23 +05:30
Kovid Goyal
9347be639b version 0.15.0 2019-11-27 09:23:01 +05:30
Kovid Goyal
ffc0c42a63 Merge branch 'faq-font-clarification' of https://github.com/ricci/kitty 2019-11-27 07:31:51 +05:30
Robert Ricci
f5e855b3ad Direct user to rebuild fc-cache in font FAQ
The configuration file that's suggested to force a font to
show up as monospace is very helpful, but it appears you may
need to force fontconfig to rebuild the cache in order for the
change to take effect.
2019-11-26 12:02:23 -07:00
Kovid Goyal
9af4dc4bff Merge branch 'redirect' of https://github.com/Luflosi/kitty 2019-11-26 22:13:51 +05:30
Luflosi
6f6180c34a Change URL to avoid redirect
Since `https://sw.kovidgoyal.net/kitty` redirects to `https://sw.kovidgoyal.net/kitty/`, it would be better to directly use the second URL.
2019-11-26 17:23:21 +01:00
Kovid Goyal
6ddd751713 Merge branch 'simplify' of https://github.com/Luflosi/kitty 2019-11-26 21:09:40 +05:30
Luflosi
2c72b06012 Simplify conditions 2019-11-26 16:06:16 +01:00
Kovid Goyal
88854c1aa4 Merge branch 'fix_stdin_source' of https://github.com/miseran/kitty 2019-11-26 06:47:21 +05:30
Reto Schnyder
5ad704469f Fix condition in stdin selection for launch 2019-11-25 20:10:18 +01:00
Kovid Goyal
c140e17a6f Merge branch 'undo_commenting_out' of https://github.com/Luflosi/kitty 2019-11-24 18:08:14 +05:30
Luflosi
4fc733a9c8 Comment commented out code back in
This piece of code is not run when the `GLFW_COCOA_MENUBAR` init hint is set to `0`, which kitty does.
This reduces the difference to GLFW upstream a little.
2019-11-24 13:29:06 +01:00
Kovid Goyal
c5c59e4c55 Merge branch 'return_type' of https://github.com/Luflosi/kitty 2019-11-24 17:56:26 +05:30
Luflosi
e0edef6719 Change return type of two functions
`on_application_reopen()` and `intercept_cocoa_fullscreen()` both only have two possible return values and can therefore have a return type of `bool`.
2019-11-24 13:06:46 +01:00
Kovid Goyal
0f46ce49e2 Merge branch 'create_menu_bar_in_callback' of https://github.com/Luflosi/kitty 2019-11-24 13:27:35 +05:30
Luflosi
f9fd39b8c1 Create macOS menu bar where GLFW creates it
GLFW creates the menu bar in the applicationWillFinishLaunching method, while kitty creates it in `create_os_window()`. This patch changes the behaviour to match GLFW.
In practice, without this change, there can be a short time where the menu bar is not fully populated.
2019-11-24 08:43:01 +01:00
Kovid Goyal
bd75157428 macOS: Disable mouse hiding by default as getting it to work robustly on Cocoa is too much effort
See #2158
2019-11-24 11:29:23 +05:30
Kovid Goyal
f987f3ba77 Merge branch 'remove_obsolete_comment' of https://github.com/Luflosi/kitty 2019-11-24 08:09:14 +05:30
Luflosi
1c16806efd Remove obsolete comment
In bef9490fa8, `unjam_event_loop()` was removed but not the corresponding comment.
2019-11-23 17:51:38 +01:00
Kovid Goyal
29155fef23 Merge branch 'glfw_upstream' of https://github.com/Luflosi/kitty 2019-11-23 18:59:07 +05:30
Luflosi
c05cbed5b2 Reduce difference to GLFW upstream 2019-11-23 13:19:06 +01:00
Kovid Goyal
4f85d4db71 Merge branch 'glfw_upstream' of https://github.com/Luflosi/kitty 2019-11-22 20:16:22 +05:30
Luflosi
468468ab9f Wayland: Don’t update cursor position in the frame
From upstream: a80788c17f.
2019-11-22 12:38:56 +01:00
Kovid Goyal
1b4a6da577 Merge branch 'glfw_upstream' of https://github.com/Luflosi/kitty 2019-11-22 07:11:14 +05:30
Luflosi
aed7a197c7 Wayland: Don’t reload the cursor on every pointer motion
From upstream: a9f674e719.
2019-11-22 02:35:14 +01:00
Kovid Goyal
c257b7ecfd Merge branch 'glfw_upstream' of https://github.com/Luflosi/kitty 2019-11-22 07:00:04 +05:30
Luflosi
d6072f6218 X11: Assume 96 DPI if RandR monitor size is zero
From upstream: e96dc5d219.
2019-11-22 02:07:34 +01:00
Kovid Goyal
4ea72a2892 Merge branch 'glfw_upstream' of https://github.com/Luflosi/kitty 2019-11-22 06:34:42 +05:30
Luflosi
89b07a1c6b Cocoa: Fix full screen window iconification
From upstream: 2c519709be.
2019-11-22 01:56:55 +01:00
Kovid Goyal
db0cd61807 Merge branch 'glfw_upstream' of https://github.com/Luflosi/kitty 2019-11-22 06:17:47 +05:30
Luflosi
6feb906953 Cocoa: Cleanup
From upstream: bd452016be.
2019-11-21 18:30:03 +01:00
Kovid Goyal
7cbf8c63bc Merge branch 'glfw_upstream' of https://github.com/Luflosi/kitty 2019-11-21 20:00:30 +05:30
Luflosi
fae51d4e00 Cocoa: Add comments for Cocoa symbol macros
From upstream: 94cb0347ab.
2019-11-21 14:40:34 +01:00
Kovid Goyal
c510584afd Dont hang trying to read shell environment if the shell never quits. Fixes #2143 2019-11-20 11:53:28 +05:30
Kovid Goyal
738878c2ff unicode input kitten: Add an option :option:kitty +kitten unicode_input --emoji-variation to control the presentation variant of selected emojis
Fixes #2139
2019-11-17 13:13:37 +05:30
Kovid Goyal
d5682fe49a Fix #2137 2019-11-17 08:35:23 +05:30
Kovid Goyal
d8dd22048a Wayland: Ensure that glfw window content scale and kitty window content scale are in sync after the window is placed on a monitor 2019-11-16 10:47:05 +05:30
Kovid Goyal
737d8b96b6 Wayland: Dont bother with creating a temporary window anyway, as it is useless 2019-11-16 10:27:01 +05:30
Kovid Goyal
c8627c9713 Expand user/env vars in csutomize processing path and note that absolute paths can be used in the docs for it. 2019-11-16 10:05:25 +05:30
Kovid Goyal
65fa7da24a Wayland: Use the primary monitor scale for windows on creation
This is needed because on creation the window may not have been assigned
to any monitors, so we fallback to using the scale of the primary
monitor. Fixes #2133. Fixes #2135
2019-11-16 10:00:41 +05:30
Kovid Goyal
c4c6ef799f Dont shadow data 2019-11-13 19:47:08 +05:30
Kovid Goyal
0d18b91895 Grammar 2019-11-13 19:45:48 +05:30
Kovid Goyal
42089aaadc typo 2019-11-13 19:45:28 +05:30
Kovid Goyal
432d0f3318 hints kitten: Allow passing extra CLI args when using --customize-procesing 2019-11-13 17:27:55 +05:30
Kovid Goyal
4ade6587e8 spelling 2019-11-13 16:57:11 +05:30
Kovid Goyal
1724f11429 Deprecate pipe in favor of launch 2019-11-13 16:08:48 +05:30
Kovid Goyal
75d66d1048 Changelog entry for launch 2019-11-13 15:44:57 +05:30
Kovid Goyal
feccef67b9 Document the new launch action 2019-11-13 15:43:38 +05:30
Kovid Goyal
a7d30a199d location should also apply to tab creation 2019-11-13 15:40:46 +05:30
Kovid Goyal
37bbfb11d3 Fix location=neighbor causing a hang on a new tab 2019-11-13 15:39:38 +05:30
Kovid Goyal
79c80b4043 Fix doc generation 2019-11-13 15:03:02 +05:30
Kovid Goyal
18a1402ae2 Remote control interface for launch 2019-11-13 15:00:13 +05:30
Kovid Goyal
5d639b91b0 Switch OS windows when focusing on platforms where it is supported 2019-11-13 14:59:49 +05:30
Kovid Goyal
080c09d22e DRYer 2019-11-13 14:41:45 +05:30
Kovid Goyal
00c2670039 Fix handing of --stdin-source and getting of active window 2019-11-13 14:39:44 +05:30
Kovid Goyal
f113184165 Micro-optimization 2019-11-13 14:39:06 +05:30
Kovid Goyal
d69f8af107 Add a --keep-focus option for launch 2019-11-13 11:48:30 +05:30
Kovid Goyal
ad2bd1bf63 Allow using @selection in the launch cmdline 2019-11-13 10:46:04 +05:30
Kovid Goyal
059786ab66 Implement piping for launch 2019-11-13 10:38:58 +05:30
Kovid Goyal
72dfa5e5e6 Allow creating overlays via launch 2019-11-13 10:14:32 +05:30
Kovid Goyal
d84da6b7b8 Documentation placeholder for the new launch interface 2019-11-13 10:09:43 +05:30
Kovid Goyal
6aa82d82ad Start work on a unified interface for launching processes 2019-11-13 09:58:28 +05:30
Kovid Goyal
a649eb2a48 Coalesce neighboring symbol maps for better lookup performance 2019-11-12 20:05:48 +05:30
Kovid Goyal
83932c8099 Add a remote control command for detach_tab 2019-11-12 15:03:58 +05:30
Kovid Goyal
95e36cece1 Add a detach_window remote control command 2019-11-12 13:04:28 +05:30
Kovid Goyal
7075a7f1c0 Only detach window after the ask overlay is removed 2019-11-12 10:59:36 +05:30
Kovid Goyal
3093610d26 Allow choosing new os window/tab during detach ask 2019-11-12 10:42:07 +05:30
Kovid Goyal
86eed7f895 Speed up taking over of tab 2019-11-12 10:38:57 +05:30
Kovid Goyal
5dc14c5861 Copy cwd when taking over tab 2019-11-12 10:24:37 +05:30
Kovid Goyal
cab87f6fb2 Ensure Tab has cwd even with no initial window 2019-11-12 10:18:42 +05:30
Kovid Goyal
fb3acd1f4a Add a detach_tab command 2019-11-12 10:07:44 +05:30
Kovid Goyal
b247cef85c ... 2019-11-12 08:46:41 +05:30
Kovid Goyal
70445f33e9 Another typo 2019-11-12 06:30:21 +05:30
Kovid Goyal
cadb4f1389 ... 2019-11-12 06:29:55 +05:30
Kovid Goyal
bf75a4de61 Also document debug() 2019-11-12 06:25:27 +05:30
Kovid Goyal
400ab584ac hints kitten: Allow completely customizing the matching and actions performed by the kitten using your own script
Fixes #2124
2019-11-11 21:26:42 +05:30
Kovid Goyal
9edad62144 hints kitten: Allow using named groups in the regular expression. The named groups are passed to the invoked program for further processing. 2019-11-11 17:34:19 +05:30
Kovid Goyal
e94205098f Fix link 2019-11-11 16:00:35 +05:30
Kovid Goyal
35ab7eb472 Add a new action :ref:detach_window that can be used to move the current window into a different tab
Fixes #1310
2019-11-11 15:47:48 +05:30
Kovid Goyal
18619b14ac Merge branch 'simplify' of https://github.com/Luflosi/kitty 2019-11-10 23:35:27 +05:30
Luflosi
97e0b9b65a Simplify code 2019-11-10 16:51:25 +01:00
Kovid Goyal
5175d9f4a6 Properly re-initialize GPU resources when detaching/attaching a window 2019-11-09 13:14:50 +05:30
Kovid Goyal
a5aed0f4ab Forgot to change tab_ref when attaching window 2019-11-09 11:23:04 +05:30
Kovid Goyal
14d693a8ff When attaching window make its parent tab active 2019-11-09 11:09:29 +05:30
Kovid Goyal
645963cc24 Cleanup tab after detaching window 2019-11-09 09:42:17 +05:30
Kovid Goyal
20751c2807 Start work on a detach_window command 2019-11-09 09:20:38 +05:30
Kovid Goyal
dda886b97c Merge branch 'caps_lock_modifier' of https://github.com/Luflosi/kitty 2019-11-09 08:31:59 +05:30
Luflosi
b796ceecdd Add Caps Lock to the list of modifier keys
When a key is pressed and `mouse_hide_wait` is less than zero, kitty will hide the mouse cursor. When a key is pressed, kitty will also scroll the history to the bottom. Both of these things don't happen if the key being pressed was a modifier key. Both of these things should not happen when Caps Lock is pressed, so this key should be added to the list of modifier keys.
`is_modifier_key()` is not used for anything else.
2019-11-09 00:41:12 +01:00
Kovid Goyal
4def89ebb5 Add a note on debugging custom kittens 2019-11-08 16:53:26 +05:30
Kovid Goyal
bd1c1839dd Add API to boss.py to move a window into a different tab 2019-11-08 16:18:52 +05:30
Kovid Goyal
8739f698f9 When attaching window and font sizes changes, resize Screen 2019-11-08 14:58:08 +05:30
Kovid Goyal
b8c8482f20 Better fix for Powerline lacking a space glyph
This does not require increasing the size of the cache key, thereby
improving cache lookup performance
2019-11-08 14:41:31 +05:30
Kovid Goyal
4348ca8cc5 Remove unused function 2019-11-08 14:29:41 +05:30
Kovid Goyal
d1aa59080f Add an API to attach and detach windows from tabs 2019-11-08 14:22:02 +05:30
Kovid Goyal
bf0ffa80be Merge branch 'feature-window-to-tab' of https://github.com/0x17de/kitty
Currently only merged the function to move internal window state.
Want to refactor the changes to tabs.py and boss.py to make them more
orthogonal.
2019-11-08 09:55:51 +05:30
Kovid Goyal
2a89a0c87e Merge branch 'master' of https://github.com/martinpelikan/kitty 2019-11-08 07:57:47 +05:30
Kovid Goyal
de84489a20 Fix a regression in 0.14.5 that caused rendering of private use glyphs with and without spaces to be identical
Fixes #2117
2019-11-08 07:55:41 +05:30
Martin Pelikan
40901778ad Update fish completion docs for fish 3.0.0
As of 3.0.0, fish sources `kitty +complete fish` by default.
2019-11-07 18:11:47 -08:00
Kovid Goyal
c1febea659 Merge branch 'restore_error_reporting' of https://github.com/Luflosi/kitty 2019-11-05 07:07:03 +05:30
Luflosi
b42f4ac288 Restore proper error reporting functionality
In 841c907efc, the `%m` format specifier was replaced by `%%m`, which just prints `%m`. To keep the functionality of `%m` without using `%m`, the error string can be printed manually.
2019-11-05 00:42:29 +01:00
Kovid Goyal
fae57a5868 Website: Add a scrollbar to the sidebar if needed 2019-11-04 18:05:08 +05:30
Kovid Goyal
7a02d09508 Merge branch 'master' of https://github.com/CD3/kitty 2019-11-01 23:23:22 +05:30
C.D. Clark III
8ec6fe960d docs: added '@selection' to pipe documentation. 2019-11-01 08:46:49 -05:00
Kovid Goyal
61a77e19ef X11: Fix content scale fallback value on KDE
From upstream: 75294462b3
2019-10-31 09:10:01 +05:30
Kovid Goyal
82e88b54c7 X11: Fix decoration enabling after window creation
From upstream: 5fc4c01302
2019-10-31 09:04:45 +05:30
Kovid Goyal
ab8975f4da Merge branch 'with_suppress' of https://github.com/Luflosi/kitty 2019-10-29 10:17:19 +05:30
Luflosi
5e7fd21c8d Use "with suppress()" to suppress a python exception 2019-10-28 18:35:21 +01:00
Kovid Goyal
30cd9b2ae4 Merge branch 'fix_two_linker_error' of https://github.com/Luflosi/kitty 2019-10-28 07:31:49 +05:30
Luflosi
4f7d12f3fd Fix error when two linker processes fail
When a linker process fails, `failed` will be set to a value other than `None`. When a second linker process fails, the `else` case will be taken because `failed is None`, which executes `compile_cmd.on_success()`. This function tries to rename or move the file generated by the linker but since the linker process failed, the file will most likely not exist. This will throw an error, which will prevent printing the actual error message from the linker.
2019-10-27 21:50:22 +01:00
Kovid Goyal
62da158823 Merge branch 'fix_potential_error' of https://github.com/Luflosi/kitty 2019-10-27 07:42:21 +05:30
Luflosi
2d19b87208 Fix potential error when $PATH is not defined
When `PATH` is not in `os.environ`, kitty could potentially throw a `KeyError`.
2019-10-27 00:10:55 +02:00
Kovid Goyal
54ca775006 Merge branch 'visual' of https://github.com/toonn/kitty 2019-10-26 09:10:15 +05:30
toonn
a64a0d64cb Prefer VISUAL to EDITOR
Fix #2096
2019-10-25 18:52:17 +02:00
Kovid Goyal
6634dc81fe Merge branch 'simplify' of https://github.com/Luflosi/kitty 2019-10-25 07:45:30 +05:30
Luflosi
a2d5eef398 Simplify access to os.environ
The `if` can be removed by using `get()` with a default parameter to access `os.environ`. This also reduces the number of accesses to `os.environ`.
2019-10-24 20:27:27 +02:00
Kovid Goyal
8184ba246a Load libcanberra dynamically at runtime, as needed
Fixes #2089
2019-10-24 09:03:52 +05:30
Kovid Goyal
54ad1d103a Fix #2087 2019-10-23 18:21:34 +05:30
Kovid Goyal
d92f8a90ef Allow changing colors by mapping a keyboard shortcut to read a kitty config file with color definitions.
Fixes #2083
2019-10-21 14:43:35 +05:30
Kovid Goyal
d33c287344 typo 2019-10-21 14:23:07 +05:30
Kovid Goyal
782eebf976 typo 2019-10-21 14:21:09 +05:30
Kovid Goyal
0fbf75b95a Allow specifying that remote control only works over a socket 2019-10-21 14:20:30 +05:30
Kovid Goyal
5781facf4b Merge branch 'fix_icat' of https://github.com/Luflosi/kitty 2019-10-21 07:32:40 +05:30
Luflosi
b710ffc403 Fix icat kitten
Fixes https://github.com/kovidgoyal/kitty/issues/2081.
This bug was introduced in 10e5fcc375.

One place in the code requires the actual `screen_size_function`, not just the result of it.
2019-10-20 21:37:14 +02:00
Kovid Goyal
7d8edccb04 Merge branch 'pending_scroll_pixels_per_screen' of https://github.com/Luflosi/kitty 2019-10-20 16:58:28 +05:30
Luflosi
3750d70173 Store pending_scroll_pixels for every screen
Scrolling in one screen shouldn't affect the `pending_scroll_pixels` for another screen in the same OS window.
2019-10-20 13:22:46 +02:00
Kovid Goyal
025e0bb546 Merge branch 'var-names-consistency-wrt-scancode' of https://github.com/bew/kitty 2019-10-20 08:08:48 +05:30
Kovid Goyal
033367de91 Merge branch 'fix_line_drawing' of https://github.com/Luflosi/kitty 2019-10-19 06:26:57 +05:30
Luflosi
f93b605b75 Fix line drawing algorithm 2019-10-18 21:26:11 +02:00
Kovid Goyal
7b4141b0c8 Add a changelog entry for powerline tabbar 2019-10-18 19:38:08 +05:30
Kovid Goyal
90acef72dc Merge branch 'add_powerline_style_tabs' of https://github.com/brujoand/kitty 2019-10-18 19:36:31 +05:30
Kovid Goyal
43f200be77 Add an entry for the new box character rendering functions 2019-10-18 17:24:33 +05:30
Kovid Goyal
2fbb167803 Merge branch 'fix-triangle-symbol-scaling' of https://github.com/bew/kitty 2019-10-18 17:13:50 +05:30
Benoit de Chezelles
2b396262f0 Update glyph ids 2019-10-18 11:48:55 +02:00
Benoit de Chezelles
74deca52b9 Remove trailing whitespace 2019-10-18 11:39:51 +02:00
Benoit de Chezelles
058d956464 Merge branch 'master' into fix-triangle-symbol-scaling 2019-10-18 11:30:46 +02:00
brujoand
0f38dc1bd1 Adding powerline style tabs 2019-10-18 11:18:28 +02:00
Kovid Goyal
576b03c047 Implement drawing thick anti-aliased lines
And actually use it for the unicode diagonal box drawing chars and also
the powerline angle separators
2019-10-18 13:19:04 +05:30
Kovid Goyal
59cb1ad1e0 Implement special rendering for the diagonal line box drawing chars 2019-10-18 11:01:51 +05:30
Benoit de Chezelles
f77acdce14 remove useless import in help msg for box drawing debug 2019-10-18 06:08:45 +02:00
Benoit de Chezelles
43a98a1df1 Add missing association between char & glyph id 2019-10-18 06:08:20 +02:00
Benoit de Chezelles
d1cf771c14 Add other corner triangles & enable in C side 2019-10-18 05:45:13 +02:00
Benoit de Chezelles
10e5fcc375 Fix usage of icat function show
The `screen_size` function was not initialized yet
2019-10-18 04:54:14 +02:00
Benoit de Chezelles
2112932d04 Add corner triangle glyphs drawing 2019-10-18 04:48:03 +02:00
Benoit de Chezelles
be505ce6e0 Fix test functions for setup_for_testing's new call syntax 2019-10-18 04:47:04 +02:00
Benoit de Chezelles
4d6472128c Rename scancode to keycode for cocoa implementation 2019-10-17 20:41:48 +02:00
Kovid Goyal
26b7b1ec63 Merge branch 'typo' of https://github.com/Luflosi/kitty 2019-10-17 18:32:42 +05:30
Luflosi
9a8f0a9b5a Fix typo 2019-10-17 13:56:46 +02:00
Kovid Goyal
16dbbf3a1e Make count-lines-of-code a little nicer 2019-10-17 15:19:13 +05:30
Kovid Goyal
8492d0a264 Merge branch 'dont_cloc_parse-graphics-command.h' of https://github.com/Luflosi/kitty 2019-10-17 14:36:53 +05:30
Luflosi
d8f8f1f590 Exclude kitty/parse-graphics-command.h from the line count
This file is automatically generated and should not count towards the total line count.
2019-10-17 10:38:55 +02:00
Kovid Goyal
b762e81da0 Merge branch 'python_encoding_header' of https://github.com/Luflosi/kitty 2019-10-17 06:28:16 +05:30
Luflosi
8b3b68ea69 Unify python encoding headers
All the other python encoding headers are of the form `vim:fileencoding=utf-8`.
2019-10-16 20:34:56 +02:00
Benoit de Chezelles
28525766a5 Final changes before 'ready for review' 2019-10-16 02:47:14 +02:00
Benoit de Chezelles
d8fc23c38f remove outdated 'fixme' 2019-10-16 02:41:26 +02:00
Benoit de Chezelles
8cae70fa36 Update doc 2019-10-16 02:36:55 +02:00
Benoit de Chezelles
7f2b98fad7 Rename all uses of 'scancode' to 'native_key' where relevant 2019-10-16 02:25:20 +02:00
Benoit de Chezelles
2b6dde2ac5 Wish: rename scancode → native_key in glfw codebase 2019-10-16 02:00:24 +02:00
Benoit de Chezelles
0c254fa7c7 GLFWkeyevent: rename scancode → native_key 2019-10-16 02:00:24 +02:00
Kovid Goyal
fe7375becc Merge branch 'grammar' of https://github.com/Luflosi/kitty 2019-10-16 04:19:54 +05:30
Luflosi
b6ee88056e Minor grammar correction 2019-10-16 00:46:52 +02:00
Kovid Goyal
96f691ad64 Merge branch 'mark_parse-graphics-command.h_as_generated' of https://github.com/Luflosi/kitty 2019-10-16 03:31:32 +05:30
Luflosi
8cf3380a77 Mark kitty/parse-graphics-command.h as being generated 2019-10-15 18:16:28 +02:00
Kovid Goyal
e8d7e3e98b Merge branch 'remove_khrplatform.h_references' of https://github.com/Luflosi/kitty 2019-10-15 20:58:16 +05:30
Luflosi
8af0a8476f Remove remaining references to kitty/khrplatform.h
`kitty/khrplatform.h` was removed in f872f955b0.
2019-10-15 17:25:47 +02:00
Kovid Goyal
2de4248f76 Merge branch 'regenerate_glfw-wrapper' of https://github.com/Luflosi/kitty 2019-10-15 20:42:49 +05:30
Luflosi
8c73ab6afb Regenerate kitty/glfw-wrapper.h 2019-10-15 17:10:02 +02:00
Kovid Goyal
ee9bd77dc4 Merge branch 'glfw_upstream' of https://github.com/Luflosi/kitty 2019-10-15 19:10:50 +05:30
Luflosi
81f31ca215 Reduce difference of glfw/glfw3.h to GLFW upstream 2019-10-15 15:37:35 +02:00
Kovid Goyal
51eff372f8 Merge branch 'glfw_upstream' of https://github.com/Luflosi/kitty 2019-10-15 18:16:22 +05:30
Luflosi
087376b44d GLFW: Documentation work
From upstream: a43d1a4937.
2019-10-15 14:37:41 +02:00
Kovid Goyal
e49047ef7d Merge branch 'glfw_upstream' of https://github.com/Luflosi/kitty 2019-10-15 18:02:17 +05:30
Luflosi
c117f36009 GLFW: Cleanup
From upstream: d5ab3e919a.
2019-10-15 14:25:46 +02:00
Kovid Goyal
5ec83ee759 Merge branch 'glfw_upstream' of https://github.com/Luflosi/kitty 2019-10-15 16:17:49 +05:30
Luflosi
410165c14d GLFW: Improve (?) reference documentation for callbacks
From upstream: 51bb76c7c3.
2019-10-15 12:11:01 +02:00
Kovid Goyal
973ef9fcda Merge branch 'fix_nix_link' of https://github.com/Luflosi/kitty 2019-10-15 04:14:04 +05:30
Luflosi
396bfb8540 Fix link to Nix kitty package
Instead of a fragment identifier, the URL now needs a query parameter.
2019-10-14 18:48:21 +02:00
Kovid Goyal
aaf597bffd Merge branch 'glfw_upstream' of https://github.com/Luflosi/kitty 2019-10-13 09:08:15 +05:30
Luflosi
63c4f64bf5 Reduce difference to GLFW upstream
From upstream: 773f4495f0.
2019-10-12 15:19:44 +02:00
Kovid Goyal
5745dc34f7 Merge branch 'glfw_upstream' of https://github.com/Luflosi/kitty 2019-10-12 17:58:50 +05:30
Luflosi
114b8cff93 Cleanup
From upstream: 62b7fe8311.
2019-10-11 20:26:27 +02:00
Kovid Goyal
261571bb69 Merge branch 'modern_objective-c' of https://github.com/Luflosi/kitty 2019-10-10 22:01:30 +05:30
Manuel Herrmann
497e2c9163 #1310 move windows into separate tabs 2019-10-10 17:13:34 +02:00
Luflosi
ac01ffaa54 Cocoa: Move slightly towards modern Objective-C 2019-10-10 14:36:52 +02:00
Kovid Goyal
eb9fe06d10 Merge branch 'correct_space' of https://github.com/Luflosi/kitty 2019-10-09 22:15:38 +05:30
Luflosi
506f2f7db7 Replace weird character with space
In 4c4c6ab0e6 you added a weird unicode character, which is apparently called an Object Replacement Character, instead of a space.
2019-10-09 18:32:49 +02:00
Kovid Goyal
f476c56f91 Drop support for the gtk_primary_selection wayland protocol
sway recently decided to start complaining when binding
wp_primary_selection_device_manager interface to gtk_primary_selection
name, which means we either have to maintain an in-tree version
of the gtk_primary_selection protocol or drop support for sway.

Sway has not quite annoyed me enough yet for the latter.

See #1977
2019-10-09 07:37:03 +05:30
Kovid Goyal
474688888d Merge branch 'glfw_upstream' of https://github.com/Luflosi/kitty 2019-10-08 17:16:51 +05:30
Luflosi
7ddbb613fe Cocoa: Fix window creation blocking after re-init
From 2fbb560eb7.
2019-10-08 13:41:10 +02:00
Kovid Goyal
adc1c06089 Merge branch 'glfw_upstream' of https://github.com/Luflosi/kitty 2019-10-08 12:12:00 +05:30
Luflosi
1f8631cc99 Cocoa: Move app delegate and menu creation to init
From ea7eb2ddab.
2019-10-07 21:24:58 +02:00
Kovid Goyal
f9e4e71285 Slightly better error message when opening controlling terminal fails 2019-10-07 20:48:31 +05:30
Kovid Goyal
5529194c8d Merge branch 'glfw_upstream' of https://github.com/Luflosi/kitty 2019-10-06 20:39:25 +05:30
Luflosi
5b008163af Cocoa: Add NSApplicationDelegate protocol
From c3ed70a4b7.
2019-10-06 16:58:06 +02:00
Kovid Goyal
802da7087c diff kitten: Allow diffing remote files easily via ssh
See #727
2019-10-04 09:08:22 +05:30
Kovid Goyal
53ab7617ca Dont use space ligatures for symbol_map fonts
space ligatures breaks in font ligatures when there is a trailing space.
So only use them for PUA and cells using a fallback font. Fixes #2019
2019-10-02 07:10:51 +05:30
Kovid Goyal
4369255a25 When drawing unicode symbols that are followed by spaces, use multiple cells to avoid resized or cut-off glyphs
Fixes #1452
2019-10-01 19:56:07 +05:30
Kovid Goyal
b709ee6842 Add a function to check if a codepoint is a symbol 2019-10-01 18:57:06 +05:30
Kovid Goyal
4a8f9efe79 Wayland: Resume key repeat on focus gained if the previously repeated key is pressed 2019-09-30 18:47:43 +05:30
Kovid Goyal
19d36fbe69 Wayland: Fix key repeat not being stopped when focus leaves window. This is expected behavior on Wayland, apparently
Fixes #2014
2019-09-30 16:45:39 +05:30
Kovid Goyal
d37e73db54 Merge branch 'fix_broken_paste' of https://github.com/Luflosi/kitty
Fixes #2008
2019-09-29 08:02:31 +05:30
Luflosi
a8f6615380 Fix broken paste on X11
Fixes https://github.com/kovidgoyal/kitty/issues/2008.
2019-09-29 02:48:09 +02:00
Kovid Goyal
97fe38fbbc monotonic_start_time needs to be a global symbol, not local to each translation unit 2019-09-28 08:18:21 +05:30
Kovid Goyal
3378175450 Hopefully the last macOS float conversion fix 2019-09-27 20:14:05 +05:30
Kovid Goyal
9f60d2aea3 More macOS float conversion fixes 2019-09-27 20:11:32 +05:30
Kovid Goyal
46d49e18c0 More macOS float fixes 2019-09-27 20:07:09 +05:30
Kovid Goyal
43fc335be2 more macOS float fixes 2019-09-27 20:05:11 +05:30
Kovid Goyal
f68339c571 float conversion fixes for macOS 2019-09-27 19:56:48 +05:30
Kovid Goyal
0d68b7078c Check for float conversion issues on build
Useful to catch any errors left over from the migration of times from
double to int64_t
2019-09-27 19:47:25 +05:30
Kovid Goyal
2e71dde780 Merge branch 'monotonic_t' of https://github.com/Luflosi/kitty 2019-09-27 19:23:27 +05:30
Kovid Goyal
51ddd584d6 Merge branch 'mark_unicode_data_as_generated' of https://github.com/Luflosi/kitty 2019-09-27 09:21:29 +05:30
Luflosi
4b090259cd Mark kitty/unicode-data.c as being generated 2019-09-26 21:54:42 +02:00
Luflosi
f3b9ff5f9f Use datatype monotonic_t instead of double to keep track of time
The time is stored in a signed 64 bit integer with nanosecond accuracy. This eliminates the possibility of floating-point inaccuracies.
`monotonic_t` can currently hold values large enough to work correctly for more than 200 years into the future.
Using a typedef instead of directly using `int64_t` everywhere will also allow easily changing the datatype in the future should the need arise for more precise or bigger time values.
2019-09-25 17:43:11 +02:00
Kovid Goyal
4ec1a8d9c3 Merge branch 'extract-glfw-key-event-data' of https://github.com/bew/kitty 2019-09-25 15:44:56 +05:30
Kovid Goyal
350cfeb7ef version 0.14.6 2019-09-25 11:28:55 +05:30
Kovid Goyal
97d379b13e Add changelog entry for DPI change PR 2019-09-25 06:34:55 +05:30
Kovid Goyal
2154d555e5 Merge branch 'update_check_interval_constant' of https://github.com/Luflosi/kitty 2019-09-25 06:23:05 +05:30
Luflosi
1389c36657 Use the update CHECK_INTERVAL constant 2019-09-25 02:46:19 +02:00
Kovid Goyal
bd1e7d6942 Merge branch 'master' of https://github.com/dcolascione/kitty 2019-09-25 05:56:17 +05:30
Benoit de Chezelles
aadab38487 Fix compilation for macos 2019-09-24 22:03:55 +02:00
Daniel Colascione
91299a279b Fix window resize on DPI change 2019-09-24 12:41:23 -07:00
Benoit de Chezelles
53275c9137 Extract key event data to struct 2019-09-24 19:15:35 +02:00
Kovid Goyal
fb1c318a09 macOS: Fix a regression in the previous release that caused a crash when pressing a unprintable key, such as the POWER key
Fixes #1997
2019-09-24 16:07:52 +05:30
Kovid Goyal
2a07b3f46a Fix #1995 2019-09-24 06:40:21 +05:30
Kovid Goyal
ffc4e99717 version 0.14.5 2019-09-23 08:41:38 +05:30
Kovid Goyal
fe807dd66f Fix missing parameter name in docs 2019-09-22 19:39:22 +05:30
Kovid Goyal
40ce5db812 Add completion for listen on 2019-09-22 16:08:37 +05:30
Kovid Goyal
649a9f4a6f oops 2019-09-22 16:01:33 +05:30
Kovid Goyal
e17ce875be Complete more CLI args 2019-09-22 16:01:12 +05:30
Kovid Goyal
415701c58a Add completion of filenames for --config 2019-09-22 15:52:45 +05:30
Kovid Goyal
f16f80b459 Merge branch 'glfw_null_unused_params' of https://github.com/Luflosi/kitty 2019-09-20 06:27:13 +05:30
Luflosi
628e6cc87f Mark unused parameters in glfw/null_*.c
kitty didn't compile on FreeBSD for me because of unused parameters in glfw/null_joystick.c, so I added the `UNUSED` attribute to them.
I also added `UNUSED` to the unused parameters in glfw/null_monitor.c and glfw/null_window.c as well even though they are probably not used.
2019-09-19 20:21:09 +02:00
Kovid Goyal
8f9a225c3a Use selection foreground color for underlines as well
Fixes #1982
2019-09-19 19:28:33 +05:30
Kovid Goyal
7b41bc95e1 Merge branch 'move_allocation_failure_check' of https://github.com/Luflosi/kitty 2019-09-19 18:45:42 +05:30
Luflosi
2d06ee5822 Move allocation failure check closer to allocation 2019-09-19 14:58:39 +02:00
Kovid Goyal
40b4fb966f Merge branch 'add_missing_key_name_aliases' of https://github.com/Luflosi/kitty 2019-09-19 05:53:42 +05:30
Luflosi
be696a9d76 Add missing keys to key_name_aliases 2019-09-18 19:36:56 +02:00
Luflosi
1ffe9bef35 Order key_name_aliases by their ASCII value 2019-09-18 16:23:38 +02:00
Luflosi
ed70d95c44 Move aliases for common key name variations to the end of key_name_aliases 2019-09-18 16:23:01 +02:00
Kovid Goyal
49bf876f73 Merge branch 'remove_plus_key_alias' of https://github.com/Luflosi/kitty 2019-09-18 19:45:19 +05:30
Luflosi
e512b4d3e3 Remove PLUS key from key_name_aliases 2019-09-18 16:07:55 +02:00
Kovid Goyal
e78b6c7c7c Merge branch 'faq' of https://github.com/jacwah/kitty 2019-09-18 09:49:09 +05:30
Jacob Wahlgren
a7403c0005 Update FAQ with FreeBSD termcap info
Thanks to amarshall's help:
https://github.com/kovidgoyal/kitty/issues/765#issuecomment-487381289
2019-09-17 22:19:51 +02:00
Kovid Goyal
5bed0dddaa typo 2019-09-15 06:19:27 +05:30
Kovid Goyal
bc302dad23 Linux: Allow using fonts with spacing=90 in addition to fonts with spacing=100
Fixes #1968
2019-09-15 06:08:40 +05:30
Kovid Goyal
41b0f8852f Only update config_key_map with those entries in key_name_aliases that exist in ENCODING 2019-09-15 04:24:32 +05:30
Kovid Goyal
2fadd3e7ba Add a note to the fontconfig FAQ about how to override spacing 2019-09-15 04:09:26 +05:30
Kovid Goyal
dcfd2b8d60 Fix incorrect rendering of some symbols when followed by a space while using the PowerLine font which does not have a space glyph
Fixes #1225
2019-09-14 17:56:52 +05:30
Kovid Goyal
7fe63a7aad Add changelog entry for key mapping PR 2019-09-14 10:20:18 +05:30
Kovid Goyal
67f2ec2421 Merge branch 'keyboard_improvement' of https://github.com/Luflosi/kitty 2019-09-14 10:17:35 +05:30
Kovid Goyal
8e7a23a7b9 Merge branch 'use_OPT' of https://github.com/Luflosi/kitty 2019-09-12 13:43:12 +05:30
Luflosi
8e96a27d51 Use the OPT() macro where possible 2019-09-12 10:02:53 +02:00
Kovid Goyal
b337d4d9d5 Merge branch 'master' of https://github.com/copy/kitty 2019-09-12 07:43:35 +05:30
Fabian
d9404c0362 Fix color index 232 (should be #080808, not black) 2019-09-11 20:01:52 +02:00
Kovid Goyal
e4ba5f449f When resetting the terminal, also reset parser state, this allows easy recovery from incomplete escape codes
Fixes #1961
2019-09-09 20:56:35 +05:30
Kovid Goyal
17fd749e8d Add some aliases when parsing config files for common key name variations 2019-09-08 19:28:41 +05:30
Luflosi
f3be5b5e57 Regenerate automatically generated key_encoding.py and keys.h 2019-09-08 12:32:20 +02:00
Luflosi
e619eb9cbb Add more keyboard keys 2019-09-08 12:32:19 +02:00
Luflosi
a65ee155c5 Indent lookup table in _glfwGetKeyName() to allow for longer keyboard key names 2019-09-08 12:32:19 +02:00
Luflosi
4037480d2b Allow for up to 256 keys instead of 128 2019-09-08 12:32:19 +02:00
Luflosi
97e6978ed8 Order keyboard keys by their ASCII value 2019-09-08 12:32:19 +02:00
Luflosi
f05eefcc20 Allow adding keys with Unicode names on macOS 2019-09-08 12:32:19 +02:00
Luflosi
3f926dfd8b Use keyboard key constants instead of hardcoded values 2019-09-08 12:32:18 +02:00
Luflosi
59f64c5e33 Blacklist GLFW_KEY_LAST_PRINTABLE in kitty/keys.py 2019-09-08 12:32:18 +02:00
Luflosi
87059a2004 Add GLFW_KEY_LAST_PRINTABLE as a GLFW constant 2019-09-08 12:32:18 +02:00
Luflosi
7c52dd2bd8 Fix update_encoding() not filtering GLFW_KEY_LAST_PRINTABLE
b3b830bb5f did not actually make `update_encoding()` filter `GLFW_KEY_LAST_PRINTABLE` because `name` contained the key name after applying `symbolic_name()`, which replaces underscores with spaces. Instead of replacing the underscore in `LAST_PRINTABLE` with a space, I moved the check above the call to `symbolic_name()`. This is more readable and future-proof in my opinion.
2019-09-08 12:32:18 +02:00
Kovid Goyal
70c2765a6e Allow reading session file from STDIN 2019-09-08 15:20:37 +05:30
Kovid Goyal
3618f4d642 Only try to wakeup talk thread if it has been started 2019-09-08 15:12:17 +05:30
Kovid Goyal
698569536d Output which loo could not be woken up 2019-09-08 14:58:11 +05:30
Kovid Goyal
c398d3d16e Cocoa: Fix glfwSetWindowSize anchor point
This makes glfwSetWindowSize use the top-left corner as anchor point
instead of the bottom-left corner.

Upstream: 7f02898264
2019-09-08 09:16:07 +05:30
Kovid Goyal
9dbc54aad6 Fix comparison of video modes of equal area
This fixes the bug of video modes being discarded if they had
a different resolution but the same area as another mode.

Upstream: 2777f6a754
2019-09-08 09:12:39 +05:30
Kovid Goyal
931cb223cd When all visible windows have the same background color, use that as the color for the global padding, instead of the configured background color
See #1957
2019-09-07 18:47:15 +05:30
Kovid Goyal
336ee53fea Merge branch 'joystick-platform' of https://github.com/jamessan/kitty 2019-09-04 08:43:16 +05:30
James McCoy
34350af61c Only use linux_joystick.c on Linux
Rather than using null_joystick.c when _plat is a bsd, use
linux_joystick.c when _plat is a linux.  This fixes a build issue with
other non-BSD, non-Linux platforms.
2019-09-03 23:02:16 -04:00
Kovid Goyal
72f7cb3b7d Merge branch 'format_key_encoding' of https://github.com/Luflosi/kitty 2019-09-02 07:49:30 +05:30
Luflosi
481047a446 Format kitty/key_encoding.py with yapf 2019-09-01 17:53:52 +02:00
Kovid Goyal
3bf1d73b07 Merge branch 'add_glfw_key_last_printable' of https://github.com/Luflosi/kitty 2019-09-01 17:52:39 +05:30
Luflosi
b3b830bb5f Make adding more printable keys slightly easier
When adding keys after `GLFW_KEY_UNDERSCORE`, one now needs to change a `#define` right below the last printable key instead of changing it elsewhere in the code.
This commit now also marks `GLFW_KEY_PLUS` and `GLFW_KEY_UNDERSCORE` as printable characters.
2019-09-01 11:24:14 +02:00
Kovid Goyal
def0c55df3 Merge branch 'add_missing_named_keys' of https://github.com/Luflosi/kitty 2019-09-01 05:43:27 +05:30
Luflosi
b995e00850 Add missing key to named_keys 2019-09-01 02:03:54 +02:00
Kovid Goyal
32dfc94909 Implement a hack to (mostly) preserve tabs when cat a file with them and then copying the text or passing screen contents to another program
It's a simple enough hack that it seems worth doing. If it causes any
issues, can always be reverted.

Fixes #1829
2019-08-31 12:37:05 +05:30
Kovid Goyal
20f7118432 version 0.14.4 2019-08-31 10:20:47 +05:30
Kovid Goyal
37e6c3f0cb Merge branch 'bool_indentation' of https://github.com/Luflosi/kitty 2019-08-30 19:08:46 +05:30
Luflosi
0459dda5c2 Fix bool indentation
The wrong indentation was caused by the removal of GLFWbool in fe62700825.
2019-08-30 15:32:20 +02:00
Kovid Goyal
a10c816c05 Merge branch 'fix_nslog_string_format' of https://github.com/Luflosi/kitty 2019-08-30 18:40:49 +05:30
Luflosi
c0c7cfacc2 Fix NSLog() printing of unicode format strings
See https://stackoverflow.com/questions/720052/nslog-incorrect-encoding.
The `%s` format placeholder for `NSLog()` expects an encoding other than UTF-8, which leads to garbled Unicode characters when trying to print a UTF-8 encoded string.
```Objective-C
NSLog(@"Ä %s %@", "Ä", @("Ä"));
```
prints `Ä √Ñ Ä`.

As can be seen in the example above, the workaround is to convert the UTF-8 encoded C-string to an `NSString` object and print that instead.
`debug_key()` calls `NSLog()`.
2019-08-30 15:03:51 +02:00
Kovid Goyal
8cdb6647ed Merge branch 'fix_update_encoding' of https://github.com/Luflosi/kitty 2019-08-30 16:20:42 +05:30
Luflosi
b68e3c85b9 Add missing MENU key to key_encoding.py 2019-08-30 12:37:23 +02:00
Luflosi
ef25d5bbd5 Fix update_encoding() not adding the last key 2019-08-30 12:36:37 +02:00
Kovid Goyal
278bf6e897 Fix #1937 2019-08-30 15:02:17 +05:30
Kovid Goyal
90a985b73a Make format_text() more secure 2019-08-28 05:41:20 +05:30
Kovid Goyal
b016353809 Some clarifications for the graphics protocol
See discussion on #33
2019-08-28 05:28:05 +05:30
Kovid Goyal
bc222af2e2 When dumping scrollback as ansi, reset SGR formatting at end of scrollback 2019-08-27 19:35:01 +05:30
Kovid Goyal
44599c9460 Merge branch 'simplify_compile_code' of https://github.com/Luflosi/kitty 2019-08-26 20:25:19 +05:30
Luflosi
902fc22670 Simplify GLFW compilation code
This commit removes the need for `is_macos` in `glfw/glfw.py` by moving a few lines of code. Instead of relying on the information that the compilation is or isn't happening on macOS, the code now does the right thing based on which `module` is being built.
This changes the order of the compilation flags slightly.
2019-08-26 16:47:19 +02:00
Kovid Goyal
d84e22fbf1 Merge branch 'fix_typos' of https://github.com/Luflosi/kitty 2019-08-26 16:34:54 +05:30
Luflosi
6cc720a350 Fix typos
Inspired by 4d3ee554b3.
Found using `codespell`.
2019-08-26 12:31:15 +02:00
Kovid Goyal
c905978874 Merge branch 'fix_issue_1924' of https://github.com/s1341/kitty
Fixes #1924
2019-08-26 10:19:50 +05:30
Kovid Goyal
bfe595a8e8 Merge branch '_glfwInputError_format' of https://github.com/Luflosi/kitty 2019-08-26 06:24:02 +05:30
Luflosi
94d56d1a9e Correct indentation for two _glfwInputError() messages
This commit changes the indentation of two error messages to match the indentation in the rest of the code.
2019-08-25 21:29:58 +02:00
s1341
bd3f0b5363 Properly handle all NULL cases 2019-08-25 17:22:06 +03:00
s1341
6fae3545c7 Fix null pointer deref 2019-08-25 16:39:39 +03:00
s1341
297963f6ab Fix issue #1924 by making prev_cell persistent across line_as_ansi calls 2019-08-25 16:25:36 +03:00
Kovid Goyal
a0ceba407e Merge branch 'drag_and_drop_text' of https://github.com/Luflosi/kitty 2019-08-24 08:39:27 +05:30
Kovid Goyal
35fa91fba2 When the OS returns a fallback font that does not actually contain glyphs for the text, do not exhaust the list of fallback fonts
Fixes #1918

Apparently fontconfig does this for Tangut components.
2019-08-24 08:27:54 +05:30
Kovid Goyal
a5d6cd169e Fix piping PNG images into the icat kitten not working
Fixes #1920
2019-08-24 08:04:04 +05:30
Luflosi
06c2263657 macOS: implement drag and drop of text into kitty
Closes #1368.
2019-08-24 01:29:33 +02:00
Kovid Goyal
472c6f6b8d When running kittens, use the colorscheme of the current window rather than the configured colorscheme
Fixes #1906
2019-08-18 18:27:44 +05:30
Kovid Goyal
afcaca85da Merge branch 'hints_regex_doc' of https://github.com/toonn/kitty 2019-08-18 07:41:14 +05:30
Toon Nolten
2575349ec2 Add expected regex syntax to hints kitten docs
The hints kitten's help documentation did not mention what syntax to use
for the regular expressions. I knew much of kitty was implemented in
python so I guessed correctly but not everyone might know this.

I also fixed some double-spaced sentences because most of them are
single-spaced.
2019-08-17 21:27:53 +02:00
Kovid Goyal
77054f688d Workaround for window managers like xmonad that in some circumstances set window size to zero. Fixes #1910 2019-08-17 18:04:08 +05:30
Kovid Goyal
c5cb24378f Merge branch 'fix_macos_show_window_title_in' of https://github.com/Luflosi/kitty 2019-08-14 06:36:25 +05:30
Luflosi
d66123dd14 Fix hiding the window title in macOS
In b5c2163238 I introduced a bug where only the window title of the first OS window would be hidden. This commit fixes that bug.
The bug was caused by the code hiding the window title being in an `if` statement that only executes once.
2019-08-13 21:02:28 +02:00
Kovid Goyal
4ef8f11f9e Merge branch 'add_frameworks_only_once' of https://github.com/Luflosi/kitty 2019-08-11 07:43:36 +05:30
Luflosi
599be7ddc9 Don't add Apple Frameworks twice
These Frameworks are added again a couple lines below in the check for `module == 'cocoa'`.
2019-08-11 02:26:12 +02:00
Kovid Goyal
685497fc8c Fix shaping test 2019-08-10 08:58:02 +05:30
Kovid Goyal
57542fc204 Only disable liga and dlig for nimbus mono 2019-08-10 08:22:36 +05:30
Kovid Goyal
8d9323aec6 Merge branch 'unnecessary_indentation' of https://github.com/Luflosi/kitty 2019-08-09 07:05:26 +05:30
Luflosi
4984a25b19 Remove unnecessary indentation 2019-08-09 03:27:22 +02:00
Kovid Goyal
3bdcb29e01 Merge branch 'trailing_whitespace' of https://github.com/Luflosi/kitty 2019-08-09 06:34:19 +05:30
Luflosi
b9ab8e6348 Remove trailing whitespace 2019-08-08 20:26:20 +02:00
Kovid Goyal
4a851701e9 Fix a regression that broke setting background_opacity via remote control
Fixes #1895
2019-08-07 15:09:04 +05:30
Kovid Goyal
eafd8af937 Merge branch 'glfw_3.4' of https://github.com/Luflosi/kitty 2019-08-03 07:38:14 +05:30
Luflosi
28bb123be8 Update the GLFW version number from 3.3 to 3.4
Closes https://github.com/kovidgoyal/kitty/issues/1884.
From a337c56848.
2019-08-02 11:00:16 -05:00
Kovid Goyal
8e1ed2f8c3 Update unicode data to 12.1 2019-08-02 14:48:18 +05:30
Kovid Goyal
4a0fcb3cff Merge branch 'macos_show_window_title_in' of https://github.com/Luflosi/kitty 2019-08-02 11:51:38 +05:30
Luflosi
b5c2163238 Add option to hide the window title on macOS
Deprecate `macos_show_window_title_in_menubar` and create a new option `macos_show_window_title_in`.
2019-08-02 00:20:43 -05:00
Kovid Goyal
d0ecdfb330 Add a :opt:kitten_alias option that can be used to alias kitten invocation for brevity and to change kitten option defaults globally
See #1879
2019-08-02 10:40:11 +05:30
Kovid Goyal
bdf7d98a36 hints kitten: Allow specifying :option:kitty +kitten hints --program multiple times to run multiple programs
See #1879
2019-08-02 10:03:04 +05:30
Kovid Goyal
e4b0980d15 DRYer 2019-08-02 07:18:42 +05:30
Kovid Goyal
d99c57aeae Merge branch 'open_context_manager' of https://github.com/Luflosi/kitty 2019-08-02 07:14:11 +05:30
Luflosi
5f855ce547 Use context managers to open files
Inspired by d50a6ddc1b.
2019-08-01 13:21:26 -05:00
Kovid Goyal
68f3b6fbeb Fix the decode_hint function to work with an arbitrary alphabet 2019-08-01 19:31:21 +05:30
Kovid Goyal
dc6d14943e Dont use a global variable for the hints alphabet 2019-08-01 19:24:09 +05:30
Kovid Goyal
05f7334db9 hints kitten: Add a :option:kitty +kitten hints --alphabet option to control what alphabets are used for hints
Fixes #1879
2019-08-01 16:25:54 +05:30
Kovid Goyal
cd707e9335 Merge branch 'wait_for_shell' of https://github.com/Luflosi/kitty 2019-08-01 12:56:12 +05:30
Luflosi
505ed5e43b Fix crash when the shell takes too long to start when reading the environment
According to https://docs.python.org/3/library/subprocess.html#subprocess.Popen.wait, `wait()` throws a `TimeoutExpired` exception when the process is not done after the timeout. I noticed this because kitty crashed for me.
The old code looks like it's trying to wait as long as it takes for the process to finish, which is what I implemented.
2019-08-01 02:03:08 -05:00
Kovid Goyal
9dc8bf5f62 Merge branch 'ignore_directories' of https://github.com/Luflosi/kitty 2019-08-01 06:38:34 +05:30
Luflosi
f8098662b6 Explicitly mark directories as such in .gitignore 2019-07-31 15:27:06 -05:00
Kovid Goyal
de7a0e86c4 Merge branch 'ignore_files_only_in_root' of https://github.com/Luflosi/kitty 2019-07-31 20:56:50 +05:30
Luflosi
ca55438fda Ignore several directories and files only in the root of the repo
These directories are always located in the root directory of the repository. Therefore it's better to only ignore these files in this location.
2019-07-31 10:16:19 -05:00
Kovid Goyal
a4b60e7eef Disable the `liga and dlig` OpenType features so that kitty works with "so-called" monospace fonts such as Nimbus Mono that have non-programming ligatures. 2019-07-31 20:02:48 +05:30
Kovid Goyal
5d22e07738 More details on login shell invocation 2019-07-31 12:20:02 +05:30
Kovid Goyal
bdade7e151 Use a new controlling terminal when reading shell environment
This is because some people do things in their rc files based
on checking the name of the controlling terminal.
2019-07-31 11:34:54 +05:30
Kovid Goyal
6958ded4c4 Dont fail to start if running the shell to read the EDITOR env var fails
Fixes #1869
2019-07-31 06:37:17 +05:30
Kovid Goyal
cc06104be6 Create FUNDING.yml
Add links to the various funding sources
2019-07-30 15:07:12 +05:30
Kovid Goyal
059c34c345 Add a version check to the installer on macOS 2019-07-30 15:01:07 +05:30
Kovid Goyal
9cbb726566 Fix #1865 2019-07-30 06:20:54 +05:30
Kovid Goyal
e8b4356a88 Merge branch 'ignore_build_only_in_root' of https://github.com/Luflosi/kitty 2019-07-29 11:37:36 +05:30
Kovid Goyal
634138cd3b Removed unused entry from .gitignore
Fixes #1859

tags is the file generated by ctags
2019-07-29 11:36:46 +05:30
Luflosi
3f6b07de81 Ignore the build directory only in the root of the repo
The `build` directory is always located at the root directory of the repository. Therefore it's better to only ignore `build` in this location.
2019-07-29 00:59:35 -05:00
158 changed files with 42710 additions and 33779 deletions

4
.gitattributes vendored
View File

@@ -3,11 +3,11 @@ kitty/emoji.h linguist-generated=true
kitty/keys.h linguist-generated=true
kitty/charsets.c linguist-generated=true
kitty/key_encoding.py linguist-generated=true
kitty/unicode-data.c
kitty/unicode-data.c linguist-generated=true
kitty/rgb.py linguist-generated=true
kitty/gl-wrapper.* linguist-generated=true
kitty/khrplatform.h linguist-generated=true
kitty/glfw-wrapper.* linguist-generated=true
kitty/parse-graphics-command.h linguist-generated=true
glfw/*.c linguist-vendored=true
glfw/*.h linguist-vendored=true
kittens/unicode_input/names.h linguist-generated=true

3
.github/FUNDING.yml vendored Normal file
View File

@@ -0,0 +1,3 @@
patreon: kovidgoyal
liberapay: kovidgoyal
custom: https://sw.kovidgoyal.net/kitty/support.html

27
.gitignore vendored
View File

@@ -1,18 +1,17 @@
*.so
*.pyc
*.pyo
tags
build
linux-package
kitty.app
compile_commands.json
link_commands.json
glad/out
kitty/launcher
*.dSYM
dev
__pycache__
glfw/wayland-*-client-protocol.[ch]
docs/_build
docs/generated
/tags
/build/
/linux-package/
/kitty.app/
/compile_commands.json
/link_commands.json
/glad/out/
/kitty/launcher/
/*.dSYM/
__pycache__/
/glfw/wayland-*-client-protocol.[ch]
/docs/_build/
/docs/generated/
.DS_Store

View File

@@ -1,8 +1,8 @@
ifdef V
VVAL=--verbose
VVAL=--verbose
endif
ifdef VERBOSE
VVAL=--verbose
VVAL=--verbose
endif
all:
@@ -28,7 +28,7 @@ asan:
profile:
python3 setup.py build $(VVAL) --profile
app:
app:
python3 setup.py kitty.app $(VVAL)
man:

View File

@@ -1,5 +1,5 @@
= kitty - the fast, featureful, GPU based, terminal emulator
See https://sw.kovidgoyal.net/kitty
See https://sw.kovidgoyal.net/kitty/
image:https://circleci.com/gh/kovidgoyal/kitty.svg?style=svg["Build status", link="https://circleci.com/gh/kovidgoyal/kitty"]

View File

@@ -92,8 +92,10 @@ def setup_openssl_environment():
if 'SSL_CERT_FILE' not in os.environ and 'SSL_CERT_DIR' not in os.environ:
if os.access('/etc/pki/tls/certs/ca-bundle.crt', os.R_OK):
os.environ['SSL_CERT_FILE'] = '/etc/pki/tls/certs/ca-bundle.crt'
sys.kitty_ssl_env_var = 'SSL_CERT_FILE'
elif os.path.isdir('/etc/ssl/certs'):
os.environ['SSL_CERT_DIR'] = '/etc/ssl/certs'
sys.kitty_ssl_env_var = 'SSL_CERT_DIR'
def main():

View File

@@ -1,2 +1,27 @@
#!/usr/bin/env bash
cloc --exclude-list-file <(echo -e 'kitty/wcwidth-std.h\nkitty/glfw.c\nkitty/keys.h\nkitty/charsets.c\nkitty/unicode-data.c\nkitty/key_encoding.py\nkitty/rgb.py\nkitty/gl.h\nkitty/gl-wrapper.h\nkitty/gl-wrapper.c\nkitty/khrplatform.h\nkitty/glfw-wrapper.h\nkitty/glfw-wrapper.c\nkitty/emoji.h\nkittens/unicode_input/names.h') kitty kittens
#!/usr/bin/env python
import subprocess
files_to_exclude = '''\
kitty/wcwidth-std.h
kitty/glfw.c
kitty/keys.h
kitty/charsets.c
kitty/unicode-data.c
kitty/key_encoding.py
kitty/rgb.py
kitty/gl.h
kitty/gl-wrapper.h
kitty/gl-wrapper.c
kitty/glfw-wrapper.h
kitty/glfw-wrapper.c
kitty/emoji.h
kittens/unicode_input/names.h
kitty/parse-graphics-command.h
'''
p = subprocess.Popen([
'cloc', '--exclude-list-file', '/dev/stdin', 'kitty', 'kittens'
], stdin=subprocess.PIPE)
p.communicate(files_to_exclude.encode('utf-8'))
raise SystemExit(p.wait())

View File

@@ -78,6 +78,8 @@ body div.document {
div.sphinxsidebar {
font-size: inherit;
line-height: inherit;
max-height: 100%;
overflow-y: auto;
}
#sidebartoc li {

View File

@@ -29,7 +29,7 @@ Build-time dependencies:
* gcc or clang
* pkg-config
* For building on Linux in addition to the above dependencies you might also need to install the ``-dev`` packages for:
``libdbus-1-dev``, ``libxcursor-dev``, ``libxrandr-dev``, ``libxi-dev``, ``libxinerama-dev``, ``libgl1-mesa-dev``, ``libxkbcommon-x11-dev``, ``libfontconfig-dev``, ``libcanberra-dev`` and ``libpython-dev``.
``libdbus-1-dev``, ``libxcursor-dev``, ``libxrandr-dev``, ``libxi-dev``, ``libxinerama-dev``, ``libgl1-mesa-dev``, ``libxkbcommon-x11-dev``, ``libfontconfig-dev``, and ``libpython-dev``,
if they are not already installed by your distro.
Install and run from source

View File

@@ -4,6 +4,128 @@ Changelog
|kitty| is a feature full, cross-platform, *fast*, GPU based terminal emulator.
To update |kitty|, :doc:`follow the instructions <binary>`.
0.15.0 [2019-11-27]
--------------------
- Add a new action :ref:`detach_window <detach_window>` that can be used to move the current
window into a different tab (:iss:`1310`)
- Add a new action :doc:`launch <launch>` that unifies launching of processes
in new kitty windows/tabs.
- Add a new style ``powerline`` for tab bar rendering, see :opt:`tab_bar_style` (:pull:`2021`)
- Allow changing colors by mapping a keyboard shortcut to read a kitty config
file with color definitions. See the :doc:`FAQ <faq>` for details
(:iss:`2083`)
- hints kitten: Allow completely customizing the matching and actions performed
by the kitten using your own script (:iss:`2124`)
- Wayland: Fix key repeat not being stopped when focus leaves window. This is
expected behavior on Wayland, apparently (:iss:`2014`)
- When drawing unicode symbols that are followed by spaces, use multiple cells
to avoid resized or cut-off glyphs (:iss:`1452`)
- diff kitten: Allow diffing remote files easily via ssh (:iss:`727`)
- unicode input kitten: Add an option :option:`kitty +kitten unicode_input
--emoji-variation` to control the presentation variant of selected emojis
(:iss:`2139`)
- Add specialised rendering for a few more box powerline and unicode symbols
(:pull:`2074` and :pull:`2021`)
- Add a new socket only mode for :opt:`allow_remote_control`. This makes
it possible for programs running on the local machine to control kitty
but not programs running over ssh.
- hints kitten: Allow using named groups in the regular expression. The named
groups are passed to the invoked program for further processing.
- Fix a regression in 0.14.5 that caused rendering of private use glyphs
with and without spaces to be identical (:iss:`2117`)
- Wayland: Fix incorrect scale used when first creating an OS window
(:iss:`2133`)
- macOS: Disable mouse hiding by default as getting it to work robustly
on Cocoa is too much effort (:iss:`2158`)
0.14.6 [2019-09-25]
---------------------
- macOS: Fix a regression in the previous release that caused a crash when
pressing a unprintable key, such as the POWER key (:iss:`1997`)
- Fix a regression in the previous release that caused kitty to not always
respond to DPI changes (:pull:`1999`)
0.14.5 [2019-09-23]
---------------------
- Implement a hack to (mostly) preserve tabs when cat-ting a file with them and then
copying the text or passing screen contents to another program (:iss:`1829`)
- When all visible windows have the same background color, use that as the
color for the global padding, instead of the configured background color
(:iss:`1957`)
- When resetting the terminal, also reset parser state, this allows easy
recovery from incomplete escape codes (:iss:`1961`)
- Allow mapping keys commonly found on European keyboards (:pull:`1928`)
- Fix incorrect rendering of some symbols when followed by a space while using
the PowerLine font which does not have a space glyph (:iss:`1225`)
- Linux: Allow using fonts with spacing=90 in addition to fonts with
spacing=100 (:iss:`1968`)
- Use selection foreground color for underlines as well (:iss:`1982`)
0.14.4 [2019-08-31]
---------------------
- hints kitten: Add a :option:`kitty +kitten hints --alphabet` option to
control what alphabets are used for hints (:iss:`1879`)
- hints kitten: Allow specifying :option:`kitty +kitten hints --program`
multiple times to run multiple programs (:iss:`1879`)
- Add a :opt:`kitten_alias` option that can be used to alias kitten invocation
for brevity and to change kitten option defaults globally (:iss:`1879`)
- macOS: Add an option :opt:`macos_show_window_title_in` to control
showing the window title in the menubar/titlebar (:pull:`1837`)
- macOS: Allow drag and drop of text from other applications into kitty
(:pull:`1921`)
- When running kittens, use the colorscheme of the current window
rather than the configured colorscheme (:iss:`1906`)
- Don't fail to start if running the shell to read the EDITOR env var fails
(:iss:`1869`)
- Disable the ``liga`` and ``dlig`` OpenType features for broken fonts
such as Nimbus Mono.
- Fix a regression that broke setting background_opacity via remote control
(:iss:`1895`)
- Fix piping PNG images into the icat kitten not working (:iss:`1920`)
- When the OS returns a fallback font that does not actually contain glyphs
for the text, do not exhaust the list of fallback fonts (:iss:`1918`)
- Fix formatting attributes not reset across line boundaries when passing
buffer as ANSI (:iss:`1924`)
0.14.3 [2019-07-29]
---------------------
@@ -192,7 +314,7 @@ To update |kitty|, :doc:`follow the instructions <binary>`.
- macOS: Fix :kbd:`cmd+period` key not working (:iss:`1318`)
- macOS: Add an option :opt:`macos_show_window_title_in_menubar` to not
- macOS: Add an option `macos_show_window_title_in_menubar` to not
show the current window title in the menu-bar (:iss:`1066`)
- macOS: Workaround for cocoa bug that could cause the mouse cursor to become

View File

@@ -1,5 +1,5 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# vim:fileencoding=utf-8
#
# Configuration file for the Sphinx documentation builder.
#
@@ -243,7 +243,17 @@ def add_html_context(app, pagename, templatename, context, *args):
# CLI docs {{{
def write_cli_docs(all_kitten_names):
from kitty.launch import options_spec as launch_options_spec
from kitty.cli import option_spec_as_rst
with open('generated/launch.rst', 'w') as f:
f.write(option_spec_as_rst(
appname='launch', ospec=launch_options_spec, heading_char='_',
message='''\
Launch an arbitrary program in a new kitty window/tab. Note that
if you specify a program-to-run you can use the special placeholder
:code:`@selection` which will be replaced by the current selection.
'''
))
with open('generated/cli-kitty.rst', 'w') as f:
f.write(option_spec_as_rst(appname='kitty').replace(
'kitty --to', 'kitty @ --to'))

View File

@@ -63,6 +63,18 @@ Really, the correct solution for this is to convince the OpenSSH maintainers to
have ssh do this automatically, if possible, when connecting to a server, so that
all terminals work transparently.
If the server is running FreeBSD, or another system that relies on termcap
rather than terminfo, you will need to convert the terminfo file on your local
machine by running (on local machine with |kitty|)::
infocmp -C xterm-kitty
The output of this command is the termcap description, which should be appended
to :file:`/usr/share/misc/termcap` on the remote server. Then run the following
command to apply your change (on the server)::
cap_mkdb /usr/share/misc/termcap
Keys such as arrow keys, backspace, delete, home/end, etc. do not work when using su or sudo?
-------------------------------------------------------------------------------------------------
@@ -97,8 +109,13 @@ How do I change the colors in a running kitty instance?
You can either use the
`OSC terminal escape codes <https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Operating-System-Commands>`_
to set colors or you can enable :doc:`remote control <remote-control>`
for |kitty| and use :ref:`at_set-colors`.
to set colors or you can define keyboard shortcuts to set colors, for example::
map f1 set_colors --configured /path/to/some/config/file/colors.conf
Or you can enable :doc:`remote control <remote-control>` for |kitty| and use :ref:`at_set-colors`.
The shortcut mapping technique has the same syntax as the remote control
command, for details, see :ref:`at_set-colors`.
A list of pre-made color themes for kitty is available at:
`kitty-themes <https://github.com/dexpota/kitty-themes>`_
@@ -152,7 +169,32 @@ only monospace fonts, since every cell in the grid has to be the same size. If
your font is not listed in ``kitty list-fonts`` it means that it is not
monospace. On Linux you can list all monospace fonts with::
fc-list : family spacing | grep spacing=100
fc-list : family spacing | grep -e spacing=100 -e spacing=90
Note that the spacing property is calculated by fontconfig based on actual
glyph widths in the font. If for some reason fontconfig concludes your favorite
monospace font does not have ``spacing=100`` you can override it by using the
following :file:`~/.config/fontconfig/fonts.conf`::
<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
<fontconfig>
<match target="scan">
<test name="family">
<string>Your Font Family Name</string>
</test>
<edit name="spacing">
<int>100</int>
</edit>
</match>
</fontconfig>
After creating (or modifying) this file, you may need to run the following
command to rebuild your fontconfig cache::
fc-cache -r
Then, the font will be available in ``kitty list-fonts``.
How can I assign a single global shortcut to bring up the kitty terminal?
@@ -172,7 +214,7 @@ For example::
map alt+s send_text all \x13
This maps :kbd:`alt+s`` to :kbd:`ctrl+s`. To figure out what bytes to use for
This maps :kbd:`alt+s` to :kbd:`ctrl+s`. To figure out what bytes to use for
the :sc:`send_text <send_text>` you can use the ``showkey`` utility. Run::
showkey -a

View File

@@ -107,7 +107,8 @@ features of the graphics protocol:
sys.stdout.flush()
cmd.clear()
write_chunked({'a': 'T', 'f': 100}, open(sys.argv[-1], 'rb').read())
with open(sys.argv[-1], 'rb') as f:
write_chunked({'a': 'T', 'f': 100}, f.read())
Save this script as :file:`png.py`, then you can use it to display any PNG
@@ -255,7 +256,10 @@ sequence of escape codes to the terminal emulator::
Note that only the first escape code needs to have the full set of control
codes such as width, height, format etc. Subsequent chunks must have
only the ``m`` key. The client **must** finish sending all chunks for a single image
before sending any other graphics related escape codes.
before sending any other graphics related escape codes. Note that the cursor
position used to display the image **must** be the position when the final chunk is
received. Finally, terminals must not display anything, until the entire sequence is
received and validated.
Detecting available transmission mediums

View File

@@ -59,7 +59,7 @@ See the :doc:`binary install instructions </binary>`. You can also
You can also use your favorite package manager to install the |kitty| package.
|kitty| packages are available for:
`macOS with Homebrew (Cask) <https://formulae.brew.sh/cask/kitty>`_,
`macOS and Linux with Nix <https://nixos.org/nixos/packages.html#kitty>`_,
`macOS and Linux with Nix <https://nixos.org/nixos/packages.html?channel=nixpkgs-unstable&query=kitty>`_,
`Ubuntu <https://launchpad.net/ubuntu/+source/kitty>`_,
`Debian <https://packages.debian.org/buster/kitty>`_,
`openSUSE <https://build.opensuse.org/package/show/X11:terminals/kitty>`_,
@@ -173,6 +173,19 @@ You can also define a shortcut to switch to the previously active window::
``nth_window`` will focus the nth window for positive numbers and the
previously active windows for negative numbers.
.. _detach_window:
You can define shortcuts to detach the current window and
move it to another tab or another OS window::
map ctrl+f2 detach_window # moves the window into a new OS window
map ctrl+f3 detach_window new-tab # moves the window into a new Tab
map ctrl+f4 detach_window ask # asks which tab to move the window into
Similarly, you can detach the current tab, with::
map ctrl+f2 detach_tab # moves the tab into a new OS window
map ctrl+f4 detach_tab ask # asks which OS Window to move the tab into
Other keyboard shortcuts
----------------------------------
@@ -402,7 +415,7 @@ comfortably within the pager.
Additionally, you can pipe the contents of the scrollback buffer to an
arbitrary, command running in a new window, tab or overlay, for example::
map f1 pipe @ansi window less +G -R
map f1 launch --stdin-source=@screen_scrollback --stdin-add-formatting less +G -R
Would open the scrollback buffer in a new window when you press the :kbd:`F1`
key. See :sc:`show_scrollback` for details.
@@ -478,7 +491,8 @@ completions happens after the call to :file:`compinit`.
fish
~~~~~~~~
Add the following to your :file:`~/.config/fish/config.fish`
For versions of fish earlier than 3.0.0, add the following to your
:file:`~/.config/fish/config.fish`. Later versions source completions by default.
.. code-block:: sh

View File

@@ -20,6 +20,10 @@ import tempfile
py3 = sys.version_info[0] > 2
is64bit = platform.architecture()[0] == '64bit'
is_macos = 'darwin' in sys.platform.lower()
if is_macos:
mac_ver = tuple(map(int, platform.mac_ver()[0].split('.')))
if mac_ver[:2] < (10, 12):
raise SystemExit('Your version of macOS is too old, at least 10.12 is required')
try:
__file__
@@ -225,7 +229,8 @@ def script_launch():
def update_intaller_wrapper():
# To run: python3 -c "import runpy; runpy.run_path('installer.py', run_name='update_wrapper')" installer.sh
src = open(__file__, 'rb').read().decode('utf-8')
with open(__file__, 'rb') as f:
src = f.read().decode('utf-8')
wrapper = sys.argv[-1]
with open(wrapper, 'r+b') as f:
raw = f.read().decode('utf-8')

View File

@@ -128,7 +128,27 @@ layout, by simply adding the line::
boss.toggle_fullscreen()
to the ``handle_result()`` function, above.
To the ``handle_result()`` function, above.
Debugging kittens
--------------------
The part of the kitten that runs in ``main()`` is just a normal program and
the output of print statements will be visible in the kitten window. Or
alternately, you can use::
from kittens.tui.loop import debug
debug('whatever')
The ``debug()`` function is just like ``print()`` except that the output
will appear in the ``STDOUT`` of the kitty process inside which the kitten is
running.
The ``handle_result()`` part of the kitten runs inside the kitty process.
The output of print statements will go to the ``STDOUT`` of the kitty process.
So if you run kitty from another kitty instance, the output will be visible
in the first kitty instance.
.. _external_kittens:

View File

@@ -23,6 +23,56 @@ options and modes of operation, see below. You can use these options to
create mappings in :file:`kitty.conf` to select various different text
snippets. See :sc:`insert_selected_path` for examples.
Completely customizing the matching and actions of the kitten
---------------------------------------------------------------
The hints kitten supports writing simple python scripts that can be used to
completely customize how it finds matches and what happens when a match is
selected. This allows the hints kitten to provide the user interface, while
you can provide the logic for finding matches and performing actions on them.
This is best illustrated with an example. Create the file
:file:`custom-hints.py` in the kitty config directory with the following
contents:
.. code-block:: python
import re
def mark(text, args, Mark, extra_cli_args, *a):
# This function is responsible for finding all
# matching text. extra_cli_args are any extra arguments
# passed on the command line when invoking the kitten.
# We mark all individual word for potential selection
for idx, m in enumerate(re.finditer(r'\w+', text)):
start, end = m.span()
mark_text = text[start:end].replace('\n', '').replace('\0', '')
# The empty dictionary below will be available as groupdicts
# in handle_result() and can contain arbitrary data.
yield Mark(idx, start, end, mark_text, {})
def handle_result(args, data, target_window_id, boss, extra_cli_args, *a):
# This function is responsible for performing some
# action on the selected text.
# matches is a list of the selected entries and groupdicts contains
# the arbitrary data associated with each entry in mark() above
matches, groupdicts = [], []
for m, g in zip(data['match'], data['groupdicts']):
if m:
matches.append(m), groupdicts.append(g)
for word, match_data in zip(matches, groupdicts):
# Lookup the word in a dictionary, the open_url function
# will open the provided url in the system browser
boss.open_url(f'https://www.google.com/search?q=define:{word}')
Now run kitty with::
kitty -o 'map f1 kitten hints --customize-processing custom-hints.py'
When you press the :kbd:`F1` key you will be able to select a word to
look it up in the Google dictionary.
Command Line Interface
-------------------------

View File

@@ -22,3 +22,8 @@ In :guilabel:`Name` mode you instead type words from the character name and use
keys/tab to select the character from the displayed matches. You can also type
a leading period and the index for the match if you don't like to use arrow
keys.
Command Line Interface
-------------------------
.. include:: ../generated/cli-kitten-unicode_input.rst

56
docs/launch.rst Normal file
View File

@@ -0,0 +1,56 @@
Launching programs in new windows/tabs
========================================
.. program:: launch
|kitty| has a :code:`launch` action that can be used to run arbitrary programs
in news windows/tabs. It can be mapped to user defined shortcuts in kitty.conf.
It is very powerful and allows sending the contents of
the current window to the launched program, as well as many other options.
In the simplest form, you can use it to open a new kitty window running the
shell, as shown below::
map f1 launch
To run a different program simply pass the command line as arguments to
launch::
map f1 launch vim path/to/some/file
To open a new window with the same working directory as the currently
active window::
map f1 launch --cwd=current
To open the new window in a new tab::
map f1 launch --type=tab
To pass the contents of the current screen and scrollback to the started process::
map f1 launch --stdin-source=@screen_scrollback less
There are many more powerful options, refer to the complete list below.
The piping environment
--------------------------
When using :option:`launch --stdin-source`, the program to which the data is
piped has a special environment variable declared, ``KITTY_PIPE_DATA`` whose
contents are::
KITTY_PIPE_DATA={scrolled_by}:{cursor_x},{cursor_y}:{lines},{columns}
where ``scrolled_by`` is the number of lines kitty is currently scrolled by,
``cursor_(x|y)`` is the position of the cursor on the screen with ``(1,1)``
being the top left corner and ``{lines},{columns}`` being the number of rows
and columns of the screen.
Syntax reference
------------------
.. include:: /generated/launch.rst

View File

@@ -1,6 +1,9 @@
Working with the screen and history buffer contents
======================================================
.. warning::
The pipe action has been deprecated in favor of the
:doc:`launch <launch>` action which is more powerful.
You can pipe the contents of the current screen and history buffer as
:file:`STDIN` to an arbitrary program using the ``pipe`` function. The program
@@ -56,6 +59,9 @@ Input placeholders
There are various different kinds of placeholders
``@selection``
Plain text, currently selected text
``@text``
Plain text, current screen + scrollback buffer

View File

@@ -2,7 +2,7 @@ Documentation for the kitty remote control protocol
======================================================
The kitty remote control protocol is a simple protocol that involves sending
data to kitty in the form of JSON. Any individual command ot kitty has the
data to kitty in the form of JSON. Any individual command of kitty has the
form::
<ESC>P@kitty-cmd<JSON object><ESC>\
@@ -21,7 +21,7 @@ standalone client, use the kitty version that you are developing against. Using
a version greater than the version of the kitty instance you are talking to,
will cause a failure.
Set ``no_response`` to True if you dont want a response from kitty.
Set ``no_response`` to True if you don't want a response from kitty.
The optional payload is a JSON object that is specific to the actual command being sent.
The fields in the object for every command are documented below.

View File

@@ -126,7 +126,7 @@ If you do not want to allow all programs running in |kitty| to control it, you c
enable remote control for only some |kitty| windows. Simply create a shortcut
such as::
map ctrl+k new_window @ some_program
map ctrl+k launch --allow-remote-control some_program
Then programs running in windows created with that shortcut can use ``kitty @``
to control kitty. Note that any program with the right level of permissions can

View File

@@ -29,10 +29,12 @@ def get_data(fname, folder='UCD'):
bn = os.path.basename(url)
local = os.path.join('/tmp', bn)
if os.path.exists(local):
data = open(local, 'rb').read()
with open(local, 'rb') as f:
data = f.read()
else:
data = urlopen(url).read()
open(local, 'wb').write(data)
with open(local, 'wb') as f:
f.write(data)
for line in data.decode('utf-8').splitlines():
line = line.strip()
if line and not line.startswith('#'):
@@ -41,6 +43,7 @@ def get_data(fname, folder='UCD'):
# Map of class names to set of codepoints in class
class_maps = {}
all_symbols = set()
name_map = {}
word_search_map = defaultdict(set)
zwj = 0x200d
@@ -87,6 +90,8 @@ def parse_ucd():
not_assigned.discard(codepoint)
if category.startswith('M'):
marks.add(codepoint)
elif category.startswith('S'):
all_symbols.add(codepoint)
# Some common synonyms
word_search_map['bee'] |= word_search_map['honeybee']
@@ -166,21 +171,20 @@ def write_case(spec, p):
@contextmanager
def create_header(path, include_data_types=True):
f = open(path, 'w')
p = partial(print, file=f)
p('// unicode data, built from the unicode standard on:', date.today())
p('// see gen-wcwidth.py')
if path.endswith('.h'):
p('#pragma once')
if include_data_types:
p('#include "data-types.h"\n')
p('START_ALLOW_CASE_RANGE')
p()
yield p
p()
if include_data_types:
p('END_ALLOW_CASE_RANGE')
f.close()
with open(path, 'w') as f:
p = partial(print, file=f)
p('// unicode data, built from the unicode standard on:', date.today())
p('// see gen-wcwidth.py')
if path.endswith('.h'):
p('#pragma once')
if include_data_types:
p('#include "data-types.h"\n')
p('START_ALLOW_CASE_RANGE')
p()
yield p
p()
if include_data_types:
p('END_ALLOW_CASE_RANGE')
def gen_emoji():
@@ -193,6 +197,7 @@ def gen_emoji():
p('\t\tdefault: return false;')
p('\t}')
p('\treturn false;\n}')
p('static inline bool\nis_emoji_modifier(char_type code) {')
p('\tswitch(code) {')
for spec in get_ranges(list(emoji_categories['Emoji_Modifier'])):
@@ -202,6 +207,15 @@ def gen_emoji():
p('\t}')
p('\treturn false;\n}')
p('static inline bool\nis_symbol(char_type code) {')
p('\tswitch(code) {')
for spec in get_ranges(list(all_symbols)):
write_case(spec, p)
p('\t\t\treturn true;')
p('\t\tdefault: return false;')
p('\t}')
p('\treturn false;\n}')
def category_test(name, p, classes, comment, static=False, extra_chars=frozenset(), exclude=frozenset()):
static = 'static inline ' if static else ''
@@ -282,7 +296,9 @@ def gen_ucd():
p('combining_type mark_for_codepoint(char_type c) {')
rmap = codepoint_to_mark_map(p, mark_map)
p('}\n')
expected = int(re.search(r'^#define VS15 (\d+)', open('kitty/unicode-data.h').read(), re.M).group(1))
with open('kitty/unicode-data.h') as f:
unicode_data = f.read()
expected = int(re.search(r'^#define VS15 (\d+)', unicode_data, re.M).group(1))
if rmap[0xfe0e] != expected:
raise ValueError('The mark for 0xfe0e has changed, you have to update VS15 to {} and VS16 to {} in unicode-data.h'.format(
rmap[0xfe0e], rmap[0xfe0f]

45
glfw/backend_utils.c vendored
View File

@@ -22,19 +22,6 @@
#define ppoll pollts
#endif
static inline double
monotonic(void) {
struct timespec ts = {0};
#ifdef CLOCK_HIGHRES
clock_gettime(CLOCK_HIGHRES, &ts);
#elif CLOCK_MONOTONIC_RAW
clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
#else
clock_gettime(CLOCK_MONOTONIC, &ts);
#endif
return (((double)ts.tv_nsec) / 1e9) + (double)ts.tv_sec;
}
void
update_fds(EventLoopData *eld) {
for (nfds_t i = 0; i < eld->watches_count; i++) {
@@ -109,7 +96,7 @@ update_timers(EventLoopData *eld) {
}
id_type
addTimer(EventLoopData *eld, const char *name, double interval, int enabled, bool repeats, timer_callback_func cb, void *cb_data, GLFWuserdatafreefun free) {
addTimer(EventLoopData *eld, const char *name, monotonic_t interval, int enabled, bool repeats, timer_callback_func cb, void *cb_data, GLFWuserdatafreefun free) {
if (eld->timers_count >= sizeof(eld->timers)/sizeof(eld->timers[0])) {
_glfwInputError(GLFW_PLATFORM_ERROR, "Too many timers added");
return 0;
@@ -117,7 +104,7 @@ addTimer(EventLoopData *eld, const char *name, double interval, int enabled, boo
Timer *t = eld->timers + eld->timers_count++;
t->interval = interval;
t->name = name;
t->trigger_at = enabled ? monotonic() + interval : DBL_MAX;
t->trigger_at = enabled ? monotonic() + interval : MONOTONIC_T_MAX;
t->repeats = repeats;
t->callback = cb;
t->callback_data = cb_data;
@@ -144,7 +131,7 @@ void
toggleTimer(EventLoopData *eld, id_type timer_id, int enabled) {
for (nfds_t i = 0; i < eld->timers_count; i++) {
if (eld->timers[i].id == timer_id) {
double trigger_at = enabled ? (monotonic() + eld->timers[i].interval) : DBL_MAX;
monotonic_t trigger_at = enabled ? (monotonic() + eld->timers[i].interval) : MONOTONIC_T_MAX;
if (trigger_at != eld->timers[i].trigger_at) {
eld->timers[i].trigger_at = trigger_at;
update_timers(eld);
@@ -155,7 +142,7 @@ toggleTimer(EventLoopData *eld, id_type timer_id, int enabled) {
}
void
changeTimerInterval(EventLoopData *eld, id_type timer_id, double interval) {
changeTimerInterval(EventLoopData *eld, id_type timer_id, monotonic_t interval) {
for (nfds_t i = 0; i < eld->timers_count; i++) {
if (eld->timers[i].id == timer_id) {
eld->timers[i].interval = interval;
@@ -165,11 +152,11 @@ changeTimerInterval(EventLoopData *eld, id_type timer_id, double interval) {
}
double
prepareForPoll(EventLoopData *eld, double timeout) {
monotonic_t
prepareForPoll(EventLoopData *eld, monotonic_t timeout) {
for (nfds_t i = 0; i < eld->watches_count; i++) eld->fds[i].revents = 0;
if (!eld->timers_count || eld->timers[0].trigger_at == DBL_MAX) return timeout;
double now = monotonic(), next_repeat_at = eld->timers[0].trigger_at;
if (!eld->timers_count || eld->timers[0].trigger_at == MONOTONIC_T_MAX) return timeout;
monotonic_t now = monotonic(), next_repeat_at = eld->timers[0].trigger_at;
if (timeout < 0 || now + timeout > next_repeat_at) {
timeout = next_repeat_at <= now ? 0 : next_repeat_at - now;
}
@@ -177,10 +164,8 @@ prepareForPoll(EventLoopData *eld, double timeout) {
}
int
pollWithTimeout(struct pollfd *fds, nfds_t nfds, double timeout) {
const long seconds = (long) timeout;
const long nanoseconds = (long) ((timeout - seconds) * 1e9);
struct timespec tv = { seconds, nanoseconds };
pollWithTimeout(struct pollfd *fds, nfds_t nfds, monotonic_t timeout) {
struct timespec tv = calc_time(timeout);
return ppoll(fds, nfds, &tv, NULL);
}
@@ -198,10 +183,10 @@ dispatchEvents(EventLoopData *eld) {
unsigned
dispatchTimers(EventLoopData *eld) {
if (!eld->timers_count || eld->timers[0].trigger_at == DBL_MAX) return 0;
if (!eld->timers_count || eld->timers[0].trigger_at == MONOTONIC_T_MAX) return 0;
static struct { timer_callback_func func; id_type id; void* data; bool repeats; } dispatches[sizeof(eld->timers)/sizeof(eld->timers[0])];
unsigned num_dispatches = 0;
double now = monotonic();
monotonic_t now = monotonic();
for (nfds_t i = 0; i < eld->timers_count && eld->timers[i].trigger_at <= now; i++) {
eld->timers[i].trigger_at = now + eld->timers[i].interval;
dispatches[num_dispatches].func = eld->timers[i].callback;
@@ -299,12 +284,12 @@ finalizePollData(EventLoopData *eld) {
}
int
pollForEvents(EventLoopData *eld, double timeout) {
pollForEvents(EventLoopData *eld, monotonic_t timeout) {
int read_ok = 0;
timeout = prepareForPoll(eld, timeout);
EVDBG("pollForEvents final timeout: %.3f", timeout);
EVDBG("pollForEvents final timeout: %.3f", monotonic_t_to_s_double(timeout));
int result;
double end_time = monotonic() + timeout;
monotonic_t end_time = monotonic() + timeout;
eld->wakeup_fd_ready = false;
while(1) {

15
glfw/backend_utils.h vendored
View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 Wayland - www.glfw.org
// GLFW 3.4 Wayland - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2014 Jonas Ådahl <jadahl@gmail.com>
//
@@ -25,6 +25,7 @@
//========================================================================
#pragma once
#include "../kitty/monotonic.h"
#include <poll.h>
#include <unistd.h>
#include <stdbool.h>
@@ -55,7 +56,7 @@ typedef struct {
typedef struct {
id_type id;
double interval, trigger_at;
monotonic_t interval, trigger_at;
timer_callback_func callback;
void *callback_data;
GLFWuserdatafreefun free;
@@ -82,14 +83,14 @@ void check_for_wakeup_events(EventLoopData *eld);
id_type addWatch(EventLoopData *eld, const char *name, int fd, int events, int enabled, watch_callback_func cb, void *cb_data);
void removeWatch(EventLoopData *eld, id_type watch_id);
void toggleWatch(EventLoopData *eld, id_type watch_id, int enabled);
id_type addTimer(EventLoopData *eld, const char *name, double interval, int enabled, bool repeats, timer_callback_func cb, void *cb_data, GLFWuserdatafreefun free);
id_type addTimer(EventLoopData *eld, const char *name, monotonic_t interval, int enabled, bool repeats, timer_callback_func cb, void *cb_data, GLFWuserdatafreefun free);
void removeTimer(EventLoopData *eld, id_type timer_id);
void removeAllTimers(EventLoopData *eld);
void toggleTimer(EventLoopData *eld, id_type timer_id, int enabled);
void changeTimerInterval(EventLoopData *eld, id_type timer_id, double interval);
double prepareForPoll(EventLoopData *eld, double timeout);
int pollWithTimeout(struct pollfd *fds, nfds_t nfds, double timeout);
int pollForEvents(EventLoopData *eld, double timeout);
void changeTimerInterval(EventLoopData *eld, id_type timer_id, monotonic_t interval);
monotonic_t prepareForPoll(EventLoopData *eld, monotonic_t timeout);
int pollWithTimeout(struct pollfd *fds, nfds_t nfds, monotonic_t timeout);
int pollForEvents(EventLoopData *eld, monotonic_t timeout);
unsigned dispatchTimers(EventLoopData *eld);
void finalizePollData(EventLoopData *eld);
bool initPollData(EventLoopData *eld, int display_fd);

View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 macOS - www.glfw.org
// GLFW 3.4 macOS - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2009-2019 Camilla Löwy <elmindreda@glfw.org>
//
@@ -27,9 +27,13 @@
//========================================================================
#include "internal.h"
#include "../kitty/monotonic.h"
#include <sys/param.h> // For MAXPATHLEN
#include <pthread.h>
// Needed for _NSGetProgname
#include <crt_externs.h>
// Change to our application bundle's resources directory, if present
//
static void changeToResourcesDirectory(void)
@@ -66,14 +70,119 @@ static void changeToResourcesDirectory(void)
chdir(resourcesPath);
}
// Set up the menu bar (manually)
// This is nasty, nasty stuff -- calls to undocumented semi-private APIs that
// could go away at any moment, lots of stuff that really should be
// localize(d|able), etc. Add a nib to save us this horror.
//
static void createMenuBar(void)
{
size_t i;
NSString* appName = nil;
NSDictionary* bundleInfo = [[NSBundle mainBundle] infoDictionary];
NSString* nameKeys[] =
{
@"CFBundleDisplayName",
@"CFBundleName",
@"CFBundleExecutable",
};
// Try to figure out what the calling application is called
for (i = 0; i < sizeof(nameKeys) / sizeof(nameKeys[0]); i++)
{
id name = bundleInfo[nameKeys[i]];
if (name &&
[name isKindOfClass:[NSString class]] &&
![name isEqualToString:@""])
{
appName = name;
break;
}
}
if (!appName)
{
char** progname = _NSGetProgname();
if (progname && *progname)
appName = @(*progname);
else
appName = @"GLFW Application";
}
NSMenu* bar = [[NSMenu alloc] init];
[NSApp setMainMenu:bar];
NSMenuItem* appMenuItem =
[bar addItemWithTitle:@"" action:NULL keyEquivalent:@""];
NSMenu* appMenu = [[NSMenu alloc] init];
[appMenuItem setSubmenu:appMenu];
[appMenu addItemWithTitle:[NSString stringWithFormat:@"About %@", appName]
action:@selector(orderFrontStandardAboutPanel:)
keyEquivalent:@""];
[appMenu addItem:[NSMenuItem separatorItem]];
NSMenu* servicesMenu = [[NSMenu alloc] init];
[NSApp setServicesMenu:servicesMenu];
[[appMenu addItemWithTitle:@"Services"
action:NULL
keyEquivalent:@""] setSubmenu:servicesMenu];
[servicesMenu release];
[appMenu addItem:[NSMenuItem separatorItem]];
[appMenu addItemWithTitle:[NSString stringWithFormat:@"Hide %@", appName]
action:@selector(hide:)
keyEquivalent:@"h"];
[[appMenu addItemWithTitle:@"Hide Others"
action:@selector(hideOtherApplications:)
keyEquivalent:@"h"]
setKeyEquivalentModifierMask:NSEventModifierFlagOption | NSEventModifierFlagCommand];
[appMenu addItemWithTitle:@"Show All"
action:@selector(unhideAllApplications:)
keyEquivalent:@""];
[appMenu addItem:[NSMenuItem separatorItem]];
[appMenu addItemWithTitle:[NSString stringWithFormat:@"Quit %@", appName]
action:@selector(terminate:)
keyEquivalent:@"q"];
NSMenuItem* windowMenuItem =
[bar addItemWithTitle:@"" action:NULL keyEquivalent:@""];
[bar release];
NSMenu* windowMenu = [[NSMenu alloc] initWithTitle:@"Window"];
[NSApp setWindowsMenu:windowMenu];
[windowMenuItem setSubmenu:windowMenu];
[windowMenu addItemWithTitle:@"Minimize"
action:@selector(performMiniaturize:)
keyEquivalent:@"m"];
[windowMenu addItemWithTitle:@"Zoom"
action:@selector(performZoom:)
keyEquivalent:@""];
[windowMenu addItem:[NSMenuItem separatorItem]];
[windowMenu addItemWithTitle:@"Bring All to Front"
action:@selector(arrangeInFront:)
keyEquivalent:@""];
// TODO: Make this appear at the bottom of the menu (for consistency)
[windowMenu addItem:[NSMenuItem separatorItem]];
[[windowMenu addItemWithTitle:@"Enter Full Screen"
action:@selector(toggleFullScreen:)
keyEquivalent:@"f"]
setKeyEquivalentModifierMask:NSEventModifierFlagControl | NSEventModifierFlagCommand];
// Prior to Snow Leopard, we need to use this oddly-named semi-private API
// to get the application menu working properly.
SEL setAppleMenuSelector = NSSelectorFromString(@"setAppleMenu:");
[NSApp performSelector:setAppleMenuSelector withObject:appMenu];
}
// Create key code translation tables
//
static void createKeyTables(void)
{
int scancode;
int keycode;
memset(_glfw.ns.keycodes, -1, sizeof(_glfw.ns.keycodes));
memset(_glfw.ns.scancodes, -1, sizeof(_glfw.ns.scancodes));
memset(_glfw.ns.key_to_keycode, -1, sizeof(_glfw.ns.key_to_keycode));
_glfw.ns.keycodes[0x1D] = GLFW_KEY_0;
_glfw.ns.keycodes[0x12] = GLFW_KEY_1;
@@ -190,11 +299,11 @@ static void createKeyTables(void)
_glfw.ns.keycodes[0x43] = GLFW_KEY_KP_MULTIPLY;
_glfw.ns.keycodes[0x4E] = GLFW_KEY_KP_SUBTRACT;
for (scancode = 0; scancode < 256; scancode++)
for (keycode = 0; keycode < 256; keycode++)
{
// Store the reverse translation for faster key name lookup
if (_glfw.ns.keycodes[scancode] >= 0)
_glfw.ns.scancodes[_glfw.ns.keycodes[scancode]] = scancode;
if (_glfw.ns.keycodes[keycode] >= 0)
_glfw.ns.key_to_keycode[_glfw.ns.keycodes[keycode]] = keycode;
}
}
@@ -276,6 +385,17 @@ static bool initializeTIS(void)
return updateUnicodeDataNS();
}
static void
display_reconfigured(CGDirectDisplayID display UNUSED, CGDisplayChangeSummaryFlags flags, void *userInfo UNUSED)
{
if (flags & kCGDisplayBeginConfigurationFlag) {
return;
}
if (flags & kCGDisplaySetModeFlag) {
// GPU possibly changed
}
}
@interface GLFWHelper : NSObject
@end
@@ -294,6 +414,103 @@ static bool initializeTIS(void)
@end // GLFWHelper
// Delegate for application related notifications {{{
@interface GLFWApplicationDelegate : NSObject <NSApplicationDelegate>
@end
@implementation GLFWApplicationDelegate
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
{
(void)sender;
_GLFWwindow* window;
for (window = _glfw.windowListHead; window; window = window->next)
_glfwInputWindowCloseRequest(window);
return NSTerminateCancel;
}
static GLFWapplicationshouldhandlereopenfun handle_reopen_callback = NULL;
- (BOOL)applicationShouldHandleReopen:(NSApplication *)sender hasVisibleWindows:(BOOL)flag
{
(void)sender;
if (!handle_reopen_callback) return YES;
if (handle_reopen_callback(flag)) return YES;
return NO;
}
- (void)applicationDidChangeScreenParameters:(NSNotification *) notification
{
(void)notification;
_GLFWwindow* window;
for (window = _glfw.windowListHead; window; window = window->next)
{
if (window->context.client != GLFW_NO_API)
[window->context.nsgl.object update];
}
_glfwPollMonitorsNS();
}
static GLFWapplicationwillfinishlaunchingfun finish_launching_callback = NULL;
- (void)applicationWillFinishLaunching:(NSNotification *)notification
{
(void)notification;
if (_glfw.hints.init.ns.menubar)
{
// In case we are unbundled, make us a proper UI application
[NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
// Menu bar setup must go between sharedApplication above and
// finishLaunching below, in order to properly emulate the behavior
// of NSApplicationMain
if ([[NSBundle mainBundle] pathForResource:@"MainMenu" ofType:@"nib"])
{
[[NSBundle mainBundle] loadNibNamed:@"MainMenu"
owner:NSApp
topLevelObjects:&_glfw.ns.nibObjects];
}
else
createMenuBar();
}
if (finish_launching_callback)
finish_launching_callback();
}
- (void)applicationDidFinishLaunching:(NSNotification *)notification
{
(void)notification;
[NSApp stop:nil];
CGDisplayRegisterReconfigurationCallback(display_reconfigured, NULL);
_glfwCocoaPostEmptyEvent();
}
- (void)applicationWillTerminate:(NSNotification *)aNotification
{
(void)aNotification;
CGDisplayRemoveReconfigurationCallback(display_reconfigured, NULL);
}
- (void)applicationDidHide:(NSNotification *)notification
{
(void)notification;
int i;
for (i = 0; i < _glfw.monitorCount; i++)
_glfwRestoreVideoModeNS(_glfw.monitors[i]);
}
@end // GLFWApplicationDelegate
// }}}
@interface GLFWApplication : NSApplication
- (void)tick_callback;
- (void)render_frame_received:(id)displayIDAsID;
@@ -335,6 +552,18 @@ is_cmd_period(NSEvent *event, NSEventModifierFlags modifierFlags) {
return false;
}
GLFWAPI GLFWapplicationshouldhandlereopenfun glfwSetApplicationShouldHandleReopen(GLFWapplicationshouldhandlereopenfun callback) {
GLFWapplicationshouldhandlereopenfun previous = handle_reopen_callback;
handle_reopen_callback = callback;
return previous;
}
GLFWAPI GLFWapplicationwillfinishlaunchingfun glfwSetApplicationWillFinishLaunching(GLFWapplicationwillfinishlaunchingfun callback) {
GLFWapplicationwillfinishlaunchingfun previous = finish_launching_callback;
finish_launching_callback = callback;
return previous;
}
int _glfwPlatformInit(void)
{
@autoreleasepool {
@@ -345,8 +574,21 @@ int _glfwPlatformInit(void)
toTarget:_glfw.ns.helper
withObject:nil];
if (NSApp)
_glfw.ns.finishedLaunching = true;
[GLFWApplication sharedApplication];
_glfw.ns.delegate = [[GLFWApplicationDelegate alloc] init];
if (_glfw.ns.delegate == nil)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Cocoa: Failed to create application delegate");
return false;
}
[NSApp setDelegate:_glfw.ns.delegate];
NSEvent* (^keydown_block)(NSEvent*) = ^ NSEvent* (NSEvent* event)
{
NSEventModifierFlags modifierFlags = [event modifierFlags] & NSEventModifierFlagDeviceIndependentFlagsMask;
@@ -385,6 +627,10 @@ int _glfwPlatformInit(void)
if (_glfw.hints.init.ns.chdir)
changeToResourcesDirectory();
// Press and Hold prevents some keys from emitting repeated characters
NSDictionary* defaults = @{@"ApplePressAndHoldEnabled":@NO};
[[NSUserDefaults standardUserDefaults] registerDefaults:defaults];
[[NSNotificationCenter defaultCenter]
addObserver:_glfw.ns.helper
selector:@selector(selectedKeyboardInputSourceChanged:)
@@ -531,7 +777,7 @@ typedef struct {
NSTimer *os_timer;
unsigned long long id;
bool repeats;
double interval;
monotonic_t interval;
GLFWuserdatafun callback;
void *callback_data;
GLFWuserdatafun free_callback_data;
@@ -551,7 +797,7 @@ remove_timer_at(size_t idx) {
}
static void schedule_timer(Timer *t) {
t->os_timer = [NSTimer scheduledTimerWithTimeInterval:t->interval repeats:(t->repeats ? YES: NO) block:^(NSTimer *os_timer) {
t->os_timer = [NSTimer scheduledTimerWithTimeInterval:monotonic_t_to_s_double(t->interval) repeats:(t->repeats ? YES: NO) block:^(NSTimer *os_timer) {
for (size_t i = 0; i < num_timers; i++) {
if (timers[i].os_timer == os_timer) {
timers[i].callback(timers[i].id, timers[i].callback_data);
@@ -562,7 +808,7 @@ static void schedule_timer(Timer *t) {
}];
}
unsigned long long _glfwPlatformAddTimer(double interval, bool repeats, GLFWuserdatafun callback, void *callback_data, GLFWuserdatafun free_callback) {
unsigned long long _glfwPlatformAddTimer(monotonic_t interval, bool repeats, GLFWuserdatafun callback, void *callback_data, GLFWuserdatafun free_callback) {
static unsigned long long timer_counter = 0;
if (num_timers >= sizeof(timers)/sizeof(timers[0]) - 1) {
_glfwInputError(GLFW_PLATFORM_ERROR, "Too many timers added");
@@ -588,7 +834,7 @@ void _glfwPlatformRemoveTimer(unsigned long long timer_id) {
}
}
void _glfwPlatformUpdateTimer(unsigned long long timer_id, double interval, bool enabled) {
void _glfwPlatformUpdateTimer(unsigned long long timer_id, monotonic_t interval, bool enabled) {
for (size_t i = 0; i < num_timers; i++) {
if (timers[i].id == timer_id) {
Timer *t = timers + i;

View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 Cocoa - www.glfw.org
// GLFW 3.4 Cocoa - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2006-2017 Camilla Löwy <elmindreda@glfw.org>
//

View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 Cocoa - www.glfw.org
// GLFW 3.4 Cocoa - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2009-2019 Camilla Löwy <elmindreda@glfw.org>
// Copyright (c) 2012 Torsten Walluhn <tw@mad-cad.net>

View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 macOS - www.glfw.org
// GLFW 3.4 macOS - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
@@ -328,7 +328,7 @@ void _glfwPollMonitorsNS(void)
if (!name)
name = _glfw_strdup("Unknown");
_GLFWmonitor* monitor = _glfwAllocMonitor(name, size.width, size.height);
_GLFWmonitor* monitor = _glfwAllocMonitor(name, (int)size.width, (int)size.height);
monitor->ns.displayID = displays[i];
monitor->ns.unitNumber = unitNumber;
createDisplayLink(monitor->ns.displayID);
@@ -354,8 +354,9 @@ void _glfwPollMonitorsNS(void)
void _glfwSetVideoModeNS(_GLFWmonitor* monitor, const GLFWvidmode* desired)
{
GLFWvidmode current;
const GLFWvidmode* best = _glfwChooseVideoMode(monitor, desired);
_glfwPlatformGetVideoMode(monitor, &current);
const GLFWvidmode* best = _glfwChooseVideoMode(monitor, desired);
if (_glfwCompareVideoModes(&current, best) == 0)
return;
@@ -454,13 +455,13 @@ void _glfwPlatformGetMonitorWorkarea(_GLFWmonitor* monitor,
const NSRect frameRect = [monitor->ns.screen visibleFrame];
if (xpos)
*xpos = frameRect.origin.x;
*xpos = (int)frameRect.origin.x;
if (ypos)
*ypos = _glfwTransformYNS(frameRect.origin.y + frameRect.size.height - 1);
*ypos = (int)_glfwTransformYNS(frameRect.origin.y + frameRect.size.height - 1);
if (width)
*width = frameRect.size.width;
*width = (int)frameRect.size.width;
if (height)
*height = frameRect.size.height;
*height = (int)frameRect.size.height;
}
@@ -505,7 +506,6 @@ GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count)
void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode *mode)
{
CVDisplayLinkRef link;
CVDisplayLinkCreateWithCGDisplay(monitor->ns.displayID, &link);
CGDisplayModeRef native = CGDisplayCopyDisplayMode(monitor->ns.displayID);

16
glfw/cocoa_platform.h vendored
View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 macOS - www.glfw.org
// GLFW 3.4 macOS - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2009-2019 Camilla Löwy <elmindreda@glfw.org>
//
@@ -36,6 +36,9 @@ typedef void* id;
typedef void* CVDisplayLinkRef;
#endif
// NOTE: Many Cocoa enum values have been renamed and we need to build across
// SDK versions where one is unavailable or the other deprecated
// We use the newer names in code and these macros to handle compatibility
#if MAC_OS_X_VERSION_MAX_ALLOWED < 101200
#define NSBitmapFormatAlphaNonpremultiplied NSAlphaNonpremultipliedBitmapFormat
#define NSEventMaskAny NSAnyEventMask
@@ -64,8 +67,9 @@ typedef void* CVDisplayLinkRef;
typedef VkFlags VkMacOSSurfaceCreateFlagsMVK;
typedef int (* GLFWcocoatextinputfilterfun)(int,int,unsigned int, unsigned long);
typedef int (* GLFWapplicationshouldhandlereopenfun)(int);
typedef int (* GLFWcocoatogglefullscreenfun)(GLFWwindow*);
typedef bool (* GLFWapplicationshouldhandlereopenfun)(int);
typedef void (* GLFWapplicationwillfinishlaunchingfun)(void);
typedef bool (* GLFWcocoatogglefullscreenfun)(GLFWwindow*);
typedef void (* GLFWcocoarenderframefun)(GLFWwindow*);
typedef struct VkMacOSSurfaceCreateInfoMVK
@@ -144,7 +148,7 @@ typedef struct _GLFWDisplayLinkNS
{
CVDisplayLinkRef displayLink;
CGDirectDisplayID displayID;
double lastRenderFrameRequestedAt;
monotonic_t lastRenderFrameRequestedAt;
} _GLFWDisplayLinkNS;
// Cocoa-specific global data
@@ -153,6 +157,7 @@ typedef struct _GLFWlibraryNS
{
CGEventSourceRef eventSource;
id delegate;
bool finishedLaunching;
bool cursorHidden;
TISInputSourceRef inputSource;
IOHIDManagerRef hidManager;
@@ -160,11 +165,12 @@ typedef struct _GLFWlibraryNS
id helper;
id keyUpMonitor;
id keyDownMonitor;
id nibObjects;
char keyName[64];
char text[256];
short int keycodes[256];
short int scancodes[GLFW_KEY_LAST + 1];
short int key_to_keycode[GLFW_KEY_LAST + 1];
char* clipboardString;
CGPoint cascadePoint;
// Where to place the cursor when re-enabled

5
glfw/cocoa_time.c vendored
View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 macOS - www.glfw.org
// GLFW 3.4 macOS - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2009-2016 Camilla Löwy <elmindreda@glfw.org>
//
@@ -42,7 +42,7 @@ void _glfwInitTimerNS(void)
mach_timebase_info_data_t info;
mach_timebase_info(&info);
_glfw.timer.ns.frequency = (info.denom * 1e9) / info.numer;
_glfw.timer.ns.frequency = (unsigned long long)((info.denom * 1e9) / info.numer);
}
@@ -59,4 +59,3 @@ uint64_t _glfwPlatformGetTimerFrequency(void)
{
return _glfw.timer.ns.frequency;
}

View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 macOS - www.glfw.org
// GLFW 3.4 macOS - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2009-2019 Camilla Löwy <elmindreda@glfw.org>
//
@@ -27,26 +27,78 @@
//========================================================================
#include "internal.h"
#include "../kitty/monotonic.h"
#include <float.h>
#include <string.h>
// Needed for _NSGetProgname
#include <crt_externs.h>
#define PARAGRAPH_UTF_8 0xc2a7 // §
#define MASCULINE_UTF_8 0xc2ba // º
#define A_DIAERESIS_UPPER_CASE_UTF_8 0xc384 // Ä
#define O_DIAERESIS_UPPER_CASE_UTF_8 0xc396 // Ö
#define U_DIAERESIS_UPPER_CASE_UTF_8 0xc39c // Ü
#define S_SHARP_UTF_8 0xc39f // ß
#define A_GRAVE_LOWER_CASE_UTF_8 0xc3a0 // à
#define A_DIAERESIS_LOWER_CASE_UTF_8 0xc3a4 // ä
#define A_RING_LOWER_CASE_UTF_8 0xc3a5 // å
#define AE_LOWER_CASE_UTF_8 0xc3a6 // æ
#define C_CEDILLA_LOWER_CASE_UTF_8 0xc3a7 // ç
#define E_GRAVE_LOWER_CASE_UTF_8 0xc3a8 // è
#define E_ACUTE_LOWER_CASE_UTF_8 0xc3a9 // é
#define I_GRAVE_LOWER_CASE_UTF_8 0xc3ac // ì
#define N_TILDE_LOWER_CASE_UTF_8 0xc3b1 // ñ
#define O_GRAVE_LOWER_CASE_UTF_8 0xc3b2 // ò
#define O_DIAERESIS_LOWER_CASE_UTF_8 0xc3b6 // ö
#define O_SLASH_LOWER_CASE_UTF_8 0xc3b8 // ø
#define U_GRAVE_LOWER_CASE_UTF_8 0xc3b9 // ù
#define U_DIAERESIS_LOWER_CASE_UTF_8 0xc3bc // ü
#define CYRILLIC_A_LOWER_CASE_UTF_8 0xd0b0 // а
#define CYRILLIC_BE_LOWER_CASE_UTF_8 0xd0b1 // б
#define CYRILLIC_VE_LOWER_CASE_UTF_8 0xd0b2 // в
#define CYRILLIC_GHE_LOWER_CASE_UTF_8 0xd0b3 // г
#define CYRILLIC_DE_LOWER_CASE_UTF_8 0xd0b4 // д
#define CYRILLIC_IE_LOWER_CASE_UTF_8 0xd0b5 // е
#define CYRILLIC_ZHE_LOWER_CASE_UTF_8 0xd0b6 // ж
#define CYRILLIC_ZE_LOWER_CASE_UTF_8 0xd0b7 // з
#define CYRILLIC_I_LOWER_CASE_UTF_8 0xd0b8 // и
#define CYRILLIC_SHORT_I_LOWER_CASE_UTF_8 0xd0b9 // й
#define CYRILLIC_KA_LOWER_CASE_UTF_8 0xd0ba // к
#define CYRILLIC_EL_LOWER_CASE_UTF_8 0xd0bb // л
#define CYRILLIC_EM_LOWER_CASE_UTF_8 0xd0bc // м
#define CYRILLIC_EN_LOWER_CASE_UTF_8 0xd0bd // н
#define CYRILLIC_O_LOWER_CASE_UTF_8 0xd0be // о
#define CYRILLIC_PE_LOWER_CASE_UTF_8 0xd0bf // п
#define CYRILLIC_ER_LOWER_CASE_UTF_8 0xd180 // р
#define CYRILLIC_ES_LOWER_CASE_UTF_8 0xd181 // с
#define CYRILLIC_TE_LOWER_CASE_UTF_8 0xd182 // т
#define CYRILLIC_U_LOWER_CASE_UTF_8 0xd183 // у
#define CYRILLIC_EF_LOWER_CASE_UTF_8 0xd184 // ф
#define CYRILLIC_HA_LOWER_CASE_UTF_8 0xd185 // х
#define CYRILLIC_TSE_LOWER_CASE_UTF_8 0xd186 // ц
#define CYRILLIC_CHE_LOWER_CASE_UTF_8 0xd187 // ч
#define CYRILLIC_SHA_LOWER_CASE_UTF_8 0xd188 // ш
#define CYRILLIC_SHCHA_LOWER_CASE_UTF_8 0xd189 // щ
#define CYRILLIC_HARD_SIGN_LOWER_CASE_UTF_8 0xd18a // ъ
#define CYRILLIC_YERU_LOWER_CASE_UTF_8 0xd18b // ы
#define CYRILLIC_SOFT_SIGN_LOWER_CASE_UTF_8 0xd18c // ь
#define CYRILLIC_E_LOWER_CASE_UTF_8 0xd18d // э
#define CYRILLIC_YU_LOWER_CASE_UTF_8 0xd18e // ю
#define CYRILLIC_YA_LOWER_CASE_UTF_8 0xd18f // я
#define CYRILLIC_IO_LOWER_CASE_UTF_8 0xd191 // ё
// Returns the style mask corresponding to the window settings
//
static NSUInteger getStyleMask(_GLFWwindow* window)
{
NSUInteger styleMask = 0;
NSUInteger styleMask = NSWindowStyleMaskMiniaturizable;
if (window->monitor || !window->decorated)
styleMask |= NSWindowStyleMaskBorderless;
else
{
styleMask |= NSWindowStyleMaskTitled |
NSWindowStyleMaskClosable |
NSWindowStyleMaskMiniaturizable;
NSWindowStyleMaskClosable;
if (window->resizable)
styleMask |= NSWindowStyleMaskResizable;
@@ -65,7 +117,7 @@ CGDirectDisplayID displayIDForWindow(_GLFWwindow *w) {
}
static unsigned long long display_link_shutdown_timer = 0;
#define DISPLAY_LINK_SHUTDOWN_CHECK_INTERVAL 30
#define DISPLAY_LINK_SHUTDOWN_CHECK_INTERVAL s_to_monotonic_t(30ll)
void
_glfwShutdownCVDisplayLink(unsigned long long timer_id UNUSED, void *user_data UNUSED) {
@@ -92,7 +144,7 @@ requestRenderFrame(_GLFWwindow *w, GLFWcocoarenderframefun callback) {
} else {
display_link_shutdown_timer = _glfwPlatformAddTimer(DISPLAY_LINK_SHUTDOWN_CHECK_INTERVAL, false, _glfwShutdownCVDisplayLink, NULL, NULL);
}
double now = glfwGetTime();
monotonic_t now = glfwGetTime();
for (size_t i = 0; i < _glfw.ns.displayLinks.count; i++) {
_GLFWDisplayLinkNS *dl = &_glfw.ns.displayLinks.entries[i];
if (dl->displayID == displayID) {
@@ -261,17 +313,21 @@ static inline const char*
format_text(const char *src) {
static char buf[256];
char *p = buf;
const char *last_char = buf + sizeof(buf) - 1;
if (!src[0]) return "<none>";
while (*src) {
p += snprintf(p, sizeof(buf) - (p - buf), "0x%x ", (unsigned char)*(src++));
int num = snprintf(p, sizeof(buf) - (p - buf), "0x%x ", (unsigned char)*(src++));
if (num < 0) return "<error>";
if (p + num >= last_char) break;
p += num;
}
if (p != buf) *(--p) = 0;
return buf;
}
static const char*
safe_name_for_scancode(unsigned int scancode) {
const char *ans = _glfwPlatformGetScancodeName(scancode);
safe_name_for_keycode(unsigned int keycode) {
const char *ans = _glfwPlatformGetNativeKeyName(keycode);
if (!ans) return "<noname>";
if ((1 <= ans[0] && ans[0] <= 31) || ans[0] == 127) ans = "<cc>";
return ans;
@@ -284,11 +340,47 @@ static int translateKey(unsigned int key, bool apply_keymap)
{
if (apply_keymap) {
// Look for the effective key name after applying any keyboard layouts/mappings
const char *name = _glfwPlatformGetScancodeName(key);
if (name && name[1] == 0) {
// Single letter key name
switch(name[0]) {
const char *name_chars = _glfwPlatformGetNativeKeyName(key);
uint32_t name = 0;
if (name_chars) {
for (int i = 0; i < 4; i++) {
if (!name_chars[i]) break;
name <<= 8;
name |= (uint8_t)name_chars[i];
}
}
if (name) {
// Key name
switch(name) {
#define K(ch, name) case ch: return GLFW_KEY_##name
K('!', EXCLAM);
K('"', DOUBLE_QUOTE);
K('#', NUMBER_SIGN);
K('$', DOLLAR);
K('&', AMPERSAND);
K('\'', APOSTROPHE);
K('(', PARENTHESIS_LEFT);
K(')', PARENTHESIS_RIGHT);
K('+', PLUS);
K(',', COMMA);
K('-', MINUS);
K('.', PERIOD);
K('/', SLASH);
K('0', 0);
K('1', 1);
K('2', 2);
K('3', 3);
K('5', 5);
K('6', 6);
K('7', 7);
K('8', 8);
K('9', 9);
K(':', COLON);
K(';', SEMICOLON);
K('<', LESS);
K('=', EQUAL);
K('>', GREATER);
K('@', AT);
K('A', A); K('a', A);
K('B', B); K('b', B);
K('C', C); K('c', C);
@@ -315,28 +407,64 @@ static int translateKey(unsigned int key, bool apply_keymap)
K('X', X); K('x', X);
K('Y', Y); K('y', Y);
K('Z', Z); K('z', Z);
K('0', 0);
K('1', 1);
K('2', 2);
K('3', 3);
K('5', 5);
K('6', 6);
K('7', 7);
K('8', 8);
K('9', 9);
K('\'', APOSTROPHE);
K(',', COMMA);
K('.', PERIOD);
K('/', SLASH);
K('-', MINUS);
K('=', EQUAL);
K(';', SEMICOLON);
K('[', LEFT_BRACKET);
K('\\', BACKSLASH);
K(']', RIGHT_BRACKET);
K('+', PLUS);
K('_', UNDERSCORE);
K('`', GRAVE_ACCENT);
K('\\', BACKSLASH);
K(PARAGRAPH_UTF_8, PARAGRAPH);
K(MASCULINE_UTF_8, MASCULINE);
K(A_DIAERESIS_UPPER_CASE_UTF_8, A_DIAERESIS);
K(O_DIAERESIS_UPPER_CASE_UTF_8, O_DIAERESIS);
K(U_DIAERESIS_UPPER_CASE_UTF_8, U_DIAERESIS);
K(S_SHARP_UTF_8, S_SHARP);
K(A_GRAVE_LOWER_CASE_UTF_8, A_GRAVE);
K(A_DIAERESIS_LOWER_CASE_UTF_8, A_DIAERESIS);
K(A_RING_LOWER_CASE_UTF_8, A_RING);
K(AE_LOWER_CASE_UTF_8, AE);
K(C_CEDILLA_LOWER_CASE_UTF_8, C_CEDILLA);
K(E_GRAVE_LOWER_CASE_UTF_8, E_GRAVE);
K(E_ACUTE_LOWER_CASE_UTF_8, E_ACUTE);
K(I_GRAVE_LOWER_CASE_UTF_8, I_GRAVE);
K(N_TILDE_LOWER_CASE_UTF_8, N_TILDE);
K(O_GRAVE_LOWER_CASE_UTF_8, O_GRAVE);
K(O_DIAERESIS_LOWER_CASE_UTF_8, O_DIAERESIS);
K(O_SLASH_LOWER_CASE_UTF_8, O_SLASH);
K(U_GRAVE_LOWER_CASE_UTF_8, U_GRAVE);
K(U_DIAERESIS_LOWER_CASE_UTF_8, U_DIAERESIS);
K(CYRILLIC_A_LOWER_CASE_UTF_8, CYRILLIC_A);
K(CYRILLIC_BE_LOWER_CASE_UTF_8, CYRILLIC_BE);
K(CYRILLIC_VE_LOWER_CASE_UTF_8, CYRILLIC_VE);
K(CYRILLIC_GHE_LOWER_CASE_UTF_8, CYRILLIC_GHE);
K(CYRILLIC_DE_LOWER_CASE_UTF_8, CYRILLIC_DE);
K(CYRILLIC_IE_LOWER_CASE_UTF_8, CYRILLIC_IE);
K(CYRILLIC_ZHE_LOWER_CASE_UTF_8, CYRILLIC_ZHE);
K(CYRILLIC_ZE_LOWER_CASE_UTF_8, CYRILLIC_ZE);
K(CYRILLIC_I_LOWER_CASE_UTF_8, CYRILLIC_I);
K(CYRILLIC_SHORT_I_LOWER_CASE_UTF_8, CYRILLIC_SHORT_I);
K(CYRILLIC_KA_LOWER_CASE_UTF_8, CYRILLIC_KA);
K(CYRILLIC_EL_LOWER_CASE_UTF_8, CYRILLIC_EL);
K(CYRILLIC_EM_LOWER_CASE_UTF_8, CYRILLIC_EM);
K(CYRILLIC_EN_LOWER_CASE_UTF_8, CYRILLIC_EN);
K(CYRILLIC_O_LOWER_CASE_UTF_8, CYRILLIC_O);
K(CYRILLIC_PE_LOWER_CASE_UTF_8, CYRILLIC_PE);
K(CYRILLIC_ER_LOWER_CASE_UTF_8, CYRILLIC_ER);
K(CYRILLIC_ES_LOWER_CASE_UTF_8, CYRILLIC_ES);
K(CYRILLIC_TE_LOWER_CASE_UTF_8, CYRILLIC_TE);
K(CYRILLIC_U_LOWER_CASE_UTF_8, CYRILLIC_U);
K(CYRILLIC_EF_LOWER_CASE_UTF_8, CYRILLIC_EF);
K(CYRILLIC_HA_LOWER_CASE_UTF_8, CYRILLIC_HA);
K(CYRILLIC_TSE_LOWER_CASE_UTF_8, CYRILLIC_TSE);
K(CYRILLIC_CHE_LOWER_CASE_UTF_8, CYRILLIC_CHE);
K(CYRILLIC_SHA_LOWER_CASE_UTF_8, CYRILLIC_SHA);
K(CYRILLIC_SHCHA_LOWER_CASE_UTF_8, CYRILLIC_SHCHA);
K(CYRILLIC_HARD_SIGN_LOWER_CASE_UTF_8, CYRILLIC_HARD_SIGN);
K(CYRILLIC_YERU_LOWER_CASE_UTF_8, CYRILLIC_YERU);
K(CYRILLIC_SOFT_SIGN_LOWER_CASE_UTF_8, CYRILLIC_SOFT_SIGN);
K(CYRILLIC_E_LOWER_CASE_UTF_8, CYRILLIC_E);
K(CYRILLIC_YU_LOWER_CASE_UTF_8, CYRILLIC_YU);
K(CYRILLIC_YA_LOWER_CASE_UTF_8, CYRILLIC_YA);
K(CYRILLIC_IO_LOWER_CASE_UTF_8, CYRILLIC_IO);
#undef K
default:
break;
@@ -349,17 +477,6 @@ static int translateKey(unsigned int key, bool apply_keymap)
return _glfw.ns.keycodes[key];
}
static void
display_reconfigured(CGDirectDisplayID display UNUSED, CGDisplayChangeSummaryFlags flags, void *userInfo UNUSED)
{
if (flags & kCGDisplayBeginConfigurationFlag) {
return;
}
if (flags & kCGDisplaySetModeFlag) {
// GPU possibly changed
}
}
// Translate a GLFW keycode to a Cocoa modifier flag
//
static NSUInteger translateKeyToModifierFlag(int key)
@@ -441,17 +558,17 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
if (fbRect.size.width != window->ns.fbWidth ||
fbRect.size.height != window->ns.fbHeight)
{
window->ns.fbWidth = fbRect.size.width;
window->ns.fbHeight = fbRect.size.height;
_glfwInputFramebufferSize(window, fbRect.size.width, fbRect.size.height);
window->ns.fbWidth = (int)fbRect.size.width;
window->ns.fbHeight = (int)fbRect.size.height;
_glfwInputFramebufferSize(window, (int)fbRect.size.width, (int)fbRect.size.height);
}
if (contentRect.size.width != window->ns.width ||
contentRect.size.height != window->ns.height)
{
window->ns.width = contentRect.size.width;
window->ns.height = contentRect.size.height;
_glfwInputWindowSize(window, contentRect.size.width, contentRect.size.height);
window->ns.width = (int)contentRect.size.width;
window->ns.height = (int)contentRect.size.height;
_glfwInputWindowSize(window, (int)contentRect.size.width, (int)contentRect.size.height);
}
}
@@ -530,77 +647,8 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
}
}
@end // }}}
// Delegate for application related notifications {{{
@interface GLFWApplicationDelegate : NSObject
@end
@implementation GLFWApplicationDelegate
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
{
(void)sender;
_GLFWwindow* window;
for (window = _glfw.windowListHead; window; window = window->next)
_glfwInputWindowCloseRequest(window);
return NSTerminateCancel;
}
static GLFWapplicationshouldhandlereopenfun handle_reopen_callback = NULL;
- (BOOL)applicationShouldHandleReopen:(NSApplication *)sender hasVisibleWindows:(BOOL)flag
{
(void)sender;
if (!handle_reopen_callback) return YES;
if (handle_reopen_callback(flag)) return YES;
return NO;
}
- (void)applicationDidChangeScreenParameters:(NSNotification *) notification
{
(void)notification;
_GLFWwindow* window;
for (window = _glfw.windowListHead; window; window = window->next)
{
if (window->context.client != GLFW_NO_API)
[window->context.nsgl.object update];
}
_glfwPollMonitorsNS();
}
- (void)applicationDidFinishLaunching:(NSNotification *)notification
{
(void)notification;
[NSApp stop:nil];
CGDisplayRegisterReconfigurationCallback(display_reconfigured, NULL);
_glfwCocoaPostEmptyEvent();
}
- (void)applicationWillTerminate:(NSNotification *)aNotification
{
(void)aNotification;
CGDisplayRemoveReconfigurationCallback(display_reconfigured, NULL);
}
- (void)applicationDidHide:(NSNotification *)notification
{
(void)notification;
int i;
for (i = 0; i < _glfw.monitorCount; i++)
_glfwRestoreVideoModeNS(_glfw.monitors[i]);
}
@end
// }}}
// Content view class for the GLFW window {{{
@@ -630,7 +678,7 @@ static GLFWapplicationshouldhandlereopenfun handle_reopen_callback = NULL;
markedRect = NSMakeRect(0.0, 0.0, 0.0, 0.0);
[self updateTrackingAreas];
[self registerForDraggedTypes:@[NSPasteboardTypeFileURL]];
[self registerForDraggedTypes:@[NSPasteboardTypeFileURL, NSPasteboardTypeString]];
}
return self;
@@ -692,8 +740,8 @@ static GLFWapplicationshouldhandlereopenfun handle_reopen_callback = NULL;
[window->context.nsgl.object update];
} @catch (NSException *e) {
_glfwInputError(GLFW_PLATFORM_ERROR,
"Failed to update NSGL Context object with error: %s (%s)",
[[e name] UTF8String], [[e reason] UTF8String]);
"Failed to update NSGL Context object with error: %s (%s)",
[[e name] UTF8String], [[e reason] UTF8String]);
}
}
@@ -829,9 +877,9 @@ static GLFWapplicationshouldhandlereopenfun handle_reopen_callback = NULL;
if (fbRect.size.width != window->ns.fbWidth ||
fbRect.size.height != window->ns.fbHeight)
{
window->ns.fbWidth = fbRect.size.width;
window->ns.fbHeight = fbRect.size.height;
_glfwInputFramebufferSize(window, fbRect.size.width, fbRect.size.height);
window->ns.fbWidth = (int)fbRect.size.width;
window->ns.fbHeight = (int)fbRect.size.height;
_glfwInputFramebufferSize(window, (int)fbRect.size.width, (int)fbRect.size.height);
}
const float xscale = fbRect.size.width / contentRect.size.width;
@@ -916,14 +964,16 @@ is_ascii_control_char(char x) {
- (void)keyDown:(NSEvent *)event
{
const unsigned int scancode = [event keyCode];
const unsigned int keycode = [event keyCode];
const NSUInteger flags = [event modifierFlags];
const int mods = translateFlags(flags);
const int key = translateKey(scancode, true);
const bool process_text = !window->ns.textInputFilterCallback || window->ns.textInputFilterCallback(key, mods, scancode, flags) != 1;
const int key = translateKey(keycode, true);
const bool process_text = !window->ns.textInputFilterCallback || window->ns.textInputFilterCallback(key, mods, keycode, flags) != 1;
const bool previous_has_marked_text = [self hasMarkedText];
[self unmarkText];
_glfw.ns.text[0] = 0;
GLFWkeyevent glfw_keyevent;
_glfwInitializeKeyEvent(&glfw_keyevent, key, keycode, GLFW_PRESS, mods);
if (!_glfw.ns.unicodeData) {
// Using the cocoa API for key handling is disabled, as there is no
// reliable way to handle dead keys using it. Only use it if the
@@ -938,7 +988,7 @@ is_ascii_control_char(char x) {
const bool in_compose_sequence = window->ns.deadKeyState != 0;
if (UCKeyTranslate(
[(NSData*) _glfw.ns.unicodeData bytes],
scancode,
keycode,
kUCKeyActionDown,
convert_cocoa_to_carbon_modifiers(flags),
LMGetKbdType(),
@@ -948,49 +998,55 @@ is_ascii_control_char(char x) {
&char_count,
text
) != noErr) {
debug_key(@"UCKeyTranslate failed for scancode: 0x%x (%s) %s\n",
scancode, safe_name_for_scancode(scancode), format_mods(mods));
debug_key(@"UCKeyTranslate failed for keycode: 0x%x (%@) %@\n",
keycode, @(safe_name_for_keycode(keycode)), @(format_mods(mods)));
window->ns.deadKeyState = 0;
return;
}
debug_key(@"scancode: 0x%x (%s) %schar_count: %lu deadKeyState: %u repeat: %d",
scancode, safe_name_for_scancode(scancode), format_mods(mods), char_count, window->ns.deadKeyState, event.ARepeat);
debug_key(@"keycode: 0x%x (%@) %@char_count: %lu deadKeyState: %u repeat: %d",
keycode, @(safe_name_for_keycode(keycode)), @(format_mods(mods)), char_count, window->ns.deadKeyState, event.ARepeat);
if (process_text) {
// this will call insertText which will fill up _glfw.ns.text
[self interpretKeyEvents:[NSArray arrayWithObject:event]];
} else {
window->ns.deadKeyState = 0;
}
if (window->ns.deadKeyState && (char_count == 0 || scancode == 0x75)) {
if (window->ns.deadKeyState && (char_count == 0 || keycode == 0x75)) {
// 0x75 is the delete key which needs to be ignored during a compose sequence
debug_key(@"Sending pre-edit text for dead key (text: %s markedText: %@).\n", format_text(_glfw.ns.text), markedText);
_glfwInputKeyboard(window, key, scancode, GLFW_PRESS, mods,
[[markedText string] UTF8String], 1); // update pre-edit text
debug_key(@"Sending pre-edit text for dead key (text: %@ markedText: %@).\n", @(format_text(_glfw.ns.text)), markedText);
glfw_keyevent.text = [[markedText string] UTF8String];
glfw_keyevent.ime_state = 1;
_glfwInputKeyboard(window, &glfw_keyevent); // update pre-edit text
return;
}
if (in_compose_sequence) {
debug_key(@"Clearing pre-edit text at end of compose sequence\n");
_glfwInputKeyboard(window, key, scancode, GLFW_PRESS, mods,
NULL, 1); // clear pre-edit text
glfw_keyevent.text = NULL;
glfw_keyevent.ime_state = 1;
_glfwInputKeyboard(window, &glfw_keyevent); // clear pre-edit text
}
}
if (is_ascii_control_char(_glfw.ns.text[0])) _glfw.ns.text[0] = 0; // don't send text for ascii control codes
debug_key(@"text: %s glfw_key: %s marked_text: %@\n",
format_text(_glfw.ns.text), _glfwGetKeyName(key), markedText);
debug_key(@"text: %@ glfw_key: %@ marked_text: %@\n",
@(format_text(_glfw.ns.text)), @(_glfwGetKeyName(key)), markedText);
if (!window->ns.deadKeyState) {
if ([self hasMarkedText]) {
_glfwInputKeyboard(window, key, scancode, GLFW_PRESS, mods,
[[markedText string] UTF8String], 1); // update pre-edit text
glfw_keyevent.text = [[markedText string] UTF8String];
glfw_keyevent.ime_state = 1;
_glfwInputKeyboard(window, &glfw_keyevent); // update pre-edit text
} else if (previous_has_marked_text) {
_glfwInputKeyboard(window, key, scancode, GLFW_PRESS, mods,
NULL, 1); // clear pre-edit text
glfw_keyevent.text = NULL;
glfw_keyevent.ime_state = 1;
_glfwInputKeyboard(window, &glfw_keyevent); // clear pre-edit text
}
if (([self hasMarkedText] || previous_has_marked_text) && !_glfw.ns.text[0]) {
// do not pass keys like BACKSPACE while there's pre-edit text, let IME handle it
return;
}
}
_glfwInputKeyboard(window, key, scancode, GLFW_PRESS, mods, _glfw.ns.text, 0);
glfw_keyevent.text = _glfw.ns.text;
glfw_keyevent.ime_state = 0;
_glfwInputKeyboard(window, &glfw_keyevent);
}
- (void)flagsChanged:(NSEvent *)event
@@ -1012,14 +1068,19 @@ is_ascii_control_char(char x) {
else
action = GLFW_RELEASE;
_glfwInputKeyboard(window, key, [event keyCode], action, mods, "", 0);
GLFWkeyevent glfw_keyevent;
_glfwInitializeKeyEvent(&glfw_keyevent, key, [event keyCode], action, mods);
_glfwInputKeyboard(window, &glfw_keyevent);
}
- (void)keyUp:(NSEvent *)event
{
const int key = translateKey([event keyCode], true);
const int mods = translateFlags([event modifierFlags]);
_glfwInputKeyboard(window, key, [event keyCode], GLFW_RELEASE, mods, "", 0);
GLFWkeyevent glfw_keyevent;
_glfwInitializeKeyEvent(&glfw_keyevent, key, [event keyCode], GLFW_RELEASE, mods);
_glfwInputKeyboard(window, &glfw_keyevent);
}
- (void)scrollWheel:(NSEvent *)event
@@ -1073,16 +1134,27 @@ is_ascii_control_char(char x) {
NSPasteboard* pasteboard = [sender draggingPasteboard];
NSDictionary* options = @{NSPasteboardURLReadingFileURLsOnlyKey:@YES};
NSArray* urls = [pasteboard readObjectsForClasses:@[[NSURL class]]
NSArray* objs = [pasteboard readObjectsForClasses:@[[NSURL class], [NSString class]]
options:options];
if (!urls) return NO;
const NSUInteger count = [urls count];
if (!objs) return NO;
const NSUInteger count = [objs count];
if (count)
{
char** paths = calloc(count, sizeof(char*));
for (NSUInteger i = 0; i < count; i++)
paths[i] = _glfw_strdup([urls[i] fileSystemRepresentation]);
{
id obj = objs[i];
if ([obj isKindOfClass:[NSURL class]]) {
paths[i] = _glfw_strdup([obj fileSystemRepresentation]);
} else if ([obj isKindOfClass:[NSString class]]) {
paths[i] = _glfw_strdup([obj UTF8String]);
} else {
_glfwInputError(GLFW_PLATFORM_ERROR,
"Cocoa: Object is neither a URL nor a string");
paths[i] = _glfw_strdup("");
}
}
_glfwInputDrop(window, (int) count, (const char**) paths);
@@ -1199,7 +1271,7 @@ void _glfwPlatformUpdateIMEState(_GLFWwindow *w, int which, int a, int b, int c,
@end
// }}}
// GLFW Window class {{{
// GLFW window class {{{
@interface GLFWWindow : NSWindow {
_GLFWwindow* glfw_window;
@@ -1252,154 +1324,6 @@ void _glfwPlatformUpdateIMEState(_GLFWwindow *w, int which, int a, int b, int c,
@end
// }}}
// Set up the menu bar (manually)
// This is nasty, nasty stuff -- calls to undocumented semi-private APIs that
// could go away at any moment, lots of stuff that really should be
// localize(d|able), etc. Add a nib to save us this horror.
//
static void createMenuBar(void)
{
size_t i;
NSString* appName = nil;
NSDictionary* bundleInfo = [[NSBundle mainBundle] infoDictionary];
NSString* nameKeys[] =
{
@"CFBundleDisplayName",
@"CFBundleName",
@"CFBundleExecutable",
};
// Try to figure out what the calling application is called
for (i = 0; i < sizeof(nameKeys) / sizeof(nameKeys[0]); i++)
{
id name = bundleInfo[nameKeys[i]];
if (name &&
[name isKindOfClass:[NSString class]] &&
![name isEqualToString:@""])
{
appName = name;
break;
}
}
if (!appName)
{
char** progname = _NSGetProgname();
if (progname && *progname)
appName = @(*progname);
else
appName = @"GLFW Application";
}
NSMenu* bar = [[NSMenu alloc] init];
[NSApp setMainMenu:bar];
NSMenuItem* appMenuItem =
[bar addItemWithTitle:@"" action:NULL keyEquivalent:@""];
NSMenu* appMenu = [[NSMenu alloc] init];
[appMenuItem setSubmenu:appMenu];
[appMenu addItemWithTitle:[NSString stringWithFormat:@"About %@", appName]
action:@selector(orderFrontStandardAboutPanel:)
keyEquivalent:@""];
[appMenu addItem:[NSMenuItem separatorItem]];
NSMenu* servicesMenu = [[NSMenu alloc] init];
[NSApp setServicesMenu:servicesMenu];
[[appMenu addItemWithTitle:@"Services"
action:NULL
keyEquivalent:@""] setSubmenu:servicesMenu];
[servicesMenu release];
[appMenu addItem:[NSMenuItem separatorItem]];
[appMenu addItemWithTitle:[NSString stringWithFormat:@"Hide %@", appName]
action:@selector(hide:)
keyEquivalent:@"h"];
[[appMenu addItemWithTitle:@"Hide Others"
action:@selector(hideOtherApplications:)
keyEquivalent:@"h"]
setKeyEquivalentModifierMask:NSEventModifierFlagOption | NSEventModifierFlagCommand];
[appMenu addItemWithTitle:@"Show All"
action:@selector(unhideAllApplications:)
keyEquivalent:@""];
[appMenu addItem:[NSMenuItem separatorItem]];
[appMenu addItemWithTitle:[NSString stringWithFormat:@"Quit %@", appName]
action:@selector(terminate:)
keyEquivalent:@"q"];
NSMenuItem* windowMenuItem =
[bar addItemWithTitle:@"" action:NULL keyEquivalent:@""];
[bar release];
NSMenu* windowMenu = [[NSMenu alloc] initWithTitle:@"Window"];
[NSApp setWindowsMenu:windowMenu];
[windowMenuItem setSubmenu:windowMenu];
[windowMenu addItemWithTitle:@"Minimize"
action:@selector(performMiniaturize:)
keyEquivalent:@"m"];
[windowMenu addItemWithTitle:@"Zoom"
action:@selector(performZoom:)
keyEquivalent:@""];
[windowMenu addItem:[NSMenuItem separatorItem]];
[windowMenu addItemWithTitle:@"Bring All to Front"
action:@selector(arrangeInFront:)
keyEquivalent:@""];
// TODO: Make this appear at the bottom of the menu (for consistency)
[windowMenu addItem:[NSMenuItem separatorItem]];
[[windowMenu addItemWithTitle:@"Enter Full Screen"
action:@selector(toggleFullScreen:)
keyEquivalent:@"f"]
setKeyEquivalentModifierMask:NSEventModifierFlagControl | NSEventModifierFlagCommand];
// Prior to Snow Leopard, we need to use this oddly-named semi-private API
// to get the application menu working properly.
SEL setAppleMenuSelector = NSSelectorFromString(@"setAppleMenu:");
[NSApp performSelector:setAppleMenuSelector withObject:appMenu];
}
// Initialize the Cocoa Application Kit
//
static bool initializeAppKit(void)
{
if (_glfw.ns.delegate)
return true;
// There can only be one application delegate, but we allocate it the
// first time a window is created to keep all window code in this file
_glfw.ns.delegate = [[GLFWApplicationDelegate alloc] init];
if (_glfw.ns.delegate == nil)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Cocoa: Failed to create application delegate");
return false;
}
[NSApp setDelegate:_glfw.ns.delegate];
if (_glfw.hints.init.ns.menubar)
{
// In case we are unbundled, make us a proper UI application
[NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
// Menu bar setup must go between sharedApplication above and
// finishLaunching below, in order to properly emulate the behavior
// of NSApplicationMain
// disabled by Kovid
/* if ([[NSBundle mainBundle] pathForResource:@"MainMenu" ofType:@"nib"]) */
/* [NSApp loadMainMenu]; */
/* else */
createMenuBar();
}
[NSApp run];
// Press and Hold prevents some keys from emitting repeated characters
NSDictionary* defaults = @{@"ApplePressAndHoldEnabled":@NO};
[[NSUserDefaults standardUserDefaults] registerDefaults:defaults];
return true;
}
// Create the Cocoa window
//
@@ -1447,7 +1371,7 @@ static bool createNativeWindow(_GLFWwindow* window,
[window->ns.object setLevel:NSMainMenuWindowLevel + 1];
else
{
[(NSWindow*)window->ns.object center];
[(NSWindow*) window->ns.object center];
_glfw.ns.cascadePoint =
NSPointToCGPoint([window->ns.object cascadeTopLeftFromPoint:
NSPointFromCGPoint(_glfw.ns.cascadePoint)]);
@@ -1504,8 +1428,11 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window,
const _GLFWfbconfig* fbconfig)
{
window->ns.deadKeyState = 0;
if (!initializeAppKit())
return false;
if (!_glfw.ns.finishedLaunching)
{
[NSApp run];
_glfw.ns.finishedLaunching = true;
}
if (!createNativeWindow(window, wndconfig, fbconfig))
return false;
@@ -1592,9 +1519,9 @@ void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos)
[window->ns.object contentRectForFrameRect:[window->ns.object frame]];
if (xpos)
*xpos = contentRect.origin.x;
*xpos = (int)contentRect.origin.x;
if (ypos)
*ypos = _glfwTransformYNS(contentRect.origin.y + contentRect.size.height - 1);
*ypos = (int)_glfwTransformYNS(contentRect.origin.y + contentRect.size.height - 1);
}
void _glfwPlatformSetWindowPos(_GLFWwindow* window, int x, int y)
@@ -1610,9 +1537,9 @@ void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height)
const NSRect contentRect = [window->ns.view frame];
if (width)
*width = contentRect.size.width;
*width = (int)contentRect.size.width;
if (height)
*height = contentRect.size.height;
*height = (int)contentRect.size.height;
}
void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height)
@@ -1623,7 +1550,14 @@ void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height)
acquireMonitor(window);
}
else
[window->ns.object setContentSize:NSMakeSize(width, height)];
{
NSRect contentRect =
[window->ns.object contentRectForFrameRect:[window->ns.object frame]];
contentRect.origin.y += contentRect.size.height - height;
contentRect.size = NSMakeSize(width, height);
[window->ns.object setFrame:[window->ns.object frameRectForContentRect:contentRect]
display:YES];
}
}
void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window,
@@ -1668,15 +1602,15 @@ void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window,
const NSRect frameRect = [window->ns.object frameRectForContentRect:contentRect];
if (left)
*left = contentRect.origin.x - frameRect.origin.x;
*left = (int)(contentRect.origin.x - frameRect.origin.x);
if (top)
*top = frameRect.origin.y + frameRect.size.height -
contentRect.origin.y - contentRect.size.height;
*top = (int)(frameRect.origin.y + frameRect.size.height -
contentRect.origin.y - contentRect.size.height);
if (right)
*right = frameRect.origin.x + frameRect.size.width -
contentRect.origin.x - contentRect.size.width;
*right = (int)(frameRect.origin.x + frameRect.size.width -
contentRect.origin.x - contentRect.size.width);
if (bottom)
*bottom = contentRect.origin.y - frameRect.origin.y;
*bottom = (int)(contentRect.origin.y - frameRect.origin.y);
}
void _glfwPlatformGetWindowContentScale(_GLFWwindow* window,
@@ -1691,9 +1625,9 @@ void _glfwPlatformGetWindowContentScale(_GLFWwindow* window,
*yscale = (float) (pixels.size.height / points.size.height);
}
double _glfwPlatformGetDoubleClickInterval(_GLFWwindow* window UNUSED)
monotonic_t _glfwPlatformGetDoubleClickInterval(_GLFWwindow* window UNUSED)
{
return [NSEvent doubleClickInterval];
return s_double_to_monotonic_t([NSEvent doubleClickInterval]);
}
void _glfwPlatformIconifyWindow(_GLFWwindow* window)
@@ -1961,14 +1895,14 @@ void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode UNUSED)
updateCursorMode(window);
}
const char* _glfwPlatformGetScancodeName(int scancode)
const char* _glfwPlatformGetNativeKeyName(int keycode)
{
UInt32 deadKeyState = 0;
UniChar characters[8];
UniCharCount characterCount = 0;
if (UCKeyTranslate([(NSData*) _glfw.ns.unicodeData bytes],
scancode,
keycode,
kUCKeyActionDisplay,
0,
LMGetKbdType(),
@@ -1988,9 +1922,9 @@ const char* _glfwPlatformGetScancodeName(int scancode)
return _glfw.ns.keyName;
}
int _glfwPlatformGetKeyScancode(int key)
int _glfwPlatformGetNativeKeyForKey(int key)
{
return _glfw.ns.scancodes[key];
return _glfw.ns.key_to_keycode[key];
}
int _glfwPlatformCreateCursor(_GLFWcursor* cursor,
@@ -2240,12 +2174,6 @@ GLFWAPI GLFWcocoatogglefullscreenfun glfwSetCocoaToggleFullscreenIntercept(GLFWw
return previous;
}
GLFWAPI GLFWapplicationshouldhandlereopenfun glfwSetApplicationShouldHandleReopen(GLFWapplicationshouldhandlereopenfun callback) {
GLFWapplicationshouldhandlereopenfun previous = handle_reopen_callback;
handle_reopen_callback = callback;
return previous;
}
GLFWAPI void glfwCocoaRequestRenderFrame(GLFWwindow *w, GLFWcocoarenderframefun callback) {
requestRenderFrame((_GLFWwindow*)w, callback);
}
@@ -2268,6 +2196,39 @@ GLFWAPI void glfwGetCocoaKeyEquivalent(int glfw_key, int glfw_mods, unsigned sho
START_ALLOW_CASE_RANGE
switch(glfw_key) {
#define K(ch, name) case GLFW_KEY_##name: *cocoa_key = ch; break;
K('!', EXCLAM);
K('"', DOUBLE_QUOTE);
K('#', NUMBER_SIGN);
K('$', DOLLAR);
K('&', AMPERSAND);
K('\'', APOSTROPHE);
K('(', PARENTHESIS_LEFT);
K(')', PARENTHESIS_RIGHT);
K('+', PLUS);
K(',', COMMA);
K('-', MINUS);
K('.', PERIOD);
K('/', SLASH);
K('0', 0);
K('1', 1);
K('2', 2);
K('3', 3);
K('5', 5);
K('6', 6);
K('7', 7);
K('8', 8);
K('9', 9);
K(':', COLON);
K(';', SEMICOLON);
K('<', LESS);
K('=', EQUAL);
K('>', GREATER);
K('@', AT);
K('[', LEFT_BRACKET);
K('\\', BACKSLASH);
K(']', RIGHT_BRACKET);
K('_', UNDERSCORE);
K('`', GRAVE_ACCENT);
K('a', A);
K('b', B);
K('c', C);
@@ -2294,28 +2255,56 @@ START_ALLOW_CASE_RANGE
K('x', X);
K('y', Y);
K('z', Z);
K('0', 0);
K('1', 1);
K('2', 2);
K('3', 3);
K('5', 5);
K('6', 6);
K('7', 7);
K('8', 8);
K('9', 9);
K('\'', APOSTROPHE);
K(',', COMMA);
K('.', PERIOD);
K('/', SLASH);
K('-', MINUS);
K('=', EQUAL);
K(';', SEMICOLON);
K('[', LEFT_BRACKET);
K(']', RIGHT_BRACKET);
K('+', PLUS);
K('_', UNDERSCORE);
K('`', GRAVE_ACCENT);
K('\\', BACKSLASH);
K(PARAGRAPH_UTF_8, PARAGRAPH);
K(MASCULINE_UTF_8, MASCULINE);
K(S_SHARP_UTF_8, S_SHARP);
K(A_GRAVE_LOWER_CASE_UTF_8, A_GRAVE);
K(A_DIAERESIS_LOWER_CASE_UTF_8, A_DIAERESIS);
K(A_RING_LOWER_CASE_UTF_8, A_RING);
K(AE_LOWER_CASE_UTF_8, AE);
K(C_CEDILLA_LOWER_CASE_UTF_8, C_CEDILLA);
K(E_GRAVE_LOWER_CASE_UTF_8, E_GRAVE);
K(E_ACUTE_LOWER_CASE_UTF_8, E_ACUTE);
K(I_GRAVE_LOWER_CASE_UTF_8, I_GRAVE);
K(N_TILDE_LOWER_CASE_UTF_8, N_TILDE);
K(O_GRAVE_LOWER_CASE_UTF_8, O_GRAVE);
K(O_DIAERESIS_LOWER_CASE_UTF_8, O_DIAERESIS);
K(O_SLASH_LOWER_CASE_UTF_8, O_SLASH);
K(U_GRAVE_LOWER_CASE_UTF_8, U_GRAVE);
K(U_DIAERESIS_LOWER_CASE_UTF_8, U_DIAERESIS);
K(CYRILLIC_A_LOWER_CASE_UTF_8, CYRILLIC_A);
K(CYRILLIC_BE_LOWER_CASE_UTF_8, CYRILLIC_BE);
K(CYRILLIC_VE_LOWER_CASE_UTF_8, CYRILLIC_VE);
K(CYRILLIC_GHE_LOWER_CASE_UTF_8, CYRILLIC_GHE);
K(CYRILLIC_DE_LOWER_CASE_UTF_8, CYRILLIC_DE);
K(CYRILLIC_IE_LOWER_CASE_UTF_8, CYRILLIC_IE);
K(CYRILLIC_ZHE_LOWER_CASE_UTF_8, CYRILLIC_ZHE);
K(CYRILLIC_ZE_LOWER_CASE_UTF_8, CYRILLIC_ZE);
K(CYRILLIC_I_LOWER_CASE_UTF_8, CYRILLIC_I);
K(CYRILLIC_SHORT_I_LOWER_CASE_UTF_8, CYRILLIC_SHORT_I);
K(CYRILLIC_KA_LOWER_CASE_UTF_8, CYRILLIC_KA);
K(CYRILLIC_EL_LOWER_CASE_UTF_8, CYRILLIC_EL);
K(CYRILLIC_EM_LOWER_CASE_UTF_8, CYRILLIC_EM);
K(CYRILLIC_EN_LOWER_CASE_UTF_8, CYRILLIC_EN);
K(CYRILLIC_O_LOWER_CASE_UTF_8, CYRILLIC_O);
K(CYRILLIC_PE_LOWER_CASE_UTF_8, CYRILLIC_PE);
K(CYRILLIC_ER_LOWER_CASE_UTF_8, CYRILLIC_ER);
K(CYRILLIC_ES_LOWER_CASE_UTF_8, CYRILLIC_ES);
K(CYRILLIC_TE_LOWER_CASE_UTF_8, CYRILLIC_TE);
K(CYRILLIC_U_LOWER_CASE_UTF_8, CYRILLIC_U);
K(CYRILLIC_EF_LOWER_CASE_UTF_8, CYRILLIC_EF);
K(CYRILLIC_HA_LOWER_CASE_UTF_8, CYRILLIC_HA);
K(CYRILLIC_TSE_LOWER_CASE_UTF_8, CYRILLIC_TSE);
K(CYRILLIC_CHE_LOWER_CASE_UTF_8, CYRILLIC_CHE);
K(CYRILLIC_SHA_LOWER_CASE_UTF_8, CYRILLIC_SHA);
K(CYRILLIC_SHCHA_LOWER_CASE_UTF_8, CYRILLIC_SHCHA);
K(CYRILLIC_HARD_SIGN_LOWER_CASE_UTF_8, CYRILLIC_HARD_SIGN);
K(CYRILLIC_YERU_LOWER_CASE_UTF_8, CYRILLIC_YERU);
K(CYRILLIC_SOFT_SIGN_LOWER_CASE_UTF_8, CYRILLIC_SOFT_SIGN);
K(CYRILLIC_E_LOWER_CASE_UTF_8, CYRILLIC_E);
K(CYRILLIC_YU_LOWER_CASE_UTF_8, CYRILLIC_YU);
K(CYRILLIC_YA_LOWER_CASE_UTF_8, CYRILLIC_YA);
K(CYRILLIC_IO_LOWER_CASE_UTF_8, CYRILLIC_IO);
K(0x35, ESCAPE);
K('\r', ENTER);

2
glfw/context.c vendored
View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 - www.glfw.org
// GLFW 3.4 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>

5
glfw/dbus_glfw.c vendored
View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 XKB - www.glfw.org
// GLFW 3.4 XKB - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2018 Kovid Goyal <kovid@kovidgoyal.net>
//
@@ -27,6 +27,7 @@
#include "internal.h"
#include "dbus_glfw.h"
#include "../kitty/monotonic.h"
#include <stdlib.h>
#include <string.h>
@@ -107,7 +108,7 @@ on_dbus_timer_ready(id_type timer_id UNUSED, void *data) {
static dbus_bool_t
add_dbus_timeout(DBusTimeout *timeout, void *data) {
int enabled = dbus_timeout_get_enabled(timeout) ? 1 : 0;
double interval = ((double)dbus_timeout_get_interval(timeout)) / 1000.0;
monotonic_t interval = ms_to_monotonic_t(dbus_timeout_get_interval(timeout));
if (interval < 0) return FALSE;
id_type timer_id = addTimer(dbus_data->eld, data, interval, enabled, true, on_dbus_timer_ready, timeout, NULL);
if (!timer_id) return FALSE;

2
glfw/dbus_glfw.h vendored
View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 XKB - www.glfw.org
// GLFW 3.4 XKB - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2018 Kovid Goyal <kovid@kovidgoyal.net>
//

2
glfw/egl_context.c vendored
View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 EGL - www.glfw.org
// GLFW 3.4 EGL - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>

2
glfw/egl_context.h vendored
View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 EGL - www.glfw.org
// GLFW 3.4 EGL - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2017 Camilla Löwy <elmindreda@glfw.org>

View File

@@ -8,11 +8,7 @@ import re
import sys
_plat = sys.platform.lower()
is_macos = 'darwin' in _plat
is_freebsd = 'freebsd' in _plat
is_netbsd = 'netbsd' in _plat
is_dragonflybsd = 'dragonfly' in _plat
is_bsd = is_freebsd or is_netbsd or is_dragonflybsd
is_linux = 'linux' in _plat
base = os.path.dirname(os.path.abspath(__file__))
@@ -23,31 +19,24 @@ def wayland_protocol_file_name(base, ext='c'):
def init_env(env, pkg_config, at_least_version, test_compile, module='x11'):
ans = env.copy()
if not is_macos:
ans.cflags.append('-pthread')
ans.ldpaths.append('-pthread')
ans.cflags.append('-fpic')
ans.cppflags.append('-D_GLFW_' + module.upper())
ans.cppflags.append('-D_GLFW_BUILD_DLL')
if is_macos:
ans.cppflags.append('-DGL_SILENCE_DEPRECATION')
ans.ldpaths.extend(
"-framework Cocoa -framework IOKit -framework CoreFoundation -framework CoreVideo".
split()
)
else:
ans.ldpaths.extend('-lrt -lm -ldl'.split())
sinfo = json.load(open(os.path.join(base, 'source-info.json')))
with open(os.path.join(base, 'source-info.json')) as f:
sinfo = json.load(f)
module_sources = list(sinfo[module]['sources'])
if module in ('x11', 'wayland'):
remove = 'linux_joystick.c' if is_bsd else 'null_joystick.c'
remove = 'null_joystick.c' if is_linux else 'linux_joystick.c'
module_sources.remove(remove)
ans.sources = sinfo['common']['sources'] + module_sources
ans.all_headers = [x for x in os.listdir(base) if x.endswith('.h')]
if module in ('x11', 'wayland'):
ans.cflags.append('-pthread')
ans.ldpaths.append('-pthread')
ans.ldpaths.extend('-lrt -lm -ldl'.split())
at_least_version('xkbcommon', 0, 5)
if module == 'x11':
@@ -56,6 +45,7 @@ def init_env(env, pkg_config, at_least_version, test_compile, module='x11'):
ans.ldpaths.extend(pkg_config(dep, '--libs'))
elif module == 'cocoa':
ans.cppflags.append('-DGL_SILENCE_DEPRECATION')
for f in 'Cocoa IOKit CoreFoundation CoreVideo'.split():
ans.ldpaths.extend(('-framework', f))
@@ -157,7 +147,8 @@ class Function:
def generate_wrappers(glfw_header):
src = open(glfw_header).read()
with open(glfw_header) as f:
src = f.read()
functions = []
first = None
for m in re.finditer(r'^GLFWAPI\s+(.+[)]);\s*$', src, flags=re.MULTILINE):
@@ -174,13 +165,14 @@ def generate_wrappers(glfw_header):
GLFWcocoatextinputfilterfun glfwSetCocoaTextInputFilter(GLFWwindow* window, GLFWcocoatextinputfilterfun callback)
GLFWcocoatogglefullscreenfun glfwSetCocoaToggleFullscreenIntercept(GLFWwindow *window, GLFWcocoatogglefullscreenfun callback)
GLFWapplicationshouldhandlereopenfun glfwSetApplicationShouldHandleReopen(GLFWapplicationshouldhandlereopenfun callback)
GLFWapplicationwillfinishlaunchingfun glfwSetApplicationWillFinishLaunching(GLFWapplicationwillfinishlaunchingfun callback)
void glfwGetCocoaKeyEquivalent(int glfw_key, int glfw_mods, void* cocoa_key, void* cocoa_mods)
void glfwCocoaRequestRenderFrame(GLFWwindow *w, GLFWcocoarenderframefun callback)
void* glfwGetX11Display(void)
int32_t glfwGetX11Window(GLFWwindow* window)
void glfwSetPrimarySelectionString(GLFWwindow* window, const char* string)
const char* glfwGetPrimarySelectionString(GLFWwindow* window, void)
int glfwGetXKBScancode(const char* key_name, int case_sensitive)
int glfwGetNativeKeyForName(const char* key_name, int case_sensitive)
void glfwRequestWaylandFrameEvent(GLFWwindow *handle, unsigned long long id, GLFWwaylandframecallbackfunc callback)
unsigned long long glfwDBusUserNotify(const char *app_name, const char* icon, const char *summary, const char *body, \
const char *action_text, int32_t timeout, GLFWDBusnotificationcreatedfun callback, void *data)
@@ -194,15 +186,23 @@ const char *action_text, int32_t timeout, GLFWDBusnotificationcreatedfun callbac
p = src.find('*/', p)
preamble = src[p + 2:first]
header = '''\
//
// THIS FILE IS GENERATED BY glfw.py
//
// SAVE YOURSELF SOME TIME, DO NOT MANUALLY EDIT
//
#pragma once
#include <stddef.h>
#include <stdint.h>
#include "monotonic.h"
{}
typedef int (* GLFWcocoatextinputfilterfun)(int,int,unsigned int,unsigned long);
typedef int (* GLFWapplicationshouldhandlereopenfun)(int);
typedef int (* GLFWcocoatogglefullscreenfun)(GLFWwindow*);
typedef bool (* GLFWapplicationshouldhandlereopenfun)(int);
typedef void (* GLFWapplicationwillfinishlaunchingfun)(void);
typedef bool (* GLFWcocoatogglefullscreenfun)(GLFWwindow*);
typedef void (* GLFWcocoarenderframefun)(GLFWwindow*);
typedef void (*GLFWwaylandframecallbackfunc)(unsigned long long id);
typedef void (*GLFWDBusnotificationcreatedfun)(unsigned long long, uint32_t, void*);

802
glfw/glfw3.h vendored

File diff suppressed because it is too large Load Diff

2
glfw/glx_context.c vendored
View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 GLX - www.glfw.org
// GLFW 3.4 GLX - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>

26
glfw/glx_context.h vendored
View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 GLX - www.glfw.org
// GLFW 3.4 GLX - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2017 Camilla Löwy <elmindreda@glfw.org>
@@ -153,18 +153,18 @@ typedef struct _GLFWlibraryGLX
PFNGLXSWAPINTERVALEXTPROC SwapIntervalEXT;
PFNGLXSWAPINTERVALMESAPROC SwapIntervalMESA;
PFNGLXCREATECONTEXTATTRIBSARBPROC CreateContextAttribsARB;
bool SGI_swap_control;
bool EXT_swap_control;
bool MESA_swap_control;
bool ARB_multisample;
bool ARB_framebuffer_sRGB;
bool EXT_framebuffer_sRGB;
bool ARB_create_context;
bool ARB_create_context_profile;
bool ARB_create_context_robustness;
bool EXT_create_context_es2_profile;
bool ARB_create_context_no_error;
bool ARB_context_flush_control;
bool SGI_swap_control;
bool EXT_swap_control;
bool MESA_swap_control;
bool ARB_multisample;
bool ARB_framebuffer_sRGB;
bool EXT_framebuffer_sRGB;
bool ARB_create_context;
bool ARB_create_context_profile;
bool ARB_create_context_robustness;
bool EXT_create_context_es2_profile;
bool ARB_create_context_no_error;
bool ARB_context_flush_control;
} _GLFWlibraryGLX;

31
glfw/ibus_glfw.c vendored
View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 XKB - www.glfw.org
// GLFW 3.4 XKB - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2018 Kovid Goyal <kovid@kovidgoyal.net>
//
@@ -107,10 +107,14 @@ get_ibus_text_from_message(DBusMessage *msg) {
}
static inline void
send_text(const char *text, int state) {
send_text(const char *text, int ime_state) {
_GLFWwindow *w = _glfwFocusedWindow();
if (w && w->callbacks.keyboard) {
w->callbacks.keyboard((GLFWwindow*) w, GLFW_KEY_UNKNOWN, 0, GLFW_PRESS, 0, text, state);
GLFWkeyevent fake_ev;
_glfwInitializeKeyEvent(&fake_ev, GLFW_KEY_UNKNOWN, 0, GLFW_PRESS, 0);
fake_ev.text = text;
fake_ev.ime_state = ime_state;
w->callbacks.keyboard((GLFWwindow*) w, &fake_ev);
}
}
@@ -393,31 +397,36 @@ ibus_key_state(unsigned int glfw_modifiers, int action) {
void
key_event_processed(DBusMessage *msg, const char* errmsg, void *data) {
uint32_t handled = 0;
KeyEvent *ev = (KeyEvent*)data;
bool is_release = ev->action == GLFW_RELEASE;
_GLFWIBUSKeyEvent *ev = (_GLFWIBUSKeyEvent*)data;
// Restore key's text from the text embedded in the structure.
ev->glfw_ev.text = ev->__embedded_text;
bool is_release = ev->glfw_ev.action == GLFW_RELEASE;
bool failed = false;
if (errmsg) {
_glfwInputError(GLFW_PLATFORM_ERROR, "IBUS: Failed to process key with error: %s", errmsg);
failed = true;
} else {
glfw_dbus_get_args(msg, "Failed to get IBUS handled key from reply", DBUS_TYPE_BOOLEAN, &handled, DBUS_TYPE_INVALID);
debug("IBUS processed scancode: 0x%x release: %d handled: %u\n", ev->keycode, is_release, handled);
debug("IBUS processed native_key: 0x%x release: %d handled: %u\n", ev->glfw_ev.native_key, is_release, handled);
}
glfw_xkb_key_from_ime(ev, handled ? true : false, failed);
free(ev);
}
bool
ibus_process_key(const KeyEvent *ev_, _GLFWIBUSData *ibus) {
ibus_process_key(const _GLFWIBUSKeyEvent *ev_, _GLFWIBUSData *ibus) {
if (!check_connection(ibus)) return false;
KeyEvent *ev = malloc(sizeof(KeyEvent));
_GLFWIBUSKeyEvent *ev = calloc(1, sizeof(_GLFWIBUSKeyEvent));
if (!ev) return false;
memcpy(ev, ev_, sizeof(KeyEvent));
uint32_t state = ibus_key_state(ev->glfw_modifiers, ev->action);
memcpy(ev, ev_, sizeof(_GLFWIBUSKeyEvent));
// Put the key's text in a field IN the structure, for proper serialization.
if (ev->glfw_ev.text) strncpy(ev->__embedded_text, ev->glfw_ev.text, sizeof(ev->__embedded_text) - 1);
ev->glfw_ev.text = NULL;
uint32_t state = ibus_key_state(ev->glfw_ev.mods, ev->glfw_ev.action);
if (!glfw_dbus_call_method_with_reply(
ibus->conn, IBUS_SERVICE, ibus->input_ctx_path, IBUS_INPUT_INTERFACE, "ProcessKeyEvent",
3000, key_event_processed, ev,
DBUS_TYPE_UINT32, &ev->ibus_sym, DBUS_TYPE_UINT32, &ev->ibus_keycode, DBUS_TYPE_UINT32,
DBUS_TYPE_UINT32, &ev->ibus_keysym, DBUS_TYPE_UINT32, &ev->ibus_keycode, DBUS_TYPE_UINT32,
&state, DBUS_TYPE_INVALID)) {
free(ev);
return false;

17
glfw/ibus_glfw.h vendored
View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 XKB - www.glfw.org
// GLFW 3.4 XKB - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2018 Kovid Goyal <kovid@kovidgoyal.net>
//
@@ -27,6 +27,7 @@
#pragma once
#include "internal.h"
#include "dbus_glfw.h"
#include <xkbcommon/xkbcommon.h>
@@ -38,18 +39,16 @@ typedef struct {
} _GLFWIBUSData;
typedef struct {
xkb_keycode_t keycode, ibus_keycode;
xkb_keysym_t keysym, ibus_sym;
unsigned int glfw_modifiers;
int action;
xkb_keycode_t ibus_keycode;
xkb_keysym_t ibus_keysym;
GLFWid window_id;
int glfw_keycode;
char text[64];
} KeyEvent;
GLFWkeyevent glfw_ev;
char __embedded_text[64];
} _GLFWIBUSKeyEvent;
void glfw_connect_to_ibus(_GLFWIBUSData *ibus);
void glfw_ibus_terminate(_GLFWIBUSData *ibus);
void glfw_ibus_set_focused(_GLFWIBUSData *ibus, bool focused);
void glfw_ibus_dispatch(_GLFWIBUSData *ibus);
bool ibus_process_key(const KeyEvent *ev_, _GLFWIBUSData *ibus);
bool ibus_process_key(const _GLFWIBUSKeyEvent *ev_, _GLFWIBUSData *ibus);
void glfw_ibus_set_cursor_geometry(_GLFWIBUSData *ibus, int x, int y, int w, int h);

12
glfw/init.c vendored
View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 - www.glfw.org
// GLFW 3.4 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2018 Camilla Löwy <elmindreda@glfw.org>
@@ -27,6 +27,7 @@
// Please use C89 style variable declarations in this file because VS 2010
//========================================================================
#define MONOTONIC_START_MODULE
#include "internal.h"
#include "mappings.h"
@@ -201,7 +202,7 @@ _glfwDebug(const char *format, ...) {
{
va_list vl;
fprintf(stderr, "[%.4f] ", glfwGetTime());
fprintf(stderr, "[%.4f] ", monotonic_t_to_s_double(glfwGetTime()));
va_start(vl, format);
vfprintf(stderr, format, vl);
va_end(vl);
@@ -214,10 +215,11 @@ _glfwDebug(const char *format, ...) {
////// GLFW public API //////
//////////////////////////////////////////////////////////////////////////
GLFWAPI int glfwInit(void)
GLFWAPI int glfwInit(monotonic_t start_time)
{
if (_glfw.initialized)
return true;
monotonic_start_time = start_time;
memset(&_glfw, 0, sizeof(_glfw));
_glfw.hints.init = _glfwInitHints;
@@ -350,13 +352,13 @@ GLFWAPI void glfwStopMainLoop(void) {
}
GLFWAPI unsigned long long glfwAddTimer(
double interval, bool repeats, GLFWuserdatafun callback,
monotonic_t interval, bool repeats, GLFWuserdatafun callback,
void *callback_data, GLFWuserdatafun free_callback)
{
return _glfwPlatformAddTimer(interval, repeats, callback, callback_data, free_callback);
}
GLFWAPI void glfwUpdateTimer(unsigned long long timer_id, double interval, bool enabled) {
GLFWAPI void glfwUpdateTimer(unsigned long long timer_id, monotonic_t interval, bool enabled) {
_glfwPlatformUpdateTimer(timer_id, interval, enabled);
}

369
glfw/input.c vendored
View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 - www.glfw.org
// GLFW 3.4 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
@@ -28,6 +28,7 @@
//========================================================================
#include "internal.h"
#include "../kitty/monotonic.h"
#include <assert.h>
#include <float.h>
@@ -256,33 +257,44 @@ static bool parseMapping(_GLFWmapping* mapping, const char* string)
////// GLFW event API //////
//////////////////////////////////////////////////////////////////////////
void _glfwInitializeKeyEvent(GLFWkeyevent *ev, int key, int native_key, int action, int mods)
{
ev->key = key;
ev->native_key = native_key;
ev->action = action;
ev->mods = mods;
ev->text = NULL;
ev->ime_state = 0;
}
// Notifies shared code of a physical key event
//
void _glfwInputKeyboard(_GLFWwindow* window, int key, int scancode, int action, int mods, const char* text, int state)
void _glfwInputKeyboard(_GLFWwindow* window, GLFWkeyevent* ev)
{
if (key >= 0 && key <= GLFW_KEY_LAST)
if (ev->key >= 0 && ev->key <= GLFW_KEY_LAST)
{
bool repeated = false;
if (action == GLFW_RELEASE && window->keys[key] == GLFW_RELEASE)
if (ev->action == GLFW_RELEASE && window->keys[ev->key] == GLFW_RELEASE)
return;
if (action == GLFW_PRESS && window->keys[key] == GLFW_PRESS)
if (ev->action == GLFW_PRESS && window->keys[ev->key] == GLFW_PRESS)
repeated = true;
if (action == GLFW_RELEASE && window->stickyKeys)
window->keys[key] = _GLFW_STICK;
if (ev->action == GLFW_RELEASE && window->stickyKeys)
window->keys[ev->key] = _GLFW_STICK;
else
window->keys[key] = (char) action;
window->keys[ev->key] = (char) ev->action;
if (repeated)
action = GLFW_REPEAT;
ev->action = GLFW_REPEAT;
}
// FIXME: will need to update ev->virtual_mods here too?
if (window->callbacks.keyboard) {
if (!window->lockKeyMods) mods &= ~(GLFW_MOD_CAPS_LOCK | GLFW_MOD_NUM_LOCK);
window->callbacks.keyboard((GLFWwindow*) window, key, scancode, action, mods, text, state);
if (!window->lockKeyMods) ev->mods &= ~(GLFW_MOD_CAPS_LOCK | GLFW_MOD_NUM_LOCK);
window->callbacks.keyboard((GLFWwindow*) window, ev);
}
}
@@ -439,132 +451,193 @@ const char* _glfwGetKeyName(int key)
switch (key)
{
// Printable keys
case GLFW_KEY_A: return "A";
case GLFW_KEY_B: return "B";
case GLFW_KEY_C: return "C";
case GLFW_KEY_D: return "D";
case GLFW_KEY_E: return "E";
case GLFW_KEY_F: return "F";
case GLFW_KEY_G: return "G";
case GLFW_KEY_H: return "H";
case GLFW_KEY_I: return "I";
case GLFW_KEY_J: return "J";
case GLFW_KEY_K: return "K";
case GLFW_KEY_L: return "L";
case GLFW_KEY_M: return "M";
case GLFW_KEY_N: return "N";
case GLFW_KEY_O: return "O";
case GLFW_KEY_P: return "P";
case GLFW_KEY_Q: return "Q";
case GLFW_KEY_R: return "R";
case GLFW_KEY_S: return "S";
case GLFW_KEY_T: return "T";
case GLFW_KEY_U: return "U";
case GLFW_KEY_V: return "V";
case GLFW_KEY_W: return "W";
case GLFW_KEY_X: return "X";
case GLFW_KEY_Y: return "Y";
case GLFW_KEY_Z: return "Z";
case GLFW_KEY_1: return "1";
case GLFW_KEY_2: return "2";
case GLFW_KEY_3: return "3";
case GLFW_KEY_4: return "4";
case GLFW_KEY_5: return "5";
case GLFW_KEY_6: return "6";
case GLFW_KEY_7: return "7";
case GLFW_KEY_8: return "8";
case GLFW_KEY_9: return "9";
case GLFW_KEY_0: return "0";
case GLFW_KEY_SPACE: return "SPACE";
case GLFW_KEY_MINUS: return "MINUS";
case GLFW_KEY_EQUAL: return "EQUAL";
case GLFW_KEY_LEFT_BRACKET: return "LEFT BRACKET";
case GLFW_KEY_RIGHT_BRACKET: return "RIGHT BRACKET";
case GLFW_KEY_BACKSLASH: return "BACKSLASH";
case GLFW_KEY_SEMICOLON: return "SEMICOLON";
case GLFW_KEY_APOSTROPHE: return "APOSTROPHE";
case GLFW_KEY_GRAVE_ACCENT: return "GRAVE ACCENT";
case GLFW_KEY_COMMA: return "COMMA";
case GLFW_KEY_PERIOD: return "PERIOD";
case GLFW_KEY_SLASH: return "SLASH";
case GLFW_KEY_WORLD_1: return "WORLD 1";
case GLFW_KEY_WORLD_2: return "WORLD 2";
case GLFW_KEY_PLUS: return "PLUS";
case GLFW_KEY_UNDERSCORE: return "UNDERSCORE";
case GLFW_KEY_SPACE: return "SPACE";
case GLFW_KEY_EXCLAM: return "EXCLAM";
case GLFW_KEY_DOUBLE_QUOTE: return "DOUBLE_QUOTE";
case GLFW_KEY_NUMBER_SIGN: return "NUMBER_SIGN";
case GLFW_KEY_DOLLAR: return "DOLLAR";
case GLFW_KEY_AMPERSAND: return "AMPERSAND";
case GLFW_KEY_APOSTROPHE: return "APOSTROPHE";
case GLFW_KEY_PARENTHESIS_LEFT: return "PARENTHESIS_LEFT";
case GLFW_KEY_PARENTHESIS_RIGHT: return "PARENTHESIS_RIGHT";
case GLFW_KEY_PLUS: return "PLUS";
case GLFW_KEY_COMMA: return "COMMA";
case GLFW_KEY_MINUS: return "MINUS";
case GLFW_KEY_PERIOD: return "PERIOD";
case GLFW_KEY_SLASH: return "SLASH";
case GLFW_KEY_0: return "0";
case GLFW_KEY_1: return "1";
case GLFW_KEY_2: return "2";
case GLFW_KEY_3: return "3";
case GLFW_KEY_4: return "4";
case GLFW_KEY_5: return "5";
case GLFW_KEY_6: return "6";
case GLFW_KEY_7: return "7";
case GLFW_KEY_8: return "8";
case GLFW_KEY_9: return "9";
case GLFW_KEY_COLON: return "COLON";
case GLFW_KEY_SEMICOLON: return "SEMICOLON";
case GLFW_KEY_LESS: return "LESS";
case GLFW_KEY_EQUAL: return "EQUAL";
case GLFW_KEY_GREATER: return "GREATER";
case GLFW_KEY_AT: return "AT";
case GLFW_KEY_A: return "A";
case GLFW_KEY_B: return "B";
case GLFW_KEY_C: return "C";
case GLFW_KEY_D: return "D";
case GLFW_KEY_E: return "E";
case GLFW_KEY_F: return "F";
case GLFW_KEY_G: return "G";
case GLFW_KEY_H: return "H";
case GLFW_KEY_I: return "I";
case GLFW_KEY_J: return "J";
case GLFW_KEY_K: return "K";
case GLFW_KEY_L: return "L";
case GLFW_KEY_M: return "M";
case GLFW_KEY_N: return "N";
case GLFW_KEY_O: return "O";
case GLFW_KEY_P: return "P";
case GLFW_KEY_Q: return "Q";
case GLFW_KEY_R: return "R";
case GLFW_KEY_S: return "S";
case GLFW_KEY_T: return "T";
case GLFW_KEY_U: return "U";
case GLFW_KEY_V: return "V";
case GLFW_KEY_W: return "W";
case GLFW_KEY_X: return "X";
case GLFW_KEY_Y: return "Y";
case GLFW_KEY_Z: return "Z";
case GLFW_KEY_LEFT_BRACKET: return "LEFT_BRACKET";
case GLFW_KEY_BACKSLASH: return "BACKSLASH";
case GLFW_KEY_RIGHT_BRACKET: return "RIGHT_BRACKET";
case GLFW_KEY_UNDERSCORE: return "UNDERSCORE";
case GLFW_KEY_GRAVE_ACCENT: return "GRAVE_ACCENT";
case GLFW_KEY_WORLD_1: return "WORLD_1";
case GLFW_KEY_WORLD_2: return "WORLD_2";
case GLFW_KEY_PARAGRAPH: return "PARAGRAPH";
case GLFW_KEY_MASCULINE: return "MASCULINE";
case GLFW_KEY_A_GRAVE: return "A_GRAVE";
case GLFW_KEY_A_DIAERESIS: return "A_DIAERESIS";
case GLFW_KEY_A_RING: return "A_RING";
case GLFW_KEY_AE: return "AE";
case GLFW_KEY_C_CEDILLA: return "C_CEDILLA";
case GLFW_KEY_E_GRAVE: return "E_GRAVE";
case GLFW_KEY_E_ACUTE: return "E_ACUTE";
case GLFW_KEY_I_GRAVE: return "I_GRAVE";
case GLFW_KEY_N_TILDE: return "N_TILDE";
case GLFW_KEY_O_GRAVE: return "O_GRAVE";
case GLFW_KEY_O_DIAERESIS: return "O_DIAERESIS";
case GLFW_KEY_O_SLASH: return "O_SLASH";
case GLFW_KEY_U_GRAVE: return "U_GRAVE";
case GLFW_KEY_U_DIAERESIS: return "U_DIAERESIS";
case GLFW_KEY_S_SHARP: return "S_SHARP";
case GLFW_KEY_CYRILLIC_A: return "CYRILLIC_A";
case GLFW_KEY_CYRILLIC_BE: return "CYRILLIC_BE";
case GLFW_KEY_CYRILLIC_VE: return "CYRILLIC_VE";
case GLFW_KEY_CYRILLIC_GHE: return "CYRILLIC_GHE";
case GLFW_KEY_CYRILLIC_DE: return "CYRILLIC_DE";
case GLFW_KEY_CYRILLIC_IE: return "CYRILLIC_IE";
case GLFW_KEY_CYRILLIC_ZHE: return "CYRILLIC_ZHE";
case GLFW_KEY_CYRILLIC_ZE: return "CYRILLIC_ZE";
case GLFW_KEY_CYRILLIC_I: return "CYRILLIC_I";
case GLFW_KEY_CYRILLIC_SHORT_I: return "CYRILLIC_SHORT_I";
case GLFW_KEY_CYRILLIC_KA: return "CYRILLIC_KA";
case GLFW_KEY_CYRILLIC_EL: return "CYRILLIC_EL";
case GLFW_KEY_CYRILLIC_EM: return "CYRILLIC_EM";
case GLFW_KEY_CYRILLIC_EN: return "CYRILLIC_EN";
case GLFW_KEY_CYRILLIC_O: return "CYRILLIC_O";
case GLFW_KEY_CYRILLIC_PE: return "CYRILLIC_PE";
case GLFW_KEY_CYRILLIC_ER: return "CYRILLIC_ER";
case GLFW_KEY_CYRILLIC_ES: return "CYRILLIC_ES";
case GLFW_KEY_CYRILLIC_TE: return "CYRILLIC_TE";
case GLFW_KEY_CYRILLIC_U: return "CYRILLIC_U";
case GLFW_KEY_CYRILLIC_EF: return "CYRILLIC_EF";
case GLFW_KEY_CYRILLIC_HA: return "CYRILLIC_HA";
case GLFW_KEY_CYRILLIC_TSE: return "CYRILLIC_TSE";
case GLFW_KEY_CYRILLIC_CHE: return "CYRILLIC_CHE";
case GLFW_KEY_CYRILLIC_SHA: return "CYRILLIC_SHA";
case GLFW_KEY_CYRILLIC_SHCHA: return "CYRILLIC_SHCHA";
case GLFW_KEY_CYRILLIC_HARD_SIGN: return "CYRILLIC_HARD_SIGN";
case GLFW_KEY_CYRILLIC_YERU: return "CYRILLIC_YERU";
case GLFW_KEY_CYRILLIC_SOFT_SIGN: return "CYRILLIC_SOFT_SIGN";
case GLFW_KEY_CYRILLIC_E: return "CYRILLIC_E";
case GLFW_KEY_CYRILLIC_YU: return "CYRILLIC_YU";
case GLFW_KEY_CYRILLIC_YA: return "CYRILLIC_YA";
case GLFW_KEY_CYRILLIC_IO: return "CYRILLIC_IO";
// Function keys
case GLFW_KEY_ESCAPE: return "ESCAPE";
case GLFW_KEY_F1: return "F1";
case GLFW_KEY_F2: return "F2";
case GLFW_KEY_F3: return "F3";
case GLFW_KEY_F4: return "F4";
case GLFW_KEY_F5: return "F5";
case GLFW_KEY_F6: return "F6";
case GLFW_KEY_F7: return "F7";
case GLFW_KEY_F8: return "F8";
case GLFW_KEY_F9: return "F9";
case GLFW_KEY_F10: return "F10";
case GLFW_KEY_F11: return "F11";
case GLFW_KEY_F12: return "F12";
case GLFW_KEY_F13: return "F13";
case GLFW_KEY_F14: return "F14";
case GLFW_KEY_F15: return "F15";
case GLFW_KEY_F16: return "F16";
case GLFW_KEY_F17: return "F17";
case GLFW_KEY_F18: return "F18";
case GLFW_KEY_F19: return "F19";
case GLFW_KEY_F20: return "F20";
case GLFW_KEY_F21: return "F21";
case GLFW_KEY_F22: return "F22";
case GLFW_KEY_F23: return "F23";
case GLFW_KEY_F24: return "F24";
case GLFW_KEY_F25: return "F25";
case GLFW_KEY_UP: return "UP";
case GLFW_KEY_DOWN: return "DOWN";
case GLFW_KEY_LEFT: return "LEFT";
case GLFW_KEY_RIGHT: return "RIGHT";
case GLFW_KEY_LEFT_SHIFT: return "LEFT SHIFT";
case GLFW_KEY_RIGHT_SHIFT: return "RIGHT SHIFT";
case GLFW_KEY_LEFT_CONTROL: return "LEFT CONTROL";
case GLFW_KEY_RIGHT_CONTROL: return "RIGHT CONTROL";
case GLFW_KEY_LEFT_ALT: return "LEFT ALT";
case GLFW_KEY_RIGHT_ALT: return "RIGHT ALT";
case GLFW_KEY_TAB: return "TAB";
case GLFW_KEY_ENTER: return "ENTER";
case GLFW_KEY_BACKSPACE: return "BACKSPACE";
case GLFW_KEY_INSERT: return "INSERT";
case GLFW_KEY_DELETE: return "DELETE";
case GLFW_KEY_PAGE_UP: return "PAGE UP";
case GLFW_KEY_PAGE_DOWN: return "PAGE DOWN";
case GLFW_KEY_HOME: return "HOME";
case GLFW_KEY_END: return "END";
case GLFW_KEY_KP_0: return "KEYPAD 0";
case GLFW_KEY_KP_1: return "KEYPAD 1";
case GLFW_KEY_KP_2: return "KEYPAD 2";
case GLFW_KEY_KP_3: return "KEYPAD 3";
case GLFW_KEY_KP_4: return "KEYPAD 4";
case GLFW_KEY_KP_5: return "KEYPAD 5";
case GLFW_KEY_KP_6: return "KEYPAD 6";
case GLFW_KEY_KP_7: return "KEYPAD 7";
case GLFW_KEY_KP_8: return "KEYPAD 8";
case GLFW_KEY_KP_9: return "KEYPAD 9";
case GLFW_KEY_KP_DIVIDE: return "KEYPAD DIVIDE";
case GLFW_KEY_KP_MULTIPLY: return "KEYPAD MULTPLY";
case GLFW_KEY_KP_SUBTRACT: return "KEYPAD SUBTRACT";
case GLFW_KEY_KP_ADD: return "KEYPAD ADD";
case GLFW_KEY_KP_DECIMAL: return "KEYPAD DECIMAL";
case GLFW_KEY_KP_EQUAL: return "KEYPAD EQUAL";
case GLFW_KEY_KP_ENTER: return "KEYPAD ENTER";
case GLFW_KEY_PRINT_SCREEN: return "PRINT SCREEN";
case GLFW_KEY_NUM_LOCK: return "NUM LOCK";
case GLFW_KEY_CAPS_LOCK: return "CAPS LOCK";
case GLFW_KEY_SCROLL_LOCK: return "SCROLL LOCK";
case GLFW_KEY_PAUSE: return "PAUSE";
case GLFW_KEY_LEFT_SUPER: return "LEFT SUPER";
case GLFW_KEY_RIGHT_SUPER: return "RIGHT SUPER";
case GLFW_KEY_MENU: return "MENU";
case GLFW_KEY_ESCAPE: return "ESCAPE";
case GLFW_KEY_F1: return "F1";
case GLFW_KEY_F2: return "F2";
case GLFW_KEY_F3: return "F3";
case GLFW_KEY_F4: return "F4";
case GLFW_KEY_F5: return "F5";
case GLFW_KEY_F6: return "F6";
case GLFW_KEY_F7: return "F7";
case GLFW_KEY_F8: return "F8";
case GLFW_KEY_F9: return "F9";
case GLFW_KEY_F10: return "F10";
case GLFW_KEY_F11: return "F11";
case GLFW_KEY_F12: return "F12";
case GLFW_KEY_F13: return "F13";
case GLFW_KEY_F14: return "F14";
case GLFW_KEY_F15: return "F15";
case GLFW_KEY_F16: return "F16";
case GLFW_KEY_F17: return "F17";
case GLFW_KEY_F18: return "F18";
case GLFW_KEY_F19: return "F19";
case GLFW_KEY_F20: return "F20";
case GLFW_KEY_F21: return "F21";
case GLFW_KEY_F22: return "F22";
case GLFW_KEY_F23: return "F23";
case GLFW_KEY_F24: return "F24";
case GLFW_KEY_F25: return "F25";
case GLFW_KEY_UP: return "UP";
case GLFW_KEY_DOWN: return "DOWN";
case GLFW_KEY_LEFT: return "LEFT";
case GLFW_KEY_RIGHT: return "RIGHT";
case GLFW_KEY_LEFT_SHIFT: return "LEFT SHIFT";
case GLFW_KEY_RIGHT_SHIFT: return "RIGHT SHIFT";
case GLFW_KEY_LEFT_CONTROL: return "LEFT CONTROL";
case GLFW_KEY_RIGHT_CONTROL: return "RIGHT CONTROL";
case GLFW_KEY_LEFT_ALT: return "LEFT ALT";
case GLFW_KEY_RIGHT_ALT: return "RIGHT ALT";
case GLFW_KEY_TAB: return "TAB";
case GLFW_KEY_ENTER: return "ENTER";
case GLFW_KEY_BACKSPACE: return "BACKSPACE";
case GLFW_KEY_INSERT: return "INSERT";
case GLFW_KEY_DELETE: return "DELETE";
case GLFW_KEY_PAGE_UP: return "PAGE UP";
case GLFW_KEY_PAGE_DOWN: return "PAGE DOWN";
case GLFW_KEY_HOME: return "HOME";
case GLFW_KEY_END: return "END";
case GLFW_KEY_KP_0: return "KEYPAD 0";
case GLFW_KEY_KP_1: return "KEYPAD 1";
case GLFW_KEY_KP_2: return "KEYPAD 2";
case GLFW_KEY_KP_3: return "KEYPAD 3";
case GLFW_KEY_KP_4: return "KEYPAD 4";
case GLFW_KEY_KP_5: return "KEYPAD 5";
case GLFW_KEY_KP_6: return "KEYPAD 6";
case GLFW_KEY_KP_7: return "KEYPAD 7";
case GLFW_KEY_KP_8: return "KEYPAD 8";
case GLFW_KEY_KP_9: return "KEYPAD 9";
case GLFW_KEY_KP_DIVIDE: return "KEYPAD DIVIDE";
case GLFW_KEY_KP_MULTIPLY: return "KEYPAD MULTIPLY";
case GLFW_KEY_KP_SUBTRACT: return "KEYPAD SUBTRACT";
case GLFW_KEY_KP_ADD: return "KEYPAD ADD";
case GLFW_KEY_KP_DECIMAL: return "KEYPAD DECIMAL";
case GLFW_KEY_KP_EQUAL: return "KEYPAD EQUAL";
case GLFW_KEY_KP_ENTER: return "KEYPAD ENTER";
case GLFW_KEY_PRINT_SCREEN: return "PRINT SCREEN";
case GLFW_KEY_NUM_LOCK: return "NUM LOCK";
case GLFW_KEY_CAPS_LOCK: return "CAPS LOCK";
case GLFW_KEY_SCROLL_LOCK: return "SCROLL LOCK";
case GLFW_KEY_PAUSE: return "PAUSE";
case GLFW_KEY_LEFT_SUPER: return "LEFT SUPER";
case GLFW_KEY_RIGHT_SUPER: return "RIGHT SUPER";
case GLFW_KEY_MENU: return "MENU";
default: return "UNKNOWN";
default: return "UNKNOWN";
}
}
@@ -683,7 +756,7 @@ GLFWAPI void glfwSetInputMode(GLFWwindow* handle, int mode, int value)
_glfwInputError(GLFW_INVALID_ENUM, "Invalid input mode 0x%08X", mode);
}
GLFWAPI const char* glfwGetKeyName(int key, int scancode)
GLFWAPI const char* glfwGetKeyName(int key, int native_key)
{
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
@@ -691,18 +764,18 @@ GLFWAPI const char* glfwGetKeyName(int key, int scancode)
{
if (key != GLFW_KEY_KP_EQUAL &&
(key < GLFW_KEY_KP_0 || key > GLFW_KEY_KP_ADD) &&
(key < GLFW_KEY_APOSTROPHE || key > GLFW_KEY_WORLD_2))
(key < GLFW_KEY_APOSTROPHE || key > GLFW_KEY_LAST_PRINTABLE))
{
return NULL;
}
scancode = _glfwPlatformGetKeyScancode(key);
native_key = _glfwPlatformGetNativeKeyForKey(key);
}
return _glfwPlatformGetScancodeName(scancode);
return _glfwPlatformGetNativeKeyName(native_key);
}
GLFWAPI int glfwGetKeyScancode(int key)
GLFWAPI int glfwGetNativeKeyForKey(int key)
{
_GLFW_REQUIRE_INIT_OR_RETURN(-1);
@@ -712,7 +785,7 @@ GLFWAPI int glfwGetKeyScancode(int key)
return GLFW_RELEASE;
}
return _glfwPlatformGetKeyScancode(key);
return _glfwPlatformGetNativeKeyForKey(key);
}
GLFWAPI int glfwGetKey(GLFWwindow* handle, int key)
@@ -1405,25 +1478,23 @@ GLFWAPI const char* glfwGetPrimarySelectionString(GLFWwindow* handle UNUSED)
}
#endif
GLFWAPI double glfwGetTime(void)
GLFWAPI monotonic_t glfwGetTime(void)
{
_GLFW_REQUIRE_INIT_OR_RETURN(0.0);
return (double) (_glfwPlatformGetTimerValue() - _glfw.timer.offset) /
_glfwPlatformGetTimerFrequency();
_GLFW_REQUIRE_INIT_OR_RETURN(0);
return monotonic();
}
GLFWAPI void glfwSetTime(double time)
GLFWAPI void glfwSetTime(monotonic_t time)
{
_GLFW_REQUIRE_INIT();
if (time != time || time < 0.0 || time > 18446744073.0)
if (time < 0)
{
_glfwInputError(GLFW_INVALID_VALUE, "Invalid time %f", time);
_glfwInputError(GLFW_INVALID_VALUE, "Invalid time %f", monotonic_t_to_s_double(time));
return;
}
_glfw.timer.offset = _glfwPlatformGetTimerValue() -
(uint64_t) (time * _glfwPlatformGetTimerFrequency());
// Do nothing
}
GLFWAPI uint64_t glfwGetTimerValue(void)

19
glfw/internal.h vendored
View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 - www.glfw.org
// GLFW 3.4 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
@@ -27,6 +27,8 @@
#pragma once
#include "../kitty/monotonic.h"
#if defined(_GLFW_USE_CONFIG_H)
#include "glfw_config.h"
#endif
@@ -638,8 +640,8 @@ int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, GLFWCursorShape shape
void _glfwPlatformDestroyCursor(_GLFWcursor* cursor);
void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor);
const char* _glfwPlatformGetScancodeName(int scancode);
int _glfwPlatformGetKeyScancode(int key);
const char* _glfwPlatformGetNativeKeyName(int native_key);
int _glfwPlatformGetNativeKeyForKey(int key);
void _glfwPlatformFreeMonitor(_GLFWmonitor* monitor);
void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos);
@@ -687,7 +689,7 @@ void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window,
int* right, int* bottom);
void _glfwPlatformGetWindowContentScale(_GLFWwindow* window,
float* xscale, float* yscale);
double _glfwPlatformGetDoubleClickInterval(_GLFWwindow* window);
monotonic_t _glfwPlatformGetDoubleClickInterval(_GLFWwindow* window);
void _glfwPlatformIconifyWindow(_GLFWwindow* window);
void _glfwPlatformRestoreWindow(_GLFWwindow* window);
void _glfwPlatformMaximizeWindow(_GLFWwindow* window);
@@ -716,7 +718,7 @@ void _glfwPlatformUpdateIMEState(_GLFWwindow *w, int which, int a, int b, int c,
void _glfwPlatformPollEvents(void);
void _glfwPlatformWaitEvents(void);
void _glfwPlatformWaitEventsTimeout(double timeout);
void _glfwPlatformWaitEventsTimeout(monotonic_t timeout);
void _glfwPlatformPostEmptyEvent(void);
void _glfwPlatformGetRequiredInstanceExtensions(char** extensions);
@@ -756,7 +758,8 @@ void _glfwInputWindowDamage(_GLFWwindow* window);
void _glfwInputWindowCloseRequest(_GLFWwindow* window);
void _glfwInputWindowMonitor(_GLFWwindow* window, _GLFWmonitor* monitor);
void _glfwInputKeyboard(_GLFWwindow* window, int key, int scancode, int action, int mods, const char* text, int state);
void _glfwInitializeKeyEvent(GLFWkeyevent *ev, int key, int native_key, int action, int mods);
void _glfwInputKeyboard(_GLFWwindow *window, GLFWkeyevent *ev);
void _glfwInputScroll(_GLFWwindow* window, double xoffset, double yoffset, int flags);
void _glfwInputMouseClick(_GLFWwindow* window, int button, int action, int mods);
void _glfwInputCursorPos(_GLFWwindow* window, double xpos, double ypos);
@@ -823,8 +826,8 @@ _GLFWwindow* _glfwFocusedWindow(void);
_GLFWwindow* _glfwWindowForId(GLFWid id);
void _glfwPlatformRunMainLoop(GLFWtickcallback, void*);
void _glfwPlatformStopMainLoop(void);
unsigned long long _glfwPlatformAddTimer(double interval, bool repeats, GLFWuserdatafun callback, void *callback_data, GLFWuserdatafun free_callback);
void _glfwPlatformUpdateTimer(unsigned long long timer_id, double interval, bool enabled);
unsigned long long _glfwPlatformAddTimer(monotonic_t interval, bool repeats, GLFWuserdatafun callback, void *callback_data, GLFWuserdatafun free_callback);
void _glfwPlatformUpdateTimer(unsigned long long timer_id, monotonic_t interval, bool enabled);
void _glfwPlatformRemoveTimer(unsigned long long timer_id);
char* _glfw_strdup(const char* source);

15
glfw/linux_joystick.c vendored
View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 Linux - www.glfw.org
// GLFW 3.4 Linux - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2017 Camilla Löwy <elmindreda@glfw.org>
@@ -144,10 +144,10 @@ static bool openJoystickDevice(const char* path)
char absBits[(ABS_CNT + 7) / 8] = {0};
struct input_id id;
if (ioctl(linjs.fd, EVIOCGBIT(0, sizeof(evBits)), evBits) < 0 ||
ioctl(linjs.fd, EVIOCGBIT(EV_KEY, sizeof(keyBits)), keyBits) < 0 ||
ioctl(linjs.fd, EVIOCGBIT(EV_ABS, sizeof(absBits)), absBits) < 0 ||
ioctl(linjs.fd, EVIOCGID, &id) < 0)
if (ioctl(linjs.fd, (int32_t)EVIOCGBIT(0, sizeof(evBits)), evBits) < 0 ||
ioctl(linjs.fd, (int32_t)EVIOCGBIT(EV_KEY, sizeof(keyBits)), keyBits) < 0 ||
ioctl(linjs.fd, (int32_t)EVIOCGBIT(EV_ABS, sizeof(absBits)), absBits) < 0 ||
ioctl(linjs.fd, (int32_t)EVIOCGID, &id) < 0)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Linux: Failed to query input device: %s",
@@ -165,7 +165,7 @@ static bool openJoystickDevice(const char* path)
char name[256] = "";
if (ioctl(linjs.fd, EVIOCGNAME(sizeof(name)), name) < 0)
if (ioctl(linjs.fd, (int32_t)EVIOCGNAME(sizeof(name)), name) < 0)
strncpy(name, "Unknown", sizeof(name));
char guid[33] = "";
@@ -222,7 +222,8 @@ static bool openJoystickDevice(const char* path)
}
}
_GLFWjoystick* js = _glfwAllocJoystick(name, guid, axisCount, buttonCount, hatCount);
_GLFWjoystick* js =
_glfwAllocJoystick(name, guid, axisCount, buttonCount, hatCount);
if (!js)
{
close(linjs.fd);

View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 Linux - www.glfw.org
// GLFW 3.4 Linux - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2014 Jonas Ådahl <jadahl@gmail.com>
//
@@ -52,7 +52,7 @@ typedef struct _GLFWlibraryLinux
int inotify;
int watch;
regex_t regex;
bool dropped;
bool dropped;
} _GLFWlibraryLinux;

5
glfw/main_loop.h vendored
View File

@@ -7,6 +7,7 @@
#pragma once
#include "internal.h"
#include "../kitty/monotonic.h"
#ifndef GLFW_LOOP_BACKEND
#define GLFW_LOOP_BACKEND x11
@@ -36,7 +37,7 @@ void _glfwPlatformRunMainLoop(GLFWtickcallback tick_callback, void* data) {
EVDBG("main loop exiting");
}
unsigned long long _glfwPlatformAddTimer(double interval, bool repeats, GLFWuserdatafreefun callback, void *callback_data, GLFWuserdatafreefun free_callback) {
unsigned long long _glfwPlatformAddTimer(monotonic_t interval, bool repeats, GLFWuserdatafreefun callback, void *callback_data, GLFWuserdatafreefun free_callback) {
return addTimer(&_glfw.GLFW_LOOP_BACKEND.eventLoopData, "user timer", interval, 1, repeats, callback, callback_data, free_callback);
}
@@ -44,7 +45,7 @@ void _glfwPlatformRemoveTimer(unsigned long long timer_id) {
removeTimer(&_glfw.GLFW_LOOP_BACKEND.eventLoopData, timer_id);
}
void _glfwPlatformUpdateTimer(unsigned long long timer_id, double interval, bool enabled) {
void _glfwPlatformUpdateTimer(unsigned long long timer_id, monotonic_t interval, bool enabled) {
changeTimerInterval(&_glfw.GLFW_LOOP_BACKEND.eventLoopData, timer_id, interval);
toggleTimer(&_glfw.GLFW_LOOP_BACKEND.eventLoopData, timer_id, enabled);
}

2
glfw/mappings.h vendored
View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 - www.glfw.org
// GLFW 3.4 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2006-2018 Camilla Löwy <elmindreda@glfw.org>
//

6
glfw/monitor.c vendored
View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 - www.glfw.org
// GLFW 3.4 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
@@ -56,6 +56,10 @@ static int compareVideoModes(const void* fp, const void* sp)
if (farea != sarea)
return farea - sarea;
// Then sort on width
if (fm->width != sm->width)
return fm->width - sm->width;
// Lastly sort on refresh rate
return fm->refreshRate - sm->refreshRate;
}

6
glfw/nsgl_context.h vendored
View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 macOS - www.glfw.org
// GLFW 3.4 macOS - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2009-2019 Camilla Löwy <elmindreda@glfw.org>
//
@@ -32,8 +32,8 @@
//
typedef struct _GLFWcontextNSGL
{
id pixelFormat;
id object;
id pixelFormat;
id object;
} _GLFWcontextNSGL;

View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 macOS - www.glfw.org
// GLFW 3.4 macOS - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2009-2019 Camilla Löwy <elmindreda@glfw.org>
//
@@ -271,7 +271,7 @@ bool _glfwCreateContextNSGL(_GLFWwindow* window,
return false;
}
NSOpenGLContext* share = NULL;
NSOpenGLContext* share = nil;
if (ctxconfig->share)
share = ctxconfig->share->context.nsgl.object;
@@ -325,7 +325,7 @@ GLFWAPI id glfwGetNSGLContext(GLFWwindow* handle)
if (window->context.client == GLFW_NO_API)
{
_glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
return NULL;
return nil;
}
return window->context.nsgl.object;

2
glfw/null_init.c vendored
View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 - www.glfw.org
// GLFW 3.4 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2016 Google Inc.
// Copyright (c) 2016-2017 Camilla Löwy <elmindreda@glfw.org>

View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 - www.glfw.org
// GLFW 3.4 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2016-2017 Camilla Löwy <elmindreda@glfw.org>
//
@@ -33,12 +33,12 @@
////// GLFW platform API //////
//////////////////////////////////////////////////////////////////////////
int _glfwPlatformPollJoystick(_GLFWjoystick* js, int mode)
int _glfwPlatformPollJoystick(_GLFWjoystick* js UNUSED, int mode UNUSED)
{
return false;
}
void _glfwPlatformUpdateGamepadGUID(char* guid)
void _glfwPlatformUpdateGamepadGUID(char* guid UNUSED)
{
}

View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 - www.glfw.org
// GLFW 3.4 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2006-2017 Camilla Löwy <elmindreda@glfw.org>
//

22
glfw/null_monitor.c vendored
View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 - www.glfw.org
// GLFW 3.4 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2016 Google Inc.
// Copyright (c) 2016-2019 Camilla Löwy <elmindreda@glfw.org>
@@ -34,15 +34,15 @@
////// GLFW platform API //////
//////////////////////////////////////////////////////////////////////////
void _glfwPlatformFreeMonitor(_GLFWmonitor* monitor)
void _glfwPlatformFreeMonitor(_GLFWmonitor* monitor UNUSED)
{
}
void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos)
void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor UNUSED, int* xpos UNUSED, int* ypos UNUSED)
{
}
void _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor,
void _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor UNUSED,
float* xscale, float* yscale)
{
if (xscale)
@@ -51,27 +51,27 @@ void _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor,
*yscale = 1.f;
}
void _glfwPlatformGetMonitorWorkarea(_GLFWmonitor* monitor,
int* xpos, int* ypos,
int* width, int* height)
void _glfwPlatformGetMonitorWorkarea(_GLFWmonitor* monitor UNUSED,
int* xpos UNUSED, int* ypos UNUSED,
int* width UNUSED, int* height UNUSED)
{
}
GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* found)
GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor UNUSED, int* found UNUSED)
{
return NULL;
}
void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode)
void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor UNUSED, GLFWvidmode* mode UNUSED)
{
}
bool _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
bool _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor UNUSED, GLFWgammaramp* ramp UNUSED)
{
return false;
}
void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp)
void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor UNUSED, const GLFWgammaramp* ramp UNUSED)
{
}

View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 - www.glfw.org
// GLFW 3.4 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2016 Google Inc.
// Copyright (c) 2016-2017 Camilla Löwy <elmindreda@glfw.org>

127
glfw/null_window.c vendored
View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 - www.glfw.org
// GLFW 3.4 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2016 Google Inc.
// Copyright (c) 2016-2019 Camilla Löwy <elmindreda@glfw.org>
@@ -28,6 +28,7 @@
//========================================================================
#include "internal.h"
#include "../kitty/monotonic.h"
static int createNativeWindow(_GLFWwindow* window,
@@ -78,28 +79,28 @@ void _glfwPlatformDestroyWindow(_GLFWwindow* window)
window->context.destroy(window);
}
void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title)
void _glfwPlatformSetWindowTitle(_GLFWwindow* window UNUSED, const char* title UNUSED)
{
}
void _glfwPlatformSetWindowIcon(_GLFWwindow* window, int count,
const GLFWimage* images)
void _glfwPlatformSetWindowIcon(_GLFWwindow* window UNUSED, int count UNUSED,
const GLFWimage* images UNUSED)
{
}
void _glfwPlatformSetWindowMonitor(_GLFWwindow* window,
_GLFWmonitor* monitor,
int xpos, int ypos,
int width, int height,
int refreshRate)
void _glfwPlatformSetWindowMonitor(_GLFWwindow* window UNUSED,
_GLFWmonitor* monitor UNUSED,
int xpos UNUSED, int ypos UNUSED,
int width UNUSED, int height UNUSED,
int refreshRate UNUSED)
{
}
void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos)
void _glfwPlatformGetWindowPos(_GLFWwindow* window UNUSED, int* xpos UNUSED, int* ypos UNUSED)
{
}
void _glfwPlatformSetWindowPos(_GLFWwindow* window, int xpos, int ypos)
void _glfwPlatformSetWindowPos(_GLFWwindow* window UNUSED, int xpos UNUSED, int ypos UNUSED)
{
}
@@ -117,13 +118,13 @@ void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height)
window->null.height = height;
}
void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window,
int minwidth, int minheight,
int maxwidth, int maxheight)
void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window UNUSED,
int minwidth UNUSED, int minheight UNUSED,
int maxwidth UNUSED, int maxheight UNUSED)
{
}
void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window, int n, int d)
void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window UNUSED, int n UNUSED, int d UNUSED)
{
}
@@ -135,13 +136,13 @@ void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* heigh
*height = window->null.height;
}
void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window,
int* left, int* top,
int* right, int* bottom)
void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window UNUSED,
int* left UNUSED, int* top UNUSED,
int* right UNUSED, int* bottom UNUSED)
{
}
void _glfwPlatformGetWindowContentScale(_GLFWwindow* window,
void _glfwPlatformGetWindowContentScale(_GLFWwindow* window UNUSED,
float* xscale, float* yscale)
{
if (xscale)
@@ -150,101 +151,101 @@ void _glfwPlatformGetWindowContentScale(_GLFWwindow* window,
*yscale = 1.f;
}
double _glfwPlatformGetDoubleClickInterval(_GLFWwindow* window)
monotonic_t _glfwPlatformGetDoubleClickInterval(_GLFWwindow* window UNUSED)
{
return 0.5;
return ms_to_monotonic_t(500ll);
}
void _glfwPlatformIconifyWindow(_GLFWwindow* window)
void _glfwPlatformIconifyWindow(_GLFWwindow* window UNUSED)
{
}
void _glfwPlatformRestoreWindow(_GLFWwindow* window)
void _glfwPlatformRestoreWindow(_GLFWwindow* window UNUSED)
{
}
void _glfwPlatformMaximizeWindow(_GLFWwindow* window)
void _glfwPlatformMaximizeWindow(_GLFWwindow* window UNUSED)
{
}
int _glfwPlatformWindowMaximized(_GLFWwindow* window)
int _glfwPlatformWindowMaximized(_GLFWwindow* window UNUSED)
{
return false;
}
int _glfwPlatformWindowHovered(_GLFWwindow* window)
int _glfwPlatformWindowHovered(_GLFWwindow* window UNUSED)
{
return false;
}
int _glfwPlatformFramebufferTransparent(_GLFWwindow* window)
int _glfwPlatformFramebufferTransparent(_GLFWwindow* window UNUSED)
{
return false;
}
void _glfwPlatformSetWindowResizable(_GLFWwindow* window, bool enabled)
void _glfwPlatformSetWindowResizable(_GLFWwindow* window UNUSED, bool enabled UNUSED)
{
}
void _glfwPlatformSetWindowDecorated(_GLFWwindow* window, bool enabled)
void _glfwPlatformSetWindowDecorated(_GLFWwindow* window UNUSED, bool enabled UNUSED)
{
}
void _glfwPlatformSetWindowFloating(_GLFWwindow* window, bool enabled)
void _glfwPlatformSetWindowFloating(_GLFWwindow* window UNUSED, bool enabled UNUSED)
{
}
float _glfwPlatformGetWindowOpacity(_GLFWwindow* window)
float _glfwPlatformGetWindowOpacity(_GLFWwindow* window UNUSED)
{
return 1.f;
}
void _glfwPlatformSetWindowOpacity(_GLFWwindow* window, float opacity)
void _glfwPlatformSetWindowOpacity(_GLFWwindow* window UNUSED, float opacity UNUSED)
{
}
void _glfwPlatformShowWindow(_GLFWwindow* window)
void _glfwPlatformShowWindow(_GLFWwindow* window UNUSED)
{
}
void _glfwPlatformRequestWindowAttention(_GLFWwindow* window)
void _glfwPlatformRequestWindowAttention(_GLFWwindow* window UNUSED)
{
}
int _glfwPlatformWindowBell(_GLFWwindow* window)
int _glfwPlatformWindowBell(_GLFWwindow* window UNUSED)
{
return false;
}
void _glfwPlatformUnhideWindow(_GLFWwindow* window)
void _glfwPlatformUnhideWindow(_GLFWwindow* window UNUSED)
{
}
void _glfwPlatformHideWindow(_GLFWwindow* window)
void _glfwPlatformHideWindow(_GLFWwindow* window UNUSED)
{
}
void _glfwPlatformFocusWindow(_GLFWwindow* window)
void _glfwPlatformFocusWindow(_GLFWwindow* window UNUSED)
{
}
int _glfwPlatformWindowFocused(_GLFWwindow* window)
int _glfwPlatformWindowFocused(_GLFWwindow* window UNUSED)
{
return false;
}
int _glfwPlatformWindowOccluded(_GLFWwindow* window)
int _glfwPlatformWindowOccluded(_GLFWwindow* window UNUSED)
{
return false;
}
int _glfwPlatformWindowIconified(_GLFWwindow* window)
int _glfwPlatformWindowIconified(_GLFWwindow* window UNUSED)
{
return false;
}
int _glfwPlatformWindowVisible(_GLFWwindow* window)
int _glfwPlatformWindowVisible(_GLFWwindow* window UNUSED)
{
return false;
}
@@ -257,7 +258,7 @@ void _glfwPlatformWaitEvents(void)
{
}
void _glfwPlatformWaitEventsTimeout(double timeout)
void _glfwPlatformWaitEventsTimeout(monotonic_t timeout UNUSED)
{
}
@@ -265,39 +266,39 @@ void _glfwPlatformPostEmptyEvent(void)
{
}
void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos)
void _glfwPlatformGetCursorPos(_GLFWwindow* window UNUSED, double* xpos UNUSED, double* ypos UNUSED)
{
}
void _glfwPlatformSetCursorPos(_GLFWwindow* window, double x, double y)
void _glfwPlatformSetCursorPos(_GLFWwindow* window UNUSED, double x UNUSED, double y UNUSED)
{
}
void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode)
void _glfwPlatformSetCursorMode(_GLFWwindow* window UNUSED, int mode UNUSED)
{
}
int _glfwPlatformCreateCursor(_GLFWcursor* cursor,
const GLFWimage* image,
int xhot, int yhot, int count)
int _glfwPlatformCreateCursor(_GLFWcursor* cursor UNUSED,
const GLFWimage* image UNUSED,
int xhot UNUSED, int yhot UNUSED, int count UNUSED)
{
return true;
}
int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape)
int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor UNUSED, int shape UNUSED)
{
return true;
}
void _glfwPlatformDestroyCursor(_GLFWcursor* cursor)
void _glfwPlatformDestroyCursor(_GLFWcursor* cursor UNUSED)
{
}
void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor)
void _glfwPlatformSetCursor(_GLFWwindow* window UNUSED, _GLFWcursor* cursor UNUSED)
{
}
void _glfwPlatformSetClipboardString(const char* string)
void _glfwPlatformSetClipboardString(const char* string UNUSED)
{
}
@@ -306,31 +307,31 @@ const char* _glfwPlatformGetClipboardString(void)
return NULL;
}
const char* _glfwPlatformGetScancodeName(int scancode)
const char* _glfwPlatformGetNativeKeyName(int native_key UNUSED)
{
return "";
}
int _glfwPlatformGetKeyScancode(int key)
int _glfwPlatformGetNativeKeyForKey(int key UNUSED)
{
return -1;
}
void _glfwPlatformGetRequiredInstanceExtensions(char** extensions)
void _glfwPlatformGetRequiredInstanceExtensions(char** extensions UNUSED)
{
}
int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance,
VkPhysicalDevice device,
uint32_t queuefamily)
int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance UNUSED,
VkPhysicalDevice device UNUSED,
uint32_t queuefamily UNUSED)
{
return false;
}
VkResult _glfwPlatformCreateWindowSurface(VkInstance instance,
_GLFWwindow* window,
const VkAllocationCallbacks* allocator,
VkSurfaceKHR* surface)
VkResult _glfwPlatformCreateWindowSurface(VkInstance instance UNUSED,
_GLFWwindow* window UNUSED,
const VkAllocationCallbacks* allocator UNUSED,
VkSurfaceKHR* surface UNUSED)
{
// This seems like the most appropriate error to return here
return VK_ERROR_INITIALIZATION_FAILED;

View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 OSMesa - www.glfw.org
// GLFW 3.4 OSMesa - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2016 Google Inc.
// Copyright (c) 2016-2017 Camilla Löwy <elmindreda@glfw.org>

View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 OSMesa - www.glfw.org
// GLFW 3.4 OSMesa - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2016 Google Inc.
// Copyright (c) 2016-2017 Camilla Löwy <elmindreda@glfw.org>

2
glfw/posix_thread.c vendored
View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 POSIX - www.glfw.org
// GLFW 3.4 POSIX - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2017 Camilla Löwy <elmindreda@glfw.org>

6
glfw/posix_thread.h vendored
View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 POSIX - www.glfw.org
// GLFW 3.4 POSIX - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2017 Camilla Löwy <elmindreda@glfw.org>
@@ -35,7 +35,7 @@
//
typedef struct _GLFWtlsPOSIX
{
bool allocated;
bool allocated;
pthread_key_t key;
} _GLFWtlsPOSIX;
@@ -44,7 +44,7 @@ typedef struct _GLFWtlsPOSIX
//
typedef struct _GLFWmutexPOSIX
{
bool allocated;
bool allocated;
pthread_mutex_t handle;
} _GLFWmutexPOSIX;

2
glfw/posix_time.c vendored
View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 POSIX - www.glfw.org
// GLFW 3.4 POSIX - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2017 Camilla Löwy <elmindreda@glfw.org>

4
glfw/posix_time.h vendored
View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 POSIX - www.glfw.org
// GLFW 3.4 POSIX - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2017 Camilla Löwy <elmindreda@glfw.org>
@@ -34,7 +34,7 @@
//
typedef struct _GLFWtimerPOSIX
{
bool monotonic;
bool monotonic;
uint64_t frequency;
} _GLFWtimerPOSIX;

2
glfw/vulkan.c vendored
View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 - www.glfw.org
// GLFW 3.4 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2018 Camilla Löwy <elmindreda@glfw.org>

13
glfw/window.c vendored
View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 - www.glfw.org
// GLFW 3.4 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
@@ -29,6 +29,7 @@
//========================================================================
#include "internal.h"
#include "../kitty/monotonic.h"
#include <assert.h>
#include <string.h>
@@ -56,8 +57,10 @@ void _glfwInputWindowFocus(_GLFWwindow* window, bool focused)
{
if (window->keys[key] == GLFW_PRESS)
{
const int scancode = _glfwPlatformGetKeyScancode(key);
_glfwInputKeyboard(window, key, scancode, GLFW_RELEASE, 0, "", 0);
const int native_key = _glfwPlatformGetNativeKeyForKey(key);
GLFWkeyevent ev;
_glfwInitializeKeyEvent(&ev, key, native_key, GLFW_RELEASE, 0);
_glfwInputKeyboard(window, &ev);
}
}
@@ -736,12 +739,12 @@ GLFWAPI void glfwGetWindowContentScale(GLFWwindow* handle,
_glfwPlatformGetWindowContentScale(window, xscale, yscale);
}
GLFWAPI double glfwGetDoubleClickInterval(GLFWwindow* handle)
GLFWAPI monotonic_t glfwGetDoubleClickInterval(GLFWwindow* handle)
{
_GLFWwindow* window = (_GLFWwindow*) handle;
assert(window != NULL);
_GLFW_REQUIRE_INIT_OR_RETURN(0.5f);
_GLFW_REQUIRE_INIT_OR_RETURN(ms_to_monotonic_t(500ll));
return _glfwPlatformGetDoubleClickInterval(window);
}

57
glfw/wl_init.c vendored
View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 Wayland - www.glfw.org
// GLFW 3.4 Wayland - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2014 Jonas Ådahl <jadahl@gmail.com>
//
@@ -29,6 +29,7 @@
#define _GNU_SOURCE
#include "internal.h"
#include "backend_utils.h"
#include "../kitty/monotonic.h"
#include <assert.h>
#include <errno.h>
@@ -164,6 +165,7 @@ static void setCursor(GLFWCursorShape shape)
wl_surface_damage(surface, 0, 0,
image->width, image->height);
wl_surface_commit(surface);
_glfw.wl.cursorPreviousShape = shape;
}
static void pointerHandleMotion(void* data UNUSED,
@@ -174,43 +176,45 @@ static void pointerHandleMotion(void* data UNUSED,
{
_GLFWwindow* window = _glfw.wl.pointerFocus;
GLFWCursorShape cursorShape = GLFW_ARROW_CURSOR;
double x, y;
if (!window)
return;
if (window->cursorMode == GLFW_CURSOR_DISABLED)
return;
window->wl.cursorPosX = wl_fixed_to_double(sx);
window->wl.cursorPosY = wl_fixed_to_double(sy);
x = wl_fixed_to_double(sx);
y = wl_fixed_to_double(sy);
switch (window->wl.decorations.focus)
{
case mainWindow:
_glfwInputCursorPos(window,
window->wl.cursorPosX, window->wl.cursorPosY);
window->wl.cursorPosX = x;
window->wl.cursorPosY = y;
_glfwInputCursorPos(window, x, y);
return;
case topDecoration:
if (window->wl.cursorPosY < _GLFW_DECORATION_WIDTH)
if (y < _GLFW_DECORATION_WIDTH)
cursorShape = GLFW_VRESIZE_CURSOR;
else
cursorShape = GLFW_ARROW_CURSOR;
break;
case leftDecoration:
if (window->wl.cursorPosY < _GLFW_DECORATION_WIDTH)
if (y < _GLFW_DECORATION_WIDTH)
cursorShape = GLFW_NW_RESIZE_CURSOR;
else
cursorShape = GLFW_HRESIZE_CURSOR;
break;
case rightDecoration:
if (window->wl.cursorPosY < _GLFW_DECORATION_WIDTH)
if (y < _GLFW_DECORATION_WIDTH)
cursorShape = GLFW_NE_RESIZE_CURSOR;
else
cursorShape = GLFW_HRESIZE_CURSOR;
break;
case bottomDecoration:
if (window->wl.cursorPosX < _GLFW_DECORATION_WIDTH)
if (x < _GLFW_DECORATION_WIDTH)
cursorShape = GLFW_SW_RESIZE_CURSOR;
else if (window->wl.cursorPosX > window->wl.width + _GLFW_DECORATION_WIDTH)
else if (x > window->wl.width + _GLFW_DECORATION_WIDTH)
cursorShape = GLFW_SE_RESIZE_CURSOR;
else
cursorShape = GLFW_VRESIZE_CURSOR;
@@ -218,7 +222,8 @@ static void pointerHandleMotion(void* data UNUSED,
default:
assert(0);
}
setCursor(cursorShape);
if (_glfw.wl.cursorPreviousShape != cursorShape)
setCursor(cursorShape);
}
static void pointerHandleButton(void* data UNUSED,
@@ -284,8 +289,8 @@ static void pointerHandleButton(void* data UNUSED,
{
xdg_toplevel_show_window_menu(window->wl.xdg.toplevel,
_glfw.wl.seat, serial,
window->wl.cursorPosX,
window->wl.cursorPosY);
(int32_t)window->wl.cursorPosX,
(int32_t)window->wl.cursorPosY);
return;
}
}
@@ -367,7 +372,7 @@ static void keyboardHandleEnter(void* data UNUSED,
struct wl_keyboard* keyboard UNUSED,
uint32_t serial UNUSED,
struct wl_surface* surface,
struct wl_array* keys UNUSED)
struct wl_array* keys)
{
// Happens in the case we just destroyed the surface.
if (!surface)
@@ -383,6 +388,15 @@ static void keyboardHandleEnter(void* data UNUSED,
_glfw.wl.keyboardFocus = window;
_glfwInputWindowFocus(window, true);
uint32_t* key;
if (keys && _glfw.wl.keyRepeatInfo.key) {
wl_array_for_each(key, keys) {
if (*key == _glfw.wl.keyRepeatInfo.key) {
toggleTimer(&_glfw.wl.eventLoopData, _glfw.wl.keyRepeatInfo.keyRepeatTimer, 1);
break;
}
}
}
}
static void keyboardHandleLeave(void* data UNUSED,
@@ -397,13 +411,14 @@ static void keyboardHandleLeave(void* data UNUSED,
_glfw.wl.keyboardFocus = NULL;
_glfwInputWindowFocus(window, false);
toggleTimer(&_glfw.wl.eventLoopData, _glfw.wl.keyRepeatInfo.keyRepeatTimer, 0);
}
static void
dispatchPendingKeyRepeats(id_type timer_id UNUSED, void *data UNUSED) {
if (_glfw.wl.keyRepeatInfo.keyboardFocus != _glfw.wl.keyboardFocus || _glfw.wl.keyboardRepeatRate == 0) return;
glfw_xkb_handle_key_event(_glfw.wl.keyRepeatInfo.keyboardFocus, &_glfw.wl.xkb, _glfw.wl.keyRepeatInfo.key, GLFW_REPEAT);
changeTimerInterval(&_glfw.wl.eventLoopData, _glfw.wl.keyRepeatInfo.keyRepeatTimer, (1.0 / (double)_glfw.wl.keyboardRepeatRate));
changeTimerInterval(&_glfw.wl.eventLoopData, _glfw.wl.keyRepeatInfo.keyRepeatTimer, (s_to_monotonic_t(1ll) / (monotonic_t)_glfw.wl.keyboardRepeatRate));
toggleTimer(&_glfw.wl.eventLoopData, _glfw.wl.keyRepeatInfo.keyRepeatTimer, 1);
}
@@ -421,6 +436,7 @@ static void keyboardHandleKey(void* data UNUSED,
int action = state == WL_KEYBOARD_KEY_STATE_PRESSED ? GLFW_PRESS : GLFW_RELEASE;
glfw_xkb_handle_key_event(window, &_glfw.wl.xkb, key, action);
bool repeatable = false;
_glfw.wl.keyRepeatInfo.key = 0;
if (action == GLFW_PRESS && _glfw.wl.keyboardRepeatRate > 0 && glfw_xkb_should_repeat(&_glfw.wl.xkb, key))
{
@@ -429,7 +445,7 @@ static void keyboardHandleKey(void* data UNUSED,
_glfw.wl.keyRepeatInfo.keyboardFocus = window;
}
if (repeatable) {
changeTimerInterval(&_glfw.wl.eventLoopData, _glfw.wl.keyRepeatInfo.keyRepeatTimer, (double)(_glfw.wl.keyboardRepeatDelay) / 1000.0);
changeTimerInterval(&_glfw.wl.eventLoopData, _glfw.wl.keyRepeatInfo.keyRepeatTimer, _glfw.wl.keyboardRepeatDelay);
}
toggleTimer(&_glfw.wl.eventLoopData, _glfw.wl.keyRepeatInfo.keyRepeatTimer, repeatable ? 1 : 0);
}
@@ -454,7 +470,7 @@ static void keyboardHandleRepeatInfo(void* data UNUSED,
return;
_glfw.wl.keyboardRepeatRate = rate;
_glfw.wl.keyboardRepeatDelay = delay;
_glfw.wl.keyboardRepeatDelay = ms_to_monotonic_t(delay);
}
static const struct wl_keyboard_listener keyboardListener = {
@@ -607,8 +623,7 @@ static void registryHandleGlobal(void* data UNUSED,
_glfwSetupWaylandDataDevice();
}
}
else if (strcmp(interface, "zwp_primary_selection_device_manager_v1") == 0 ||
strcmp(interface, "gtk_primary_selection_device_manager") == 0)
else if (strcmp(interface, "zwp_primary_selection_device_manager_v1") == 0)
{
_glfw.wl.primarySelectionDeviceManager =
wl_registry_bind(registry, name,
@@ -728,8 +743,8 @@ int _glfwPlatformInit(void)
"Wayland: Failed to initialize event loop data");
}
glfw_dbus_init(&_glfw.wl.dbus, &_glfw.wl.eventLoopData);
_glfw.wl.keyRepeatInfo.keyRepeatTimer = addTimer(&_glfw.wl.eventLoopData, "wayland-key-repeat", 0.5, 0, true, dispatchPendingKeyRepeats, NULL, NULL);
_glfw.wl.cursorAnimationTimer = addTimer(&_glfw.wl.eventLoopData, "wayland-cursor-animation", 0.5, 0, true, animateCursorImage, NULL, NULL);
_glfw.wl.keyRepeatInfo.keyRepeatTimer = addTimer(&_glfw.wl.eventLoopData, "wayland-key-repeat", ms_to_monotonic_t(500ll), 0, true, dispatchPendingKeyRepeats, NULL, NULL);
_glfw.wl.cursorAnimationTimer = addTimer(&_glfw.wl.eventLoopData, "wayland-cursor-animation", ms_to_monotonic_t(500ll), 0, true, animateCursorImage, NULL, NULL);
_glfw.wl.registry = wl_display_get_registry(_glfw.wl.display);
wl_registry_add_listener(_glfw.wl.registry, &registryListener, NULL);

2
glfw/wl_monitor.c vendored
View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 Wayland - www.glfw.org
// GLFW 3.4 Wayland - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2014 Jonas Ådahl <jadahl@gmail.com>
//

6
glfw/wl_platform.h vendored
View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 Wayland - www.glfw.org
// GLFW 3.4 Wayland - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2014 Jonas Ådahl <jadahl@gmail.com>
//
@@ -156,6 +156,7 @@ typedef struct _GLFWwindowWayland
// We need to track the monitors the window spans on to calculate the
// optimal scaling factor.
int scale;
bool initial_scale_notified;
_GLFWmonitor** monitors;
int monitorsCount;
int monitorsSize;
@@ -247,10 +248,11 @@ typedef struct _GLFWlibraryWayland
struct wl_cursor_theme* cursorTheme;
struct wl_surface* cursorSurface;
GLFWCursorShape cursorPreviousShape;
uint32_t pointerSerial;
int32_t keyboardRepeatRate;
int32_t keyboardRepeatDelay;
monotonic_t keyboardRepeatDelay;
struct {
uint32_t key;
id_type keyRepeatTimer;

58
glfw/wl_window.c vendored
View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 Wayland - www.glfw.org
// GLFW 3.4 Wayland - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2014 Jonas Ådahl <jadahl@gmail.com>
//
@@ -32,6 +32,7 @@
#include "backend_utils.h"
#include "memfd.h"
#include "linux_notify.h"
#include "../kitty/monotonic.h"
#include <stdio.h>
#include <stdlib.h>
@@ -54,13 +55,18 @@ static bool checkScaleChange(_GLFWwindow* window)
if (_glfw.wl.compositorVersion < 3)
return false;
// Get the scale factor from the highest scale monitor.
// Get the scale factor from the highest scale monitor that this window is on
for (i = 0; i < window->wl.monitorsCount; ++i)
{
monitorScale = window->wl.monitors[i]->wl.scale;
if (scale < monitorScale)
scale = monitorScale;
}
if (window->wl.monitorsCount < 1 && _glfw.monitorCount > 0) {
// The window has not yet been assigned to any monitors, use the primary monitor
_GLFWmonitor *m = _glfw.monitors[0];
if (m && m->wl.scale > scale) scale = m->wl.scale;
}
// Only change the framebuffer size if the scale changed.
if (scale != window->wl.scale)
@@ -69,6 +75,10 @@ static bool checkScaleChange(_GLFWwindow* window)
wl_surface_set_buffer_scale(window->wl.surface, scale);
return true;
}
if (window->wl.monitorsCount > 0 && !window->wl.initial_scale_notified) {
window->wl.initial_scale_notified = true;
return true;
}
return false;
}
@@ -173,7 +183,7 @@ static void dispatchChangesAfterConfigure(_GLFWwindow *window, int32_t width, in
* SCM_RIGHTS methods.
*
* posix_fallocate() is used to guarantee that disk space is available
* for the file at the given size. If disk space is insufficent, errno
* for the file at the given size. If disk space is insufficient, errno
* is set to ENOSPC. If posix_fallocate() is not supported, program may
* receive SIGBUS on accessing mmap()'ed file contents instead.
*/
@@ -241,8 +251,8 @@ static struct wl_buffer* createShmBuffer(const GLFWimage* image)
if (fd < 0)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Wayland: Creating a buffer file for %d B failed: %%m",
length);
"Wayland: Creating a buffer file for %d B failed: %s",
length, strerror(errno));
return NULL;
}
@@ -250,7 +260,7 @@ static struct wl_buffer* createShmBuffer(const GLFWimage* image)
if (data == MAP_FAILED)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Wayland: mmap failed: %%m");
"Wayland: mmap failed: %s", strerror(errno));
close(fd);
return NULL;
}
@@ -545,9 +555,9 @@ static void xdgToplevelHandleConfigure(void* data,
aspectRatio = (float)width / (float)height;
targetRatio = (float)window->numer / (float)window->denom;
if (aspectRatio < targetRatio)
height = width / targetRatio;
height = (int32_t)((float)width / targetRatio);
else if (aspectRatio > targetRatio)
width = height * targetRatio;
width = (int32_t)((float)height * targetRatio);
}
}
}
@@ -684,7 +694,7 @@ setCursorImage(_GLFWcursorWayland* cursorWayland)
image = cursorWayland->cursor->images[cursorWayland->currentImage];
buffer = wl_cursor_image_get_buffer(image);
if (image->delay) {
changeTimerInterval(&_glfw.wl.eventLoopData, _glfw.wl.cursorAnimationTimer, ((double)image->delay) / 1000.0);
changeTimerInterval(&_glfw.wl.eventLoopData, _glfw.wl.cursorAnimationTimer, ms_to_monotonic_t(image->delay));
toggleTimer(&_glfw.wl.eventLoopData, _glfw.wl.cursorAnimationTimer, 1);
} else {
toggleTimer(&_glfw.wl.eventLoopData, _glfw.wl.cursorAnimationTimer, 0);
@@ -745,11 +755,11 @@ abortOnFatalError(int last_error) {
}
static void
handleEvents(double timeout)
handleEvents(monotonic_t timeout)
{
struct wl_display* display = _glfw.wl.display;
errno = 0;
EVDBG("starting handleEvents(%.2f)", timeout);
EVDBG("starting handleEvents(%.2f)", monotonic_t_to_s_double(timeout));
while (wl_display_prepare_read(display) != 0) {
while(1) {
@@ -1052,9 +1062,9 @@ void _glfwPlatformGetWindowContentScale(_GLFWwindow* window,
*yscale = (float) window->wl.scale;
}
double _glfwPlatformGetDoubleClickInterval(_GLFWwindow* window UNUSED)
monotonic_t _glfwPlatformGetDoubleClickInterval(_GLFWwindow* window UNUSED)
{
return 0.5;
return ms_to_monotonic_t(500ll);
}
void _glfwPlatformIconifyWindow(_GLFWwindow* window)
@@ -1227,11 +1237,11 @@ void _glfwPlatformPollEvents(void)
void _glfwPlatformWaitEvents(void)
{
double timeout = wl_display_dispatch_pending(_glfw.wl.display) > 0 ? 0 : -1;
monotonic_t timeout = wl_display_dispatch_pending(_glfw.wl.display) > 0 ? 0 : -1;
handleEvents(timeout);
}
void _glfwPlatformWaitEventsTimeout(double timeout)
void _glfwPlatformWaitEventsTimeout(monotonic_t timeout)
{
if (wl_display_dispatch_pending(_glfw.wl.display) > 0) timeout = 0;
handleEvents(timeout);
@@ -1268,12 +1278,12 @@ void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode UNUSED)
_glfwPlatformSetCursor(window, window->wl.currentCursor);
}
const char* _glfwPlatformGetScancodeName(int scancode)
const char* _glfwPlatformGetNativeKeyName(int native_key)
{
return glfw_xkb_keysym_name(scancode);
return glfw_xkb_keysym_name(native_key);
}
int _glfwPlatformGetKeyScancode(int key)
int _glfwPlatformGetNativeKeyForKey(int key)
{
return glfw_xkb_sym_for_key(key);
}
@@ -1462,8 +1472,8 @@ static void send_text(char *text, int fd)
{
if (text) {
size_t len = strlen(text), pos = 0;
double start = glfwGetTime();
while (pos < len && glfwGetTime() - start < 2.0) {
monotonic_t start = glfwGetTime();
while (pos < len && glfwGetTime() - start < s_to_monotonic_t(2ll)) {
ssize_t ret = write(fd, text + pos, len - pos);
if (ret < 0) {
if (errno == EAGAIN || errno == EINTR) continue;
@@ -1496,7 +1506,7 @@ static char* read_offer_string(int data_pipe) {
struct pollfd fds;
fds.fd = data_pipe;
fds.events = POLLIN;
double start = glfwGetTime();
monotonic_t start = glfwGetTime();
#define bail(...) { \
_glfwInputError(GLFW_PLATFORM_ERROR, __VA_ARGS__); \
free(buf); buf = NULL; \
@@ -1504,7 +1514,7 @@ static char* read_offer_string(int data_pipe) {
return NULL; \
}
while (glfwGetTime() - start < 2) {
while (glfwGetTime() - start < s_to_monotonic_t(2ll)) {
int ret = poll(&fds, 1, 2000);
if (ret == -1) {
if (errno == EINTR) continue;
@@ -1836,7 +1846,7 @@ static inline bool _glfwEnsureDataDevice(void) {
if (!_glfw.wl.dataDevice)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Wayland: Cannot use clipboard, failed to create data device");
"Wayland: Cannot use clipboard, failed to create data device");
return false;
}
}
@@ -2031,7 +2041,7 @@ GLFWAPI struct wl_surface* glfwGetWaylandWindow(GLFWwindow* handle)
return window->wl.surface;
}
GLFWAPI int glfwGetXKBScancode(const char* keyName, bool caseSensitive) {
GLFWAPI int glfwGetNativeKeyForName(const char* keyName, bool caseSensitive) {
return glfw_xkb_keysym_from_name(keyName, caseSensitive);
}

14
glfw/x11_init.c vendored
View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 X11 - www.glfw.org
// GLFW 3.4 X11 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
@@ -433,12 +433,10 @@ static bool initExtensions(void)
//
void _glfwGetSystemContentScaleX11(float* xscale, float* yscale, bool bypass_cache)
{
// NOTE: Default to the display-wide DPI as we don't currently have a policy
// for which monitor a window is considered to be on
float xdpi = DisplayWidth(_glfw.x11.display, _glfw.x11.screen) *
25.4f / DisplayWidthMM(_glfw.x11.display, _glfw.x11.screen);
float ydpi = DisplayHeight(_glfw.x11.display, _glfw.x11.screen) *
25.4f / DisplayHeightMM(_glfw.x11.display, _glfw.x11.screen);
// Start by assuming the default X11 DPI
// NOTE: Some desktop environments (KDE) may remove the Xft.dpi field when it
// would be set to 96, so assume that is the case if we cannot find it
float xdpi = 96.f, ydpi = 96.f;
// NOTE: Basing the scale on Xft.dpi where available should provide the most
// consistent user experience (matches Qt, Gtk, etc), although not
@@ -468,7 +466,7 @@ void _glfwGetSystemContentScaleX11(float* xscale, float* yscale, bool bypass_cac
if (XrmGetResource(db, "Xft.dpi", "Xft.Dpi", &type, &value))
{
if (type && strcmp(type, "String") == 0)
xdpi = ydpi = atof(value.addr);
xdpi = ydpi = (float)atof(value.addr);
}
XrmDestroyDatabase(db);

12
glfw/x11_monitor.c vendored
View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 X11 - www.glfw.org
// GLFW 3.4 X11 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
@@ -166,6 +166,16 @@ void _glfwPollMonitorsX11(void)
heightMM = oi->mm_height;
}
if (widthMM <= 0 || heightMM <= 0)
{
// HACK: If RandR does not provide a physical size, assume the
// X11 default 96 DPI and calcuate from the CRTC viewport
// NOTE: These members are affected by rotation, unlike the mode
// info and output info members
widthMM = (int) (ci->width * 25.4f / 96.f);
heightMM = (int) (ci->height * 25.4f / 96.f);
}
_GLFWmonitor* monitor = _glfwAllocMonitor(oi->name, widthMM, heightMM);
monitor->x11.output = sr->outputs[i];
monitor->x11.crtc = oi->crtc;

2
glfw/x11_platform.h vendored
View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 X11 - www.glfw.org
// GLFW 3.4 X11 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>

96
glfw/x11_window.c vendored
View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 X11 - www.glfw.org
// GLFW 3.4 X11 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
@@ -31,6 +31,7 @@
#include "internal.h"
#include "backend_utils.h"
#include "linux_notify.h"
#include "../kitty/monotonic.h"
#include <X11/cursorfont.h>
#include <X11/Xmd.h>
@@ -51,6 +52,10 @@
#define Button6 6
#define Button7 7
// Motif WM hints flags
#define MWM_HINTS_DECORATIONS 2
#define MWM_DECOR_ALL 1
#define _GLFW_XDND_VERSION 5
@@ -61,8 +66,8 @@
static unsigned _glfwDispatchX11Events(void);
static void
handleEvents(double timeout) {
EVDBG("starting handleEvents(%.2f)", timeout);
handleEvents(monotonic_t timeout) {
EVDBG("starting handleEvents(%.2f)", monotonic_t_to_s_double(timeout));
int display_read_ok = pollForEvents(&_glfw.x11.eventLoopData, timeout);
EVDBG("display_read_ok: %d", display_read_ok);
if (display_read_ok) {
@@ -77,9 +82,9 @@ handleEvents(double timeout) {
}
static bool
waitForX11Event(double timeout) {
// returns true iff there is X11 data waiting to be read, does not run watches and timers
double end_time = glfwGetTime() + timeout;
waitForX11Event(monotonic_t timeout) {
// returns true if there is X11 data waiting to be read, does not run watches and timers
monotonic_t end_time = glfwGetTime() + timeout;
while(true) {
if (timeout >= 0) {
const int result = pollWithTimeout(_glfw.x11.eventLoopData.fds, 1, timeout);
@@ -109,7 +114,7 @@ static bool waitForVisibilityNotify(_GLFWwindow* window)
VisibilityNotify,
&dummy))
{
if (!waitForX11Event(0.1))
if (!waitForX11Event(ms_to_monotonic_t(100ll)))
return false;
}
@@ -508,8 +513,8 @@ static bool createNativeWindow(_GLFWwindow* window,
if (wndconfig->scaleToMonitor)
{
width *= _glfw.x11.contentScaleX;
height *= _glfw.x11.contentScaleY;
width *= (int)_glfw.x11.contentScaleX;
height *= (int)_glfw.x11.contentScaleY;
}
// Create a colormap based on the visual used by the current context
@@ -880,7 +885,7 @@ static const char* getSelectionString(Atom selection)
Atom actualType;
int actualFormat;
unsigned long itemCount, bytesAfter;
double start = glfwGetTime();
monotonic_t start = glfwGetTime();
XEvent notification, dummy;
XConvertSelection(_glfw.x11.display,
@@ -895,10 +900,10 @@ static const char* getSelectionString(Atom selection)
SelectionNotify,
&notification))
{
double time = glfwGetTime();
if (time - start > 2)
monotonic_t time = glfwGetTime();
if (time - start > s_to_monotonic_t(2ll))
return "";
waitForX11Event(2.0 - (time - start));
waitForX11Event(s_to_monotonic_t(2ll) - (time - start));
}
if (notification.xselection.property == None)
@@ -935,10 +940,10 @@ static const char* getSelectionString(Atom selection)
isSelPropNewValueNotify,
(XPointer) &notification))
{
double time = glfwGetTime();
if (time - start > 2)
monotonic_t time = glfwGetTime();
if (time - start > s_to_monotonic_t(2ll))
return "";
waitForX11Event(2.0 - (time - start));
waitForX11Event(s_to_monotonic_t(2ll) - (time - start));
}
XFree(data);
@@ -2066,7 +2071,7 @@ void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window,
isFrameExtentsEvent,
(XPointer) window))
{
if (!waitForX11Event(0.5))
if (!waitForX11Event(ms_to_monotonic_t(500ll)))
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"X11: The window manager has a broken _NET_REQUEST_FRAME_EXTENTS implementation; please report this issue");
@@ -2103,9 +2108,9 @@ void _glfwPlatformGetWindowContentScale(_GLFWwindow* window UNUSED,
*yscale = _glfw.x11.contentScaleY;
}
double _glfwPlatformGetDoubleClickInterval(_GLFWwindow* window UNUSED)
monotonic_t _glfwPlatformGetDoubleClickInterval(_GLFWwindow* window UNUSED)
{
return 0.5;
return ms_to_monotonic_t(500ll);
}
void _glfwPlatformIconifyWindow(_GLFWwindow* window)
@@ -2350,33 +2355,24 @@ void _glfwPlatformSetWindowResizable(_GLFWwindow* window, bool enabled UNUSED)
void _glfwPlatformSetWindowDecorated(_GLFWwindow* window, bool enabled)
{
if (enabled)
struct
{
XDeleteProperty(_glfw.x11.display,
window->x11.handle,
_glfw.x11.MOTIF_WM_HINTS);
}
else
{
struct
{
unsigned long flags;
unsigned long functions;
unsigned long decorations;
long input_mode;
unsigned long status;
} hints;
unsigned long flags;
unsigned long functions;
unsigned long decorations;
long input_mode;
unsigned long status;
} hints = {0};
hints.flags = 2; // Set decorations
hints.decorations = 0; // No decorations
hints.flags = MWM_HINTS_DECORATIONS;
hints.decorations = enabled ? MWM_DECOR_ALL : 0;
XChangeProperty(_glfw.x11.display, window->x11.handle,
_glfw.x11.MOTIF_WM_HINTS,
_glfw.x11.MOTIF_WM_HINTS, 32,
PropModeReplace,
(unsigned char*) &hints,
sizeof(hints) / sizeof(long));
}
XChangeProperty(_glfw.x11.display, window->x11.handle,
_glfw.x11.MOTIF_WM_HINTS,
_glfw.x11.MOTIF_WM_HINTS, 32,
PropModeReplace,
(unsigned char*) &hints,
sizeof(hints) / sizeof(long));
}
void _glfwPlatformSetWindowFloating(_GLFWwindow* window, bool enabled)
@@ -2512,7 +2508,7 @@ _glfwDispatchX11Events(void) {
}
XFlush(_glfw.x11.display);
// XFlush can cause events to be queued, we dont use QueuedAfterFlush here
// XFlush can cause events to be queued, we don't use QueuedAfterFlush here
// as something might have inserted events into the queue, but we want to guarantee
// a flush.
dispatched += dispatch_x11_queued_events(XEventsQueued(_glfw.x11.display, QueuedAlready));
@@ -2527,11 +2523,11 @@ void _glfwPlatformPollEvents(void)
void _glfwPlatformWaitEvents(void)
{
double timeout = _glfwDispatchX11Events() ? 0 : -1;
monotonic_t timeout = _glfwDispatchX11Events() ? 0 : -1;
handleEvents(timeout);
}
void _glfwPlatformWaitEventsTimeout(double timeout)
void _glfwPlatformWaitEventsTimeout(monotonic_t timeout)
{
if (_glfwDispatchX11Events()) timeout = 0;
handleEvents(timeout);
@@ -2585,13 +2581,13 @@ void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode)
XFlush(_glfw.x11.display);
}
const char* _glfwPlatformGetScancodeName(int scancode)
const char* _glfwPlatformGetNativeKeyName(int native_key)
{
return glfw_xkb_keysym_name(scancode);
return glfw_xkb_keysym_name(native_key);
}
int _glfwPlatformGetKeyScancode(int key)
int _glfwPlatformGetNativeKeyForKey(int key)
{
return glfw_xkb_sym_for_key(key);
}
@@ -2870,7 +2866,7 @@ GLFWAPI Window glfwGetX11Window(GLFWwindow* handle)
return window->x11.handle;
}
GLFWAPI int glfwGetXKBScancode(const char* keyName, bool caseSensitive) {
GLFWAPI int glfwGetNativeKeyForName(const char* keyName, bool caseSensitive) {
return glfw_xkb_keysym_from_name(keyName, caseSensitive);
}

239
glfw/xkb_glfw.c vendored
View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 XKB - www.glfw.org
// GLFW 3.4 XKB - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2018 Kovid Goyal <kovid@kovidgoyal.net>
//
@@ -37,19 +37,130 @@ START_ALLOW_CASE_RANGE
#define map_key(key) \
switch(key) { \
S(space, SPACE); \
S(exclam, EXCLAM); \
S(quotedbl, DOUBLE_QUOTE); \
S(numbersign, NUMBER_SIGN); \
S(dollar, DOLLAR); \
S(ampersand, AMPERSAND); \
S(apostrophe, APOSTROPHE); \
S(parenleft, PARENTHESIS_LEFT); \
S(parenright, PARENTHESIS_RIGHT); \
S(plus, PLUS); \
S(comma, COMMA); \
S(minus, MINUS); \
S(period, PERIOD); \
S(slash, SLASH); \
R(0, 9, 0, 9); \
S(colon, COLON); \
S(semicolon, SEMICOLON); \
S(less, LESS); \
S(equal, EQUAL); \
S(greater, GREATER); \
S(at, AT); \
D(A, Z, A, Z); \
S(bracketleft, LEFT_BRACKET); \
S(backslash, BACKSLASH); \
S(bracketright, RIGHT_BRACKET); \
S(plus, PLUS); \
S(underscore, UNDERSCORE); \
S(grave, GRAVE_ACCENT); \
R(a, z, A, Z); \
S(paragraph, PARAGRAPH); \
S(masculine, MASCULINE); \
S(agrave, A_GRAVE); \
F(Agrave, A_GRAVE); \
S(adiaeresis, A_DIAERESIS); \
F(Adiaeresis, A_DIAERESIS); \
S(aring, A_RING); \
F(Aring, A_RING); \
S(ae, AE); \
F(AE, AE); \
S(ccedilla, C_CEDILLA); \
F(Ccedilla, C_CEDILLA); \
S(egrave, E_GRAVE); \
F(Egrave, E_GRAVE); \
S(aacute, E_ACUTE); \
F(Eacute, E_ACUTE); \
S(igrave, I_GRAVE); \
F(Igrave, I_GRAVE); \
S(ntilde, N_TILDE); \
F(Ntilde, N_TILDE); \
S(ograve, O_GRAVE); \
F(Ograve, O_GRAVE); \
S(odiaeresis, O_DIAERESIS); \
F(Odiaeresis, O_DIAERESIS); \
S(oslash, O_SLASH); \
F(Oslash, O_SLASH); \
S(ugrave, U_GRAVE); \
F(Ugrave, U_GRAVE); \
S(udiaeresis, U_DIAERESIS); \
F(Udiaeresis, U_DIAERESIS); \
S(ssharp, S_SHARP); \
S(Cyrillic_a, CYRILLIC_A); \
F(Cyrillic_A, CYRILLIC_A); \
S(Cyrillic_be, CYRILLIC_BE); \
F(Cyrillic_BE, CYRILLIC_BE); \
S(Cyrillic_ve, CYRILLIC_VE); \
F(Cyrillic_VE, CYRILLIC_VE); \
S(Cyrillic_ghe, CYRILLIC_GHE); \
F(Cyrillic_GHE, CYRILLIC_GHE); \
S(Cyrillic_de, CYRILLIC_DE); \
F(Cyrillic_DE, CYRILLIC_DE); \
S(Cyrillic_ie, CYRILLIC_IE); \
F(Cyrillic_IE, CYRILLIC_IE); \
S(Cyrillic_zhe, CYRILLIC_ZHE); \
F(Cyrillic_ZHE, CYRILLIC_ZHE); \
S(Cyrillic_ze, CYRILLIC_ZE); \
F(Cyrillic_ZE, CYRILLIC_ZE); \
S(Cyrillic_i, CYRILLIC_I); \
F(Cyrillic_I, CYRILLIC_I); \
S(Cyrillic_shorti, CYRILLIC_SHORT_I); \
F(Cyrillic_SHORTI, CYRILLIC_SHORT_I); \
S(Cyrillic_ka, CYRILLIC_KA); \
F(Cyrillic_KA, CYRILLIC_KA); \
S(Cyrillic_el, CYRILLIC_EL); \
F(Cyrillic_EL, CYRILLIC_EL); \
S(Cyrillic_em, CYRILLIC_EM); \
F(Cyrillic_EM, CYRILLIC_EM); \
S(Cyrillic_en, CYRILLIC_EN); \
F(Cyrillic_EN, CYRILLIC_EN); \
S(Cyrillic_o, CYRILLIC_O); \
F(Cyrillic_O, CYRILLIC_O); \
S(Cyrillic_pe, CYRILLIC_PE); \
F(Cyrillic_PE, CYRILLIC_PE); \
S(Cyrillic_er, CYRILLIC_ER); \
F(Cyrillic_ER, CYRILLIC_ER); \
S(Cyrillic_es, CYRILLIC_ES); \
F(Cyrillic_ES, CYRILLIC_ES); \
S(Cyrillic_te, CYRILLIC_TE); \
F(Cyrillic_TE, CYRILLIC_TE); \
S(Cyrillic_u, CYRILLIC_U); \
F(Cyrillic_U, CYRILLIC_U); \
S(Cyrillic_ef, CYRILLIC_EF); \
F(Cyrillic_EF, CYRILLIC_EF); \
S(Cyrillic_ha, CYRILLIC_HA); \
F(Cyrillic_HA, CYRILLIC_HA); \
S(Cyrillic_tse, CYRILLIC_TSE); \
F(Cyrillic_TSE, CYRILLIC_TSE); \
S(Cyrillic_che, CYRILLIC_CHE); \
F(Cyrillic_CHE, CYRILLIC_CHE); \
S(Cyrillic_sha, CYRILLIC_SHA); \
F(Cyrillic_SHA, CYRILLIC_SHA); \
S(Cyrillic_shcha, CYRILLIC_SHCHA); \
F(Cyrillic_SHCHA, CYRILLIC_SHCHA); \
S(Cyrillic_hardsign, CYRILLIC_HARD_SIGN); \
F(Cyrillic_HARDSIGN, CYRILLIC_HARD_SIGN); \
S(Cyrillic_yeru, CYRILLIC_YERU); \
F(Cyrillic_YERU, CYRILLIC_YERU); \
S(Cyrillic_softsign, CYRILLIC_SOFT_SIGN); \
F(Cyrillic_SOFTSIGN, CYRILLIC_SOFT_SIGN); \
S(Cyrillic_e, CYRILLIC_E); \
F(Cyrillic_E, CYRILLIC_E); \
S(Cyrillic_yu, CYRILLIC_YU); \
F(Cyrillic_YU, CYRILLIC_YU); \
S(Cyrillic_ya, CYRILLIC_YA); \
F(Cyrillic_YA, CYRILLIC_YA); \
S(Cyrillic_io, CYRILLIC_IO); \
F(Cyrillic_IO, CYRILLIC_IO); \
S(Escape, ESCAPE); \
S(Return, ENTER); \
S(Tab, TAB); \
@@ -91,9 +202,6 @@ START_ALLOW_CASE_RANGE
S(Alt_R, RIGHT_ALT); \
S(Super_R, RIGHT_SUPER); \
S(Menu, MENU); \
R(0, 9, 0, 9); \
R(a, z, A, Z); \
D(A, Z, A, Z); \
R(F1, F25, F1, F25); \
R(KP_0, KP_9, KP_0, KP_9); \
@@ -329,24 +437,22 @@ glfw_xkb_update_modifiers(_GLFWXKBData *xkb, xkb_mod_mask_t depressed, xkb_mod_m
}
bool
glfw_xkb_should_repeat(_GLFWXKBData *xkb, xkb_keycode_t scancode) {
glfw_xkb_should_repeat(_GLFWXKBData *xkb, xkb_keycode_t keycode) {
#ifdef _GLFW_WAYLAND
scancode += 8;
keycode += 8;
#endif
return xkb_keymap_key_repeats(xkb->keymap, scancode);
return xkb_keymap_key_repeats(xkb->keymap, keycode);
}
static KeyEvent key_event = {0};
static inline xkb_keysym_t
compose_symbol(struct xkb_compose_state *composeState, xkb_keysym_t sym, int *compose_completed) {
compose_symbol(struct xkb_compose_state *composeState, xkb_keysym_t sym, int *compose_completed, char *key_text, int n) {
*compose_completed = 0;
if (sym == XKB_KEY_NoSymbol || !composeState) return sym;
if (xkb_compose_state_feed(composeState, sym) != XKB_COMPOSE_FEED_ACCEPTED) return sym;
switch (xkb_compose_state_get_status(composeState)) {
case XKB_COMPOSE_COMPOSED:
xkb_compose_state_get_utf8(composeState, key_event.text, sizeof(key_event.text));
xkb_compose_state_get_utf8(composeState, key_text, n);
*compose_completed = 1;
return xkb_compose_state_get_one_sym(composeState);
case XKB_COMPOSE_COMPOSING:
@@ -426,66 +532,74 @@ glfw_xkb_update_ime_state(_GLFWwindow *w, _GLFWXKBData *xkb, int which, int a, i
}
void
glfw_xkb_key_from_ime(KeyEvent *ev, bool handled_by_ime, bool failed) {
glfw_xkb_key_from_ime(_GLFWIBUSKeyEvent *ev, bool handled_by_ime, bool failed) {
_GLFWwindow *window = _glfwWindowForId(ev->window_id);
if (failed && window && window->callbacks.keyboard) {
// notify application to remove any existing pre-edit text
window->callbacks.keyboard((GLFWwindow*) window, GLFW_KEY_UNKNOWN, 0, GLFW_PRESS, 0, "", 1);
GLFWkeyevent fake_ev;
_glfwInitializeKeyEvent(&fake_ev, GLFW_KEY_UNKNOWN, 0, GLFW_PRESS, 0);
fake_ev.ime_state = 1;
window->callbacks.keyboard((GLFWwindow*) window, &fake_ev);
}
static xkb_keycode_t last_handled_press_keycode = 0;
// We filter out release events that correspond to the last press event
// handled by the IME system. This wont fix the case of multiple key
// handled by the IME system. This won't fix the case of multiple key
// presses before a release, but is better than nothing. For that case
// you'd need to implement a ring buffer to store pending key presses.
xkb_keycode_t prev_handled_press = last_handled_press_keycode;
last_handled_press_keycode = 0;
bool is_release = ev->action == GLFW_RELEASE;
debug("From IBUS: scancode: 0x%x name: %s is_release: %d\n", ev->keycode, glfw_xkb_keysym_name(ev->keysym), is_release);
if (window && !handled_by_ime && !(is_release && ev->keycode == prev_handled_press)) {
bool is_release = ev->glfw_ev.action == GLFW_RELEASE;
debug("From IBUS: native_key: 0x%x name: %s is_release: %d\n", ev->glfw_ev.native_key, glfw_xkb_keysym_name(ev->glfw_ev.key), is_release);
if (window && !handled_by_ime && !(is_release && ev->glfw_ev.native_key == (int) prev_handled_press)) {
debug("↳ to application: glfw_keycode: 0x%x (%s) keysym: 0x%x (%s) action: %s %s text: %s\n",
ev->glfw_keycode, _glfwGetKeyName(ev->glfw_keycode), ev->keysym, glfw_xkb_keysym_name(ev->keysym),
(ev->action == GLFW_RELEASE ? "RELEASE" : (ev->action == GLFW_PRESS ? "PRESS" : "REPEAT")),
format_mods(ev->glfw_modifiers), ev->text
ev->glfw_ev.native_key, _glfwGetKeyName(ev->glfw_ev.native_key), ev->glfw_ev.key, glfw_xkb_keysym_name(ev->glfw_ev.key),
(ev->glfw_ev.action == GLFW_RELEASE ? "RELEASE" : (ev->glfw_ev.action == GLFW_PRESS ? "PRESS" : "REPEAT")),
format_mods(ev->glfw_ev.mods), ev->glfw_ev.text
);
_glfwInputKeyboard(window, ev->glfw_keycode, ev->keysym, ev->action, ev->glfw_modifiers, ev->text, 0);
ev->glfw_ev.ime_state = 0;
_glfwInputKeyboard(window, &ev->glfw_ev);
} else debug("↳ discarded\n");
if (!is_release && handled_by_ime) last_handled_press_keycode = ev->keycode;
if (!is_release && handled_by_ime)
last_handled_press_keycode = ev->glfw_ev.native_key;
}
void
glfw_xkb_handle_key_event(_GLFWwindow *window, _GLFWXKBData *xkb, xkb_keycode_t scancode, int action) {
glfw_xkb_handle_key_event(_GLFWwindow *window, _GLFWXKBData *xkb, xkb_keycode_t xkb_keycode, int action) {
static char key_text[64] = {0};
const xkb_keysym_t *syms, *clean_syms, *default_syms;
xkb_keysym_t glfw_sym;
xkb_keycode_t code_for_sym = scancode;
key_event.ibus_keycode = scancode;
xkb_keysym_t xkb_sym;
xkb_keycode_t code_for_sym = xkb_keycode, ibus_keycode = xkb_keycode;
GLFWkeyevent glfw_ev;
_glfwInitializeKeyEvent(&glfw_ev, GLFW_KEY_UNKNOWN, 0, GLFW_PRESS, 0); // init with default values
#ifdef _GLFW_WAYLAND
code_for_sym += 8;
#else
key_event.ibus_keycode -= 8;
ibus_keycode -= 8;
#endif
debug("%s scancode: 0x%x ", action == GLFW_RELEASE ? "Release" : "Press", scancode);
debug("%s xkb_keycode: 0x%x ", action == GLFW_RELEASE ? "Release" : "Press", xkb_keycode);
XKBStateGroup *sg = &xkb->states;
int num_syms = xkb_state_key_get_syms(sg->state, code_for_sym, &syms);
int num_clean_syms = xkb_state_key_get_syms(sg->clean_state, code_for_sym, &clean_syms);
key_event.text[0] = 0;
key_text[0] = 0;
// According to the documentation of xkb_compose_state_feed it does not
// support multi-sym events, so we ignore them
if (num_syms != 1 || num_clean_syms != 1) {
debug("num_syms: %d num_clean_syms: %d ignoring event\n", num_syms, num_clean_syms);
return;
}
glfw_sym = clean_syms[0];
xkb_sym = clean_syms[0];
debug("clean_sym: %s ", glfw_xkb_keysym_name(clean_syms[0]));
if (action == GLFW_PRESS || action == GLFW_REPEAT) {
const char *text_type = "composed_text";
int compose_completed;
glfw_sym = compose_symbol(sg->composeState, syms[0], &compose_completed);
if (glfw_sym == XKB_KEY_NoSymbol && !compose_completed) {
xkb_sym = compose_symbol(sg->composeState, syms[0], &compose_completed, key_text, sizeof(key_text));
if (xkb_sym == XKB_KEY_NoSymbol && !compose_completed) {
debug("compose not complete, ignoring.\n");
return;
}
debug("composed_sym: %s ", glfw_xkb_keysym_name(glfw_sym));
if (glfw_sym == syms[0]) { // composed sym is the same as non-composed sym
debug("composed_sym: %s ", glfw_xkb_keysym_name(xkb_sym));
if (xkb_sym == syms[0]) { // composed sym is the same as non-composed sym
// Only use the clean_sym if no mods other than the mods we report
// are active (for example if ISO_Shift_Level_* mods are active
// they are not reported by GLFW so the key should be the shifted
@@ -493,37 +607,58 @@ glfw_xkb_handle_key_event(_GLFWwindow *window, _GLFWXKBData *xkb, xkb_keycode_t
xkb_mod_mask_t consumed_unknown_mods = xkb_state_key_get_consumed_mods(sg->state, code_for_sym) & sg->activeUnknownModifiers;
if (sg->activeUnknownModifiers) debug("%s", format_xkb_mods(xkb, "active_unknown_mods", sg->activeUnknownModifiers));
if (consumed_unknown_mods) { debug("%s", format_xkb_mods(xkb, "consumed_unknown_mods", consumed_unknown_mods)); }
else glfw_sym = clean_syms[0];
else xkb_sym = clean_syms[0];
// xkb returns text even if alt and/or super are pressed
if ( ((GLFW_MOD_CONTROL | GLFW_MOD_ALT | GLFW_MOD_SUPER) & sg->modifiers) == 0) xkb_state_key_get_utf8(sg->state, code_for_sym, key_event.text, sizeof(key_event.text));
if ( ((GLFW_MOD_CONTROL | GLFW_MOD_ALT | GLFW_MOD_SUPER) & sg->modifiers) == 0) {
xkb_state_key_get_utf8(sg->state, code_for_sym, key_text, sizeof(key_text));
}
text_type = "text";
}
if ((1 <= key_event.text[0] && key_event.text[0] <= 31) || key_event.text[0] == 127) key_event.text[0] = 0; // don't send text for ascii control codes
if (key_event.text[0]) { debug("%s: %s ", text_type, key_event.text); }
if ((1 <= key_text[0] && key_text[0] <= 31) || key_text[0] == 127) {
key_text[0] = 0; // don't send text for ascii control codes
}
if (key_text[0]) { debug("%s: %s ", text_type, key_text); }
}
int glfw_keycode = glfw_key_for_sym(glfw_sym);
int glfw_sym = glfw_key_for_sym(xkb_sym);
bool is_fallback = false;
if (glfw_keycode == GLFW_KEY_UNKNOWN && !key_event.text[0]) {
if (glfw_sym == GLFW_KEY_UNKNOWN && !key_text[0]) {
int num_default_syms = xkb_state_key_get_syms(sg->default_state, code_for_sym, &default_syms);
if (num_default_syms > 0) {
glfw_sym = default_syms[0];
glfw_keycode = glfw_key_for_sym(glfw_sym);
xkb_sym = default_syms[0];
glfw_sym = glfw_key_for_sym(xkb_sym);
is_fallback = true;
}
}
debug(
"%s%s: %d (%s) xkb_key: %d (%s)\n",
format_mods(sg->modifiers),
is_fallback ? "glfw_fallback_key" : "glfw_key", glfw_keycode, _glfwGetKeyName(glfw_keycode),
glfw_sym, glfw_xkb_keysym_name(glfw_sym)
is_fallback ? "glfw_fallback_key" : "glfw_key", glfw_sym, _glfwGetKeyName(glfw_sym),
xkb_sym, glfw_xkb_keysym_name(xkb_sym)
);
key_event.action = action; key_event.glfw_modifiers = sg->modifiers;
key_event.keycode = scancode; key_event.keysym = glfw_sym;
key_event.window_id = window->id; key_event.glfw_keycode = glfw_keycode;
key_event.ibus_sym = syms[0];
if (ibus_process_key(&key_event, &xkb->ibus)) {
debug("↳ to IBUS: keycode: 0x%x keysym: 0x%x (%s) %s\n", key_event.ibus_keycode, key_event.ibus_sym, glfw_xkb_keysym_name(key_event.ibus_sym), format_mods(key_event.glfw_modifiers));
// NOTE: On linux, the reported native key identifier is the XKB keysym value.
// Do not confuse `native_key` with `xkb_keycode` (the native keycode reported for the
// glfw event VS the X internal code for a key).
//
// We use the XKB keysym instead of the X keycode to be able to go back-and-forth between
// the GLFW keysym and the XKB keysym when needed, which is not possible using the X keycode,
// because of the lost information when resolving the keycode to the keysym, like consumed
// mods.
glfw_ev.native_key = xkb_sym;
glfw_ev.action = action;
glfw_ev.key = glfw_sym;
glfw_ev.mods = sg->modifiers;
glfw_ev.text = key_text;
_GLFWIBUSKeyEvent ibus_ev;
ibus_ev.glfw_ev = glfw_ev;
ibus_ev.ibus_keycode = ibus_keycode;
ibus_ev.window_id = window->id;
ibus_ev.ibus_keysym = syms[0];
if (ibus_process_key(&ibus_ev, &xkb->ibus)) {
debug("↳ to IBUS: keycode: 0x%x keysym: 0x%x (%s) %s\n", ibus_ev.ibus_keycode, ibus_ev.ibus_keysym, glfw_xkb_keysym_name(ibus_ev.ibus_keysym), format_mods(ibus_ev.glfw_ev.mods));
} else {
_glfwInputKeyboard(window, glfw_keycode, glfw_sym, action, sg->modifiers, key_event.text, 0);
_glfwInputKeyboard(window, &glfw_ev);
}
}

12
glfw/xkb_glfw.h vendored
View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 XKB - www.glfw.org
// GLFW 3.4 XKB - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2018 Kovid Goyal <kovid@kovidgoyal.net>
//
@@ -67,8 +67,8 @@ typedef struct {
#ifdef _GLFW_X11
int32_t keyboard_device_id;
bool available;
bool detectable;
bool available;
bool detectable;
int majorOpcode;
int eventBase;
int errorBase;
@@ -87,10 +87,10 @@ void glfw_xkb_release(_GLFWXKBData *xkb);
bool glfw_xkb_create_context(_GLFWXKBData *xkb);
bool glfw_xkb_compile_keymap(_GLFWXKBData *xkb, const char *map_str);
void glfw_xkb_update_modifiers(_GLFWXKBData *xkb, xkb_mod_mask_t depressed, xkb_mod_mask_t latched, xkb_mod_mask_t locked, xkb_layout_index_t base_group, xkb_layout_index_t latched_group, xkb_layout_index_t locked_group);
bool glfw_xkb_should_repeat(_GLFWXKBData *xkb, xkb_keycode_t scancode);
bool glfw_xkb_should_repeat(_GLFWXKBData *xkb, xkb_keycode_t keycode);
const char* glfw_xkb_keysym_name(xkb_keysym_t sym);
xkb_keysym_t glfw_xkb_sym_for_key(int key);
void glfw_xkb_handle_key_event(_GLFWwindow *window, _GLFWXKBData *xkb, xkb_keycode_t scancode, int action);
void glfw_xkb_handle_key_event(_GLFWwindow *window, _GLFWXKBData *xkb, xkb_keycode_t keycode, int action);
int glfw_xkb_keysym_from_name(const char *name, bool case_sensitive);
void glfw_xkb_update_ime_state(_GLFWwindow *w, _GLFWXKBData *xkb, int which, int a, int b, int c, int d);
void glfw_xkb_key_from_ime(KeyEvent *ev, bool handled_by_ime, bool failed);
void glfw_xkb_key_from_ime(_GLFWIBUSKeyEvent *ev, bool handled_by_ime, bool failed);

View File

@@ -2,14 +2,17 @@
# vim:fileencoding=utf-8
# License: GPL v3 Copyright: 2018, Kovid Goyal <kovid at kovidgoyal.net>
import atexit
import os
import signal
import subprocess
import sys
import tempfile
import warnings
from collections import defaultdict
from contextlib import suppress
from functools import partial
from gettext import gettext as _
from contextlib import suppress
from kitty.cli import CONFIG_HELP, parse_args
from kitty.constants import appname
@@ -506,7 +509,7 @@ def showwarning(message, category, filename, lineno, file=None, line=None):
showwarning.warnings = []
help_text = 'Show a side-by-side diff of the specified files/directories'
help_text = 'Show a side-by-side diff of the specified files/directories. You can also use ssh:hostname:remote-file-path to diff remote files.'
usage = 'file_or_directory_left file_or_directory_right'
@@ -516,6 +519,20 @@ def terminate_processes(processes):
os.kill(pid, signal.SIGKILL)
def get_remote_file(path):
if path.startswith('ssh:'):
parts = path.split(':', 2)
if len(parts) == 3:
hostname, rpath = parts[1:]
with tempfile.NamedTemporaryFile(suffix='-' + os.path.basename(rpath), prefix='remote:', delete=False) as tf:
atexit.register(os.remove, tf.name)
p = subprocess.Popen(['ssh', hostname, 'cat', rpath], stdout=tf)
if p.wait() != 0:
raise SystemExit(p.returncode)
return tf.name
return path
def main(args):
warnings.showwarning = showwarning
args, items = parse_args(args[1:], OPTIONS, usage, help_text, 'kitty +kitten diff')
@@ -528,6 +545,7 @@ def main(args):
opts = init_config(args)
set_diff_command(opts.diff_cmd)
lines_for_path.replace_tab_by = opts.replace_tab_by
left, right = map(get_remote_file, (left, right))
for f in left, right:
if not os.path.exists(f):
raise SystemExit('{} does not exist'.format(f))

View File

@@ -20,35 +20,41 @@ from ..tui.loop import Loop
from ..tui.operations import faint, styled
URL_PREFIXES = 'http https file ftp'.split()
HINT_ALPHABET = string.digits + string.ascii_lowercase
DEFAULT_HINT_ALPHABET = string.digits + string.ascii_lowercase
screen_size = screen_size_function()
class Mark:
__slots__ = ('index', 'start', 'end', 'text')
__slots__ = ('index', 'start', 'end', 'text', 'groupdict')
def __init__(self, index, start, end, text):
def __init__(self, index, start, end, text, groupdict):
self.index, self.start, self.end = index, start, end
self.text = text
self.groupdict = groupdict
@lru_cache(maxsize=2048)
def encode_hint(num):
def encode_hint(num, alphabet):
res = ''
d = len(HINT_ALPHABET)
d = len(alphabet)
while not res or num > 0:
num, i = divmod(num, d)
res = HINT_ALPHABET[i] + res
res = alphabet[i] + res
return res
def decode_hint(x):
return int(x, 36)
def decode_hint(x, alphabet=DEFAULT_HINT_ALPHABET):
base = len(alphabet)
index_map = {c: i for i, c in enumerate(alphabet)}
i = 0
for char in x:
i = i * base + index_map[char]
return i
def highlight_mark(m, text, current_input):
hint = encode_hint(m.index)
def highlight_mark(m, text, current_input, alphabet):
hint = encode_hint(m.index, alphabet)
if current_input and not hint.startswith(current_input):
return faint(text)
hint = hint[len(current_input):] or ' '
@@ -63,11 +69,11 @@ def highlight_mark(m, text, current_input):
)
def render(text, current_input, all_marks, ignore_mark_indices):
def render(text, current_input, all_marks, ignore_mark_indices, alphabet):
for mark in reversed(all_marks):
if mark.index in ignore_mark_indices:
continue
mtext = highlight_mark(mark, text[mark.start:mark.end], current_input)
mtext = highlight_mark(mark, text[mark.start:mark.end], current_input, alphabet)
text = text[:mark.start] + mtext + text[mark.end:]
text = text.replace('\0', '')
@@ -79,6 +85,7 @@ class Hints(Handler):
def __init__(self, text, all_marks, index_map, args):
self.text, self.index_map = text, index_map
self.alphabet = args.alphabet or DEFAULT_HINT_ALPHABET
self.all_marks = all_marks
self.ignore_mark_indices = set()
self.args = args
@@ -88,6 +95,14 @@ class Hints(Handler):
self.chosen = []
self.reset()
@property
def text_matches(self):
return [m.text + self.match_suffix for m in self.chosen]
@property
def groupdicts(self):
return [m.groupdict for m in self.chosen]
def get_match_suffix(self, args):
if args.add_trailing_space == 'always':
return ' '
@@ -111,16 +126,16 @@ class Hints(Handler):
def on_text(self, text, in_bracketed_paste):
changed = False
for c in text:
if c in HINT_ALPHABET:
if c in self.alphabet:
self.current_input += c
changed = True
if changed:
matches = [
m for idx, m in self.index_map.items()
if encode_hint(idx).startswith(self.current_input)
if encode_hint(idx, self.alphabet).startswith(self.current_input)
]
if len(matches) == 1:
self.chosen.append(matches[0].text + self.match_suffix)
self.chosen.append(matches[0])
if self.multiple:
self.ignore_mark_indices.add(matches[0].index)
self.reset()
@@ -137,8 +152,8 @@ class Hints(Handler):
self.draw_screen()
elif key_event is enter_key and self.current_input:
try:
idx = decode_hint(self.current_input)
self.chosen.append(self.index_map[idx].text + self.match_suffix)
idx = decode_hint(self.current_input, self.alphabet)
self.chosen.append(self.index_map[idx])
self.ignore_mark_indices.add(idx)
except Exception:
self.current_input = ''
@@ -164,18 +179,19 @@ class Hints(Handler):
def draw_screen(self):
if self.current_text is None:
self.current_text = render(self.text, self.current_input, self.all_marks, self.ignore_mark_indices)
self.current_text = render(self.text, self.current_input, self.all_marks, self.ignore_mark_indices, self.alphabet)
self.cmd.clear_screen()
self.write(self.current_text)
def regex_finditer(pat, minimum_match_length, text):
has_named_groups = bool(pat.groupindex)
for m in pat.finditer(text):
s, e = m.span(pat.groups)
s, e = m.span(0 if has_named_groups else pat.groups)
while e > s + 1 and text[e-1] == '\0':
e -= 1
if e - s >= minimum_match_length:
yield s, e
yield s, e, m.groupdict()
closing_bracket_map = {'(': ')', '[': ']', '{': '}', '<': '>', '*': '*', '"': '"', "'": "'"}
@@ -234,21 +250,23 @@ def quotes(text, s, e):
def mark(pattern, post_processors, text, args):
pat = re.compile(pattern)
for idx, (s, e) in enumerate(regex_finditer(pat, args.minimum_match_length, text)):
for idx, (s, e, groupdict) in enumerate(regex_finditer(pat, args.minimum_match_length, text)):
for func in post_processors:
s, e = func(text, s, e)
mark_text = text[s:e].replace('\n', '').replace('\0', '')
yield Mark(idx, s, e, mark_text)
yield Mark(idx, s, e, mark_text, groupdict)
def run_loop(args, text, all_marks, index_map):
def run_loop(args, text, all_marks, index_map, extra_cli_args=()):
loop = Loop()
handler = Hints(text, all_marks, index_map, args)
loop.loop(handler)
if handler.chosen and loop.return_code == 0:
return {'match': handler.chosen, 'program': args.program,
'multiple_joiner': args.multiple_joiner,
'type': args.type}
return {
'match': handler.text_matches, 'programs': args.program,
'multiple_joiner': args.multiple_joiner, 'customize_processing': args.customize_processing,
'type': args.type, 'groupdicts': handler.groupdicts, 'extra_cli_args': extra_cli_args
}
raise SystemExit(loop.return_code)
@@ -305,11 +323,29 @@ def parse_input(text):
return convert_text(text, cols)
def run(args, text):
def load_custom_processor(customize_processing):
from kitty.constants import config_dir
customize_processing = os.path.expandvars(os.path.expanduser(customize_processing))
if os.path.isabs(customize_processing):
custom_path = customize_processing
else:
custom_path = os.path.join(config_dir, customize_processing)
import runpy
return runpy.run_path(custom_path, run_name='__main__')
def run(args, text, extra_cli_args=()):
try:
pattern, post_processors = functions_for(args)
text = parse_input(text)
all_marks = tuple(mark(pattern, post_processors, text, args))
pattern, post_processors = functions_for(args)
if args.customize_processing:
m = load_custom_processor(args.customize_processing)
if 'mark' in m:
all_marks = tuple(m['mark'](text, args, Mark, extra_cli_args))
else:
all_marks = tuple(mark(pattern, post_processors, text, args))
else:
all_marks = tuple(mark(pattern, post_processors, text, args))
if not all_marks:
input(_('No {} found, press Enter to quit.').format(
'URLs' if args.type == 'url' else 'matches'
@@ -327,16 +363,18 @@ def run(args, text):
input('Press Enter to quit.')
raise SystemExit(1)
return run_loop(args, text, all_marks, index_map)
return run_loop(args, text, all_marks, index_map, extra_cli_args)
# CLI {{{
OPTIONS = r'''
--program
default=default
type=list
What program to use to open matched text. Defaults to the default open program
for the operating system. Use a value of :file:`-` to paste the match into the
for the operating system. Use a value of :file:`-` to paste the match into the
terminal window instead. A value of :file:`@` will copy the match to the clipboard.
A value of :file:`default` will run the default open program. Can be specified
multiple times to run multiple programs.
--type
@@ -348,11 +386,14 @@ The type of text to search for.
--regex
default=(?m)^\s*(.+)\s*$
The regular expression to use when :option:`kitty +kitten hints --type`=regex.
If you specify a group in the regular expression only the group
will be matched. This allow you to match text ignoring a prefix/suffix, as
needed. The default expression matches lines. To match text over
multiple lines you should prefix the regular expression with :code:`(?ms)`,
which turns on MULTILINE and DOTALL modes for the regex engine.
The regular expression is in python syntax. If you specify a numbered group in
the regular expression only the group will be matched. This allow you to match
text ignoring a prefix/suffix, as needed. The default expression matches lines.
To match text over multiple lines you should prefix the regular expression with
:code:`(?ms)`, which turns on MULTILINE and DOTALL modes for the regex engine.
If you specify named groups and a :option:`kitty +kitten hints --program` then
the program will be passed arguments corresponding to each named group of
the form key=value.
--url-prefixes
@@ -362,7 +403,7 @@ Comma separated list of recognized URL prefixes.
--word-characters
Characters to consider as part of a word. In addition, all characters marked as
alpha-numeric in the unicode database will be considered as word characters.
alphanumeric in the unicode database will be considered as word characters.
Defaults to the select_by_word_characters setting from kitty.conf.
@@ -401,6 +442,22 @@ default=1
type=int
The offset (from zero) at which to start hint numbering. Note that only numbers
greater than or equal to zero are respected.
--alphabet
The list of characters to use for hints. The default is to use numbers and lowercase
English alphabets. Specify your preference as a string of characters. Note that
unless you specify the hints offset as zero the first match will be highlighted with
the second character you specify.
--customize-processing
Name of a python file in the kitty config directory which will be imported to provide
custom implementations for pattern finding and performing actions
on selected matches. See https://sw.kovidgoyal.net/kitty/kittens/hints.html
for details. You can also specify absolute paths to load the script from elsewhere.
'''.format(','.join(sorted(URL_PREFIXES))).format
help_text = 'Select text from the screen using the keyboard. Defaults to searching for URLs.'
usage = ''
@@ -427,16 +484,23 @@ def main(args):
print(e.args[0], file=sys.stderr)
input(_('Press Enter to quit'))
return
if items:
if items and not args.customize_processing:
print('Extra command line arguments present: {}'.format(' '.join(items)), file=sys.stderr)
input(_('Press Enter to quit'))
return
return run(args, text)
return run(args, text, items)
def handle_result(args, data, target_window_id, boss):
program = data['program']
matches = tuple(filter(None, data['match']))
if data['customize_processing']:
m = load_custom_processor(data['customize_processing'])
if 'handle_result' in m:
return m['handle_result'](args, data, target_window_id, boss, data['extra_cli_args'])
programs = data['programs'] or ('default',)
matches, groupdicts = [], []
for m, g in zip(data['match'], data['groupdicts']):
if m:
matches.append(m), groupdicts.append(g)
joiner = data['multiple_joiner']
try:
is_int = int(joiner)
@@ -444,6 +508,7 @@ def handle_result(args, data, target_window_id, boss):
is_int = None
text_type = data['type']
@lru_cache()
def joined_text():
if is_int is not None:
try:
@@ -459,20 +524,25 @@ def handle_result(args, data, target_window_id, boss):
q = {'newline': '\n\r', 'space': ' '}.get(joiner, '')
return q.join(matches)
if program == '-':
w = boss.window_id_map.get(target_window_id)
if w is not None:
w.paste(joined_text())
elif program == '@':
set_clipboard_string(joined_text())
else:
cwd = None
w = boss.window_id_map.get(target_window_id)
if w is not None:
cwd = w.cwd_of_child
program = None if program == 'default' else program
for m in matches:
boss.open_url(m, program, cwd=cwd)
for program in programs:
if program == '-':
w = boss.window_id_map.get(target_window_id)
if w is not None:
w.paste(joined_text())
elif program == '@':
set_clipboard_string(joined_text())
else:
cwd = None
w = boss.window_id_map.get(target_window_id)
if w is not None:
cwd = w.cwd_of_child
program = None if program == 'default' else program
for m, groupdict in zip(matches, groupdicts):
if groupdict:
m = []
for k, v in groupdict.items():
m.append('{}={}'.format(k, v or ''))
boss.open_url(m, program, cwd=cwd)
handle_result.type_of_input = 'screen'

View File

@@ -22,7 +22,6 @@ from ..tui.images import (
)
from ..tui.operations import clear_images_on_screen, serialize_gr_command
screen_size = None
OPTIONS = '''\
--align
type=choices
@@ -97,6 +96,21 @@ Do not print out anything to stdout during operation.
'''
screen_size = None
def get_screen_size_function():
global screen_size
if screen_size is None:
screen_size = screen_size_function()
return screen_size
def get_screen_size():
screen_size = get_screen_size_function()
return screen_size()
def options_spec():
if not hasattr(options_spec, 'ans'):
options_spec.ans = OPTIONS.format(
@@ -122,7 +136,7 @@ def calculate_in_cell_x_offset(width, cell_width, align):
def set_cursor(cmd, width, height, align):
ss = screen_size()
ss = get_screen_size()
cw = int(ss.width / ss.cols)
num_of_cells_needed = int(ceil(width / cw))
if num_of_cells_needed > ss.cols:
@@ -143,7 +157,7 @@ def set_cursor(cmd, width, height, align):
def set_cursor_for_place(place, cmd, width, height, align):
x = place.left + 1
ss = screen_size()
ss = get_screen_size()
cw = int(ss.width / ss.cols)
num_of_cells_needed = int(ceil(width / cw))
cmd['X'] = calculate_in_cell_x_offset(width, cw, align)
@@ -189,16 +203,18 @@ def show(outfile, width, height, fmt, transmit_mode='t', align='center', place=N
def process(path, args, is_tempfile):
m = identify(path)
ss = screen_size()
ss = get_screen_size()
available_width = args.place.width * (ss.width / ss.cols) if args.place else ss.width
available_height = args.place.height * (ss.height / ss.rows) if args.place else 10 * m.height
needs_scaling = m.width > available_width or m.height > available_height
needs_scaling = needs_scaling or args.scale_up
file_removed = False
if m.fmt == 'png' and not needs_scaling:
outfile = path
transmit_mode = 't' if is_tempfile else 'f'
fmt = 100
width, height = m.width, m.height
file_removed = transmit_mode == 't'
else:
fmt = 24 if m.mode == 'rgb' else 32
transmit_mode = 't'
@@ -206,6 +222,7 @@ def process(path, args, is_tempfile):
show(outfile, width, height, fmt, transmit_mode, align=args.align, place=args.place)
if not args.place:
print() # ensure cursor is on a new line
return file_removed
def scan(d):
@@ -272,6 +289,7 @@ usage = 'image-file-or-url-or-directory ...'
def process_single_item(item, args, url_pat=None, maybe_dir=True):
is_tempfile = False
file_removed = False
try:
if isinstance(item, bytes):
tf = NamedTemporaryFile(prefix='stdin-image-data-', delete=False)
@@ -287,7 +305,7 @@ def process_single_item(item, args, url_pat=None, maybe_dir=True):
raise SystemExit('Failed to download image at URL: {} with error: {}'.format(item, e))
item = tf.name
is_tempfile = True
process(item, args, is_tempfile)
file_removed = process(item, args, is_tempfile)
elif item.lower().startswith('file://'):
from urllib.parse import urlparse
from urllib.request import url2pathname
@@ -297,20 +315,19 @@ def process_single_item(item, args, url_pat=None, maybe_dir=True):
else:
item = item.path
item = url2pathname(item)
process(item, args, is_tempfile)
file_removed = process(item, args, is_tempfile)
else:
if maybe_dir and os.path.isdir(item):
for (x, mt) in scan(item):
process_single_item(x, args, url_pat=None, maybe_dir=False)
else:
process(item, args, is_tempfile)
file_removed = process(item, args, is_tempfile)
finally:
if is_tempfile:
if is_tempfile and not file_removed:
os.remove(item)
def main(args=sys.argv):
global screen_size
args, items = parse_args(args[1:], options_spec, usage, help_text, '{} +kitten icat'.format(appname))
if args.print_window_size:
@@ -330,7 +347,7 @@ def main(args=sys.argv):
sys.stdin.close()
sys.stdin = open(os.ctermid(), 'r')
screen_size = screen_size_function()
screen_size = get_screen_size_function()
signal.signal(signal.SIGWINCH, lambda signum, frame: setattr(screen_size, 'changed', True))
if screen_size().width == 0:
if args.detect_support:

View File

@@ -4,6 +4,7 @@
import os
import sys
from contextlib import suppress
from kitty.cli import parse_args
@@ -30,9 +31,8 @@ def real_main(args):
def main(args):
try:
real_main(args)
except KeyboardInterrupt:
pass
with suppress(KeyboardInterrupt):
real_main(args)
except Exception:
import traceback
traceback.print_exc()

View File

@@ -76,6 +76,9 @@ def parse_ssh_args(args):
if arg in boolean_ssh_args:
ssh_args.append(arg)
continue
if arg.startswith('-p') and arg[2:].isdigit():
ssh_args.append(arg)
continue
if arg in other_ssh_args:
if i != len(all_args) - 1:
raise SystemExit('Option {} cannot occur in the middle'.format(arg))
@@ -95,7 +98,7 @@ def parse_ssh_args(args):
def quote(x):
# we have to escape unbalanced quotes and other unparseable
# we have to escape unbalanced quotes and other unparsable
# args as they will break the shell script
# But we do not want to quote things like * or 'echo hello'
# See https://github.com/kovidgoyal/kitty/issues/1787

View File

@@ -249,7 +249,8 @@ class ImageManager:
cmd, standard_b64encode(rgba_path.encode(fsenc)))
else:
import zlib
data = open(rgba_path, 'rb').read()
with open(rgba_path, 'rb') as f:
data = f.read()
cmd['S'] = len(data)
data = zlib.compress(data)
cmd['o'] = 'z'

View File

@@ -5,25 +5,27 @@
import os
import string
import subprocess
import sys
from contextlib import suppress
from functools import lru_cache
from gettext import gettext as _
from contextlib import suppress
from kitty.cli import parse_args
from kitty.config import cached_values_for
from kitty.constants import config_dir
from kitty.utils import get_editor
from kitty.fast_data_types import wcswidth
from kitty.fast_data_types import wcswidth, is_emoji_presentation_base
from kitty.key_encoding import (
DOWN, ESCAPE, F1, F2, F3, F4, F12, LEFT, RELEASE, RIGHT, SHIFT, TAB, UP,
enter_key
)
from kitty.utils import get_editor
from ..tui.line_edit import LineEdit
from ..tui.handler import Handler
from ..tui.line_edit import LineEdit
from ..tui.loop import Loop
from ..tui.operations import (
clear_screen, colored, cursor, faint, set_line_wrapping,
set_window_title, sgr, styled
clear_screen, colored, cursor, faint, set_line_wrapping, set_window_title,
sgr, styled
)
HEX, NAME, EMOTICONS, FAVORITES = 'HEX', 'NAME', 'EMOTICONS', 'FAVORITES'
@@ -131,7 +133,8 @@ def decode_hint(x):
class Table:
def __init__(self):
def __init__(self, emoji_variation):
self.emoji_variation = emoji_variation
self.layout_dirty = True
self.last_rows = self.last_cols = -1
self.codepoints = []
@@ -161,7 +164,10 @@ class Table:
self.layout_dirty = False
def safe_chr(codepoint):
return chr(codepoint).encode('utf-8', 'replace').decode('utf-8')
ans = chr(codepoint).encode('utf-8', 'replace').decode('utf-8')
if self.emoji_variation and is_emoji_presentation_base(codepoint):
ans += self.emoji_variation
return ans
if self.mode is NAME:
def as_parts(i, codepoint):
@@ -248,8 +254,13 @@ def is_index(w):
class UnicodeInput(Handler):
def __init__(self, cached_values):
def __init__(self, cached_values, emoji_variation='none'):
self.cached_values = cached_values
self.emoji_variation = ''
if emoji_variation == 'text':
self.emoji_variation = '\ufe0e'
elif emoji_variation == 'graphic':
self.emoji_variation = '\ufe0f'
self.line_edit = LineEdit()
self.recent = list(self.cached_values.get('recent', DEFAULT_SET))
self.current_char = None
@@ -257,9 +268,17 @@ class UnicodeInput(Handler):
self.last_updated_code_point_at = None
self.choice_line = ''
self.mode = globals().get(cached_values.get('mode', 'HEX'), 'HEX')
self.table = Table()
self.table = Table(self.emoji_variation)
self.update_prompt()
@property
def resolved_current_char(self):
ans = self.current_char
if ans:
if self.emoji_variation and is_emoji_presentation_base(ord(ans[0])):
ans += self.emoji_variation
return ans
def update_codepoints(self):
codepoints = None
if self.mode is HEX:
@@ -320,8 +339,10 @@ class UnicodeInput(Handler):
self.choice_line = ''
else:
c, color = self.current_char, 'green'
if self.emoji_variation and is_emoji_presentation_base(ord(c[0])):
c += self.emoji_variation
self.choice_line = _('Chosen:') + ' {} U+{} {}'.format(
colored(c, 'green'), hex(ord(c))[2:], faint(styled(name(c) or '', italic=True)))
colored(c, 'green'), hex(ord(c[0]))[2:], faint(styled(name(c) or '', italic=True)))
self.prompt = self.prompt_template.format(colored(c, color))
def init_terminal_state(self):
@@ -475,17 +496,43 @@ class UnicodeInput(Handler):
self.refresh()
help_text = 'Input a unicode character'
usage = ''
OPTIONS = '''
--emoji-variation
type=choices
default=none
choices=none,graphic,text
Whether to use the textual or the graphical form for emoji. By default the
default form specified in the unicode standard for the symbol is used.
'''.format
def parse_unicode_input_args(args):
return parse_args(args, OPTIONS, usage, help_text, 'kitty +kitten unicode_input')
def main(args):
try:
args, items = parse_unicode_input_args(args[1:])
except SystemExit as e:
if e.code != 0:
print(e.args[0], file=sys.stderr)
input(_('Press Enter to quit'))
return
loop = Loop()
with cached_values_for('unicode-input') as cached_values:
handler = UnicodeInput(cached_values)
handler = UnicodeInput(cached_values, args.emoji_variation)
loop.loop(handler)
if handler.current_char and loop.return_code == 0:
with suppress(Exception):
handler.recent.remove(ord(handler.current_char))
recent = [ord(handler.current_char)] + handler.recent
cached_values['recent'] = recent[:len(DEFAULT_SET)]
return handler.current_char
return handler.resolved_current_char
if loop.return_code != 0:
raise SystemExit(loop.return_code)
@@ -497,10 +544,10 @@ def handle_result(args, current_char, target_window_id, boss):
if __name__ == '__main__':
import sys
if '-h' in sys.argv or '--help' in sys.argv:
print('Choose a unicode character to input into the terminal')
raise SystemExit(0)
ans = main(sys.argv)
if ans:
print(ans)
elif __name__ == '__doc__':
sys.cli_docs['usage'] = usage
sys.cli_docs['options'] = OPTIONS
sys.cli_docs['help_text'] = help_text

File diff suppressed because one or more lines are too long

View File

@@ -23,10 +23,10 @@ from .constants import (
from .fast_data_types import (
ChildMonitor, background_opacity_of, change_background_opacity,
change_os_window_state, create_os_window, current_os_window,
destroy_global_data, get_clipboard_string, global_font_size,
mark_os_window_for_close, os_window_font_size, patch_global_colors,
safe_pipe, set_clipboard_string, set_in_sequence_mode, thread_write,
toggle_fullscreen, toggle_maximized
destroy_global_data, focus_os_window, get_clipboard_string,
global_font_size, mark_os_window_for_close, os_window_font_size,
patch_global_colors, safe_pipe, set_clipboard_string, set_in_sequence_mode,
thread_write, toggle_fullscreen, toggle_maximized
)
from .keys import get_shortcut, shortcut_matches
from .layout import set_layout_options
@@ -58,9 +58,9 @@ def data_for_at(w, arg, add_wrap_markers=False):
if arg == '@selection':
return w.text_for_selection()
if arg == '@ansi':
if arg in ('@ansi', '@ansi_screen_scrollback'):
return as_text(as_ansi=True, add_history=True)
if arg == '@text':
if arg in ('@text', '@screen_scrollback'):
return as_text(add_history=True)
if arg == '@screen':
return as_text()
@@ -121,7 +121,7 @@ class Boss:
talk_fd = getattr(single_instance, 'socket', None)
talk_fd = -1 if talk_fd is None else talk_fd.fileno()
listen_fd = -1
if opts.allow_remote_control and args.listen_on:
if args.listen_on and (opts.allow_remote_control in ('y', 'socket-only')):
listen_fd = listen_on(args.listen_on)
self.child_monitor = ChildMonitor(
self.on_child_death,
@@ -146,9 +146,9 @@ class Boss:
from .fast_data_types import cocoa_set_notification_activated_callback
cocoa_set_notification_activated_callback(self.notification_activated)
def add_os_window(self, startup_session, os_window_id=None, wclass=None, wname=None, opts_for_size=None, startup_id=None):
def add_os_window(self, startup_session=None, os_window_id=None, wclass=None, wname=None, opts_for_size=None, startup_id=None):
if os_window_id is None:
opts_for_size = opts_for_size or startup_session.os_window_size or self.opts
opts_for_size = opts_for_size or getattr(startup_session, 'os_window_size', None) or self.opts
cls = wclass or self.args.cls or appname
with startup_notification_handler(do_notify=startup_id is not None, startup_id=startup_id) as pre_show_callback:
os_window_id = create_os_window(
@@ -235,7 +235,7 @@ class Boss:
if tab:
yield tab
def set_active_window(self, window):
def set_active_window(self, window, switch_os_window_if_needed=False):
for os_window_id, tm in self.os_window_map.items():
for tab in tm:
for w in tab:
@@ -243,6 +243,8 @@ class Boss:
if tab is not self.active_tab:
tm.set_active_tab(tab)
tab.set_active_window(w)
if switch_os_window_if_needed and current_os_window() != os_window_id:
focus_os_window(os_window_id, True)
return os_window_id
def _new_os_window(self, args, cwd_from=None):
@@ -276,9 +278,9 @@ class Boss:
self.child_monitor.add_child(window.id, window.child.pid, window.child.child_fd, window.screen)
self.window_id_map[window.id] = window
def _handle_remote_command(self, cmd, window=None):
def _handle_remote_command(self, cmd, window=None, from_peer=False):
response = None
if self.opts.allow_remote_control or getattr(window, 'allow_remote_control', False):
if self.opts.allow_remote_control == 'y' or from_peer or getattr(window, 'allow_remote_control', False):
try:
response = handle_cmd(self, window, cmd)
except Exception as err:
@@ -287,7 +289,7 @@ class Boss:
if not getattr(err, 'hide_traceback', False):
response['tb'] = traceback.format_exc()
else:
response = {'ok': False, 'error': 'Remote control is disabled. Add allow_remote_control yes to your kitty.conf'}
response = {'ok': False, 'error': 'Remote control is disabled. Add allow_remote_control to your kitty.conf'}
return response
def peer_message_received(self, msg):
@@ -295,7 +297,7 @@ class Boss:
cmd_prefix = '\x1bP@kitty-cmd'
if msg.startswith(cmd_prefix):
cmd = msg[len(cmd_prefix):-2]
response = self._handle_remote_command(cmd)
response = self._handle_remote_command(cmd, from_peer=True)
if response is not None:
response = (cmd_prefix + json.dumps(response) + '\x1b\\').encode('utf-8')
return response
@@ -321,6 +323,16 @@ class Boss:
if window is not None:
window.send_cmd_response(response)
def _cleanup_tab_after_window_removal(self, src_tab):
if len(src_tab) < 1:
tm = src_tab.tab_manager_ref()
if tm is not None:
tm.remove(src_tab)
src_tab.destroy()
if len(tm) == 0:
if not self.shutting_down:
mark_os_window_for_close(src_tab.os_window_id)
def on_child_death(self, window_id):
window = self.window_id_map.pop(window_id, None)
if window is None:
@@ -334,20 +346,22 @@ class Boss:
os_window_id = window.os_window_id
window.destroy()
tm = self.os_window_map.get(os_window_id)
if tm is None:
return
for tab in tm:
if window in tab:
break
else:
return
tab.remove_window(window)
if len(tab) == 0:
tm.remove(tab)
tab.destroy()
if len(tm) == 0:
if not self.shutting_down:
mark_os_window_for_close(os_window_id)
tab = None
if tm is not None:
for q in tm:
if window in q:
tab = q
break
if tab is not None:
tab.remove_window(window)
self._cleanup_tab_after_window_removal(tab)
if window.action_on_removal:
try:
window.action_on_removal(window)
except Exception:
import traceback
traceback.print_exc()
window.action_on_close = window.action_on_removal = None
def close_window(self, window=None):
if window is None:
@@ -512,27 +526,27 @@ class Boss:
if t is not None:
return t.active_window
def dispatch_special_key(self, key, scancode, action, mods):
def dispatch_special_key(self, key, native_key, action, mods):
# Handles shortcuts, return True if the key was consumed
key_action = get_shortcut(self.keymap, mods, key, scancode)
key_action = get_shortcut(self.keymap, mods, key, native_key)
if key_action is None:
sequences = get_shortcut(self.opts.sequence_map, mods, key, scancode)
sequences = get_shortcut(self.opts.sequence_map, mods, key, native_key)
if sequences:
self.pending_sequences = sequences
set_in_sequence_mode(True)
return True
else:
self.current_key_press_info = key, scancode, action, mods
self.current_key_press_info = key, native_key, action, mods
return self.dispatch_action(key_action)
def process_sequence(self, key, scancode, action, mods):
def process_sequence(self, key, native_key, action, mods):
if not self.pending_sequences:
set_in_sequence_mode(False)
remaining = {}
matched_action = None
for seq, key_action in self.pending_sequences.items():
if shortcut_matches(seq[0], mods, key, scancode):
if shortcut_matches(seq[0], mods, key, native_key):
seq = seq[1:]
if seq:
remaining[seq] = key_action
@@ -619,12 +633,12 @@ class Boss:
if tm is not None:
tm.update_tab_bar_data()
def on_drop(self, os_window_id, paths):
def on_drop(self, os_window_id, strings):
tm = self.os_window_map.get(os_window_id)
if tm is not None:
w = tm.active_window
if w is not None:
w.paste('\n'.join(paths))
w.paste('\n'.join(strings))
def on_os_window_closed(self, os_window_id, viewport_width, viewport_height):
self.cached_values['window-size'] = viewport_width, viewport_height
@@ -670,7 +684,7 @@ class Boss:
output += str(s.linebuf.line(i))
return output
def _run_kitten(self, kitten, args=(), input_data=None, window=None):
def _run_kitten(self, kitten, args=(), input_data=None, window=None, custom_callback=None, action_on_removal=None):
orig_args, args = list(args), list(args)
from kittens.runner import create_kitten_handler
end_kitten = create_kitten_handler(kitten, orig_args)
@@ -716,8 +730,13 @@ class Boss:
},
cwd=w.cwd_of_child,
overlay_for=w.id
))
overlay_window.action_on_close = partial(self.on_kitten_finish, w.id, end_kitten)
),
copy_colors_from=w
)
wid = w.id
overlay_window.action_on_close = partial(self.on_kitten_finish, wid, custom_callback or end_kitten)
if action_on_removal is not None:
overlay_window.action_on_removal = lambda *a: action_on_removal(wid, self)
return overlay_window
def kitten(self, kitten, *args):
@@ -879,6 +898,9 @@ class Boss:
stdin = stdin.encode('utf-8')
return env, stdin
def data_for_at(self, which, window=None, add_wrap_markers=False):
return data_for_at(window or self.active_window, which, add_wrap_markers=add_wrap_markers)
def special_window_for_cmd(self, cmd, window=None, stdin=None, cwd_from=None, as_overlay=False):
w = window or self.active_window
env, stdin = self.process_stdin_source(w, stdin)
@@ -892,6 +914,25 @@ class Boss:
overlay_for = w.id if as_overlay and w.overlay_for is None else None
return SpecialWindow(cmd, stdin, cwd_from=cwd_from, overlay_for=overlay_for, env=env)
def run_background_process(self, cmd, cwd=None, env=None, stdin=None, cwd_from=None):
import subprocess
if cwd_from:
with suppress(Exception):
cwd = cwd_of_process(cwd_from)
if stdin:
r, w = safe_pipe(False)
try:
subprocess.Popen(cmd, env=env, stdin=r, cwd=cwd)
except Exception:
os.close(w)
else:
thread_write(w, stdin)
finally:
os.close(r)
else:
subprocess.Popen(cmd, env=env, cwd=cwd)
def pipe(self, source, dest, exe, *args):
cmd = [exe] + list(args)
window = self.active_window
@@ -917,24 +958,8 @@ class Boss:
func = set_clipboard_string if dest == 'clipboard' else set_primary_selection
func(stdin)
else:
import subprocess
env, stdin = self.process_stdin_source(stdin=source, window=window)
cwd = None
if cwd_from:
with suppress(Exception):
cwd = cwd_of_process(cwd_from)
if stdin:
r, w = safe_pipe(False)
try:
subprocess.Popen(cmd, env=env, stdin=r, cwd=cwd)
except Exception:
os.close(w)
else:
thread_write(w, stdin)
finally:
os.close(r)
else:
subprocess.Popen(cmd, env=env, cwd=cwd)
self.run_background_process(cmd, cwd_from=cwd_from, stdin=stdin, env=env)
def args_to_special_window(self, args, cwd_from=None):
args = list(args)
@@ -989,14 +1014,20 @@ class Boss:
def _new_window(self, args, cwd_from=None):
tab = self.active_tab
if tab is not None:
allow_remote_control = False
location = None
if args and args[0].startswith('!'):
location = args[0][1:].lower()
args = args[1:]
if args and args[0] == '@':
args = args[1:]
allow_remote_control = True
if args:
return tab.new_special_window(self.args_to_special_window(args, cwd_from=cwd_from), location=location)
return tab.new_special_window(
self.args_to_special_window(args, cwd_from=cwd_from),
location=location, allow_remote_control=allow_remote_control)
else:
return tab.new_window(cwd_from=cwd_from, location=location)
return tab.new_window(cwd_from=cwd_from, location=location, allow_remote_control=allow_remote_control)
def new_window(self, *args):
self._new_window(args)
@@ -1008,6 +1039,11 @@ class Boss:
cwd_from = w.child.pid_for_cwd if w is not None else None
self._new_window(args, cwd_from=cwd_from)
def launch(self, *args):
from kitty.launch import parse_launch_args, launch
opts, args = parse_launch_args(args)
launch(self, opts, args)
def move_tab_forward(self):
tm = self.active_tab_manager
if tm is not None:
@@ -1094,3 +1130,132 @@ class Boss:
msg = '\n'.join(map(format_bad_line, bad_lines)).rstrip()
self.show_error(_('Errors in kitty.conf'), msg)
def set_colors(self, *args):
from .cmds import parse_subcommand_cli, cmd_set_colors, set_colors
opts, items = parse_subcommand_cli(cmd_set_colors, ['set-colors'] + list(args))
payload = cmd_set_colors(None, opts, items)
set_colors(self, self.active_window, payload)
def _move_window_to(self, window=None, target_tab_id=None, target_os_window_id=None):
window = window or self.active_window
if not window:
return
src_tab = self.tab_for_window(window)
if src_tab is None:
return
if target_os_window_id == 'new':
target_os_window_id = self.add_os_window()
tm = self.os_window_map[target_os_window_id]
target_tab = tm.new_tab(empty_tab=True)
else:
target_os_window_id = target_os_window_id or current_os_window()
if target_tab_id == 'new':
tm = self.os_window_map[target_os_window_id]
target_tab = tm.new_tab(empty_tab=True)
else:
for tab in self.all_tabs:
if tab.id == target_tab_id:
target_tab = tab
target_os_window_id = tab.os_window_id
break
else:
return
underlaid_window, overlaid_window = src_tab.detach_window(window)
if underlaid_window:
target_tab.attach_window(underlaid_window)
if overlaid_window:
target_tab.attach_window(overlaid_window)
self._cleanup_tab_after_window_removal(src_tab)
target_tab.make_active()
def _move_tab_to(self, tab=None, target_os_window_id=None):
tab = tab or self.active_tab
if tab is None:
return
if target_os_window_id is None:
target_os_window_id = self.add_os_window()
tm = self.os_window_map[target_os_window_id]
target_tab = tm.new_tab(empty_tab=True)
target_tab.take_over_from(tab)
self._cleanup_tab_after_window_removal(tab)
target_tab.make_active()
def detach_window(self, *args):
if not args or args[0] == 'new':
return self._move_window_to(target_os_window_id='new')
if args[0] == 'new-tab':
return self._move_window_to(target_tab_id='new')
lines = [
'Choose a tab to move the window to',
''
]
tab_id_map = {}
current_tab = self.active_tab
for i, tab in enumerate(self.all_tabs):
if tab is not current_tab:
tab_id_map[i + 1] = tab.id
lines.append('{} {}'.format(i + 1, tab.title))
new_idx = len(tab_id_map) + 1
tab_id_map[new_idx] = 'new'
lines.append('{} {}'.format(new_idx, 'New tab'))
new_idx = len(tab_id_map) + 1
tab_id_map[new_idx] = None
lines.append('{} {}'.format(new_idx, 'New OS Window'))
def done(data, target_window_id, self):
done.tab_id = tab_id_map[int(data['match'][0].partition(' ')[0])]
def done2(target_window_id, self):
tab_id = done.tab_id
target_window = None
for w in self.all_windows:
if w.id == target_window_id:
target_window = w
break
if tab_id is None:
self._move_window_to(window=target_window, target_os_window_id='new')
else:
self._move_window_to(window=target_window, target_tab_id=tab_id)
self._run_kitten(
'hints', args=('--type=regex', r'--regex=(?m)^\d+ .+$',),
input_data='\r\n'.join(lines).encode('utf-8'), custom_callback=done, action_on_removal=done2)
def detach_tab(self, *args):
if not args or args[0] == 'new':
return self._move_tab_to()
lines = [
'Choose an OS window to move the tab to',
''
]
os_window_id_map = {}
current_os_window = getattr(self.active_tab, 'os_window_id', 0)
for i, osw in enumerate(self.os_window_map):
tm = self.os_window_map[osw]
if current_os_window != osw and tm.active_tab and tm.active_tab:
os_window_id_map[i + 1] = osw
lines.append('{} {}'.format(i + 1, tm.active_tab.title))
new_idx = len(os_window_id_map) + 1
os_window_id_map[new_idx] = None
lines.append('{} {}'.format(new_idx, 'New OS Window'))
def done(data, target_window_id, self):
done.os_window_id = os_window_id_map[int(data['match'][0].partition(' ')[0])]
def done2(target_window_id, self):
os_window_id = done.os_window_id
target_tab = self.active_tab
for w in self.all_windows:
if w.id == target_window_id:
target_tab = w.tabref()
break
if target_tab and target_tab.os_window_id == os_window_id:
return
self._move_tab_to(tab=target_tab, target_os_window_id=os_window_id)
self._run_kitten(
'hints', args=('--type=regex', r'--regex=(?m)^\d+ .+$',),
input_data='\r\n'.join(lines).encode('utf-8'), custom_callback=done, action_on_removal=done2)

View File

@@ -114,7 +114,7 @@ vec3 choose_color(float q, vec3 a, vec3 b) {
return mix(b, a, q);
}
float are_integers_equal(float a, float b) { // return 1 iff equal otherwise 0
float are_integers_equal(float a, float b) { // return 1 if equal otherwise 0
float delta = abs(a - b); // delta can be 0, 1 or larger
return step(delta, 0.5); // 0 if 0.5 < delta else 1
}
@@ -172,13 +172,15 @@ void main() {
foreground = color_to_vec(resolved_fg);
float has_dim = float((text_attrs >> DIM_SHIFT) & ONE);
effective_text_alpha = inactive_text_alpha * mix(1.0, dim_opacity, has_dim);
#ifdef USE_SELECTION_FG
// Selection
foreground = choose_color(float(is_selected & ONE), color_to_vec(highlight_fg), foreground);
#endif
// Underline and strike through (rendered via sprites)
float in_url = float((is_selected & TWO) >> 1);
decoration_fg = choose_color(in_url, color_to_vec(url_color), to_color(colors[2], resolved_fg));
#ifdef USE_SELECTION_FG
// Selection
vec3 selection_color = color_to_vec(highlight_fg);
foreground = choose_color(float(is_selected & ONE), selection_color, foreground);
decoration_fg = choose_color(float(is_selected & ONE), selection_color, decoration_fg);
#endif
// Underline and strike through (rendered via sprites)
underline_pos = choose_color(in_url, to_sprite_pos(pos, url_style, ZERO, ZERO), to_sprite_pos(pos, (text_attrs >> DECORATION_SHIFT) & THREE, ZERO, ZERO));
strike_pos = to_sprite_pos(pos, ((text_attrs >> STRIKE_SHIFT) & ONE) * FOUR, ZERO, ZERO);

View File

@@ -11,6 +11,7 @@
#include "screen.h"
#include "fonts.h"
#include "charsets.h"
#include "monotonic.h"
#include <termios.h>
#include <unistd.h>
#include <float.h>
@@ -34,7 +35,7 @@ extern PyTypeObject Screen_Type;
#endif
#define USE_RENDER_FRAMES (global_state.has_render_frames && OPT(sync_to_monitor))
static void (*parse_func)(Screen*, PyObject*, double);
static void (*parse_func)(Screen*, PyObject*, monotonic_t);
typedef struct {
char *data;
@@ -110,10 +111,10 @@ static size_t reaped_pids_count = 0;
// The max time (in secs) to wait for events from the window system
// before ticking over the main loop. Negative values mean wait forever.
static double maximum_wait = -1.0;
static monotonic_t maximum_wait = -1;
static inline void
set_maximum_wait(double val) {
set_maximum_wait(monotonic_t val) {
if (val >= 0 && (val < maximum_wait || maximum_wait < 0)) maximum_wait = val;
}
@@ -168,7 +169,7 @@ dealloc(ChildMonitor* self) {
static void
wakeup_io_loop(ChildMonitor *self, bool in_signal_handler) {
wakeup_loop(&self->io_loop_data, in_signal_handler);
wakeup_loop(&self->io_loop_data, in_signal_handler, "io_loop");
}
static void* io_loop(void *data);
@@ -296,11 +297,11 @@ shutdown_monitor(ChildMonitor *self, PyObject *a UNUSED) {
}
static inline bool
do_parse(ChildMonitor *self, Screen *screen, double now) {
do_parse(ChildMonitor *self, Screen *screen, monotonic_t now) {
bool input_read = false;
screen_mutex(lock, read);
if (screen->read_buf_sz || screen->pending_mode.used) {
double time_since_new_input = now - screen->new_input_at;
monotonic_t time_since_new_input = now - screen->new_input_at;
if (time_since_new_input >= OPT(input_delay)) {
bool read_buf_full = screen->read_buf_sz >= READ_BUF_SZ;
input_read = true;
@@ -308,7 +309,7 @@ do_parse(ChildMonitor *self, Screen *screen, double now) {
if (read_buf_full) wakeup_io_loop(self, false); // Ensure the read fd has POLLIN set
screen->new_input_at = 0;
if (screen->pending_mode.activated_at) {
double time_since_pending = MAX(0, now - screen->pending_mode.activated_at);
monotonic_t time_since_pending = MAX(0, now - screen->pending_mode.activated_at);
set_maximum_wait(screen->pending_mode.wait_time - time_since_pending);
}
} else set_maximum_wait(OPT(input_delay) - time_since_new_input);
@@ -322,7 +323,7 @@ parse_input(ChildMonitor *self) {
// Parse all available input that was read in the I/O thread.
size_t count = 0, remove_count = 0;
bool input_read = false;
double now = monotonic();
monotonic_t now = monotonic();
PyObject *msg = NULL;
children_mutex(lock);
while (remove_queue_count) {
@@ -485,22 +486,22 @@ pyset_iutf8(ChildMonitor *self, PyObject *args) {
extern void cocoa_update_menu_bar_title(PyObject*);
static inline void
collect_cursor_info(CursorRenderInfo *ans, Window *w, double now, OSWindow *os_window) {
collect_cursor_info(CursorRenderInfo *ans, Window *w, monotonic_t now, OSWindow *os_window) {
ScreenRenderData *rd = &w->render_data;
Cursor *cursor = rd->screen->cursor;
ans->x = cursor->x; ans->y = cursor->y;
ans->is_visible = false;
if (rd->screen->scrolled_by || !screen_is_cursor_visible(rd->screen)) return;
double time_since_start_blink = now - os_window->cursor_blink_zero_time;
monotonic_t time_since_start_blink = now - os_window->cursor_blink_zero_time;
bool cursor_blinking = OPT(cursor_blink_interval) > 0 && os_window->is_focused && (OPT(cursor_stop_blinking_after) == 0 || time_since_start_blink <= OPT(cursor_stop_blinking_after));
bool do_draw_cursor = true;
if (cursor_blinking) {
int t = (int)(time_since_start_blink * 1000);
int d = (int)(OPT(cursor_blink_interval) * 1000);
int t = monotonic_t_to_ms(time_since_start_blink);
int d = monotonic_t_to_ms(OPT(cursor_blink_interval));
int n = t / d;
do_draw_cursor = n % 2 == 0 ? true : false;
double bucket = (n + 1) * d;
double delay = (bucket / 1000.0) - time_since_start_blink;
monotonic_t bucket = ms_to_monotonic_t((n + 1) * d);
monotonic_t delay = bucket - time_since_start_blink;
set_maximum_wait(delay);
}
if (!do_draw_cursor) { ans->is_visible = false; return; }
@@ -518,7 +519,7 @@ update_window_title(Window *w, OSWindow *os_window) {
Py_INCREF(os_window->window_title);
set_os_window_title(os_window, PyUnicode_AsUTF8(w->title));
#ifdef __APPLE__
if (os_window->is_focused && OPT(macos_show_window_title_in_menubar)) cocoa_update_menu_bar_title(w->title);
if (os_window->is_focused && (OPT(macos_show_window_title_in) & MENUBAR)) cocoa_update_menu_bar_title(w->title);
#endif
return true;
}
@@ -526,7 +527,7 @@ update_window_title(Window *w, OSWindow *os_window) {
}
static inline bool
prepare_to_render_os_window(OSWindow *os_window, double now, unsigned int *active_window_id, color_type *active_window_bg, unsigned int *num_visible_windows) {
prepare_to_render_os_window(OSWindow *os_window, monotonic_t now, unsigned int *active_window_id, color_type *active_window_bg, unsigned int *num_visible_windows, bool *all_windows_have_same_bg) {
#define TD os_window->tab_bar_render_data
bool needs_render = os_window->needs_render;
os_window->needs_render = false;
@@ -543,16 +544,22 @@ prepare_to_render_os_window(OSWindow *os_window, double now, unsigned int *activ
}
Tab *tab = os_window->tabs + os_window->active_tab;
*active_window_bg = OPT(background);
*all_windows_have_same_bg = true;
*num_visible_windows = 0;
color_type first_window_bg = 0;
for (unsigned int i = 0; i < tab->num_windows; i++) {
Window *w = tab->windows + i;
#define WD w->render_data
if (w->visible && WD.screen) {
*num_visible_windows += 1;
color_type window_bg = colorprofile_to_color(WD.screen->color_profile, WD.screen->color_profile->overridden.default_bg, WD.screen->color_profile->configured.default_bg);
if (*num_visible_windows == 1) first_window_bg = window_bg;
if (first_window_bg != window_bg) all_windows_have_same_bg = false;
if (w->last_drag_scroll_at > 0) {
if (now - w->last_drag_scroll_at >= 0.02) {
if (now - w->last_drag_scroll_at >= ms_to_monotonic_t(20ll)) {
if (drag_scroll(w, os_window)) {
w->last_drag_scroll_at = now;
set_maximum_wait(0.02);
set_maximum_wait(ms_to_monotonic_t(20ll));
needs_render = true;
} else w->last_drag_scroll_at = 0;
} else set_maximum_wait(now - w->last_drag_scroll_at);
@@ -563,7 +570,7 @@ prepare_to_render_os_window(OSWindow *os_window, double now, unsigned int *activ
collect_cursor_info(&WD.screen->cursor_render_info, w, now, os_window);
if (w->cursor_visible_at_last_render != WD.screen->cursor_render_info.is_visible || w->last_cursor_x != WD.screen->cursor_render_info.x || w->last_cursor_y != WD.screen->cursor_render_info.y || w->last_cursor_shape != WD.screen->cursor_render_info.shape) needs_render = true;
update_window_title(w, os_window);
*active_window_bg = colorprofile_to_color(WD.screen->color_profile, WD.screen->color_profile->overridden.default_bg, WD.screen->color_profile->configured.default_bg);
*active_window_bg = window_bg;
} else WD.screen->cursor_render_info.is_visible = false;
if (send_cell_data_to_gpu(WD.vao_idx, WD.gvao_idx, WD.xstart, WD.ystart, WD.dx, WD.dy, WD.screen, os_window)) needs_render = true;
if (WD.screen->start_visual_bell_at != 0) needs_render = true;
@@ -573,7 +580,7 @@ prepare_to_render_os_window(OSWindow *os_window, double now, unsigned int *activ
}
static inline void
render_os_window(OSWindow *os_window, double now, unsigned int active_window_id, color_type active_window_bg, unsigned int num_visible_windows) {
render_os_window(OSWindow *os_window, monotonic_t now, unsigned int active_window_id, color_type active_window_bg, unsigned int num_visible_windows, bool all_windows_have_same_bg) {
// ensure all pixels are cleared to background color at least once in every buffer
if (os_window->clear_count++ < 3) blank_os_window(os_window);
Tab *tab = os_window->tabs + os_window->active_tab;
@@ -581,11 +588,11 @@ render_os_window(OSWindow *os_window, double now, unsigned int active_window_id,
bool static_live_resize_in_progress = os_window->live_resize.in_progress && OPT(resize_draw_strategy) == RESIZE_DRAW_STATIC;
float x_ratio = 1, y_ratio = 1;
if (static_live_resize_in_progress) {
x_ratio = os_window->viewport_width / (double) os_window->live_resize.width;
y_ratio = os_window->viewport_height / (double) os_window->live_resize.height;
x_ratio = (float) os_window->viewport_width / (float) os_window->live_resize.width;
y_ratio = (float) os_window->viewport_height / (float) os_window->live_resize.height;
}
if (!static_live_resize_in_progress) {
draw_borders(br->vao_idx, br->num_border_rects, br->rect_buf, br->is_dirty, os_window->viewport_width, os_window->viewport_height, active_window_bg, num_visible_windows, os_window);
draw_borders(br->vao_idx, br->num_border_rects, br->rect_buf, br->is_dirty, os_window->viewport_width, os_window->viewport_height, active_window_bg, num_visible_windows, all_windows_have_same_bg, os_window);
br->is_dirty = false;
}
if (TD.screen && os_window->num_tabs >= OPT(tab_bar_min_tabs)) draw_cells(TD.vao_idx, 0, TD.xstart, TD.ystart, TD.dx * x_ratio, TD.dy * y_ratio, TD.screen, os_window, true, false);
@@ -595,7 +602,7 @@ render_os_window(OSWindow *os_window, double now, unsigned int active_window_id,
bool is_active_window = i == tab->active_window;
draw_cells(WD.vao_idx, WD.gvao_idx, WD.xstart, WD.ystart, WD.dx * x_ratio, WD.dy * y_ratio, WD.screen, os_window, is_active_window, true);
if (WD.screen->start_visual_bell_at != 0) {
double bell_left = global_state.opts.visual_bell_duration - (now - WD.screen->start_visual_bell_at);
monotonic_t bell_left = OPT(visual_bell_duration) - (now - WD.screen->start_visual_bell_at);
set_maximum_wait(bell_left);
}
w->cursor_visible_at_last_render = WD.screen->cursor_render_info.is_visible; w->last_cursor_x = WD.screen->cursor_render_info.x; w->last_cursor_y = WD.screen->cursor_render_info.y; w->last_cursor_shape = WD.screen->cursor_render_info.shape;
@@ -632,17 +639,17 @@ draw_resizing_text(OSWindow *w) {
}
static inline bool
no_render_frame_received_recently(OSWindow *w, double now, double max_wait) {
no_render_frame_received_recently(OSWindow *w, monotonic_t now, monotonic_t max_wait) {
bool ans = now - w->last_render_frame_received_at > max_wait;
if (ans) log_error("No render frame received in %f seconds, re-requesting at: %f", max_wait, now);
if (ans) log_error("No render frame received in %f seconds, re-requesting at: %f", monotonic_t_to_s_double(max_wait), monotonic_t_to_s_double(now));
return ans;
}
static inline void
render(double now, bool input_read) {
render(monotonic_t now, bool input_read) {
EVDBG("input_read: %d", input_read);
static double last_render_at = -DBL_MAX;
double time_since_last_render = now - last_render_at;
static monotonic_t last_render_at = MONOTONIC_T_MIN;
monotonic_t time_since_last_render = now - last_render_at;
if (!input_read && time_since_last_render < OPT(repaint_delay)) {
set_maximum_wait(OPT(repaint_delay) - time_since_last_render);
return;
@@ -656,7 +663,7 @@ render(double now, bool input_read) {
continue;
}
if (USE_RENDER_FRAMES && w->render_state != RENDER_FRAME_READY) {
if (w->render_state == RENDER_FRAME_NOT_REQUESTED || no_render_frame_received_recently(w, now, 0.25)) request_frame_render(w);
if (w->render_state == RENDER_FRAME_NOT_REQUESTED || no_render_frame_received_recently(w, now, ms_to_monotonic_t(250ll))) request_frame_render(w);
continue;
}
make_os_window_context_current(w);
@@ -676,11 +683,12 @@ render(double now, bool input_read) {
needs_render = true;
}
unsigned int active_window_id = 0, num_visible_windows = 0;
bool all_windows_have_same_bg;
color_type active_window_bg = 0;
if (!w->fonts_data) { log_error("No fonts data found for window id: %llu", w->id); continue; }
if (prepare_to_render_os_window(w, now, &active_window_id, &active_window_bg, &num_visible_windows)) needs_render = true;
if (prepare_to_render_os_window(w, now, &active_window_id, &active_window_bg, &num_visible_windows, &all_windows_have_same_bg)) needs_render = true;
if (w->last_active_window_id != active_window_id || w->last_active_tab != w->active_tab || w->focused_at_last_render != w->is_focused) needs_render = true;
if (needs_render) render_os_window(w, now, active_window_id, active_window_bg, num_visible_windows);
if (needs_render) render_os_window(w, now, active_window_id, active_window_bg, num_visible_windows, all_windows_have_same_bg);
}
last_render_at = now;
#undef TD
@@ -799,7 +807,7 @@ add_python_timer(PyObject *self UNUSED, PyObject *args) {
double interval;
int repeats = 1;
if (!PyArg_ParseTuple(args, "Od|p", &callback, &interval, &repeats)) return NULL;
unsigned long long timer_id = add_main_loop_timer(interval, repeats ? true: false, python_timer_callback, callback, python_timer_cleanup);
unsigned long long timer_id = add_main_loop_timer(s_double_to_monotonic_t(interval), repeats ? true: false, python_timer_callback, callback, python_timer_cleanup);
Py_INCREF(callback);
return Py_BuildValue("K", timer_id);
}
@@ -814,7 +822,7 @@ remove_python_timer(PyObject *self UNUSED, PyObject *args) {
static inline void
process_pending_resizes(double now) {
process_pending_resizes(monotonic_t now) {
global_state.has_pending_resizes = false;
for (size_t i = 0; i < global_state.num_os_windows; i++) {
OSWindow *w = global_state.os_windows + i;
@@ -823,11 +831,11 @@ process_pending_resizes(double now) {
if (w->live_resize.from_os_notification) {
if (w->live_resize.os_says_resize_complete || (now - w->live_resize.last_resize_event_at) > 1) update_viewport = true;
} else {
double debounce_time = OPT(resize_debounce_time);
monotonic_t debounce_time = OPT(resize_debounce_time);
// if more than one resize event has occurred, wait at least 0.2 secs
// before repainting, to avoid rapid transitions between the cells banner
// and the normal screen
if (w->live_resize.num_of_resize_events > 1 && OPT(resize_draw_strategy) == RESIZE_DRAW_SIZE) debounce_time = MAX(0.2, debounce_time);
if (w->live_resize.num_of_resize_events > 1 && OPT(resize_draw_strategy) == RESIZE_DRAW_SIZE) debounce_time = MAX(ms_to_monotonic_t(200ll), debounce_time);
if (now - w->live_resize.last_resize_event_at >= debounce_time) update_viewport = true;
else {
global_state.has_pending_resizes = true;
@@ -909,7 +917,7 @@ process_global_state(void *data) {
maximum_wait = -1;
bool state_check_timer_enabled = false;
double now = monotonic();
monotonic_t now = monotonic();
if (global_state.has_pending_resizes) process_pending_resizes(now);
bool input_read = parse_input(self);
render(now, input_read);
@@ -1160,7 +1168,7 @@ io_loop(void *data) {
size_t i;
int ret;
bool has_more, data_received, has_pending_wakeups = false;
double last_main_loop_wakeup_at = -1, now = -1;
monotonic_t last_main_loop_wakeup_at = -1, now = -1;
Screen *screen;
ChildMonitor *self = (ChildMonitor*)data;
set_thread_name("KittyChildMon");
@@ -1181,8 +1189,8 @@ io_loop(void *data) {
}
if (has_pending_wakeups) {
now = monotonic();
double time_delta = OPT(input_delay) - (now - last_main_loop_wakeup_at);
if (time_delta >= 0) ret = poll(fds, self->count + EXTRA_FDS, (int)ceil(1000 * time_delta));
monotonic_t time_delta = OPT(input_delay) - (now - last_main_loop_wakeup_at);
if (time_delta >= 0) ret = poll(fds, self->count + EXTRA_FDS, monotonic_t_to_ms(time_delta));
else ret = 0;
} else {
ret = poll(fds, self->count + EXTRA_FDS, -1);
@@ -1414,7 +1422,7 @@ prune_finished_writes(void) {
static void
wakeup_talk_loop(bool in_signal_handler) {
wakeup_loop(&talk_data.loop_data, in_signal_handler);
if (talk_thread_started) wakeup_loop(&talk_data.loop_data, in_signal_handler, "talk_loop");
}
static inline void

View File

@@ -4,9 +4,9 @@
import fcntl
import os
import sys
from collections import defaultdict
from contextlib import contextmanager
from contextlib import suppress
from contextlib import contextmanager, suppress
import kitty.fast_data_types as fast_data_types
@@ -30,14 +30,16 @@ if is_macos:
else:
def cmdline_of_process(pid):
return list(filter(None, open('/proc/{}/cmdline'.format(pid), 'rb').read().decode('utf-8').split('\0')))
with open('/proc/{}/cmdline'.format(pid), 'rb') as f:
return list(filter(None, f.read().decode('utf-8').split('\0')))
def cwd_of_process(pid):
ans = '/proc/{}/cwd'.format(pid)
return os.path.realpath(ans)
def _environ_of_process(pid):
return open('/proc/{}/environ'.format(pid), 'rb').read().decode('utf-8')
with open('/proc/{}/environ'.format(pid), 'rb') as f:
return f.read().decode('utf-8')
def process_group_map():
ans = defaultdict(list)
@@ -47,7 +49,8 @@ else:
except Exception:
continue
try:
raw = open('/proc/' + x + '/stat', 'rb').read().decode('utf-8')
with open('/proc/' + x + '/stat', 'rb') as f:
raw = f.read().decode('utf-8')
except EnvironmentError:
continue
try:
@@ -118,31 +121,47 @@ def remove_cloexec(fd):
fcntl.fcntl(fd, fcntl.F_SETFD, fcntl.fcntl(fd, fcntl.F_GETFD) & ~fcntl.FD_CLOEXEC)
def remove_blocking(fd):
os.set_blocking(fd, False)
def process_env():
ans = os.environ
ssl_env_var = getattr(sys, 'kitty_ssl_env_var', None)
if ssl_env_var is not None:
ans = ans.copy()
ans.pop(ssl_env_var, None)
return ans
def default_env():
try:
return default_env.env
except AttributeError:
return os.environ
return process_env()
def set_default_env(val=None):
env = os.environ.copy()
env = process_env().copy()
if val:
env.update(val)
default_env.env = env
def openpty():
master, slave = os.openpty() # Note that master and slave are in blocking mode
remove_cloexec(slave)
fast_data_types.set_iutf8_fd(master, True)
return master, slave
class Child:
child_fd = pid = None
forked = False
def __init__(self, argv, cwd, opts, stdin=None, env=None, cwd_from=None):
self.allow_remote_control = False
if argv and argv[0] == '@':
self.allow_remote_control = True
if len(argv) > 1:
argv = argv[1:]
def __init__(self, argv, cwd, opts, stdin=None, env=None, cwd_from=None, allow_remote_control=False):
self.allow_remote_control = allow_remote_control
self.argv = argv
if cwd_from is not None:
try:
@@ -166,7 +185,7 @@ class Child:
env['TERM'] = self.opts.term
env['COLORTERM'] = 'truecolor'
if self.cwd:
# needed incase cwd is a symlink, in which case shells
# needed in case cwd is a symlink, in which case shells
# can use it to display the current directory name rather
# than the resolved path
env['PWD'] = self.cwd
@@ -178,9 +197,7 @@ class Child:
if self.forked:
return
self.forked = True
master, slave = os.openpty() # Note that master and slave are in blocking mode
remove_cloexec(slave)
fast_data_types.set_iutf8_fd(master, True)
master, slave = openpty()
stdin, self.stdin = self.stdin, None
ready_read_fd, ready_write_fd = os.pipe()
remove_cloexec(ready_read_fd)
@@ -194,8 +211,20 @@ class Child:
argv = list(self.argv)
exe = argv[0]
if is_macos and exe == shell_path:
# Some macOS machines need the shell to have argv[0] prefixed by
# hyphen, see https://github.com/kovidgoyal/kitty/issues/247
# bash will only source ~/.bash_profile if it detects it is a login
# shell (see the invocation section of the bash man page), which it
# does if argv[0] is prefixed by a hyphen see
# https://github.com/kovidgoyal/kitty/issues/247
# it is apparently common to use ~/.bash_profile instead of the
# more correct ~/.bashrc on macOS to setup env vars, so if
# the default shell is used prefix argv[0] by '-'
#
# it is arguable whether graphical terminals should start shells
# in login mode in general, there are at least a few Linux users
# that also make this incorrect assumption, see for example
# https://github.com/kovidgoyal/kitty/issues/1870
# xterm, urxvt, konsole and gnome-terminal do not do it in my
# testing.
argv[0] = ('-' + exe.split('/')[-1])
pid = fast_data_types.spawn(exe, self.cwd, tuple(argv), env, master, slave, stdin_read_fd, stdin_write_fd, ready_read_fd, ready_write_fd)
os.close(slave)
@@ -206,7 +235,7 @@ class Child:
fast_data_types.thread_write(stdin_write_fd, stdin)
os.close(ready_read_fd)
self.terminal_ready_fd = ready_write_fd
fcntl.fcntl(self.child_fd, fcntl.F_SETFL, fcntl.fcntl(self.child_fd, fcntl.F_GETFL) | os.O_NONBLOCK)
remove_blocking(self.child_fd)
return pid
def mark_terminal_ready(self):
@@ -238,6 +267,13 @@ class Child:
except Exception:
return list(self.argv)
@property
def foreground_cmdline(self):
try:
return cmdline_of_process(self.pid_for_cwd) or self.cmdline
except Exception:
return self.cmdline
@property
def environ(self):
try:
@@ -263,3 +299,14 @@ class Child:
def foreground_cwd(self):
with suppress(Exception):
return cwd_of_process(self.pid_for_cwd) or None
@property
def foreground_environ(self):
try:
return environ_of_process(self.pid_for_cwd)
except Exception:
try:
return environ_of_process(self.pid)
except Exception:
pass
return {}

View File

@@ -225,7 +225,7 @@ Run the :italic:`{appname}` terminal emulator. You can also specify the :italic:
to run inside :italic:`{appname}` as normal arguments following the :italic:`options`.
For example: {appname} /bin/sh
For comprehensive documentation for kitty, please see: https://sw.kovidgoyal.net/kitty''').format(appname=appname)
For comprehensive documentation for kitty, please see: https://sw.kovidgoyal.net/kitty/''').format(appname=appname)
def print_help_for_seq(seq, usage, message, appname):
@@ -423,8 +423,8 @@ class Options:
class Namespace:
def __init__(self, kwargs):
for name in kwargs:
setattr(self, name, kwargs[name])
for name, val in kwargs.items():
setattr(self, name, val)
def parse_cmdline(oc, disabled, args=None):
@@ -514,7 +514,7 @@ Detach from the controlling terminal, if any
--session
Path to a file containing the startup :italic:`session` (tabs, windows, layout, programs).
See the README file for details and an example.
Use - to read from STDIN. See the README file for details and an example.
--hold
@@ -728,9 +728,11 @@ def create_opts(args, debug_config=False, accumulate_bad_lines=None):
import subprocess
print(' '.join(subprocess.check_output(['sw_vers']).decode('utf-8').splitlines()).strip())
if os.path.exists('/etc/issue'):
print(open('/etc/issue', encoding='utf-8', errors='replace').read().strip())
with open('/etc/issue', encoding='utf-8', errors='replace') as f:
print(f.read().strip())
if os.path.exists('/etc/lsb-release'):
print(open('/etc/lsb-release', encoding='utf-8', errors='replace').read().strip())
with open('/etc/lsb-release', encoding='utf-8', errors='replace') as f:
print(f.read().strip())
config = tuple(x for x in config if os.path.exists(x))
if config:
print(green('Loaded config files:'), ', '.join(config))

View File

@@ -157,7 +157,8 @@ def replay(raw):
def main(path):
raw = open(path).read()
with open(path) as f:
raw = f.read()
replay(raw)
with suppress(EOFError, KeyboardInterrupt):
input()

View File

@@ -7,10 +7,16 @@ import os
import sys
from contextlib import suppress
from .cli import parse_args, parse_option_spec, get_defaults_from_seq
from .cli import (
Namespace, get_defaults_from_seq, parse_args, parse_option_spec
)
from .config import parse_config, parse_send_text_bytes
from .constants import appname
from .fast_data_types import focus_os_window
from .launch import (
launch as do_launch, options_spec as launch_options_spec,
parse_launch_args
)
from .tabs import SpecialWindow
from .utils import natsort_ints
@@ -375,6 +381,100 @@ def set_tab_title(boss, window, payload):
# }}}
# detach_window {{{
@cmd(
'Detach a window and place it in a different/new tab',
'Detach the specified window and either move it into a new tab, a new OS window'
' or add it to the specified tab. Use the special value :code:`new` for --target-tab'
' to move to a new tab. If no target tab is specified the window is moved to a new OS window.',
options_spec=MATCH_WINDOW_OPTION + '\n\n' + MATCH_TAB_OPTION.replace('--match -m', '--target-tab -t') + '''\n
--self
type=bool-set
If specified detach the window this command is run in, rather than the active window.
''',
argspec=''
)
def cmd_detach_window(global_opts, opts, args):
'''
match: Which window to detach
target: Which tab to move the detached window to
self: Boolean indicating whether to detach the window the command is run in
'''
return {'match': opts.match, 'target': opts.target_tab, 'self': opts.self}
def detach_window(boss, window, payload):
pg = cmd_detach_window.payload_get
match = pg(payload, 'match')
if match:
windows = tuple(boss.match_windows(match))
if not windows:
raise MatchError(match)
else:
windows = [window if window and pg(payload, 'self') else boss.active_window]
match = pg(payload, 'target_tab')
kwargs = {}
if match:
if match == 'new':
kwargs['target_tab_id'] = 'new'
else:
tabs = tuple(boss.match_tabs(match))
if not tabs:
raise MatchError(match, 'tabs')
kwargs['target_tab_id'] = tabs[0].id
if not kwargs:
kwargs['target_os_window_id'] = 'new'
for window in windows:
boss._move_window_to(window=window, **kwargs)
# }}}
# detach_tab {{{
@cmd(
'Detach a tab and place it in a different/new OS Window',
'Detach the specified tab and either move it into a new OS window'
' or add it to the OS Window containing the tab specified by --target-tab',
options_spec=MATCH_TAB_OPTION + '\n\n' + MATCH_TAB_OPTION.replace('--match -m', '--target-tab -t') + '''\n
--self
type=bool-set
If specified detach the tab this command is run in, rather than the active tab.
''',
argspec=''
)
def cmd_detach_tab(global_opts, opts, args):
'''
match: Which tab to detach
target: Which OS Window to move the detached tab to
self: Boolean indicating whether to detach the tab the command is run in
'''
return {'match': opts.match, 'target': opts.target_tab, 'self': opts.self}
def detach_tab(boss, window, payload):
pg = cmd_detach_tab.payload_get
match = pg(payload, 'match')
if match:
tabs = tuple(boss.match_tabs(match))
if not tabs:
raise MatchError(match)
else:
tabs = [window.tabref() if pg(payload, 'self') and window and window.tabref() else boss.active_tab]
match = pg(payload, 'target_tab')
kwargs = {}
if match:
targets = tuple(boss.match_tabs(match))
if not targets:
raise MatchError(match, 'tabs')
kwargs['target_os_window_id'] = targets[0].os_window_id
for tab in tabs:
boss._move_tab_to(tab=tab, **kwargs)
# }}}
# goto_layout {{{
@cmd(
'Set the window layout',
@@ -675,6 +775,76 @@ def new_window(boss, window, payload):
# }}}
# launch {{{
@cmd(
'Run an arbitrary process in a new window/tab',
' Prints out the id of the newly opened window. Any command line arguments'
' are assumed to be the command line used to run in the new window, if none'
' are provided, the default shell is run. For example:'
' :italic:`kitty @ launch --title Email mutt`.',
options_spec=MATCH_TAB_OPTION + '\n\n' + '''\
--no-response
type=bool-set
Do not print out the id of the newly created window.
--self
type=bool-set
If specified the tab containing the window this command is run in is used
instead of the active tab
''' + '\n\n' + launch_options_spec().replace(':option:`launch', ':option:`kitty @ launch'),
argspec='[CMD ...]'
)
def cmd_launch(global_opts, opts, args):
'''
args+: The command line to run in the new window, as a list, use an empty list to run the default shell
match: The tab to open the new window in
window_title: Title for the new window
cwd: Working directory for the new window
env: List of environment varibles of the form NAME=VALUE
tab_title: Title for the new tab
type: The type of window to open
keep_focus: Boolean indicating whether the current window should retain focus or not
copy_colors: Boolean indicating whether to copy the colors from the current window
copy_cmdline: Boolean indicating whether to copy the cmdline from the current window
copy_env: Boolean indicating whether to copy the environ from the current window
location: Where in the tab to open the new window
allow_remote_control: Boolean indicating whether to allow remote control from the new window
stdin_source: Where to get stdin for thew process from
stdin_add_formatting: Boolean indicating whether to add formatting codes to stdin
stdin_add_line_wrap_markers: Boolean indicating whether to add line wrap markers to stdin
no_response: Boolean indicating whether to send back the window id
'''
if opts.no_response:
global_opts.no_command_response = True
ans = {'args': args or []}
for attr, val in opts.__dict__.items():
ans[attr] = val
return ans
def launch(boss, window, payload):
pg = cmd_launch.payload_get
default_opts = parse_launch_args()[0]
opts = {}
for key, default_value in default_opts.__dict__.items():
opts[key] = payload.get(key, default_value)
opts = Namespace(opts)
match = pg(payload, 'match')
if match:
tabs = tuple(boss.match_tabs(match))
if not tabs:
raise MatchError(match, 'tabs')
else:
tabs = [boss.active_tab]
if pg(payload, 'self') and window and window.tabref():
tabs = [window.tabref()]
tab = tabs[0]
w = do_launch(boss, opts, pg(payload, 'args') or None, target_tab=tab)
return None if pg(payload, 'no_response') else str(getattr(w, 'id', 0))
# }}}
# focus_window {{{
@cmd(
'Focus the specified window',
@@ -882,7 +1052,7 @@ this option, any color arguments are ignored and --configured and --all are impl
def cmd_set_colors(global_opts, opts, args):
'''
colors+: An object mapping names to colors as 24-bit RGB integers
cursor_text_color: A 24-bit clor for text under the cursor
cursor_text_color: A 24-bit color for text under the cursor
match_window: Window to change colors in
match_tab: Tab to change colors in
all: Boolean indicating change colors everywhere or not
@@ -999,7 +1169,7 @@ def cmd_set_background_opacity(global_opts, opts, args):
def set_background_opacity(boss, window, payload):
if not boss.opts.dynamic_background_opacity:
raise OpacityError('You must turn on the dynamic_background_opacity option in kitty.conf to be able to set background opacity')
windows = windows_for_payload(payload)
windows = windows_for_payload(boss, window, payload)
for os_window_id in {w.os_window_id for w in windows}:
boss._set_os_window_background_opacity(os_window_id, payload['opacity'])
# }}}

View File

@@ -7,6 +7,7 @@
#include "state.h"
#include "monotonic.h"
#include <Cocoa/Cocoa.h>
#include <AvailabilityMacros.h>
@@ -231,8 +232,6 @@ cocoa_send_notification(PyObject *self UNUSED, PyObject *args) {
// global menu {{{
void
cocoa_create_global_menu(void) {
@autoreleasepool {
NSString* app_name = find_app_name();
NSMenu* bar = [[NSMenu alloc] init];
GlobalMenuTarget *global_menu_target = [GlobalMenuTarget shared_instance];
@@ -324,13 +323,11 @@ cocoa_create_global_menu(void) {
[NSApp setServicesProvider:[[[ServiceProvider alloc] init] autorelease]];
} // autoreleasepool
}
void
cocoa_update_menu_bar_title(PyObject *pytitle) {
NSString *title = [[NSString alloc] initWithUTF8String:PyUnicode_AsUTF8(pytitle)];
NSString *title = @(PyUnicode_AsUTF8(pytitle));
NSMenu *bar = [NSApp mainMenu];
if (title_menu != NULL) {
[bar removeItem:title_menu];
@@ -339,7 +336,6 @@ cocoa_update_menu_bar_title(PyObject *pytitle) {
NSMenu *m = [[NSMenu alloc] initWithTitle:[NSString stringWithFormat:@" :: %@", title]];
[title_menu setSubmenu:m];
[m release];
[title release];
} // }}}
bool
@@ -411,7 +407,7 @@ cocoa_get_lang(PyObject UNUSED *self) {
} // autoreleasepool
}
double
monotonic_t
cocoa_cursor_blink_interval(void) {
@autoreleasepool {
@@ -420,12 +416,12 @@ cocoa_cursor_blink_interval(void) {
double off_period_ms = [defaults doubleForKey:@"NSTextInsertionPointBlinkPeriodOff"];
double period_ms = [defaults doubleForKey:@"NSTextInsertionPointBlinkPeriod"];
double max_value = 60 * 1000.0, ans = -1.0;
if (on_period_ms || off_period_ms) {
if (on_period_ms != 0. || off_period_ms != 0.) {
ans = on_period_ms + off_period_ms;
} else if (period_ms) {
} else if (period_ms != 0.) {
ans = period_ms;
}
return ans > max_value ? 0.0 : ans;
return ans > max_value ? 0ll : ms_double_to_monotonic_t(ans);
} // autoreleasepool
}
@@ -477,6 +473,17 @@ cleanup() {
} // autoreleasepool
}
void
cocoa_hide_window_title(void *w)
{
@autoreleasepool {
NSWindow *window = (NSWindow*)w;
[window setTitleVisibility:NSWindowTitleHidden];
} // autoreleasepool
}
static PyMethodDef module_methods[] = {
{"cocoa_get_lang", (PyCFunction)cocoa_get_lang, METH_NOARGS, ""},
{"cocoa_set_new_window_trigger", (PyCFunction)cocoa_set_new_window_trigger, METH_VARARGS, ""},

View File

@@ -36,12 +36,12 @@ init_FG_BG_table(void) {
// colors 16..232: the 6x6x6 color cube
const uint8_t valuerange[6] = {0x00, 0x5f, 0x87, 0xaf, 0xd7, 0xff};
uint8_t i, j=16;
for(i = 0; i < 217; i++, j++) {
for(i = 0; i < 216; i++, j++) {
uint8_t r = valuerange[(i / 36) % 6], g = valuerange[(i / 6) % 6], b = valuerange[i % 6];
FG_BG_256[j] = (r << 16) | (g << 8) | b;
}
// colors 233..255: grayscale
for(i = 1; i < 24; i++, j++) {
// colors 232..255: grayscale
for(i = 0; i < 24; i++, j++) {
uint8_t v = 8 + i * 10;
FG_BG_256[j] = (v << 16) | (v << 8) | v;
}
@@ -98,6 +98,15 @@ update_ansi_color_table(ColorProfile *self, PyObject *val) {
Py_RETURN_NONE;
}
void
copy_color_profile(ColorProfile *dest, ColorProfile *src) {
memcpy(dest->color_table, src->color_table, sizeof(dest->color_table));
memcpy(dest->orig_color_table, src->orig_color_table, sizeof(dest->color_table));
memcpy(&dest->configured, &src->configured, sizeof(dest->configured));
memcpy(&dest->overridden, &src->overridden, sizeof(dest->overridden));
dest->dirty = true;
}
static PyObject*
patch_color_profiles(PyObject *module UNUSED, PyObject *args) {
PyObject *spec, *profiles, *v; ColorProfile *self; int change_configured; PyObject *cursor_text_color;

View File

@@ -16,7 +16,7 @@ from .shell import options_for_cmd
To add completion for a new shell, you need to:
1) Add an entry to completion scripts for your shell, this is
a simple function that call's kitty's completion code and passes the
a simple function that calls kitty's completion code and passes the
results to the shell's completion system. This can be output by
`kitty +complete setup shell_name` and its output goes into
your shell's rc file.
@@ -185,11 +185,37 @@ def kitty_cli_opts(ans, prefix=None):
def complete_kitty_cli_arg(ans, opt, prefix):
prefix = prefix or ''
if opt and opt['dest'] == 'override':
if not opt:
return
dest = opt['dest']
if dest == 'override':
from kitty.config import option_names_for_completion
k = 'Config directives'
ans.match_groups[k] = {k+'=': None for k in option_names_for_completion() if k.startswith(prefix)}
ans.no_space_groups.add(k)
elif dest == 'config':
def is_conf_file(x):
if os.path.isdir(x):
return True
return x.lower().endswith('.conf')
complete_files_and_dirs(ans, prefix, files_group_name='Config files', predicate=is_conf_file)
elif dest == 'session':
complete_files_and_dirs(ans, prefix, files_group_name='Session files')
elif dest == 'directory':
complete_files_and_dirs(ans, prefix, files_group_name='Directories', predicate=os.path.isdir)
elif dest == 'start_as':
k = 'Start as'
ans.match_groups[k] = {x: x for x in 'normal,fullscreen,maximized,minimized'.split(',') if x.startswith(prefix)}
ans.no_space_groups.add(k)
elif dest == 'listen_on':
if ':' not in prefix:
k = 'Address type'
ans.match_groups[k] = {x: x for x in ('unix:', 'tcp:') if x.startswith(prefix)}
ans.no_space_groups.add(k)
elif prefix.startswith('unix:') and not prefix.startswith('@'):
complete_files_and_dirs(ans, prefix[len('unix:'):], files_group_name='UNIX sockets', add_prefix='unix:')
def complete_alias_map(ans, words, new_word, option_map, complete_args=None):
@@ -273,9 +299,12 @@ def path_completion(prefix=''):
return dirs, files
def complete_files_and_dirs(ans, prefix, files_group_name='Files', predicate=None):
def complete_files_and_dirs(ans, prefix, files_group_name='Files', predicate=None, add_prefix=None):
dirs, files = path_completion(prefix or '')
files = filter(predicate, files)
if add_prefix:
dirs = (add_prefix + x for x in dirs)
files = (add_prefix + x for x in files)
if dirs:
ans.match_groups['Directories'] = dict.fromkeys(dirs)

View File

@@ -177,12 +177,11 @@ def load_config(Options, defaults, parse_config, merge_configs, *paths, override
if not path:
continue
try:
f = open(path, encoding='utf-8', errors='replace')
with open(path, encoding='utf-8', errors='replace') as f:
vals = parse_config(f)
except FileNotFoundError:
continue
with f:
vals = parse_config(f)
ans = merge_configs(ans, vals)
ans = merge_configs(ans, vals)
if overrides is not None:
vals = parse_config(overrides)
ans = merge_configs(ans, vals)

View File

@@ -20,21 +20,7 @@ from .conf.utils import (
from .config_data import all_options, parse_mods, type_map
from .constants import cache_dir, defconf, is_macos
from .utils import log_error
from .key_names import get_key_name_lookup
named_keys = {
"'": 'APOSTROPHE',
',': 'COMMA',
'-': 'MINUS',
'_': 'UNDERSCORE',
'.': 'PERIOD',
'/': 'SLASH',
';': 'SEMICOLON',
'=': 'EQUAL',
'[': 'LEFT_BRACKET',
']': 'RIGHT_BRACKET',
'`': 'GRAVE_ACCENT'
}
from .key_names import get_key_name_lookup, key_name_aliases
def parse_shortcut(sc):
@@ -45,7 +31,7 @@ def parse_shortcut(sc):
if mods is None:
return None, None, None
key = parts[-1].upper()
key = getattr(defines, 'GLFW_KEY_' + named_keys.get(key, key), None)
key = getattr(defines, 'GLFW_KEY_' + key_name_aliases.get(key, key), None)
is_native = False
if key is None:
q = parts[-1]
@@ -64,7 +50,8 @@ func_with_args, args_funcs = key_func()
@func_with_args(
'pass_selection_to_program', 'new_window', 'new_tab', 'new_os_window',
'new_window_with_cwd', 'new_tab_with_cwd', 'new_os_window_with_cwd'
'new_window_with_cwd', 'new_tab_with_cwd', 'new_os_window_with_cwd',
'launch'
)
def shlex_parse(func, rest):
return func, to_cmdline(rest)
@@ -106,6 +93,20 @@ def goto_tab_parse(func, rest):
return func, args
@func_with_args('detach_window')
def detach_window_parse(func, rest):
if rest not in ('new', 'new-tab', 'ask'):
rest = 'new'
return func, (rest,)
@func_with_args('detach_tab')
def detach_tab_parse(func, rest):
if rest not in ('new', 'ask'):
rest = 'new'
return func, (rest,)
@func_with_args('set_background_opacity', 'goto_layout', 'kitty_shell')
def simple_parse(func, rest):
return func, [rest]
@@ -207,6 +208,15 @@ def pipe(func, rest):
return func, rest
@func_with_args('set_colors')
def set_colors(func, rest):
import shlex
rest = shlex.split(rest)
if len(rest) < 1:
log_error('Too few arguments to set_colors function')
return func, rest
@func_with_args('nth_window')
def nth_window(func, rest):
try:
@@ -263,6 +273,21 @@ class KeyDefinition:
self.trigger = defines.resolve_key_mods(kitty_mod, self.trigger[0]), self.trigger[1], self.trigger[2]
self.rest = tuple((defines.resolve_key_mods(kitty_mod, mods), is_native, key) for mods, is_native, key in self.rest)
def resolve_kitten_aliases(self, aliases):
if not self.action.args:
return
kitten = self.action.args[0]
rest = self.action.args[1] if len(self.action.args) > 1 else ''
changed = False
for key, expanded in aliases.items():
if key == kitten:
changed = True
kitten = expanded[0]
if len(expanded) > 1:
rest = expanded[1] + ' ' + rest
if changed:
self.action = self.action._replace(args=[kitten + (' ' + rest).rstrip()])
def parse_key(val, key_definitions):
parts = val.split(maxsplit=1)
@@ -385,6 +410,13 @@ def handle_symbol_map(key, val, ans):
ans['symbol_map'].update(parse_symbol_map(val))
@special_handler
def handle_kitten_alias(key, val, ans):
parts = val.split(maxsplit=2)
if len(parts) >= 2:
ans['kitten_aliases'][parts[0]] = parts[1:]
@special_handler
def handle_send_text(key, val, ans):
# For legacy compatibility
@@ -407,6 +439,25 @@ def handle_deprecated_hide_window_decorations_aliases(key, val, ans):
ans['hide_window_decorations'] = True
@deprecated_handler('macos_show_window_title_in_menubar')
def handle_deprecated_macos_show_window_title_in_menubar_alias(key, val, ans):
if not hasattr(handle_deprecated_macos_show_window_title_in_menubar_alias, key):
handle_deprecated_macos_show_window_title_in_menubar_alias.key = True
log_error('The option {} is deprecated. Use macos_show_window_title_in menubar instead.'.format(key))
macos_show_window_title_in = ans.get('macos_show_window_title_in', 'all')
if to_bool(val):
if macos_show_window_title_in == 'none':
macos_show_window_title_in = 'menubar'
elif macos_show_window_title_in == 'window':
macos_show_window_title_in = 'all'
else:
if macos_show_window_title_in == 'all':
macos_show_window_title_in = 'window'
elif macos_show_window_title_in == 'menubar':
macos_show_window_title_in = 'none'
ans['macos_show_window_title_in'] = macos_show_window_title_in
def expandvars(val, env):
def sub(m):
@@ -444,7 +495,7 @@ def option_names_for_completion():
def parse_config(lines, check_keys=True, accumulate_bad_lines=None):
ans = {'symbol_map': {}, 'keymap': {}, 'sequence_map': {}, 'key_definitions': [], 'env': {}}
ans = {'symbol_map': {}, 'keymap': {}, 'sequence_map': {}, 'key_definitions': [], 'env': {}, 'kitten_aliases': {}}
parse_config_base(
lines,
defaults,
@@ -594,8 +645,11 @@ def finalize_keys(opts):
defns = []
else:
defns.append(d)
kitten_aliases = opts.kitten_aliases
for d in defns:
d.resolve(opts.kitty_mod)
if kitten_aliases and d.action.func == 'kitten':
d.resolve_kitten_aliases(kitten_aliases)
keymap = {}
sequence_map = {}

View File

@@ -112,7 +112,9 @@ Here, the key name for the :kbd:`A` key is :kbd:`0x61` and you can use it with::
to map :kbd:`ctrl+a` to something.
You can use the special action :code:`no_op` to unmap a keyboard shortcut that is
assigned in the default configuration.
assigned in the default configuration::
map kitty_mod+space no_op
You can combine multiple actions to be triggered by a single shortcut, using the
syntax below::
@@ -391,10 +393,13 @@ Use negative numbers to change scroll direction.'''))
g('mouse') # {{{
o('mouse_hide_wait', 3.0, option_type=float, long_text=_('''
o('mouse_hide_wait', 0.0 if is_macos else 3.0, option_type=float, long_text=_('''
Hide mouse cursor after the specified number of seconds
of the mouse not being used. Set to zero to disable mouse cursor hiding.
Set to a negative value to hide the mouse cursor immediately when typing text.'''))
Set to a negative value to hide the mouse cursor immediately when typing text.
Disabled by default on macOS as getting it to work robustly with
the ever-changing sea of bugs that is Cocoa is too much effort.
'''))
o('url_color', '#0087bd', option_type=to_color, long_text=_('''
The color and style for highlighting URLs on mouse-over.
@@ -461,7 +466,7 @@ The modifiers to override mouse selection even when a terminal application has g
o('select_by_word_characters', ':@-./_~?&=%+#', long_text=_('''
Characters considered part of a word when double clicking. In addition to these characters
any character that is marked as an alpha-numeric character in the unicode
any character that is marked as an alphanumeric character in the unicode
database will be matched.'''))
o('click_interval', -1.0, option_type=float, long_text=_('''
@@ -677,10 +682,10 @@ Which edge to show the tab bar on, top or bottom'''))
o('tab_bar_margin_width', 0.0, option_type=positive_float, long_text=_('''
The margin to the left and right of the tab bar (in pts)'''))
o('tab_bar_style', 'fade', option_type=choices('fade', 'separator', 'hidden'), long_text=_('''
The tab bar style, can be one of: :code:`fade`, :code:`separator` or :code:`hidden`. In the fade style,
each tab's edges fade into the background color, in the separator style, tabs are
separated by a configurable separator.
o('tab_bar_style', 'fade', option_type=choices('fade', 'separator', 'powerline', 'hidden'), long_text=_('''
The tab bar style, can be one of: :code:`fade`, :code:`separator`, :code:`powerline`, or :code:`hidden`.
In the fade style, each tab's edges fade into the background color, in the separator style, tabs are
separated by a configurable separator, and the powerline shows the tabs as a continuous line.
'''))
o('tab_bar_min_tabs', 2, option_type=lambda x: max(1, positive_int(x)), long_text=_('''
@@ -810,9 +815,9 @@ ensure that the shell starts in interactive mode and reads its startup rc files.
o('editor', '.', long_text=_('''
The console editor to use when editing the kitty config file or similar tasks.
A value of . means to use the environment variable EDITOR. Note that this
environment variable has to be set not just in your shell startup scripts but
system-wide, otherwise kitty will not see it.
A value of . means to use the environment variables VISUAL and EDITOR in that
order. Note that this environment variable has to be set not just in your shell
startup scripts but system-wide, otherwise kitty will not see it.
'''))
o('close_on_child_death', False, long_text=_('''
@@ -824,11 +829,23 @@ Note that setting it to yes means that any background processes still using the
terminal can fail silently because their stdout/stderr/stdin no longer work.
'''))
o('allow_remote_control', False, long_text=_('''
def allow_remote_control(x):
if x != 'socket-only':
x = 'y' if to_bool(x) else 'n'
return x
o('allow_remote_control', 'no', option_type=allow_remote_control, long_text=_('''
Allow other programs to control kitty. If you turn this on other programs can
control all aspects of kitty, including sending text to kitty windows,
opening new windows, closing windows, reading the content of windows, etc.
Note that this even works over ssh connections.
control all aspects of kitty, including sending text to kitty windows, opening
new windows, closing windows, reading the content of windows, etc. Note that
this even works over ssh connections. You can chose to either allow any program
running within kitty to control it, with :code:`yes` or only programs that
connect to the socket specified with the :option:`kitty --listen-on` command
line option, if you use the value :code:`socket-only`. The latter is useful if
you want to prevent programs running on a remote computer over ssh from
controlling kitty.
'''))
o(
@@ -964,9 +981,15 @@ o('macos_traditional_fullscreen', False, long_text=_('''
Use the traditional full-screen transition, that is faster, but less pretty.
'''))
o('macos_show_window_title_in_menubar', True, long_text=_('''
Show the title of the currently active window in the macOS
menu-bar, making use of otherwise wasted space.'''))
o('macos_show_window_title_in', 'all', option_type=choices('all', 'window', 'menubar', 'none'), long_text=_('''
Show or hide the window title in the macOS window or menu-bar.
A value of :code:`window` will show the title of the currently
active window at the top of the macOS window. A value of
:code:`menubar` will show the title of the currently active window
in the macOS menu-bar, making use of otherwise wasted space.
:code:`all` will show the title everywhere and :code:`none`
hides the title in the window and the menu-bar.
'''))
# Disabled by default because of https://github.com/kovidgoyal/kitty/issues/794
o('macos_custom_beam_cursor', False, long_text=_('''
@@ -992,6 +1015,14 @@ o('clear_all_shortcuts', False, long_text=_('''
You can have kitty remove all shortcut definition seen up to this point. Useful, for
instance, to remove the default shortcuts.'''))
o('kitten_alias', 'hints hints --hints-offset=0', add_to_default=False, long_text=_('''
You can create aliases for kitten names, this allows overriding the defaults
for kitten options and can also be used to shorten repeated mappings of the same
kitten with a specific group of options. For example, the above alias
changes the default value of :option:`kitty +kitten hints --hints-offset`
to zero for all mappings, including the builtin ones.
'''))
g('shortcuts.clipboard') # {{{
k('copy_to_clipboard', 'kitty_mod+c', 'copy_to_clipboard', _('Copy to clipboard'), long_text=_('''
There is also a :code:`copy_or_interrupt` action that can be optionally mapped to :kbd:`Ctrl+c`.
@@ -1045,13 +1076,13 @@ if is_macos:
k('show_scrollback', 'kitty_mod+h', 'show_scrollback', _('Browse scrollback buffer in less'), long_text=_('''
You can pipe the contents of the current screen + history buffer as
:file:`STDIN` to an arbitrary program using the ``pipe`` function. For example,
:file:`STDIN` to an arbitrary program using the ``launch`` function. For example,
the following opens the scrollback buffer in less in an overlay window::
map f1 pipe @ansi overlay less +G -R
map f1 launch --stdin-source=@screen_scrollback --stdin-add-formatting --type=overlay less +G -R
For more details on piping screen and buffer contents to external programs,
see :doc:`pipe`.
see :doc:`launch`.
'''))
@@ -1061,30 +1092,33 @@ g('shortcuts.window') # {{{
k('new_window', 'kitty_mod+enter', 'new_window', _(''), long_text=_('''
You can open a new window running an arbitrary program, for example::
map kitty_mod+y new_window mutt
map kitty_mod+y launch mutt
You can open a new window with the current working directory set to the
working directory of the current window using::
map ctrl+alt+enter new_window_with_cwd
map ctrl+alt+enter launch --cwd=current
You can open a new window that is allowed to control kitty via
the kitty remote control facility by prefixing the command line with @.
Any programs running in that window will be allowed to control kitty.
For example::
map ctrl+enter new_window @ some_program
map ctrl+enter launch --allow-remote-control some_program
You can open a new window next to the currently active window or as the first window,
with::
map ctrl+n new_window !neighbor some_program
map ctrl+f new_window !first some_program
map ctrl+n launch --location=neighbor some_program
map ctrl+f launch --location=first some_program
For more details, see :doc:`launch`.
'''))
if is_macos:
k('new_window', 'cmd+enter', 'new_window', _('New window'), add_to_docs=False)
k('new_os_window', 'kitty_mod+n', 'new_os_window', _('New OS window'))
k('new_os_window', 'kitty_mod+n', 'new_os_window', _('New OS window'), _(
'Works like new_window above, except that it opens a top level OS kitty window.'
' In particular you can use new_os_window_with_cwd to open a window with the current working directory.'))
if is_macos:
k('new_os_window', 'cmd+n', 'new_os_window', _('New OS window'), add_to_docs=False)
k('close_window', 'kitty_mod+w', 'close_window', _('Close window'))

View File

@@ -9,7 +9,7 @@ from collections import namedtuple
from contextlib import suppress
appname = 'kitty'
version = (0, 14, 3)
version = (0, 15, 0)
str_version = '.'.join(map(str, version))
_plat = sys.platform.lower()
is_macos = 'darwin' in _plat
@@ -25,7 +25,7 @@ def kitty_exe():
if ans is None:
rpath = sys._xoptions.get('bundle_exe_dir')
if not rpath:
items = os.environ['PATH'].split(os.pathsep)
items = filter(None, os.environ.get('PATH', '').split(os.pathsep))
seen = set()
for candidate in items:
if candidate not in seen:
@@ -49,9 +49,8 @@ def _get_config_dir():
locations.append(os.path.expanduser('~/.config'))
if is_macos:
locations.append(os.path.expanduser('~/Library/Preferences'))
if 'XDG_CONFIG_DIRS' in os.environ:
for loc in os.environ['XDG_CONFIG_DIRS'].split(os.pathsep):
locations.append(os.path.abspath(os.path.expanduser(loc)))
for loc in filter(None, os.environ.get('XDG_CONFIG_DIRS', '').split(os.pathsep)):
locations.append(os.path.abspath(os.path.expanduser(loc)))
for loc in locations:
if loc:
q = os.path.join(loc, appname)

View File

@@ -278,7 +278,7 @@ get_glyph_width(PyObject *s, glyph_index g) {
CGGlyph gg = g;
CGRect bounds;
CTFontGetBoundingRectsForGlyphs(self->ct_font, kCTFontOrientationHorizontal, &gg, &bounds, 1);
return bounds.size.width;
return (int)ceil(bounds.size.width);
}
static inline float
@@ -326,7 +326,7 @@ cell_metrics(PyObject *s, unsigned int* cell_width, unsigned int* cell_height, u
}
}
*cell_width = MAX(1u, width);
*underline_position = floor(self->ascent - self->underline_position + 0.5);
*underline_position = (unsigned int)floor(self->ascent - self->underline_position + 0.5);
*underline_thickness = (unsigned int)ceil(MAX(0.1, self->underline_thickness));
*baseline = (unsigned int)self->ascent;
// float line_height = MAX(1, floor(self->ascent + self->descent + MAX(0, self->leading) + 0.5));
@@ -437,7 +437,7 @@ render_glyphs(CTFontRef font, unsigned int width, unsigned int height, unsigned
CGContextSetShouldSmoothFonts(render_ctx, true);
CGContextSetGrayFillColor(render_ctx, 1, 1); // white glyphs
CGContextSetGrayStrokeColor(render_ctx, 1, 1);
CGContextSetLineWidth(render_ctx, global_state.opts.macos_thicken_font);
CGContextSetLineWidth(render_ctx, OPT(macos_thicken_font));
CGContextSetTextDrawingMode(render_ctx, kCGTextFillStroke);
CGContextSetTextMatrix(render_ctx, CGAffineTransformIdentity);
CGContextSetTextPosition(render_ctx, 0, height - baseline);
@@ -457,7 +457,7 @@ render_simple_text_impl(PyObject *s, const char *text, unsigned int baseline) {
CTFontGetGlyphsForCharacters(font, chars, glyphs, num_chars);
CTFontGetAdvancesForGlyphs(font, kCTFontOrientationDefault, glyphs, advances, num_chars);
CGRect bounding_box = CTFontGetBoundingRectsForGlyphs(font, kCTFontOrientationDefault, glyphs, boxes, num_chars);
StringCanvas ans = { .width = 0, .height = 2 * bounding_box.size.height };
StringCanvas ans = { .width = 0, .height = (size_t)(2 * bounding_box.size.height) };
for (size_t i = 0, y = 0; i < num_chars; i++) {
positions[i] = CGPointMake(ans.width, y);
ans.width += advances[i].width; y += advances[i].height;
@@ -530,6 +530,14 @@ static PyMethodDef methods[] = {
{NULL} /* Sentinel */
};
const char*
postscript_name_for_face(const PyObject *face_) {
const CTFace *self = (const CTFace*)face_;
if (self->postscript_name) return PyUnicode_AsUTF8(self->postscript_name);
return "";
}
static PyObject *
repr(CTFace *self) {
char buf[1024] = {0};

Some files were not shown because too many files have changed in this diff Show More