Compare commits

..

1073 Commits

Author SHA1 Message Date
Kovid Goyal
36a20f7b00 Temporarily disable spawn test as it is failing in the Linux build container
Will investigate later
2020-06-23 17:37:04 +05:30
Kovid Goyal
35cbf49b08 version 0.18.1 2020-06-23 17:29:22 +05:30
Kovid Goyal
21836cedda Merge branch 'glfw_upstream' of https://github.com/Luflosi/kitty 2020-06-21 22:07:44 +05:30
Luflosi
0a892b72e6 Fix GLU header inclusion being disabled
From upstream: 81f475bccb.
2020-06-21 18:07:31 +02:00
Kovid Goyal
2c6e5a6e73 Get multiprocessing working in kitty
Monkeypatch the stdlib multiprocessing module to
use kitty as its python interpreter for spawning worker
processes.
2020-06-21 14:47:24 +05:30
Kovid Goyal
2cb25cf5a8 Build the launcher when freezing on macOS as well
Can be used by the test suite
2020-06-21 14:37:36 +05:30
Kovid Goyal
e07916425e macOS: Fix for diff kitten not working with python 3.8
Fixes #2780
2020-06-20 19:03:45 +05:30
Kovid Goyal
f62e2374e4 Ensure mimetype is sent to github 2020-06-20 13:02:34 +05:30
Kovid Goyal
eb4ee2f0af version 0.18.0 2020-06-20 12:48:59 +05:30
Kovid Goyal
be3c76da20 Fix remote control command docs order randomized 2020-06-20 12:45:05 +05:30
Kovid Goyal
b15e58621c Fix the kitty shell launched via a mapping needlessly requiring :opt:allow_remote_control to be turned on. 2020-06-20 12:43:46 +05:30
Kovid Goyal
601a6c9e3d Allow sending arbitrary signals to the current foreground process in a window using either a mapping in kitty.conf or via remote control
Fixes #2778
2020-06-20 12:37:27 +05:30
Kovid Goyal
3ff184348e Merge branch 'unused-macro' of https://github.com/Luflosi/kitty 2020-06-19 18:33:28 +05:30
Luflosi
c8efcd2be1 Remove unused macro 2020-06-19 14:31:58 +02:00
Kovid Goyal
9c116a2975 Fix #2776 2020-06-19 12:13:32 +05:30
Kovid Goyal
8818b5d8df Set CFBundleAllowMixedLocalizations in the app bundle to have NSLocale.currentLocale return the correct locale on non-English systems 2020-06-18 20:16:36 +05:30
Kovid Goyal
e96dfadae7 Ensure cocoa_get_lang() returns a valid locale or None
See #1233
2020-06-18 20:15:01 +05:30
Kovid Goyal
deb564e5a6 Even more integrations 2020-06-17 18:09:34 +05:30
Kovid Goyal
ffc71c348c A couple more integrations with external tools 2020-06-17 18:07:19 +05:30
Kovid Goyal
19df7b94ea Clarify documentation a bit 2020-06-16 09:53:08 +05:30
Kovid Goyal
a3ecc79f0d Dont actually need -- since kitty's option processing code is smart enough to stop looking for options after the first non-optional argument 2020-06-16 09:31:42 +05:30
Kovid Goyal
b140b15119 Add a -- to linenum hints examples 2020-06-16 08:30:34 +05:30
Kovid Goyal
b7b2b6075a Add mdcat 2020-06-15 09:31:51 +05:30
Kovid Goyal
7525e152b8 Make comment a bit better 2020-06-15 06:55:52 +05:30
Kovid Goyal
bc9dfec615 Fix #2764 2020-06-15 06:53:35 +05:30
Kovid Goyal
7824739034 Ensure selection GPU buffer is refreshed after a resize
Fixes #2747 (I hope since I cannot reproduce)
2020-06-13 22:59:46 +05:30
Kovid Goyal
e7b60a3628 Fix #2763 2020-06-13 20:09:26 +05:30
Kovid Goyal
97c3061b8f Allow having no tab separator
Fixes #2761
2020-06-13 12:33:15 +05:30
Kovid Goyal
1a042c873c Add a link to vim-test 2020-06-11 08:02:17 +05:30
Kovid Goyal
064aa3a150 Wayland: Ensure cursor theme is loaded before trying to set cursor 2020-06-11 07:57:08 +05:30
Kovid Goyal
8a178ebe55 Wayland: Apply the same framebuffer selection optimisation
Not as much of a win, since EGL only causes approx 1K getpid() calls of
which this optimization eliminates only half
2020-06-09 21:59:25 +05:30
Kovid Goyal
9a97f0bced X11: Further reduce startup time
Use the GLX 1.3 API function to choose the best framebuffer config
instead of doing it ourselves. Reduces the number fo getpid() calls by
a further ~15K
2020-06-09 20:18:07 +05:30
Kovid Goyal
5c7471910d Fix #2752 2020-06-09 09:51:15 +05:30
Kovid Goyal
27b6517594 X11: Reduce startup time by ~25% by only querying GLX for framebuffer configurations once
On my system reduces the number of getpid() calls from 67982 to 17327
I dont know why get framebuffer config attributes requires getpid() and
why it is so slow, probably a driver bug. Fixes #2754
2020-06-09 01:04:09 +05:30
Kovid Goyal
cd4dacb406 Fix #2753 2020-06-08 21:40:59 +05:30
Kovid Goyal
5f6faa1bf0 Make a central list of integrations in the docs
Fixes #2750
2020-06-08 14:49:59 +05:30
Kovid Goyal
cfc5a952f8 Add --no-response to @ last-used-layout 2020-06-08 09:16:26 +05:30
Kovid Goyal
10b186957b Update link to termpdf.py 2020-06-08 08:57:50 +05:30
Kovid Goyal
f597481736 Update changelog for last merge 2020-06-06 22:32:52 +05:30
Kovid Goyal
9fa97e6187 Merge branch 'mouse-events' of https://github.com/trygveaa/kitty 2020-06-06 22:27:54 +05:30
Kovid Goyal
3844321f20 Use a multiple of 8 size for mouse_button_pressed 2020-06-06 22:24:01 +05:30
Trygve Aaberge
8efe08c45b Support more mouse buttons for terminal mouse events
Previously, the mouse back and forward buttons sent the same codes as
scroll up and down. Now they instead send the same codes as xterm. Mouse
button 10 (in X11 numbering) also now sends the same as xterm, instead
of not sending anything.

This also changes the `send_mouse_event` function which can be called
from kittens to use X11 numbering for mouse buttons instead of what it
previously used, which turns out to be a hybrid of X11 and GLFW. It was
documented to use GLFW numbering, but GLFW doesn't have numbers for
scroll events (that's separate events with x/y offsets) and 4 and 5 in
GLFW is actually back and forward, while `send_mouse_event` interpreted
it as scroll up and down.

That means that this is a breaking change for `send_mouse_event` because
it swaps the number for the middle and right button to be consistent
with X11. I did this because I think it's better to use one consistent
numbering scheme for the function, and because people probably know X11
numbering better than GLFW numbering and GLFW doesn't have numbers for
the scroll buttons.
2020-06-06 14:19:06 +02:00
Trygve Aaberge
c78563b452 Report modifier key state when sending move and drag events to the terminal program 2020-06-06 12:28:42 +02:00
Trygve Aaberge
122e172092 Track modifier state correctly
When a modifier key is pressed, that modifier is not included in mods.
When it is released, it is included. Therefore, we have to special case
the modifier keys when storing the modifiers that are active. When a
modifier key is pressed, we add the modifier to
mods_at_last_key_or_button_event, and when it is released, we remove it.

This fixes an issue where move and drag events would still be sent to
the terminal program after pressing shift, but would stop being sent
after releasing shift until another key or button was pressed.
2020-06-06 12:28:42 +02:00
Kovid Goyal
8f85c0d167 Use bypy in update-on-ubuntu 2020-06-06 09:23:36 +05:30
Kovid Goyal
ac6d1ce174 Use bypy in the publish script 2020-06-06 09:19:48 +05:30
Kovid Goyal
03e0bf4c0e Migrate update-on-ox to use bypy 2020-06-06 09:11:50 +05:30
Kovid Goyal
1cb183f5e1 Add a note about what sort of ligatures disable_ligatures affects 2020-06-06 09:11:32 +05:30
Kovid Goyal
d78a553910 Fix #2739 2020-06-06 07:50:43 +05:30
Kovid Goyal
1326532850 macOS: Notarize the kitty application
This required the kitty package to be moved from Frameworks to
Resources, because Apple cant codesign .pyc files and its notarization
requires everything in Frameworks to be signed. Hopefully that does not
break anything. Also removed the kitty-deref-symlink since it is not
needed anyway and was only present for backwards compatibility.

Fixes #2040
2020-06-05 22:52:30 +05:30
Kovid Goyal
408508247d Merge branch 'replace_glfw_true' of https://github.com/Luflosi/kitty 2020-06-05 22:32:53 +05:30
Luflosi
e2be09e028 Remove GLFW_TRUE in comment
In 55ad228166 I forgot to replace `GLFW_TRUE` with `true` in a comment.
2020-06-05 18:51:50 +02:00
Kovid Goyal
c7c14f184c X11: Recompile keymaps on XkbNewKeyboardNotify events
Hopefully fixes #2726
2020-06-05 22:11:15 +05:30
Kovid Goyal
24ca919f33 Merge branch 'fake_scroll_correct_window' of https://github.com/Luflosi/kitty 2020-06-05 20:20:40 +05:30
Luflosi
85fe783652 Fix fake scroll when scrolling in unfocused kitty window
Scrolling should happen in the kitty window under the mouse cursor, not in the currently active kitty window.
2020-06-05 16:44:11 +02:00
Kovid Goyal
04b6bf3b74 bypy builds on macOS 2020-06-05 19:38:00 +05:30
Kovid Goyal
8b2fb105d0 Fix #2735 2020-06-05 19:24:40 +05:30
Kovid Goyal
558caa232d Merge branch 'glfw_upstream' of https://github.com/Luflosi/kitty 2020-06-05 07:10:39 +05:30
Luflosi
d8886edbeb Null: Make platform more conformant
From upstream: e0c77f71f9.
2020-06-05 00:27:47 +02:00
Kovid Goyal
f72ecf1791 Start work on building macOS binary with bypy 2020-06-04 23:18:48 +05:30
Kovid Goyal
45d1b978d8 bypy now builds the Linux binary 2020-06-04 19:54:01 +05:30
Kovid Goyal
0b780cc065 Merge branch 'glfw_upstream' of https://github.com/Luflosi/kitty 2020-06-04 19:24:40 +05:30
Luflosi
5263f6598c Add feature available/implemented errors
From upstream: 9a87c2a4b4.
2020-06-04 13:55:52 +02:00
Kovid Goyal
f9e60e7ef6 Start work on using bypy to build the binaries 2020-06-04 13:51:50 +05:30
Kovid Goyal
45c00d0b1f Merge branch 'glfw_upstream' of https://github.com/Luflosi/kitty 2020-06-04 07:15:09 +05:30
Luflosi
c70e2f7d3e Add statement to docs for glfwTerminate
From upstream: 7486e12f88.
2020-06-03 20:07:09 +02:00
Kovid Goyal
1ec0bed1ce Merge branch 'glfw_upstream' of https://github.com/Luflosi/kitty 2020-06-03 22:45:24 +05:30
Luflosi
46b5e4513a Win32: Fix VS /W4 compile warnings
From upstream: a84a30ab63.
2020-06-03 19:05:05 +02:00
Kovid Goyal
ffb5196f3b Merge branch 'glfw_upstream' of https://github.com/Luflosi/kitty 2020-06-03 22:04:21 +05:30
Luflosi
107f1af3c4 Fix desktop GL header not always being suppressed
From upstream: 105cf32e0b.
2020-06-03 11:32:59 +02:00
Kovid Goyal
03b1484c96 Wayland: Abort on fatal error should bypass quit confirmation 2020-06-03 14:39:27 +05:30
Kovid Goyal
aaf64ad63e Add links to config settings to change mouse modifiers in the main mouse docs 2020-06-03 08:17:28 +05:30
Kovid Goyal
f548e795d5 Merge branch 'glfw_upstream' of https://github.com/Luflosi/kitty 2020-06-02 17:05:02 +05:30
Luflosi
767da68239 Reduce difference to GLFW upstream
Only whitespace, formatting and comments were changed. This does not alter any functionality.
2020-06-02 11:45:08 +02:00
Kovid Goyal
f44e0ff4bd Merge branch 'patch-1' of https://github.com/TheDaemoness/kitty 2020-06-02 10:54:44 +05:30
TheDaemoness
7f226f2ea1 Avoid incrementing hidden cursors' images 2020-06-02 05:10:51 +00:00
Kovid Goyal
1c82a39a6e Merge branch 'glfw_upstream' of https://github.com/Luflosi/kitty 2020-06-02 08:13:33 +05:30
Kovid Goyal
b70cf276b4 Change the cursor image immediately on scale change 2020-06-02 08:09:27 +05:30
Kovid Goyal
80b2df2ef4 Better code when using a stack cursor 2020-06-02 07:59:32 +05:30
Kovid Goyal
ad27452275 Wayland: Avoid infinite timer fires if arrow cursor is animated 2020-06-02 07:53:15 +05:30
Kovid Goyal
196a0b6b7e Merge branch 'patch-1' of https://github.com/TheDaemoness/kitty 2020-06-02 07:49:57 +05:30
Luflosi
f356f63994 wayland: save serial from all input sources
From upstream: 92b3fd02e5.
2020-06-01 21:29:14 +02:00
TheDaemoness
4947fb6b57 Fix a missing cursorWayland-scale assignment. 2020-06-01 17:41:16 +00:00
Kovid Goyal
622f12b84e Add a changelog entry for wayland hidpi cursors 2020-06-01 21:26:18 +05:30
Kovid Goyal
c1f84ce603 cleanup for wayland hidpi cursors merge 2020-06-01 21:14:56 +05:30
Kovid Goyal
14912461ad Use left_ptr as default arrow cursor on Wayland
Matches X11.
2020-06-01 20:33:54 +05:30
Kovid Goyal
a9f265e8b7 Initialize a couple of local vars 2020-06-01 20:33:54 +05:30
TheDaemoness
199ee20adb Fixed an instance of eager cursor loading.
Also fixed a minor formatting issue.
2020-06-01 20:33:53 +05:30
TheDaemoness
7c3c87abf6 Initial implementation of proper HiDPI cursor support on Wayland. 2020-06-01 20:33:53 +05:30
Kovid Goyal
b0ad44bcf2 Fix #2714 2020-06-01 20:31:05 +05:30
Kovid Goyal
9ba808ec3c Merge branch 'ft/csi-code-rep' of https://github.com/keynslug/kitty 2020-06-01 14:31:34 +05:30
Kovid Goyal
eacf849e3a Add bounds check to left_shift_line()
Fixes #2710
2020-05-31 08:10:58 +05:30
Andrew Mayorov
42c2791182 Do not cap repetitions by row length
Instead cap by 65535 as a safeguard. This is more in line with ECMA 48.
2020-05-29 20:36:30 +03:00
Andrew Mayorov
390e883ecf Update terminfo with CSI REP support 2020-05-29 01:06:16 +03:00
Andrew Mayorov
9fe631ee3f Provide support for CSI REP control code 2020-05-29 01:05:49 +03:00
Kovid Goyal
82d8c4b230 Fix #2699 2020-05-27 20:18:05 +05:30
Kovid Goyal
9775bb0a9d Merge branch 'patch-1' of https://github.com/aslpavel/kitty 2020-05-27 09:05:09 +05:30
Pavel
139c9a2d6d Fix incorrect examples in graphic protocol
Examples in `Deleting images` section were incorrect.
2020-05-26 20:39:31 +01:00
Kovid Goyal
542880f87b Merge branch 'glfw_upstream' of https://github.com/Luflosi/kitty 2020-05-25 22:17:42 +05:30
Luflosi
3846286bee Wayland: Implement raw mouse motion control
From upstream: 44af6bb936.
2020-05-25 18:21:32 +02:00
Kovid Goyal
72be402a2d Merge branch 'glfw_upstream' of https://github.com/Luflosi/kitty 2020-05-25 21:47:56 +05:30
Luflosi
c6b9cb759a Wayland: Rename handlers for more unicity
From upstream: 754b7feaa1.

1fa66ca45d didn't include the changes to `wl_window.c`.
2020-05-25 15:29:17 +02:00
Kovid Goyal
13ccf269a6 Merge branch 'glfw_upstream' of https://github.com/Luflosi/kitty 2020-05-25 15:25:01 +05:30
Luflosi
fcc7a0255a Align joystick axis to gamepad button behavior
From upstream: 02874d9c14.
2020-05-25 11:44:14 +02:00
Luflosi
e7447f38cf Fix half-axis to gamepad button value mapping
From upstream: c32dc3a085.
2020-05-25 11:44:02 +02:00
Kovid Goyal
7ae35631a6 Merge branch 'glfw_upstream' of https://github.com/Luflosi/kitty 2020-05-25 10:32:54 +05:30
Luflosi
55ad228166 Rename raw input to raw mouse motion, cleanup
From upstream: 1155c83013.
2020-05-24 21:57:29 +02:00
Luflosi
48fb051253 Add GLFW_RAW_INPUT and glfwRawInputSupported
From upstream: 9e29f556fd.
2020-05-24 20:49:52 +02:00
Kovid Goyal
f97e8b7eeb The title for @ set-window-title is optional 2020-05-24 21:51:33 +05:30
Kovid Goyal
84f914742b Fix command names using undersore instead of hyphens in completion for the shell 2020-05-24 21:34:34 +05:30
Kovid Goyal
0d704f3715 kitty shell: show the previously active window id 2020-05-24 16:40:10 +05:30
Kovid Goyal
d8896eb210 Fix #2688 2020-05-24 12:40:54 +05:30
Kovid Goyal
b9d74e2012 Merge branch 'glfw_upstream' of https://github.com/Luflosi/kitty 2020-05-24 08:16:51 +05:30
Luflosi
803fba9cfd Cocoa: Replace display link with IOKit query
From upstream: 4ec7daf3e9.
2020-05-23 16:28:31 +02:00
Kovid Goyal
581548ed67 Merge branch 'freebsd' of https://github.com/rkitover/kitty 2020-05-23 19:56:51 +05:30
Kovid Goyal
9a8c0f8e7e Merge branch 'cut_utf-8' of https://github.com/Luflosi/kitty 2020-05-23 19:53:40 +05:30
Rafael Kitover
328f569c16 Fix child spawn on FreeBSD.
Fix typo: "#ifdef TIOCSTTY" -> "#ifdef TIOCSCTTY"

Include standard header sys/ioctl.h for ioctl(), needed on MacOS.

Include standard header termios.h for TIOCSCTTY.

Fixes this error on spawn of child shell process:

bash: cannot set terminal process group (-1): Inappropriate ioctl for
device
bash: no job control in this shell

Tested on FreeBSD and Linux.

- Fix #2529

Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2020-05-23 12:21:57 +00:00
Luflosi
7931654a7c Ensure valid UTF-8 when cutting string 2020-05-23 13:59:23 +02:00
Kovid Goyal
6eb0c10339 Merge branch 'glfw_upstream' of https://github.com/Luflosi/kitty 2020-05-23 17:24:03 +05:30
Luflosi
269f294d19 Use CALayer instead of NSView for EGLNativeWindowType
From upstream: 91eebe922d.
2020-05-23 12:48:26 +02:00
Kovid Goyal
d19e2f1350 Merge branch 'glfw_upstream' of https://github.com/Luflosi/kitty 2020-05-23 16:17:30 +05:30
Luflosi
3b745b82db X11: Clarify function name and comment
From upstream: 5f9dfe3d83.
2020-05-23 11:34:17 +02:00
Kovid Goyal
02f30c2a03 Merge branch 'master' of https://github.com/ahlinc/kitty 2020-05-23 10:47:26 +05:30
Andrew Hlynskyi
54002b386a Fixed issue with a cwd for kitty_mod+h scroll buffer viewer
There is an issue with ability to save scroll buffer from a default less
scroll buffer viewer by just typing relative path to an output file,
because the running less instance inherits cwd from Kitty's cwd
instead of cwd of active window.

How to reproduce:
  1. Start Kitty.
  2. Go to some place.
  3. Press 'kitty_mod+h'
  4. Press 's' and you'll see a less prompt like 'log file:'
  5. Type a just file name without any path and press Enter then press 'q'
  6. See that there is no such file in a current shell directory.
2020-05-23 07:19:45 +03:00
Kovid Goyal
0e2ff077af Fix #2682 2020-05-23 09:03:44 +05:30
Kovid Goyal
012cf70321 Merge branch 'glfw_upstream' of https://github.com/Luflosi/kitty 2020-05-23 07:22:07 +05:30
Luflosi
9da0ba52db X11: Clarify code flow for Clang static analysis
From upstream: ef5220d6b1.
2020-05-22 23:32:12 +02:00
Kovid Goyal
7bfb07e59e Merge branch 'simplify' of https://github.com/Luflosi/kitty 2020-05-22 19:58:48 +05:30
Luflosi
9cb2c4b1ff Simplify code
There is already a check if `m` is `NULL`, so there is no need for a second `NULL` check after that.
2020-05-22 16:04:28 +02:00
Kovid Goyal
8c088fad0f Merge branch 'master' of https://github.com/ahlinc/kitty 2020-05-22 08:23:55 +05:30
Andrew Hlynskyi
392722aed0 Fixed misprint in .github/ISSUE_TEMPLATE/bug_report.md 2020-05-21 22:24:04 +03:00
Kovid Goyal
fabfb30fc4 Merge branch 'convert-tabs-to-spaces' of https://github.com/Luflosi/kitty 2020-05-21 19:51:02 +05:30
Luflosi
c7cb021e92 Convert two tabs to spaces
The rest of the file is also indented with spaces.
2020-05-21 15:34:08 +02:00
Kovid Goyal
be05d9c3e9 Proper confirm_os_window_close check condition 2020-05-21 15:12:20 +05:30
Kovid Goyal
e38690e8d9 Dont link against librt and libdl on OpenBSD
These are part of libc there
2020-05-21 11:43:55 +05:30
Kovid Goyal
7172115559 Merge branch 'patch-1' of https://github.com/TheDaemoness/kitty 2020-05-21 07:37:56 +05:30
TheDaemoness
7314019832 Fixed a typo and added some missing files. 2020-05-20 20:10:37 +00:00
TheDaemoness
b9684941c4 Create .editorconfig
[Most major editors](https://editorconfig.org/#download) support EditorConfig for declaring per-file per-project indentation rules. It costs almost nothing to maintain, and it makes it easier to follow the coding styles already used in kitty.
2020-05-20 19:46:13 +00:00
Kovid Goyal
a27289352c Merge branch 'master' of https://github.com/ahlinc/kitty 2020-05-20 19:56:58 +05:30
Andrew Hlynskyi
dc77009e55 Fixed confirm_os_window_close bug introduced in commit 7bf83603c8 2020-05-20 15:29:21 +03:00
Kovid Goyal
d12e10830d Wayland: Fix kitty being killed on some Wayland compositors if a hidden window has a lot of output
Sway falls over and dies if it receives many render frame
requests. So send only a single one per damaged window and hope and pray
that the compositor hasn't dropped it. Shrug, Wayland, no surprise.
Fixes #2329
2020-05-20 14:19:09 +05:30
Kovid Goyal
936f6c22f0 Merge branch 'configure_library_paths' of https://github.com/Luflosi/kitty 2020-05-20 07:17:07 +05:30
Kovid Goyal
9712be903d Fix #2667 2020-05-20 07:05:35 +05:30
Luflosi
7441cefdbb Make paths to libraries configurable at build time 2020-05-19 18:36:46 +02:00
Kovid Goyal
7bf83603c8 Forgot to treat confirm_os_window_close as a count 2020-05-19 08:19:17 +05:30
Kovid Goyal
6768bc1705 Fix SIGTERM/SIGINT on macOS causing kitty to enter an infinite loop 2020-05-18 17:53:35 +05:30
Kovid Goyal
707cb37212 Have the confirm on close also apply to quitting kitty
Use a dedicated API for handling quit requests on macOS rather than a
quit canary. Also create a mappable "quit" action for all platforms.
2020-05-18 16:06:40 +05:30
Kovid Goyal
1cf0a8b78e Allow only a single OS window close confirmation per OS window 2020-05-18 13:56:19 +05:30
Kovid Goyal
3d2cb37af0 Linux: Workaround for broken Nvidia drivers for old cards
Fixes #456
2020-05-18 13:41:23 +05:30
Kovid Goyal
09fbd6f5e0 Merge branch 'master' of https://github.com/ahlinc/kitty 2020-05-18 09:59:31 +05:30
Andrew Hlynskyi
474bef65cb Fixed marks grouping and coloring for simultaneous multi marks definition 2020-05-18 06:53:56 +03:00
Kovid Goyal
e97454c4a5 And ever more coalesce tests 2020-05-17 23:20:26 +05:30
Kovid Goyal
936dc74a27 Some more coalesce tests 2020-05-17 23:08:27 +05:30
Kovid Goyal
362e4266bb Better coalescing of multiple symbol_maps
When specifying multiple symbol_map values in kitty.conf later ones
should override conflicting previous ones. Fixes #2662
2020-05-17 23:03:28 +05:30
Kovid Goyal
d08f2e10f1 Add bug label to bug bug report template 2020-05-17 13:12:35 +05:30
Kovid Goyal
f1e5ee74a6 Add a feature request template 2020-05-17 13:11:23 +05:30
Kovid Goyal
7832d33348 Add a bug report template 2020-05-17 13:07:49 +05:30
Kovid Goyal
de25f94fae When extending selections to words, recognize ://
As part of the word even if : is not in select_word_chars. This allows
double-clicking to select common URLs with the default select_word_chars
2020-05-16 13:49:39 +05:30
Kovid Goyal
98625e9c36 Add an option confirm_on_os_window_close to ask for confirmation when closing an OS window with multiple kitty windows. 2020-05-15 13:39:58 +05:30
Kovid Goyal
5768cc98b6 ... 2020-05-15 13:31:35 +05:30
Kovid Goyal
da1cc6c1c5 Add a yes/no mode to the ask kitten 2020-05-15 13:16:14 +05:30
Kovid Goyal
50384fac97 DRYer 2020-05-14 09:18:29 +05:30
Kovid Goyal
424bd8a6cd Only compile tab template once 2020-05-14 09:15:11 +05:30
Kovid Goyal
421fae2b57 Merge branch 'fix/tab-title-template-f-string' of https://github.com/chriszarate/kitty 2020-05-14 09:09:18 +05:30
chriszarate
8bb8615a5a Compile template and restrict globals for eval 2020-05-13 23:30:12 -04:00
Kovid Goyal
80f8692e92 Tall/fat layout: Fix resizing of windows when number of windows is <= num of full size windows not working 2020-05-13 23:33:23 +05:30
Kovid Goyal
25623c758d Tall and Fat layouts: Add a `mirrored` option to put the full size window on the opposite edge of the screen
Fixes #2654
2020-05-13 23:19:34 +05:30
Kovid Goyal
e1a0a195a9 Forgot to change one call site for switch_focus_to 2020-05-13 21:39:26 +05:30
Kovid Goyal
f8cf49a90c Merge branch 'simplify' of https://github.com/Luflosi/kitty 2020-05-13 17:22:39 +05:30
Luflosi
ac9f8595c9 DRYer
Don't write `cppflags.extend()` twice.
2020-05-13 13:43:43 +02:00
Kovid Goyal
97f22bbff6 Update changelog 2020-05-13 11:01:04 +05:30
chriszarate
d6ddfa9d18 Use f-string instead of format for tab_title templates 2020-05-12 22:29:03 -04:00
Kovid Goyal
5e48ae8bac pep8 2020-05-12 22:54:08 +05:30
Kovid Goyal
cdd943ded4 Port layout tests to new API 2020-05-12 22:43:55 +05:30
Kovid Goyal
39b2bf963c Port the splits layout to the new groups API 2020-05-12 22:43:54 +05:30
Kovid Goyal
06827fd437 Update docs to point to new layouts package 2020-05-12 22:43:54 +05:30
Kovid Goyal
70ccc1cf6d Port Grid layout to new groups API 2020-05-12 22:43:54 +05:30
Kovid Goyal
f801c47d1e Port vertical/horz layouts to new groups API 2020-05-12 22:43:54 +05:30
Kovid Goyal
01c0e8da93 Tall and Fat layouts ported to new groups API 2020-05-12 22:43:54 +05:30
Kovid Goyal
e844ad6db3 Respect per-window margin/padding in stack layout
Also use the margin/padding of the base window for all overlay windows
2020-05-12 22:43:54 +05:30
Kovid Goyal
3f8c042bc3 Preserve active idx when removing windows/tabs 2020-05-12 22:43:54 +05:30
Kovid Goyal
707ad705a4 Notify on active window changed when adding/removing to same group 2020-05-12 22:43:54 +05:30
Kovid Goyal
79a780004f Remove references to overlay_for from boss 2020-05-12 22:43:54 +05:30
Kovid Goyal
81b28bc1bd More work on refactoring window groups, stack layout works 2020-05-12 22:43:54 +05:30
Kovid Goyal
e9c4d540b1 More work on refactoring window groups 2020-05-12 22:43:54 +05:30
Kovid Goyal
50d9718c68 Start work on refactoring management of windows 2020-05-12 22:43:53 +05:30
Kovid Goyal
e39da2b2bb Merge branch 'icat-http-timeout' of https://github.com/lamby/kitty 2020-05-11 16:58:21 +05:30
Chris Lamb
f08ec1522a Set a default socket timeout when retrieving remote items in icat.
Otherwise we can easily hang when "icat"-ing resources from unreliable
websites/webcams, etc.
2020-05-11 12:24:57 +01:00
Kovid Goyal
e61e93712c Merge branch 'patch-3' of https://github.com/ctrlcctrlv/kitty 2020-05-11 11:47:14 +05:30
Fredrick Brennan
c9e198e02e Graphics protocol: note best detection method
Per https://github.com/kovidgoyal/kitty/issues/2636#issuecomment-626467852
2020-05-10 23:02:12 -07:00
Kovid Goyal
0ce181b578 Fix #2639 2020-05-10 21:28:55 +05:30
Kovid Goyal
99950fe448 DECQRM responses for mouse tracking modes 2020-05-09 20:55:51 +05:30
Kovid Goyal
d8daf84a09 Fix #2636 2020-05-09 17:21:23 +05:30
Kovid Goyal
3d32202b3a version 0.17.4 2020-05-09 10:48:21 +05:30
Kovid Goyal
4f4d562670 Fix background_tint making the window semi-transparent
Fixes #2618
2020-05-09 09:06:18 +05:30
Kovid Goyal
28fc9c69da Allow showing the name of the current layout and the number of windows in tab titles
Fixes #2634
2020-05-09 08:00:17 +05:30
Kovid Goyal
6edf00e699 Wayland: Fix OS window title not updating for hidden windows
Fixes #2629
2020-05-05 17:51:36 +05:30
Kovid Goyal
a0d6445dda Move expandvars to utils 2020-05-05 08:22:08 +05:30
Kovid Goyal
e74797037c ... 2020-05-04 13:30:35 +05:30
Kovid Goyal
3fb125dba7 Fix mypy editor integration for changes in syntastic 2020-05-04 13:19:03 +05:30
Kovid Goyal
3c8640f9ad Infrastructure for close confirmation 2020-05-02 18:19:08 +05:30
Kovid Goyal
2e63a4c83f Wayland: Remove unused link-time dependency
6aca3e99f0
2020-05-01 15:00:38 +05:30
Kovid Goyal
9da5bee178 X11: Filter out Xlib errors from other connections
2c8e0512dd
2020-05-01 14:59:16 +05:30
Kovid Goyal
2fc6f3b542 Merge changes from upstream
e65de2941c
2020-05-01 14:57:55 +05:30
Kovid Goyal
4754f42e51 Merge branch 'omit-final-tab-separator' of https://github.com/trygveaa/kitty 2020-05-01 14:05:26 +05:30
Trygve Aaberge
941fe918fb Omit final tab separator
This makes tab separators only drawn between the tabs.

Relates to #2616
2020-05-01 10:29:18 +02:00
Kovid Goyal
f4e82e972e ... 2020-05-01 08:10:11 +05:30
Kovid Goyal
f66dbf111d Pass env to get_vcs_revs() 2020-05-01 08:03:31 +05:30
Kovid Goyal
1a2da5c49d Use python3 in session.vim 2020-04-30 23:12:37 +05:30
Kovid Goyal
8327dabb29 Allow @ send-text over a socket to work with more than 1MB of text 2020-04-30 08:58:46 +05:30
Kovid Goyal
195ea6c140 Dont send back an rc disallowed response for commands that dont expect responses 2020-04-29 21:53:20 +05:30
Kovid Goyal
fcc0707174 Fix kitty @ send-text not working with text larger than 1024 bytes when using --listen-on
Fixes #2607
2020-04-29 21:48:09 +05:30
Kovid Goyal
aa9c3cd634 Report modifier key state when sending wheel events to the terminal program 2020-04-29 20:02:55 +05:30
Kovid Goyal
b541341681 Avoid use of goto 2020-04-29 14:37:26 +05:30
Kovid Goyal
e5d50aca6d ... 2020-04-29 09:21:36 +05:30
Kovid Goyal
b738f4d4ff Fix a regression that broke drag and drop on macOS
Fixes #2605
2020-04-29 09:12:04 +05:30
Kovid Goyal
5c38aabf0e ... 2020-04-29 07:50:01 +05:30
Kovid Goyal
03e9ed6947 Fix set_window_padding() only working on first window 2020-04-28 22:34:32 +05:30
Kovid Goyal
63493fad22 Fix a regression that caused clicking in the padding/margins of windows in the stack layout to switch the window to the first window
Fixes #2604
2020-04-28 22:23:38 +05:30
Kovid Goyal
696b857f91 By default, double clicking no longer considers the : as part of words
Fixes #2602
2020-04-28 19:57:40 +05:30
Kovid Goyal
53ae2bbe0d Merge branch 'use_loop' of https://github.com/Luflosi/kitty 2020-04-28 19:40:40 +05:30
Luflosi
01069e919d Use loop instead of calling dlopen() multiple times
Having an array of library names and iterating over it looks nicer than having several variables and calling `dlopen()` multiple times manually.
It should also make it easier to use custom library names instead by using the preprocessor, which I plan to do in the near future.
2020-04-28 15:53:58 +02:00
Kovid Goyal
fc0095f505 Merge branch 'master' of https://github.com/ixydo/kitty 2020-04-27 21:34:52 +05:30
Jinn Koriech
421528e130 Update note about icat + tmux to be more generic 2020-04-27 16:40:24 +01:00
Jinn Koriech
7b70356515 Add note clarifying that icat won't work with tmux
When using icat with tmux we get the following:

```
$ kitty icat ~/Pictures/fc.jpg 
Terminal does not support reporting screen sizes via the TIOCGWINSZ ioctl
```

I found a suggestion[1] this is due to limitations between kitty and tmux, so I'm raising this PR to either confirm this is the case and make it clear in the documentation, or to have it rejected so an issue can be raised to address the feature.

1: https://unix.stackexchange.com/a/484776/41996
2020-04-27 14:11:16 +01:00
Kovid Goyal
e803505aad CoreText: When centering glyphs ignore negative origins
This is needed for FiraCode ligatures to line up correctly. See
https://github.com/kovidgoyal/kitty/issues/2591#issuecomment-619937030
2020-04-27 18:02:53 +05:30
Kovid Goyal
ad1ff455a0 macOS: Fix a regression in the previous release that caused ligatures to be not be centered horizontally
Fixes #2591
2020-04-27 16:17:05 +05:30
Kovid Goyal
7692cb5c3d Merge branch 'graphics-big-endian' of https://github.com/jamessan/kitty 2020-04-26 09:36:53 +05:30
James McCoy
a94e208db3 Use T_PYSSIZET for GraphicsManager.image_count
GraphicsManager.image_count is declared as a size_t, so the Python type
needs to be the same width.  On 64-bit big-endian architectures, this
mismatch was showing up as test failures:

    ======================================================================
    FAIL: test_gr_delete (kitty_tests.graphics.TestGraphics)
    ----------------------------------------------------------------------
    Traceback (most recent call last):
      File "/<<PKGBUILDDIR>>/kitty_tests/graphics.py", line 319, in test_gr_delete
        self.ae(len(layers(s)), 0), self.ae(s.grman.image_count, 1)
        ch = 20
        cw = 10
        delete = <function TestGraphics.test_gr_delete.<locals>.delete at 0x3ffb7fc38b0>
        dx = 0.2
        dy = 0.4
        layers = <function put_helpers.<locals>.layers at 0x3ffb77709d0>
        put_image = <function put_helpers.<locals>.put_image at 0x3ffb77708b0>
        put_ref = <function put_helpers.<locals>.put_ref at 0x3ffb7770940>
        rect_eq = <function put_helpers.<locals>.rect_eq at 0x3ffb7770a60>
        s = <fast_data_types.Screen object at 0x1b60df0>
        self = <kitty_tests.graphics.TestGraphics testMethod=test_gr_delete>
    AssertionError: 0 != 1
2020-04-25 23:25:18 -04:00
Kovid Goyal
ba9d5cf3ff Merge branch 'use-fPIC' of https://github.com/jamessan/kitty 2020-04-25 21:11:10 +05:30
James McCoy
0dff0d03f9 Use -fPIC instead of -fpic
With large objects, use of -fpic will fail to link on certain
architectures due to size limitations of the global offset table (GOT).
For example, the link stage for glfw-wayland.so fails on sparc64, as
below.  Using -fPIC avoids these size limitations.

    ./glfw/osmesa_context.c:73:(.text+0xf2c): relocation truncated to fit: R_SPARC_GOT13 against symbol `_glfw' defined in .bss section in /tmp/glfw-wayland.so.SYvdxr.ltrans0.ltrans.o
    /tmp/glfw-wayland.so.SYvdxr.ltrans0.ltrans.o: in function `swapIntervalEGL':
    ./glfw/egl_context.c:238:(.text+0xf68): relocation truncated to fit: R_SPARC_GOT13 against symbol `_glfw' defined in .bss section in /tmp/glfw-wayland.so.SYvdxr.ltrans0.ltrans.o
    /tmp/glfw-wayland.so.SYvdxr.ltrans0.ltrans.o: in function `destroyContextOSMesa':
    ./glfw/osmesa_context.c:80:(.text+0x10a4): relocation truncated to fit: R_SPARC_GOT13 against symbol `_glfw' defined in .bss section in /tmp/glfw-wayland.so.SYvdxr.ltrans0.ltrans.o
    /tmp/glfw-wayland.so.SYvdxr.ltrans0.ltrans.o: in function `data_offer_action':
    ./glfw/wl_window.c:1692:(.text+0x15e4): relocation truncated to fit: R_SPARC_GOT13 against symbol `_glfw' defined in .bss section in /tmp/glfw-wayland.so.SYvdxr.ltrans0.ltrans.o
    /tmp/glfw-wayland.so.SYvdxr.ltrans0.ltrans.o: in function `data_offer_source_actions':
    ./glfw/wl_window.c:1683:(.text+0x1648): relocation truncated to fit: R_SPARC_GOT13 against symbol `_glfw' defined in .bss section in /tmp/glfw-wayland.so.SYvdxr.ltrans0.ltrans.o
    /tmp/glfw-wayland.so.SYvdxr.ltrans0.ltrans.o: in function `keyboardHandleRepeatInfo':
    ./glfw/wl_init.c:471:(.text+0x1704): relocation truncated to fit: R_SPARC_GOT13 against symbol `_glfw' defined in .bss section in /tmp/glfw-wayland.so.SYvdxr.ltrans0.ltrans.o
    /tmp/glfw-wayland.so.SYvdxr.ltrans0.ltrans.o: in function `checkScaleChange':
    ./glfw/wl_window.c:55:(.text+0x1768): relocation truncated to fit: R_SPARC_GOT13 against symbol `_glfw' defined in .bss section in /tmp/glfw-wayland.so.SYvdxr.ltrans0.ltrans.o
    /tmp/glfw-wayland.so.SYvdxr.ltrans0.ltrans.o: in function `primary_selection_copy_callback_done':
    ./glfw/wl_window.c:1833:(.text+0x18bc): relocation truncated to fit: R_SPARC_GOT13 against symbol `_glfw' defined in .bss section in /tmp/glfw-wayland.so.SYvdxr.ltrans0.ltrans.o
    /tmp/glfw-wayland.so.SYvdxr.ltrans0.ltrans.o: in function `clipboard_copy_callback_done':
    ./glfw/wl_window.c:1825:(.text+0x1910): relocation truncated to fit: R_SPARC_GOT13 against symbol `_glfw' defined in .bss section in /tmp/glfw-wayland.so.SYvdxr.ltrans0.ltrans.o
    /tmp/glfw-wayland.so.SYvdxr.ltrans0.ltrans.o: in function `primary_selection_source_canceled':
    ./glfw/wl_window.c:1582:(.text+0x1968): relocation truncated to fit: R_SPARC_GOT13 against symbol `_glfw' defined in .bss section in /tmp/glfw-wayland.so.SYvdxr.ltrans0.ltrans.o
    /tmp/glfw-wayland.so.SYvdxr.ltrans0.ltrans.o: in function `data_source_canceled':
    ./glfw/wl_window.c:1576:(.text+0x19c0): additional relocation overflows omitted from the output
    collect2: error: ld returned 1 exit status
2020-04-25 10:08:28 -04:00
Kovid Goyal
c92aca5d19 Use a Literal as the type for choice based options 2020-04-24 19:45:51 +05:30
Kovid Goyal
5762baeed7 Typing fixes 2020-04-24 19:27:22 +05:30
Kovid Goyal
601cf01222 Fix #2581 2020-04-24 19:24:11 +05:30
Kovid Goyal
0eef48b516 Use literals as the type for cli opts that take choices 2020-04-24 15:28:04 +05:30
Kovid Goyal
3c1954f329 ... 2020-04-24 15:07:44 +05:30
Kovid Goyal
cc29640604 version 0.17.3 2020-04-23 08:39:07 +05:30
Kovid Goyal
d0329460b8 Fix #2573 2020-04-21 22:04:34 +05:30
Kovid Goyal
717c0c96de Allow mapping arbitrary remote control commands to key presses in kitty.conf 2020-04-19 20:14:23 +05:30
Kovid Goyal
b3f161efce ... 2020-04-19 19:39:56 +05:30
Kovid Goyal
0286940163 Allow changing margings/padding via remote control
Fixes #2546
2020-04-19 19:29:36 +05:30
Kovid Goyal
d4a4ee386f Fix minimal borders in grid layout 2020-04-19 17:58:35 +05:30
Kovid Goyal
33498f9133 ... 2020-04-19 11:01:22 +05:30
Kovid Goyal
da3d4d1bef ... 2020-04-19 09:51:06 +05:30
Kovid Goyal
c69b8870d2 Allow individually setting margins and padding for each edge (left, right, top, bottom) 2020-04-19 09:36:26 +05:30
Kovid Goyal
85b55b31b6 Add a new :opt:listen_on option in kitty.conf
Also allow using environment variables in this option
Fixes #2569
2020-04-19 09:23:52 +05:30
Kovid Goyal
948919e42b Forgot to apply --title on creation of subsequent OS windows
Also update changelog
2020-04-19 08:42:30 +05:30
Kovid Goyal
85c40090ed Fix #2570 2020-04-19 08:36:29 +05:30
Kovid Goyal
98b50ec145 ... 2020-04-19 08:28:40 +05:30
Kovid Goyal
1ab4f7d2d0 Fix a regression in 0.17 that broke displaying graphics over SSH
The new types GraphicsCommand can generate a command with only a payload
and no control keys, as the last command during chunked transfer.
Fix the parser to handle this. Fixes #2568
2020-04-19 08:13:33 +05:30
Kovid Goyal
98801b6fa6 Update changelog 2020-04-19 07:22:02 +05:30
Kovid Goyal
bdd68284b5 Merge branch 'terminfo' of https://github.com/wladh/kitty 2020-04-19 07:21:10 +05:30
Vlad Hanciuta
a61d70ea9a Add strikethrough capabilities to terminfo
The termcap aliases are not standard, but they are used by Vim, it
seems. As far as I can tell, there are no standard termcap attribute for
strikethrough.
2020-04-18 16:37:09 +01:00
Vlad Hanciuta
e271719dd2 Add strikeout capability to terminfo 2020-04-18 16:05:30 +01:00
Kovid Goyal
a08efa1fc5 Fix failing test 2020-04-17 19:57:37 +05:30
Kovid Goyal
ffac3600e0 Layouts: Apply per window padding and margin values
Also make the calculation of blank rects more robust and with less code,
which should hopefully fix #1762
2020-04-17 19:47:34 +05:30
Kovid Goyal
6499f8ac24 Allow window objects to store custom margin/padding 2020-04-17 09:02:08 +05:30
Kovid Goyal
63307cb1d8 Code to serialize state 2020-04-17 08:42:45 +05:30
Kovid Goyal
0a6fb362f6 kitty @ kitten: Allow no_ui kittens to return data to the remote client
Fixes #2552 since the OP can now write a kitten to query the window
manager and return position data even over SSH.
2020-04-15 08:29:55 +05:30
Kovid Goyal
457fcbfb90 Merge branch 'master' of https://github.com/akobel/kitty 2020-04-15 07:44:27 +05:30
Alexander Kobel
3b6277b9e2 Hide "No render frame received" without --debug-rendering 2020-04-14 19:36:58 +02:00
Alexander Kobel
e6e61028b1 Rename --debug-gl to --debug-rendering 2020-04-14 19:35:40 +02:00
Kovid Goyal
e9be66126b Merge branch 'hints-support-empty-word-characters' of https://github.com/trygveaa/kitty 2020-04-14 08:17:13 +05:30
Trygve Aaberge
681fe7f2f2 Don't set word_characters to select_by_word_characters when empty string
This allows you to pass in --word-characters "" which will make hints
only match \w.
2020-04-13 23:02:44 +02:00
Kovid Goyal
0196920533 icat kitten: Fix display of 16-bit depth images
Fixes #2542
2020-04-13 23:05:10 +05:30
Kovid Goyal
5f5bb3ace0 Update Changelog 2020-04-12 20:10:29 +05:30
Kovid Goyal
3c970e0122 Merge branch 'kitten-send-mouse-events' of https://github.com/trygveaa/kitty 2020-04-12 20:09:45 +05:30
Trygve Aaberge
43af6e3b8a Add support for sending mouse events from a kitten
This allows you to a control a program running in kitty from a kitten
using mouse events. If the program is not receiving mouse events of that
type, it is not sent.
2020-04-12 16:19:50 +02:00
Kovid Goyal
ac8cfc12fb Merge branch 'docs-fix-kitten-custom-indentation' of https://github.com/trygveaa/kitty 2020-04-12 19:49:18 +05:30
Trygve Aaberge
b19472e0f5 Fix indentation in kittens/custom.rst to 4 spaces
This file used 3 spaces some places and 4 spaces other places. Other
files like diff.rst and hints.rst use 4 spaces.
2020-04-12 16:04:32 +02:00
Kovid Goyal
b4d08044a0 ... 2020-04-12 17:01:39 +05:30
Kovid Goyal
b2fe02e63f Merge branch 'patch-1' of https://github.com/LesnyRumcajs/kitty 2020-04-12 16:55:10 +05:30
Kovid Goyal
d1a5d30233 Add another test for marking 2020-04-12 16:54:38 +05:30
LesnyRumcajs
bba30138e1 Update Fedora link
The link was pointing to a deprecated `copr`. Let's point it to official Fedora repos! (as copr page suggests anyway)
2020-04-12 13:13:02 +02:00
Kovid Goyal
082546a1e7 Marks: Fix marks not handling wide characters and tab characters correctly
Fixes #2534
2020-04-12 13:28:21 +05:30
Kovid Goyal
41ffd58e26 A bit of cleanup 2020-04-11 21:22:17 +05:30
Kovid Goyal
b4f24e4e1e Merge branch 'must_draw_borders_flag' of https://github.com/franco/kitty 2020-04-11 21:19:52 +05:30
Franco Sebregondi
75c8ffd715 Add flag to Layout to enforce drawing a border
Layout.must_draw_borders = True enforces drawing of a border even
though only a single window is visible. See #2531.
2020-04-11 17:01:44 +02:00
Kovid Goyal
688606ff7c Merge branch 'ignore-keyboard-layout-switch-keys' of https://github.com/trygveaa/kitty 2020-04-10 21:46:07 +05:30
Trygve Aaberge
2e3f9dffa7 Ignore keys for switching keyboard layout
XKB has various options for using keys to switch the keyboard layout.
When these are set, XKB will return keysyms which are unknown to GLFW,
so kitty will fallback to using a keymap without the options set, which
causes the keys to be interpreted as the original keysyms.

However, when these options are set, kitty shouldn't interpret the keys.
Therefore, check for some specific keysyms and return before translating
to GLFW keysyms.

There may be more keysyms which should be ignored, but as far as I can
see from https://gitlab.freedesktop.org/xkeyboard-config/xkeyboard-config/-/blob/xkeyboard-config-2.29/symbols/group
these are the ones which can be triggered by XKB options.

Fixes #2519
2020-04-10 17:21:53 +02:00
Kovid Goyal
859033415b macOS: Fix incorrect horizontal positioning of some full-width East Asian characters
Fixes #1457
Also render multi-cell PUA characters centered, matching behavior on other platforms
2020-04-09 13:25:19 +05:30
Kovid Goyal
1f1b52b580 Fix specifying options for layouts in the startup session file not working
Fixes #2520
2020-04-09 12:40:09 +05:30
Kovid Goyal
4e7bf80447 diff kitten: New option to control the background color for filler lines in the margin
Fixes #2518
2020-04-08 20:42:49 +05:30
Kovid Goyal
e39df50884 Merge branch 'patch-1' of https://github.com/georgeabr/kitty 2020-04-08 18:56:15 +05:30
George Abraham
8d6a9d45c2 Changing match target to "font"
As suggested in #2516, changing match target to "font" in the fonts.conf file.
2020-04-08 14:02:54 +01:00
Kovid Goyal
0862e85577 Rewrite wcswidth as a state machine 2020-04-07 10:10:30 +05:30
Kovid Goyal
0b9a37139e Render any flag pair in two cells not just known ones 2020-04-06 23:00:34 +05:30
Kovid Goyal
6357f7b811 Update wcswidth() to match new country flag rendering 2020-04-06 22:56:34 +05:30
Kovid Goyal
24197dc422 Render known country flags designated by a pair of unicode codepoints in two cells instead of four. 2020-04-06 22:16:59 +05:30
Kovid Goyal
9bc2ab3245 Function to detect flag pairs 2020-04-06 21:16:14 +05:30
Kovid Goyal
bf4e8c490c Update to Unicode 13.0
Fixes #2513
2020-04-06 18:59:35 +05:30
Kovid Goyal
590a4d70ee Fix --stdin-add-formatting not working
Fixes #2512
2020-04-06 09:35:16 +05:30
Kovid Goyal
40341d2ddd ... 2020-04-04 09:17:38 +05:30
Kovid Goyal
0cd2c41ee3 Update changelog 2020-04-03 22:42:06 +05:30
Kovid Goyal
5d65cdb6a8 Fix reverse video not being rendered correctly when using transparency or a background image
Fixes #2419
2020-04-03 22:40:33 +05:30
Kovid Goyal
759a15ccbb X11: Handle invalid data being sent with drag events by some applications
Fixes #2505
2020-04-02 21:01:19 +05:30
Kovid Goyal
5aead5eebe Replace new-window with launch in the docs 2020-04-01 08:39:37 +05:30
Kovid Goyal
a325a5fdee Merge branch 'strikethrough-info-from-font' of https://github.com/trygveaa/kitty 2020-03-31 09:34:07 +05:30
Trygve Aaberge
931e91f1a7 Read strikethrough info from font when using FreeType
This reads the strikethrough position and thickness from the font so it
is rendered correctly.

This is only implemented for FreeType, not Core Text, because I didn't
find any way to get the info from Core Text, and I don't have a Mac to
test it on either. When using Core Text or when the font doesn't provide
the info, the same approximation as before is used.
2020-03-30 20:09:30 +02:00
Kovid Goyal
6e13509720 Allow entry points and external command combined completion on first word 2020-03-30 11:38:54 +05:30
Kovid Goyal
5b4844e71e oops
Broke normal completion in previous commit. Delegate should only be used
when actual unknown words are present
2020-03-30 11:12:00 +05:30
Kovid Goyal
66cbbea9bb Add completion for executables at kitty invocation in zsh
So now kitty vi<TAB> and kitty vim something<TAB> delegate
completion to zsh for the command that will be executed inside kitty.
2020-03-30 10:54:17 +05:30
Kovid Goyal
b65119b8a9 Color separators in the tab bar using inactive bg except for the last one 2020-03-29 09:20:17 +05:30
Kovid Goyal
86703da917 version 0.17.2 2020-03-29 09:09:16 +05:30
Kovid Goyal
610e9afdf0 Add completion of conf filenames to kitty @ set-colors 2020-03-29 08:41:27 +05:30
Kovid Goyal
e3af9f68d3 Linux: Fix selection of fonts with multiple width variants not preferring the normal width faces
Fixes #2491
2020-03-29 01:52:33 +05:30
Kovid Goyal
747ac85e7c Add an :option:launch --watcher option that allows defining callbacks that are called for various events in the window's life-cycle
Fixes #2440
2020-03-28 12:13:42 +05:30
Kovid Goyal
8c23f9e526 DRYer 2020-03-28 09:20:28 +05:30
Kovid Goyal
e6e339fcd3 ... 2020-03-28 08:44:48 +05:30
Kovid Goyal
f04680ac47 Fix a regression in 0.17 that broke the kitty @ launch remote command and also broke the --tab-title option when creating a new tab.
Fixes #2488
2020-03-28 08:43:32 +05:30
Kovid Goyal
90985cc846 Merge branch 'hints-copy-to-primary-selection' of https://github.com/trygveaa/kitty 2020-03-28 08:21:08 +05:30
Trygve Aaberge
63917944f2 Add an option to hints for copying to the primary selection 2020-03-27 20:23:02 +01:00
Kovid Goyal
793605f80f Update changelog 2020-03-26 22:06:13 +05:30
Kovid Goyal
93a281c7e3 Add a new mappable action `close_other_windows_in_tab` to close all but the active window
Fixes #2484
2020-03-26 22:05:00 +05:30
Kovid Goyal
8f1c6c4d74 Fix #2482 2020-03-26 00:53:19 +05:30
Kovid Goyal
1610dba7ab patch tab bar colors correctly 2020-03-26 00:46:30 +05:30
Kovid Goyal
d9d419991c Respect tab_bar_background again 2020-03-26 00:41:19 +05:30
Kovid Goyal
f9e86b19aa Fix #2480 2020-03-26 00:20:10 +05:30
Kovid Goyal
fffb976e43 Fix blank space at the start of tab bar in powerline style when first tab is inactive
Fix #2478
2020-03-25 19:20:35 +05:30
Kovid Goyal
0da566b49f Hints kitten: Adjust the default regex used to detect line numbers to handle line+column numbers
See #2268
2020-03-25 10:03:25 +05:30
Kovid Goyal
da55717d20 The splits layout needs its own draw_minimal_borders implementation 2020-03-25 09:54:06 +05:30
Kovid Goyal
254836902c Merge branch 'fix/window-border' of https://github.com/pyrho/kitty 2020-03-25 09:35:46 +05:30
Damien Rajon
d01f8d1865 fix(window): inactive window border fix
Fixes #2474.
2020-03-25 00:09:10 +01:00
Kovid Goyal
a46c3f7007 Replace use of cast() 2020-03-24 22:03:10 +05:30
Kovid Goyal
4e58062025 Improve rendering of :option: in cli docs 2020-03-24 22:03:00 +05:30
Kovid Goyal
aa3be0535f version 0.17.1 2020-03-24 19:45:19 +05:30
Kovid Goyal
8ebf5e007c Fix rc setting cursor_text_color to background not working 2020-03-24 19:43:31 +05:30
Kovid Goyal
c2957e7f12 Fix a regression in 0.17 that caused kitty @ set-colors to require setting cursor_text_color
Fixes #2470
2020-03-24 19:29:25 +05:30
Kovid Goyal
bf7c26d357 CoreText: Prefer less bold variants over heavier variants when auto-selecting the bold face 2020-03-24 19:27:14 +05:30
Kovid Goyal
0547102bdd Fix #2468 2020-03-24 18:33:32 +05:30
Kovid Goyal
a07369ce69 Update changelog 2020-03-24 18:14:14 +05:30
Kovid Goyal
21c5610431 ... 2020-03-24 18:02:44 +05:30
Kovid Goyal
6dbdf72f40 CoreText: When matching fonts prefer non-expanded/condensed variants 2020-03-24 17:55:38 +05:30
Kovid Goyal
76a6bba643 Fix #2466 2020-03-24 17:07:37 +05:30
Kovid Goyal
b0b8222a96 ... 2020-03-24 17:04:17 +05:30
Kovid Goyal
0d87b8fac5 Fix a regression in 0.17 that caused tab bar background to be rendered after the last tab as well
Fixes #2464
2020-03-24 16:05:02 +05:30
Kovid Goyal
5227b1f98b Fix :opt:cursor_underline_thickness not working
Fixes #2465
2020-03-24 15:53:13 +05:30
Kovid Goyal
c4f7c5c1cd More explanation for OSC 52 extension 2020-03-24 11:58:30 +05:30
Kovid Goyal
33a84a609c ... 2020-03-24 11:35:34 +05:30
Kovid Goyal
037111715a ... 2020-03-24 11:34:29 +05:30
Kovid Goyal
93271b93e6 version 0.17.0 2020-03-24 10:33:51 +05:30
Kovid Goyal
04488ada06 Merge branch 'png2icns' of https://github.com/Luflosi/kitty 2020-03-21 08:50:57 +05:30
Luflosi
21c7002c68 Add support for png2icns as an alternative to iconutil
png2icns is used when building kitty with nix because iconutil seems to be closed-source.
libicns also has an iconutil clone called icnsutil in the source tree but the last release is from 2012, which does not include this utility yet.
2020-03-21 02:11:08 +01:00
Luflosi
97cae0e355 Simplify code
This piece of code ends up just extracting `appname` from `iconset_dir`.
2020-03-21 00:10:16 +01:00
Luflosi
85fc0a59b1 Rename variable logo_dir -> iconset_dir 2020-03-21 00:10:16 +01:00
Kovid Goyal
eddd45bbc3 diff kitten: Fix images losing position when scrolling using mouse wheel/touchpad 2020-03-19 18:46:10 +05:30
Kovid Goyal
e2339697b9 Fix #2449 2020-03-19 17:22:58 +05:30
Kovid Goyal
cfe9b408ce Move startup of first child out of the constructor of Boss 2020-03-19 16:48:16 +05:30
Kovid Goyal
83e8018787 Exclude very small values for content scale 2020-03-19 14:13:23 +05:30
Kovid Goyal
372d2008a6 Actually, we should use text/plain rather than text/uri-list since we are already converting to filesystem paths 2020-03-19 13:40:02 +05:30
Kovid Goyal
ab9a36f8c1 Port cocoa backend to use new drop API 2020-03-19 13:36:03 +05:30
Kovid Goyal
2458c3a7c6 Implement drag and drop of text/plain for Wayland as well 2020-03-19 13:28:21 +05:30
Kovid Goyal
e827e6fa21 X11: Allow drag and drop of text/plain in addition to text/uri-list
Fixes #2441
2020-03-18 22:37:23 +05:30
Kovid Goyal
342f0981d8 Add tests for selection extension by right click 2020-03-18 20:57:19 +05:30
Kovid Goyal
9c19e88288 Allow extending selections by dragging with right button pressed
Fixes #2445
2020-03-18 20:52:25 +05:30
Kovid Goyal
7329bd4910 Fix incorrect first line selection rendering when scrolling down 2020-03-18 20:27:54 +05:30
Kovid Goyal
b9ad62226e Fix selection not being extended by right click when scrolling down
Fix #2443
2020-03-18 20:17:38 +05:30
Kovid Goyal
3bff3bcbe4 Fix selection not updating properly while scrolling
Fixes #2442
2020-03-18 18:48:59 +05:30
Kovid Goyal
a06fdad034 Use a dedicated exception for rc_cmd.fatal() 2020-03-17 11:40:42 +05:30
Kovid Goyal
a49bd98ec6 ... 2020-03-15 13:36:09 +05:30
Kovid Goyal
90f41108d3 ... 2020-03-15 13:30:02 +05:30
Kovid Goyal
382c31ddf2 Use a stub rather than TYPE_CHECKING 2020-03-15 13:27:40 +05:30
Kovid Goyal
871ca4dda6 oops 2020-03-15 08:58:46 +05:30
Kovid Goyal
fa003f8233 Fix #2431 2020-03-15 08:55:04 +05:30
Kovid Goyal
12f37bcfad Dont strip trailing punctuation from end of URL if next line startswith url characters 2020-03-15 08:47:52 +05:30
Kovid Goyal
e86c712424 Dont strip :code:& and :code:- from the end of URLs
Fixes #2436
2020-03-15 08:29:56 +05:30
Kovid Goyal
e8a9935cb2 Allow setting WM_CLASS and WM_NAME when creating new OS windows with the launch command 2020-03-15 08:12:28 +05:30
Kovid Goyal
f353131b44 Fix #2433 2020-03-15 07:54:55 +05:30
Kovid Goyal
7c4a2ba329 Fix #2434 2020-03-14 20:19:26 +05:30
Kovid Goyal
dfb543bd94 ... 2020-03-14 15:27:38 +05:30
Kovid Goyal
c912eef040 Minor strictness increases 2020-03-14 14:59:31 +05:30
Kovid Goyal
5f06d3a427 Disallow untyped decorators 2020-03-14 14:50:04 +05:30
Kovid Goyal
a70fa9abc5 oops 2020-03-14 14:38:56 +05:30
Kovid Goyal
5956277863 All defs are now typed 2020-03-14 14:37:11 +05:30
Kovid Goyal
d3f37eeba4 more typing work 2020-03-14 11:42:05 +05:30
Kovid Goyal
ea48332f46 more typing work 2020-03-14 09:52:56 +05:30
Kovid Goyal
eb12511646 The uber-fussy sway does not like calling wl_data_offer_finish on a version 1 data manager 2020-03-14 09:12:06 +05:30
Kovid Goyal
aa11ddf32c Wayland: Fix a crash when drag and dropping into kitty
Fixes #2432
2020-03-14 08:20:44 +05:30
Kovid Goyal
a348f64833 more typing work 2020-03-13 21:41:07 +05:30
Kovid Goyal
626a96e20f Clean up code for matching windows/tabs in rc 2020-03-13 21:03:06 +05:30
Kovid Goyal
60995ff04b Fix #2429 2020-03-13 19:14:49 +05:30
Kovid Goyal
ba4e711715 Fix #2428 2020-03-13 18:13:11 +05:30
Kovid Goyal
891b184195 misc typing fixes 2020-03-13 16:45:39 +05:30
Kovid Goyal
5414dc398e Correct a few type definitions in layout.py 2020-03-13 16:21:36 +05:30
Kovid Goyal
917559f883 more typing work 2020-03-13 16:13:26 +05:30
Kovid Goyal
9f2fb76309 more typing work 2020-03-12 15:09:21 +05:30
Kovid Goyal
b6692849d6 more typing work 2020-03-12 14:52:11 +05:30
Kovid Goyal
b27f6d5957 more typing work 2020-03-12 14:26:51 +05:30
Kovid Goyal
cda1e28b32 more typing work 2020-03-12 13:51:51 +05:30
Kovid Goyal
8a3e71d3d0 oops 2020-03-12 11:28:58 +05:30
Kovid Goyal
149ae2866a more typing work 2020-03-12 08:10:51 +05:30
Kovid Goyal
21707171bb Simplify the protocol for the send-text remote command 2020-03-12 07:14:47 +05:30
Kovid Goyal
2ebdf738ca more typing work 2020-03-11 20:08:16 +05:30
Kovid Goyal
0e871a89aa more typing work 2020-03-11 09:57:49 +05:30
Kovid Goyal
2d4f194f0d more typing work 2020-03-11 09:43:28 +05:30
Kovid Goyal
ce94a9b2df More typing work 2020-03-11 09:35:59 +05:30
Kovid Goyal
bfbb3c7068 Merge branch 'zsh_compdef_comment' of https://github.com/Luflosi/kitty 2020-03-11 07:17:47 +05:30
Luflosi
6d1fd20542 Add #compdef comment to zsh completion
This will allow adding completions without using `kitty + complete setup zsh | source /dev/stdin` by piping the code into a file named `_kitty` in a directory in `$fpath` instead of piping to `source`. This is especially handy for package managers that package kitty.
See https://github.com/zsh-users/zsh-completions/blob/master/zsh-completions-howto.org.
The `compdef _kitty kitty` line at the end doesn't seem to have any ill effects when using the completion code in a completion function file. When piping the code to `source` like before, the added line should be interpreted as a comment and be ignored.
2020-03-10 20:48:43 +01:00
Kovid Goyal
bb8cab3a02 Add type information for tui operations cmds 2020-03-10 22:25:57 +05:30
Kovid Goyal
10435c23c2 more typing work 2020-03-10 20:25:09 +05:30
Kovid Goyal
01142cdc8c Add type information to the Graphics Command infrastructure 2020-03-10 20:14:04 +05:30
Kovid Goyal
fc0adfd965 more typing work 2020-03-10 15:48:51 +05:30
Kovid Goyal
8803eeb890 more typing work 2020-03-10 12:58:53 +05:30
Kovid Goyal
25be705bcf DRYer 2020-03-09 21:19:17 +05:30
Kovid Goyal
d8f214a267 oops 2020-03-09 21:11:21 +05:30
Kovid Goyal
f74fb846e5 Fix #2421 2020-03-09 21:10:04 +05:30
Kovid Goyal
8ae110691e More typing work 2020-03-09 21:06:13 +05:30
Kovid Goyal
abff2292c1 Workaround for sphinx type info being available magically on the CI server 2020-03-09 18:37:23 +05:30
Kovid Goyal
7d690bbad2 Run mypy on CI 2020-03-09 18:24:55 +05:30
Kovid Goyal
7298de646a more typing work 2020-03-09 18:17:24 +05:30
Kovid Goyal
3c2f3ecd8e Fix #2420 2020-03-09 17:24:51 +05:30
Kovid Goyal
ac2c21e046 more typing work 2020-03-09 16:13:00 +05:30
Kovid Goyal
c817ba9eae more typing work 2020-03-09 13:32:45 +05:30
Kovid Goyal
92827ae647 More typing work 2020-03-09 09:56:37 +05:30
Kovid Goyal
5bdb405635 More typing work 2020-03-09 08:56:02 +05:30
Kovid Goyal
9beae321d7 More typing work 2020-03-08 22:08:18 +05:30
Kovid Goyal
353db678a2 Add typing to box_drawing 2020-03-08 21:30:50 +05:30
Kovid Goyal
9b973ef99c More typing work 2020-03-08 20:36:50 +05:30
Kovid Goyal
308d171dae More typing work 2020-03-08 18:55:30 +05:30
Kovid Goyal
7057bc663e Implement proper editor integration for mypy 2020-03-08 14:39:46 +05:30
Kovid Goyal
d84cff0baf The hints kitten should by default use the URL prefixes from kitty.conf 2020-03-08 13:26:55 +05:30
Kovid Goyal
645890ccc8 Make the set of URL prefixes that are recognized while hovering with the mouse configurable
Fixes #2416
2020-03-08 13:16:34 +05:30
Kovid Goyal
cc1336a616 More typing work
Also use a mypy based linter when editing
2020-03-08 11:02:14 +05:30
Kovid Goyal
9b32f18109 Refactor remote control commands into individual modules
Also add type information
2020-03-08 08:39:26 +05:30
Kovid Goyal
a0321376d5 Fix `@selection` placeholder not working with launch command
Fixes #2417
2020-03-08 08:00:36 +05:30
Kovid Goyal
0a6e264d09 Fix #2414 2020-03-07 15:15:27 +05:30
Kovid Goyal
afec07b124 More typing work 2020-03-06 14:19:46 +05:30
Kovid Goyal
8a34fede55 More typing work 2020-03-06 08:35:23 +05:30
Kovid Goyal
686b5f297e Ensure glfw is imported from the correct place 2020-03-06 08:23:01 +05:30
Kovid Goyal
6609d219f4 Add type checking for glfw module as well 2020-03-06 07:59:55 +05:30
Kovid Goyal
804998ca69 oops 2020-03-06 07:55:54 +05:30
Kovid Goyal
de5254469c Fix #2412 2020-03-06 07:48:41 +05:30
Kovid Goyal
ef879bab9c Fix #2411 2020-03-06 07:19:33 +05:30
Kovid Goyal
f729985346 More typing work
Also move notification_activated into a standalone function which will
hopefully fix #2410
2020-03-06 07:07:18 +05:30
Kovid Goyal
1e998b6a3f Use mypy in daemon mode 2020-03-05 20:38:51 +05:30
Kovid Goyal
77e9460eea Make mypy a bit stricter 2020-03-05 19:57:28 +05:30
Kovid Goyal
81a58186c6 Drop support for python 3.5 2020-03-05 18:31:20 +05:30
Kovid Goyal
ac149be2bb py3.5 compat 2020-03-05 18:23:45 +05:30
Kovid Goyal
a76a163db5 kitty.config is typed 2020-03-05 18:17:21 +05:30
Kovid Goyal
4ae59d3f77 The launch module is now fully typed 2020-03-05 16:20:56 +05:30
Kovid Goyal
d83a450260 A command for test.py to generate the typing stubs and run mypy 2020-03-05 15:58:30 +05:30
Kovid Goyal
61acc0784e Dont store generated stubs in source control 2020-03-05 15:50:54 +05:30
Kovid Goyal
f05890719d Add type checking for the various CLI options objects 2020-03-05 15:47:12 +05:30
Kovid Goyal
0f4e7921ee Create an auto-generated stub file for the kitty Options object 2020-03-04 19:14:50 +05:30
Kovid Goyal
ec8c96b8e6 diff kitten: Highlight pyi files as python 2020-03-04 11:52:58 +05:30
Kovid Goyal
f0b29e15c3 The utils and constants modules are now fully typechecked 2020-03-04 10:26:41 +05:30
Kovid Goyal
8ad62106e0 No global typing issues in all code (excluding tests) 2020-03-04 08:10:20 +05:30
Kovid Goyal
36eb52424f No top level typing issues for kittens 2020-03-04 07:49:28 +05:30
Kovid Goyal
c9ce2f47dc No top level typing issues found in kitty package 2020-03-04 07:31:22 +05:30
Kovid Goyal
5035ed61ee More typing work 2020-03-04 06:26:02 +05:30
Kovid Goyal
a4cc10c41b More typing work 2020-03-04 06:10:57 +05:30
Kovid Goyal
5730ce5f53 More typing work 2020-03-03 20:18:24 +05:30
Kovid Goyal
27524bfc3d Restore global key definitions so as not to break third party kittens that might use them 2020-03-03 15:06:10 +05:30
Kovid Goyal
8843ded1c9 Refactor key encoding
Cannot have key names in global namespace as not all key names are valid
python identifiers. So move them into a dict.
2020-03-03 14:54:30 +05:30
Kovid Goyal
64b497589f Start adding typing info 2020-03-03 14:31:25 +05:30
Kovid Goyal
ee48fd7151 ... 2020-03-03 12:25:02 +05:30
Kovid Goyal
291cd5e23f Also switch badges in manual 2020-03-01 17:13:27 +05:30
Kovid Goyal
be668cfd9a Switch status badge to github actions 2020-03-01 17:11:39 +05:30
Kovid Goyal
f889c1c75a Switch to using GitHub actions for CI 2020-03-01 17:02:53 +05:30
Kovid Goyal
55c5f3e9fd ... 2020-02-29 11:17:01 +05:30
Kovid Goyal
242d335095 A new `copy_and_clear_or_interrupt` function
Fixes #2403
2020-02-28 21:17:05 +05:30
Kovid Goyal
c763db94ce Fix #2401 2020-02-28 10:28:01 +05:30
Kovid Goyal
a391732600 left half of cell should happen only if url is truly empty 2020-02-28 07:37:10 +05:30
Kovid Goyal
06b45fcace Fix #2402 2020-02-28 07:19:31 +05:30
Kovid Goyal
bdac5f7d5b Add a bounds check in text_for_range() as well 2020-02-27 21:33:42 +05:30
Kovid Goyal
74865efddb move break condition into for loop 2020-02-27 21:31:42 +05:30
Kovid Goyal
b1f4d16692 Left in a printf() 2020-02-27 21:23:27 +05:30
Kovid Goyal
01b8e2c3f5 ... 2020-02-27 21:16:48 +05:30
Kovid Goyal
8c1ef94b26 Bounds check for apply selection
Fixes #2400
2020-02-27 20:27:20 +05:30
Kovid Goyal
507fbc7abf Fix #2399 2020-02-27 07:14:44 +05:30
Kovid Goyal
2f8002c567 Add a test for #1616 2020-02-26 09:20:08 +05:30
Kovid Goyal
551e28d8e0 Run tests python3.8 on linux 2020-02-26 07:34:31 +05:30
Kovid Goyal
e84163e838 Remove unused code 2020-02-26 07:31:43 +05:30
Kovid Goyal
3a64b835fb DRYer 2020-02-26 07:28:39 +05:30
Kovid Goyal
08a44ed4dd Fix #2397
Have to send selection data to GPU on first render.
2020-02-26 07:22:22 +05:30
Kovid Goyal
4b8cc23a86 Fix selection marking incorrect when scrolling 2020-02-25 22:06:53 +05:30
Kovid Goyal
c4b2de8939 Refactor function to not combine input and output parameters 2020-02-25 21:49:31 +05:30
Kovid Goyal
e2a603dcda Fix failing selection test
Unintialized memory use, was not creating an issue in debug builds only
on the CI servers
2020-02-25 21:44:54 +05:30
Kovid Goyal
294d01def6 Clear the click queue before a multi-click 2020-02-25 21:20:41 +05:30
Kovid Goyal
05f289f912 Make py 3.8 available in the CI docker image 2020-02-25 21:14:16 +05:30
Kovid Goyal
4343c4067e Make clang happy 2020-02-25 20:33:19 +05:30
Kovid Goyal
c167dcc4e9 Allow selection of single cells with the mouse. Also improve mouse selection to follow semantics common to most programs
Fixes #945
Fixes #1007
2020-02-25 20:19:38 +05:30
Kovid Goyal
9a67176719 Fix scrolling selection tests 2020-02-25 20:17:49 +05:30
Kovid Goyal
42d1a4755a Add tests for multiline movement 2020-02-25 20:03:14 +05:30
Kovid Goyal
1690e6933f Clean up handling of scrolling in selections 2020-02-25 20:03:14 +05:30
Kovid Goyal
5bbc15583e Non-scrolling based selection tests all pass 2020-02-25 20:03:14 +05:30
Kovid Goyal
e03aabd972 Some consting 2020-02-25 20:03:14 +05:30
Kovid Goyal
6f5968eeb0 Get rid of the ugly macro used for iteration over selections 2020-02-25 20:03:14 +05:30
Kovid Goyal
71b6e8f12a More selection fixes 2020-02-25 20:03:14 +05:30
Kovid Goyal
9c486f6e69 Track left to right for selections based on actual mouse positions
Cant use the selection boundaries as these can be programmatically
altered when extending selection by word or line.
2020-02-25 20:03:14 +05:30
Kovid Goyal
2f24588c66 Fix cell select mode tests 2020-02-25 20:03:14 +05:30
Kovid Goyal
6b1ea326a0 Initial implementation of half cell based selection 2020-02-25 20:03:14 +05:30
Kovid Goyal
4512d0dbac Update test for changes to ANSI serialization 2020-02-25 19:23:05 +05:30
Kovid Goyal
511c4da6a3 Workaround for bug in less that causes colors to reset at wrapped lines
Fixes #2381
2020-02-25 19:14:24 +05:30
Kovid Goyal
af8fdf1dbe Dont use a macro for as_text_generic 2020-02-25 15:33:12 +05:30
Kovid Goyal
b7d12de0a7 Avoid transitions in line_as_ansi on marks 2020-02-25 14:49:17 +05:30
Kovid Goyal
2d870fc84a Fix colors in scrollback pager off if the window has redefined terminal colors using escape codes
Fixes #2381
2020-02-25 10:46:51 +05:30
Kovid Goyal
6e87929603 Dont imply inline comments are supported in the config file 2020-02-24 18:52:51 +05:30
Kovid Goyal
2b441df9e9 Log an error for invalid detach_tab argument 2020-02-24 18:43:15 +05:30
Kovid Goyal
3e672ac178 Log an error for invalid detach_window arguments 2020-02-24 18:42:52 +05:30
Kovid Goyal
12a24d5c86 Remove unused code 2020-02-24 07:10:05 +05:30
Kovid Goyal
dec1a0886d typo 2020-02-23 19:34:31 +05:30
Kovid Goyal
a82e45ad71 Allow passing the currently active kitty window id in the launch command
See #2391
2020-02-23 19:17:26 +05:30
Kovid Goyal
82e5750d71 Merge branch 'tui-line-edit-cursor-end' of https://github.com/trygveaa/kitty 2020-02-23 18:21:27 +05:30
Trygve Aaberge
6a3eb3f3d7 tui line_edit: Set correct cursor position on end
Previously, the cursor would end up one character after the last typed
character when pressing end in the unicode input kitten.
2020-02-23 11:58:44 +01:00
Kovid Goyal
533a739e2b Put back the Brewfile 2020-02-22 19:07:17 +05:30
Kovid Goyal
b12a8331f1 Bump version of macOS for brew based CI 2020-02-22 18:59:34 +05:30
Kovid Goyal
8f4ec036e7 Install sphinx via pip rather than brew
That's what brew advises
2020-02-22 18:47:46 +05:30
Kovid Goyal
cba36f2240 brew bundle seems to have been removed 2020-02-22 18:36:07 +05:30
Kovid Goyal
b54ffbefe4 Ignore setlocale() failures on Linux as well
There are apparently some Linux systems that manage to bork their
locales out there. So just go on with the C locale on these systems.
2020-02-22 18:13:49 +05:30
Kovid Goyal
6d470e4da0 Merge branch 'patch-1' of https://github.com/MaxNoe/kitty 2020-02-20 15:57:18 +05:30
Kovid Goyal
4e1ebec8c2 Merge branch 'fix-menory-leak' of https://github.com/Luflosi/kitty 2020-02-20 15:55:18 +05:30
Maximilian Nöthe
e9779258e9 Make links clickable in INSTALL.md 2020-02-20 11:10:49 +01:00
Luflosi
5c83f45bc6 Fix memory leak when realloc() fails 2020-02-20 10:54:10 +01:00
Kovid Goyal
eb65aca1f4 Merge branch 'fix-boolean-assign-to-pointer' of https://github.com/Luflosi/kitty 2020-02-20 08:02:30 +05:30
Luflosi
5d7e393c93 Fix boolean value assigned to pointer
Found with Cppcheck.
2020-02-20 02:51:40 +01:00
Kovid Goyal
d6d01102fe diff kitten: Fix directory diffing with removed binary files failing
Fixes #2378
2020-02-19 19:53:19 +05:30
Kovid Goyal
1ad802b194 Make re-using the tall neighbor code safer 2020-02-19 15:42:01 +05:30
Kovid Goyal
4a191b65bb Fix a regression in the previous release that broke switching to neighboring windows in the Grid layout when there are less than four windows
Fixes #2377
2020-02-19 15:27:56 +05:30
Kovid Goyal
65cc9f4e1b Merge branch 'patch-1' of https://github.com/felixonmars/kitty 2020-02-19 08:28:15 +05:30
Felix Yan
9f4b13b523 Correct a typo in cmds.py 2020-02-19 05:12:25 +08:00
Kovid Goyal
97e1b62a1e Merge branch 'typo' of https://github.com/Luflosi/kitty 2020-02-18 21:02:48 +05:30
Luflosi
3ac966a38b Fix typo 2020-02-18 16:00:28 +01:00
Kovid Goyal
6f1fda0a48 Store cell half information in selection objects 2020-02-18 17:45:07 +05:30
Kovid Goyal
c00b486864 Track which horizontal half of the cell the mouse is in 2020-02-18 10:20:26 +05:30
Kovid Goyal
7928fff645 Update list of GLFW keys in the doc to use kitty's forked GLFW 2020-02-17 17:52:35 +05:30
Kovid Goyal
0285f5a1ad oops 2020-02-17 16:24:40 +05:30
Kovid Goyal
56e5c8be32 macOS: When switching inpt method while a pending multi-key input is in progress, clear the pending input
Fixes #2358
2020-02-17 15:30:03 +05:30
Kovid Goyal
ef569976cb Merge branch 'glfw_upstream' of https://github.com/Luflosi/kitty 2020-02-17 09:40:55 +05:30
Luflosi
f8ae048d60 X11: Fix setting the clipboard string to itself
From upstream: 0c27ed1d0e.
2020-02-17 01:12:52 +01:00
Kovid Goyal
c51f4df0ca When the application running in the terminal grabs the mouse, pass middle clicks to the application unless the terminal_select_modifiers are pressed
Fixes #2368
2020-02-16 22:55:18 +05:30
Kovid Goyal
84453bf15c Add a test for #2284 2020-02-16 21:14:08 +05:30
Kovid Goyal
917350f058 Fix incorrect rendering of selection when using rectangular select and scrolling
Fixes #2351
2020-02-16 21:10:09 +05:30
Kovid Goyal
0c58662eb6 Fix fade style tab bar showing opaque background after last tab 2020-02-16 15:11:55 +05:30
Kovid Goyal
52ca75855e Use some of th eglyphs from the poweline extra glyphs set in the symbol_map example 2020-02-16 12:17:34 +05:30
Kovid Goyal
49a07651b9 Merge branch 'typo' of https://github.com/Luflosi/kitty 2020-02-16 08:13:06 +05:30
Luflosi
90a8ba3789 Fix typo in comment 2020-02-15 18:52:18 +01:00
Kovid Goyal
734c3199f0 Fix rendering of combining characters with fonts that have glyphs for precomposed characters but not decomposed versions
Fix #2365
2020-02-15 21:55:17 +05:30
Kovid Goyal
64567646d9 Build with fortify source on clang as well 2020-02-13 11:20:57 +05:30
Kovid Goyal
1a1638cc7f Build with _FORTIFY_SOURCE on gcc 2020-02-13 10:39:57 +05:30
Kovid Goyal
fdf055312c DRYer 2020-02-13 10:07:55 +05:30
Kovid Goyal
b0b8b06b56 Scrolling test 2020-02-13 10:02:44 +05:30
Kovid Goyal
9c1ffb1adf Test for rectangle select 2020-02-13 08:52:33 +05:30
Kovid Goyal
563bafea08 Merge options when testing 2020-02-13 08:33:57 +05:30
Kovid Goyal
efe4c32ffd Fix mock window not being zeroes on creation 2020-02-12 21:34:19 +05:30
Kovid Goyal
0f003a9a77 Remove unused code 2020-02-12 21:28:48 +05:30
Kovid Goyal
3eff929652 More mouse interaction tests 2020-02-12 21:19:25 +05:30
Kovid Goyal
3010ebfef5 More mouse interaction tests 2020-02-12 19:02:38 +05:30
Kovid Goyal
ff14f47781 First mouse interaction test 2020-02-12 15:21:59 +05:30
Kovid Goyal
0b99a5caae APIs for testing mouse interaction 2020-02-12 10:14:17 +05:30
Kovid Goyal
467b96f2f2 Ensure vao_idx is invalid when releasing gpu resources 2020-02-12 09:20:41 +05:30
Kovid Goyal
18751a05c0 Dont use splitlines() to replace \n with \r in pasted text
splitlines breaks on a whole bunch of characters besides \r and \n.
2020-02-11 08:16:20 +05:30
Kovid Goyal
9007623d0c macOS: Fix menubar title not updating on OS Window focus change
Fixes #2350
2020-02-10 07:27:40 +05:30
Kovid Goyal
c1abb7038d Fix border/margin/padding sizes not being recalculated on DPI change
Fixes #2346
Fixes #2347
2020-02-09 08:31:09 +05:30
Kovid Goyal
53f7eebc4d Add changelog entry 2020-02-09 08:04:18 +05:30
Kovid Goyal
d54d29122d Merge branch 'Nudin-patch-1' of https://github.com/Nudin/kitty 2020-02-09 08:03:06 +05:30
Michael F. Schönitzer
1d71791b3c Bugfix exception when executing marker functions
Fixes the exception below that happened for function-markers:
```
Traceback (most recent call last):
  File "/usr/bin/../lib/kitty/kitty/boss.py", line 540, in dispatch_special_key
    return self.dispatch_action(key_action)
  File "/usr/bin/../lib/kitty/kitty/boss.py", line 612, in dispatch_action
    passthrough = f(*key_action.args)
  File "/usr/bin/../lib/kitty/kitty/window.py", line 615, in toggle_marker
    self.screen.set_marker(marker_from_spec(ftype, spec, flags))
  File "/usr/bin/../lib/kitty/kitty/marks.py", line 92, in marker_from_spec
    return marker_from_function(runpy.run_path(path, run_name='__marker__').marker)
```
2020-02-08 19:28:53 +01:00
Kovid Goyal
0c6145d4f2 ... 2020-02-08 14:08:10 +05:30
Kovid Goyal
62e273c5bb unicode input kitten: Allow pressing :kbd:ctrl+tab to change the input mode
Fixes #2343
2020-02-08 13:29:50 +05:30
Kovid Goyal
d82f399be7 ... 2020-02-06 21:16:16 +05:30
Kovid Goyal
20a7050564 Merge branch 'underline_thickness_option' of https://github.com/noomly/kitty 2020-02-06 21:14:34 +05:30
Kovid Goyal
b235f411b0 X11: Fix arrow mouse cursor using right pointing instead of the default left pointing arrow
Fixes #2341
2020-02-06 21:11:09 +05:30
Eyal Chojnowski
99faeeacfc Add PR number to changelog 2020-02-06 16:24:51 +01:00
Eyal Chojnowski
08ad4f389d Fix linting 2020-02-06 16:21:32 +01:00
Eyal Chojnowski
edba63d0d9 Make underline cursor thickness configurable 2020-02-06 16:15:12 +01:00
Kovid Goyal
e33f882abc Changelog entry for cursor beam thickness option 2020-02-06 17:52:40 +05:30
Kovid Goyal
53e059f4f7 Merge branch 'beam_thickness_configurable' of https://github.com/noomly/kitty 2020-02-06 17:49:34 +05:30
Eyal Chojnowski
830364e026 Fix option_type 2020-02-06 13:05:10 +01:00
Eyal Chojnowski
332714a925 Make cursor beam thickness configurable 2020-02-06 12:54:42 +01:00
Kovid Goyal
1eee6deb22 Fix #2339 2020-02-06 16:21:40 +05:30
Kovid Goyal
547f138703 Bound width and height for render_curosr 2020-02-06 06:55:13 +05:30
Kovid Goyal
b6c345fc3c Merge branch 'patch-2' of https://github.com/ctrlcctrlv/kitty 2020-02-05 09:58:07 +05:30
Fredrick Brennan
29c40a4957 Update changelog.rst
This change was discussed privately, lest I appear presumptuous for thanking myself :-)
2020-02-05 12:22:54 +08:00
Kovid Goyal
72af821e1b Freeing bgimage should always null its pointer 2020-02-04 09:51:35 +05:30
Kovid Goyal
5fe4d10f38 Only do processing if pager is not an absolute path 2020-02-03 08:05:34 +05:30
Kovid Goyal
3b36470e84 When resolving scrollback pager if it is not present in system PATH try using shell PATH 2020-02-03 08:03:35 +05:30
Kovid Goyal
f9e8a4050c Allow leading and trailing spaces in tab_title_template by using quotes
Fixes #2332
2020-02-02 21:02:34 +05:30
Kovid Goyal
ce308286df Dont need to bind blit vertex array as cells vertex array is already bound 2020-02-02 20:56:42 +05:30
Kovid Goyal
b670973226 When unsetting bg image borders need to be redone to ensure blank rects are present 2020-02-02 20:51:31 +05:30
Kovid Goyal
01b11b8a53 Allow removing background image via @ set-background-image 2020-02-02 20:41:52 +05:30
Kovid Goyal
75c47a8659 Proper fix for not drawing blank rects when bg image is present 2020-02-02 20:20:45 +05:30
Kovid Goyal
5b4e0ed483 Fix #2331
Some leftover unused code from the bg image merge
2020-02-02 20:09:17 +05:30
Kovid Goyal
7432a7f346 Bind empty VAO when tinting 2020-02-02 14:48:47 +05:30
Kovid Goyal
0830fc3b5a Make background_image tint useable even without a background image in a transparent window 2020-02-02 12:40:29 +05:30
Kovid Goyal
ab2c901e85 Implement bg image tint for transparent windows 2020-02-02 12:34:35 +05:30
Kovid Goyal
3774cc54c7 Fix rendering of semi-transparent bg images in semi-transparent windows
Output colors must be premultiplied
2020-02-02 11:45:48 +05:30
Kovid Goyal
330ed8e4ae Add an option to tint background images using the current background color
Note still has to be implemented for transparent windows
2020-02-02 11:22:21 +05:30
Kovid Goyal
eddae44d6d Fix leak when changing background image using remote control 2020-02-02 09:27:58 +05:30
Kovid Goyal
226488717a Add completion for image filenames at command line
Sadly could not get it to work with the shell
2020-02-01 12:33:11 +05:30
Kovid Goyal
2f9dabd344 Fix unwanted scaling when tiling bg image 2020-02-01 11:41:06 +05:30
Kovid Goyal
cf1b7c0adb Allow set_background_image to work over SSH 2020-02-01 11:35:12 +05:30
Kovid Goyal
eb57d0d431 Remote control command to set background image 2020-02-01 10:50:56 +05:30
Kovid Goyal
8116ee015a API for changing the background image of OS windows
Uses reference counting
2020-02-01 09:17:41 +05:30
Kovid Goyal
0fa3cec61f Add support for specifying a background image
Fixes #163
2020-01-31 20:22:29 +05:30
Kovid Goyal
eb60464177 No need to zero background opacity
We anyway dont draw the default background color in
draw_interleaved(_premult)
2020-01-31 18:51:02 +05:30
Kovid Goyal
44b2651a0f Fix draw_cells_interleaved_premult() for drawing with and without a background image 2020-01-31 15:40:00 +05:30
Kovid Goyal
f2e91b5ed2 Remove incorrect setting of bgimage unit in graphics program 2020-01-31 15:28:21 +05:30
Kovid Goyal
e72b60c882 tiling->tiled 2020-01-31 15:11:30 +05:30
Kovid Goyal
5263babc9a Use a single program for drawing background images 2020-01-31 15:09:47 +05:30
Kovid Goyal
9034b50b3a Dont use a separate background image opacity setting 2020-01-31 14:05:25 +05:30
Kovid Goyal
fdd7fe1948 Properly release resources used by bgimage
Also allow per OS Window bg images in the future
2020-01-31 12:17:54 +05:30
Kovid Goyal
8e7b8b70dc A VAO is not needed to draw background images 2020-01-31 11:34:34 +05:30
Kovid Goyal
9bf24bdff5 Cleanup png_path_to_bitmap() 2020-01-31 09:46:16 +05:30
Kovid Goyal
ee53edd96d Fix conversion of background_image option to C
Should handle None and not rely on the python object's lifetime.
Also some miscellaneous cleanups.
2020-01-31 09:03:19 +05:30
Kovid Goyal
1bc5d7038d Merge branch 'bgimage' of https://github.com/ctrlcctrlv/kitty 2020-01-31 07:58:55 +05:30
Fredrick Brennan
8a6b8b415c More stylistic fixes 2020-01-31 09:48:28 +08:00
Kovid Goyal
86174c81c8 Some tests for splits layout 2020-01-30 20:30:52 +05:30
Kovid Goyal
374500d7b0 py3.5 compat 2020-01-30 18:55:58 +05:30
Kovid Goyal
319a141967 grammar 2020-01-30 18:52:40 +05:30
Kovid Goyal
c0d0062ef8 Add docs for individual layouts
Also changelog entry for the splits layout
Fixes #2308
2020-01-30 18:50:28 +05:30
Fredrick Brennan
aaaa34e119 Move a bunch of unneeded stuff 2020-01-30 18:08:25 +08:00
Fredrick Brennan
fba9502a9d Fix background_image_linear 2020-01-30 18:01:28 +08:00
Kovid Goyal
6670cc1534 Dont swap when removing overlay window in splits 2020-01-30 15:28:51 +05:30
Kovid Goyal
970729dca0 Work on expanding documentation for layouts 2020-01-30 15:06:23 +05:30
Fredrick Brennan
6627586d6e Fix pedantic compiler test 2020-01-30 17:31:37 +08:00
Fredrick Brennan
9f364209af Add background_image 2020-01-30 17:23:42 +08:00
Kovid Goyal
c31a39a052 Action to convert between vertical and horizontal splits 2020-01-30 14:34:40 +05:30
Kovid Goyal
36fda90814 Implement window movement for splits 2020-01-30 13:33:15 +05:30
Kovid Goyal
7ccfbc16e9 DRYer 2020-01-30 07:26:32 +05:30
Kovid Goyal
ad3b527bc4 Neighboring windows for splits 2020-01-30 07:09:33 +05:30
Kovid Goyal
f7eef3f456 Minimal borders for the splits layout 2020-01-30 06:12:45 +05:30
Kovid Goyal
1870364888 When laying out windows in splits shove them offscreen if their widths/heights become too small as too small values will cause crashes 2020-01-30 06:12:45 +05:30
Kovid Goyal
d7dfc85cf7 A __repr__ for Pairs 2020-01-30 06:12:45 +05:30
Kovid Goyal
c047e5f16a Implement perpendicular axis resizing for splits 2020-01-30 06:12:45 +05:30
Kovid Goyal
8d21f63ec2 Resizing of a single split 2020-01-30 06:12:45 +05:30
Kovid Goyal
85b6a91e5c Blank rects for splits layout 2020-01-30 06:12:45 +05:30
Kovid Goyal
c788e30b66 Implement adding of windows to splits layout 2020-01-30 06:12:45 +05:30
Kovid Goyal
a99caed693 Basic implementation of splits layout 2020-01-30 06:12:45 +05:30
Kovid Goyal
9589fb5275 Clarify docs for background_opacity 2020-01-30 05:59:52 +05:30
Kovid Goyal
1a6dc530a4 Improve create_marker docs 2020-01-29 14:41:01 +05:30
Kovid Goyal
60835871eb Better error message when user does not specify strategy for disabling ligatures 2020-01-28 15:23:08 +05:30
Kovid Goyal
644ee646a2 version 0.16.0 2020-01-28 08:48:00 +05:30
Kovid Goyal
8f1ec053ef ... 2020-01-27 08:50:29 +05:30
Kovid Goyal
2e3037ce3a Wayland: Fix window titles being set to very long strings on the order of 8KB causing a crash
Fixes #1526
2020-01-27 08:49:25 +05:30
Kovid Goyal
109a856b91 Fix #2313 2020-01-26 08:00:06 +05:30
Kovid Goyal
eaec854bfb ... 2020-01-25 11:51:17 +05:30
Kovid Goyal
2c6cc6f047 Remove unused slot 2020-01-25 11:22:22 +05:30
Kovid Goyal
f32ae10339 Use a global cache instead of a per window cache for grid size calculation 2020-01-25 11:21:05 +05:30
Kovid Goyal
c46317f96f Use typed layout data 2020-01-25 11:11:55 +05:30
Kovid Goyal
a67e4e550e Merge branch 'issue2310' of https://github.com/ctrlcctrlv/kitty 2020-01-24 13:43:15 +05:30
Fredrick Brennan
65a7b19f40 Make each OS window have its own framebuffer
This commit fixes graphics rendering when more than one OS window is
open, all OS windows are semi-transparent, and multiple windows contain
graphics.

This commit closes #2310.
2020-01-24 16:06:57 +08:00
Kovid Goyal
1b5daf930a Make the comment explaining wayland polling more detailed 2020-01-23 15:08:54 +05:30
Kovid Goyal
748ca81d4b Wayland: Fix a freeze in rare circumstances when having multiple OS Windows
Fixes #2307
Fixes #1722
2020-01-23 15:07:22 +05:30
Kovid Goyal
0ea7d24ba4 Fix incorrect offset when rendering images and there are +z-index, -z-index and --z-index images 2020-01-21 08:09:04 +05:30
Kovid Goyal
6c9861cb76 Fix incorrect blending of default bg color when using draw_cells_interleaved_premult with images but no below images 2020-01-21 07:59:44 +05:30
Kovid Goyal
a1125b5cc8 Move draw_bg multiplication into vertex shader 2020-01-21 07:58:34 +05:30
Kovid Goyal
b4e189d2bf Merge branch 'simplify' of https://github.com/Luflosi/kitty 2020-01-21 06:54:28 +05:30
Luflosi
dbc763fca0 Remove useless code from shader 2020-01-21 00:28:55 +01:00
Kovid Goyal
4c03ffeae2 Merge branch 'patch-1' of https://github.com/ctrlcctrlv/kitty 2020-01-18 15:11:03 +05:30
Fredrick Brennan
2719ac7d01 Add :pull:2248 to changelog.rst
It was missing
2020-01-18 17:34:27 +08:00
Kovid Goyal
219b81b5ee typo 2020-01-18 08:19:42 +05:30
Kovid Goyal
8e1443360f Merge branch 'force_ltr' of https://github.com/ctrlcctrlv/kitty 2020-01-18 08:07:56 +05:30
Kovid Goyal
d55242aa82 Merge branch 'master' of https://github.com/mfilenko/kitty 2020-01-17 21:40:10 +05:30
Max Filenko
ba531969ec List layouts in their default order 2020-01-17 16:28:44 +01:00
Max Filenko
c12e7587cb Document default configuration 2020-01-17 16:28:30 +01:00
Kovid Goyal
3aac0860a2 Merge branch 'glfw_upstream' of https://github.com/Luflosi/kitty 2020-01-17 20:28:26 +05:30
Luflosi
e4fd12001c Cocoa: Add fully dynamic loading of Vulkan loader
From upstream: 7da87aaae7.
2020-01-17 14:18:28 +01:00
Luflosi
3581ffe04b Cocoa: Select Vulkan surface extension at runtime
From upstream: 15d91801b7.
2020-01-17 14:18:21 +01:00
Luflosi
f6901e4a3d Cocoa: Add support for VK_EXT_metal_surface
From upstream: c5cb4a253a.
2020-01-17 14:18:05 +01:00
Fredrick Brennan
5a2cc4578e force_ltr also makes FriBidi usable
Add above fact to documentation.
2020-01-17 17:57:26 +08:00
Fredrick Brennan
6b5acc4d3d Add force_ltr
Close #2252
2020-01-17 16:22:40 +08:00
Kovid Goyal
43326c9bd0 Fix URL detection not working for urls of the form scheme:///url
Fixes #2292
2020-01-17 07:49:01 +05:30
Kovid Goyal
96f3253e6d goto_tab now maps numbers larger than the last tab to the last tab
Fixes #2291
2020-01-16 20:17:17 +05:30
Kovid Goyal
f5090c951a Merge branch 'with_open' of https://github.com/Luflosi/kitty 2020-01-16 19:41:55 +05:30
Luflosi
edacdc5e25 Use python context manager to open file 2020-01-16 14:11:54 +01:00
Kovid Goyal
c67661af61 oops 2020-01-15 21:39:13 +05:30
Kovid Goyal
5e60329adf Changelog entry to titlebar-only 2020-01-15 21:37:20 +05:30
Kovid Goyal
6b4f8408de Merge branch 'macos_hide_titlebar' of https://github.com/Luflosi/kitty 2020-01-15 21:36:03 +05:30
Luflosi
ea1ef709c6 macOS: Allow hiding the titlebar only instead of all window decorations
Thanks to @ntruong for writing cb8279ec54 and  6807411365, the code was very helpful.
2020-01-15 16:35:36 +01:00
Kovid Goyal
bbf247c5c0 Merge branch 'glfw_upstream' of https://github.com/Luflosi/kitty 2020-01-15 19:32:12 +05:30
Kovid Goyal
8243fd505f Make mark colors per window 2020-01-15 18:42:37 +05:30
Luflosi
ed9f9db1b0 X11: Fix parent window handle initialization
From upstream: 9372ba95fa.
2020-01-15 13:19:33 +01:00
Luflosi
74bed658e1 X11: Fix no window position events during resize
From upstream: fe57e3c292.
2020-01-15 13:19:32 +01:00
Kovid Goyal
2f7bdc274d Fix failing test 2020-01-15 11:48:13 +05:30
Kovid Goyal
1347ff27d9 Changelog entry for triple click change 2020-01-15 11:46:50 +05:30
Kovid Goyal
5bf4d520f5 Merge branch 'master' of https://github.com/copy/kitty 2020-01-15 11:43:20 +05:30
Kovid Goyal
cf8d665eb7 Allow having more than one full height window in the :code:tall layout
Fixes #2276
2020-01-15 11:28:58 +05:30
Fabian
b2eee6df5c Multiline triple-click selections: Don't ignore leading spaces in first line 2020-01-14 21:04:59 -06:00
Kovid Goyal
e8121b39ec Add newer layout classes to tests 2020-01-15 08:14:45 +05:30
Kovid Goyal
5359abab76 next version should be 0.16.0 2020-01-15 08:05:45 +05:30
Kovid Goyal
01644ac3f0 Changelog entry for marks 2020-01-15 08:05:12 +05:30
Kovid Goyal
8fbf552494 Allow opening new tabs/windows before the current tab/window as well as after it with the :option:launch --location option. 2020-01-15 08:02:05 +05:30
Kovid Goyal
9c3390c5e6 Allow specifying a marker when launching windows 2020-01-15 07:22:32 +05:30
Kovid Goyal
24d45b99e3 typo 2020-01-15 07:13:32 +05:30
Kovid Goyal
936f2186cc Allow scrolling to marks 2020-01-15 07:11:34 +05:30
Kovid Goyal
c68b302fa2 Merge branch 'wayland' of https://github.com/kennylevinsen/kitty 2020-01-15 06:51:24 +05:30
Kenny Levinsen
ca7cab1a2d wayland: Consistently use errno for errors 2020-01-14 20:06:13 +01:00
Kenny Levinsen
083b294659 wayland: Simplify dispatch_pending error handling
wl_display_dispatch_pending does not return EAGAIN, and always sets an
error when it fails. This allows us to handle errors in a simpler
manner.
2020-01-14 20:04:23 +01:00
Kenny Levinsen
bc24716476 wayland: errno does not have to be cleared
As long as errno is only read on error from an errno-setting function,
then there is no need to reset errno between uses.
2020-01-14 20:04:23 +01:00
Kenny Levinsen
4acab65016 wayland: Only cancel display read after prepare success
The display reader count only increments when wl_display_prepare_read
succeeds.  Calling wl_display_cancel_read when wl_display_prepare_read
has not succeeded results in a negative reader count, which does not
have well-defined behavior.
2020-01-14 20:00:47 +01:00
Kenny Levinsen
f6b03f106c wayland: Cancel display read before abortOnFatalError
Calling wl_display_cancel_read immediately ensures that other readers
waiting on us will have a chance to wake up and discover the error in a
timely manner.
2020-01-14 19:59:02 +01:00
Kovid Goyal
8f9bbeabd7 Fix reference to --debug-config 2020-01-14 19:50:18 +05:30
Kovid Goyal
ac72ac7af2 Wayland: On dispatch error cancel read before running fatal error handlers
Might help #1722
2020-01-14 19:48:28 +05:30
Kovid Goyal
68e00bc8e1 Proper fix for #2270
Fixes #2270
2020-01-14 18:50:06 +05:30
Kovid Goyal
922d6b3b32 Fix #2270 2020-01-14 17:20:35 +05:30
Kovid Goyal
4dde98305e Allow setting markers using remote control 2020-01-14 15:06:52 +05:30
Kovid Goyal
3593189a75 Add a link to the marks docs 2020-01-14 13:45:37 +05:30
Kovid Goyal
4f135be86c Allow creating markers dynamically 2020-01-13 20:05:50 +05:30
Kovid Goyal
605b32f78a Merge branch 'dryer' of https://github.com/Luflosi/kitty 2020-01-13 19:42:56 +05:30
Luflosi
476a8b1429 DRYer
Inspired by e0c66ea5ba.
2020-01-13 14:35:17 +01:00
Kovid Goyal
da9165aebf More marker docs 2020-01-13 12:54:29 +05:30
Kovid Goyal
455a1e9532 Basic docs for marking 2020-01-13 12:38:58 +05:30
Kovid Goyal
f12031e284 Make the run-program example a little fancier 2020-01-13 12:16:43 +05:30
Kovid Goyal
df551bc992 Change marker 1 color 2020-01-13 11:58:18 +05:30
Kovid Goyal
35fb702833 Use only a single marker function
Multipe colors/expressions can instead be combined at definition time
2020-01-13 11:57:19 +05:30
Kovid Goyal
072cd29e3c Make add_marker easier to use with combine 2020-01-13 09:56:39 +05:30
Kovid Goyal
624dd78460 Actually apply mark colors when rendering 2020-01-13 09:51:03 +05:30
Kovid Goyal
51c4737a29 Test function marking 2020-01-13 06:50:37 +05:30
Kovid Goyal
d63ea11cac Marking now works 2020-01-13 06:50:37 +05:30
Kovid Goyal
3d307794be Function to get marks for testing 2020-01-13 06:50:36 +05:30
Kovid Goyal
d32a05925f Code to add and remove markers using maps 2020-01-13 06:50:36 +05:30
Kovid Goyal
04006ea81e Wrapper functions to handle passing matching values to C code 2020-01-13 06:50:36 +05:30
Kovid Goyal
1723616968 Code to apply match colors based on match results 2020-01-13 06:50:36 +05:30
Kovid Goyal
23bc2171c9 Avoid a double call for mark functions 2020-01-13 06:50:36 +05:30
Kovid Goyal
0b3602f764 Code to add markers to Screen 2020-01-13 06:50:36 +05:30
Kovid Goyal
0e448347cd Fix #2279 2020-01-13 06:50:14 +05:30
Kovid Goyal
e0c66ea5ba DRYer 2020-01-12 21:42:12 +05:30
Kovid Goyal
268de9a9d5 Merge branch 'add_CIRCUMFLEX_to_control_codes' of https://github.com/Luflosi/kitty 2020-01-12 21:03:27 +05:30
Luflosi
74eb523178 Add GLFW_KEY_CIRCUMFLEX to control_codes
See https://github.com/kovidgoyal/kitty/issues/1990.
2020-01-12 16:27:40 +01:00
Kovid Goyal
8c540d5a46 Fix #2277 2020-01-12 20:00:08 +05:30
Kovid Goyal
2045055ae3 Use actual color value comparison when detecting default background color
This is very slightly more GPU intensive but means that even if
an application explicitly sets the color to be the same as the default
color, it will be transparent.
2020-01-12 18:14:03 +05:30
Kovid Goyal
d8ed135b46 Clean up rendering of cell backgrounds 2020-01-12 13:20:23 +05:30
Kovid Goyal
3a4ba7e834 Remove un-needed variable 2020-01-12 10:55:14 +05:30
Kovid Goyal
fab57fbdf1 Micro-optimization 2020-01-12 10:53:27 +05:30
Kovid Goyal
76a93b6cd6 DRYer 2020-01-12 10:52:42 +05:30
Kovid Goyal
f44c3a4606 Forgot to update comment describing render pipeline 2020-01-12 10:26:25 +05:30
Kovid Goyal
714bee7f45 Only use an extra draw call for the background when drawing interleaved cells if it is actually required 2020-01-12 09:37:16 +05:30
Kovid Goyal
91673642b3 icat: Allow easily specifying z-index values below background threshold 2020-01-12 09:36:11 +05:30
Kovid Goyal
fee08d746c Merge branch 'replace_exception_with_alias' of https://github.com/Luflosi/kitty 2020-01-11 21:21:52 +05:30
Luflosi
527ff0238a Replace all instances of EnvironmentError with OSError
According to the text just above https://docs.python.org/3/library/exceptions.html#EnvironmentError, `EnvironmentError` has been an alias of `OSError` since Python 3.3. Replacing it makes the code more consistent since `OSError` is used in other places in the code too.
2020-01-11 16:47:36 +01:00
Kovid Goyal
789d649b5c defaultbg should be a local variable 2020-01-11 16:59:50 +05:30
Fredrick Brennan
8020657d8c Allow drawing images below cells w/background 2020-01-11 16:56:59 +05:30
Kovid Goyal
a15d3ff12d ... 2020-01-10 10:19:02 +05:30
Kovid Goyal
fbce95aeda Add an example for open file hints 2020-01-10 10:18:18 +05:30
Kovid Goyal
9bc1b5a2d9 hints kitten: Allow pressing :sc:goto_file_line to quickly open the selected file at the selected line in vim
Fixes #2268
2020-01-10 10:01:03 +05:30
Kovid Goyal
6a8b7bf92f Merge branch 'with_suppress' of https://github.com/Luflosi/kitty 2020-01-09 20:58:37 +05:30
Luflosi
48728bdfdc Use "with suppress()" to suppress a python exception 2020-01-09 16:21:56 +01:00
Kovid Goyal
b6416cf8a9 Merge branch 'glfw_upstream' of https://github.com/Luflosi/kitty 2020-01-09 06:58:30 +05:30
Luflosi
053de5763a X11: Fix BadMatch focusing a window on non-EWMH WM
From upstream: aa5e313561.
2020-01-08 19:50:17 +01:00
Kovid Goyal
fdb915d0c8 Merge branch 'zindex' of https://github.com/ctrlcctrlv/kitty 2020-01-08 18:20:34 +05:30
Fredrick Brennan
c2769c9aed Add --z-index to icat kitten
Meow.
2020-01-08 20:08:01 +08:00
Kovid Goyal
57deb19d0b typo 2020-01-07 10:45:05 +05:30
Kovid Goyal
321771b150 Merge branch 'resize-by-increments' of https://github.com/aes/kitty 2020-01-07 10:44:55 +05:30
Kovid Goyal
61dd2011f5 Dont rely on fontconfig to get postscript names 2020-01-07 09:30:41 +05:30
Kovid Goyal
8a5f189213 Ignore invalid font features when parsing config 2020-01-07 09:20:04 +05:30
Kovid Goyal
14560b008a Clean up font features merge 2020-01-07 08:54:32 +05:30
Kovid Goyal
db85e07d41 Merge branch 'master' of https://github.com/ctrlcctrlv/kitty 2020-01-07 07:18:31 +05:30
Kovid Goyal
07c838fe24 Merge branch 'round_printed_timeout' of https://github.com/Luflosi/kitty 2020-01-06 07:14:53 +05:30
Luflosi
1583b1b0c6 Print warning message timeout rounded to two digits after the dot
The timeout is 0.25 seconds. Printing 0.25 instead of 0.250000 looks a lot nicer and a resolution of 10 milliseconds should be enough for this warning message anyways.
2020-01-05 16:10:10 +01:00
Fredrick Brennan
d250555cd0 Make font_feature_settings respect disable_ligatures 2020-01-04 20:11:34 +08:00
Fredrick Brennan
dbd0dab154 Revert addition of ffs_set to Font struct
It was from an earlier stage of development and is not needed
2020-01-04 15:37:05 +08:00
Fredrick Brennan
b479ea410d Prevent leaks
Thanks @martinetd
2020-01-04 15:34:47 +08:00
Fredrick Brennan
1db613e95b Add font_feature_settings
Close #2247
2020-01-04 14:36:20 +08:00
Kovid Goyal
70071fe1f6 Merge branch 'simplify' of https://github.com/Luflosi/kitty 2020-01-03 07:46:58 +05:30
Luflosi
58688dda38 Remove duplicate code
The hints, once set with `glfwWindowHint()`, retain their values until changed again. This means, that the `GLFW_DECORATED` hint only needs to be set once, even on non-macOS.
2020-01-03 03:01:53 +01:00
Kovid Goyal
756d65c41e Merge branch 'glfw_upstream' of https://github.com/Luflosi/kitty 2020-01-03 07:18:25 +05:30
Luflosi
b9a08eacb0 X11: Cleanup
From upstream: 8149a5fc00.
2020-01-03 02:37:19 +01:00
Kovid Goyal
b653711446 Merge branch 'glfw_upstream' of https://github.com/Luflosi/kitty 2020-01-03 06:48:30 +05:30
Luflosi
e725c647ef Cocoa: Only create per-monitor display link once
From upstream: b4a8eb9b19.
2020-01-02 18:05:38 +01:00
Kovid Goyal
003f77b257 Merge branch 'add_macos_help_menu_item' of https://github.com/Luflosi/kitty 2019-12-29 22:03:08 +05:30
Luflosi
10b578e6d2 Add help menu to macOS menu bar
Most macOS Apps have a Help menu as the last menu item in the menu bar. They usually have a menu item with the keyboard shortcut <kbd>⌘</kbd>+<kbd>?</kbd>, which shows some kind of help or documentation. I named the menu item "Visit kitty website" and let it open the kitty website as documentation.
macOS also magically adds a search feature to the help menu.
2019-12-29 17:24:12 +01:00
Kovid Goyal
151c6c2c70 Merge branch 'always_show_menu_item' of https://github.com/Luflosi/kitty 2019-12-29 20:53:22 +05:30
Luflosi
53e6de9bd9 Always show the macOS New OS Window menu item
When there is no keyboard shortcut for a new OS window, the macOS menu item should still exist, it should just not have a keyboard shortcut.
2019-12-29 15:27:52 +01:00
Kovid Goyal
66a455a079 Merge branch 'simplify' of https://github.com/Luflosi/kitty 2019-12-29 19:45:07 +05:30
Luflosi
f8855410e0 Simplify some code in kitty/cocoa_window.m
`addItemWithTitle:` can be used instead of `initWithTitle:`. It returns an `NSMenuItem`, which removes the need for allocating an `NSMenuItem` manually and releasing it again.
2019-12-29 14:33:19 +01:00
Kovid Goyal
93e8074325 ... 2019-12-28 08:49:53 +05:30
Kovid Goyal
296f512bfb Forgot you cant use sizeof on arrays passed as function parameters 2019-12-28 08:44:32 +05:30
Kovid Goyal
c8f20d0edf Ensure key name is null terminated 2019-12-28 08:33:13 +05:30
Kovid Goyal
286f3630d7 Merge branch 'macos_fix_keyboard_shortcut_encoding' of https://github.com/Luflosi/kitty 2019-12-28 08:26:03 +05:30
Luflosi
38423505b1 Remove numpad keys from macOS keyboard shortcuts
See previous commit message for the reason.
2019-12-27 15:12:26 +01:00
Luflosi
9a3c621eb6 Fix macOS keyboard shortcut encoding
`glfwGetCocoaKeyEquivalent()` in `glfw/cocoa_window.m` expects the returned characters to be of type `unichar`, which won't work for all unicode characters because it is defined as `unsigned short` according to https://developer.apple.com/documentation/foundation/unichar?language=objc, which is only guaranteed to be at least 16 bits in size. The code calling this function also expects the encoding to be UTF-16.
When I added the various keys in https://github.com/kovidgoyal/kitty/pull/1928, I missed these facts. This means, that `glfwGetCocoaKeyEquivalent()` will behave unexpectedly when called with any of the new-ish keys. Luckily this function is currently only used for determining the macOS shortcut for `new_os_window` but I plan on using it more in the future.
Some of the constants, e.g. `NSBackspaceCharacter` are UTF-16 constants, so we can't just use UTF-8 everywhere.
I fixed the problem by using either UTF-8 characters packed into a `uint32_t` or UTF-16 characters in a `unichar` and then converting them to a UTF-8 encoded char string.

`NSEventModifierFlagNumericPad` isn't guaranteed to fit in a `unichar`, which made this undefined behaviour. It also didn't work. I tried to make it work using `NSEventModifierFlagNumericPad` as a modifier instead, as can be seen in this commit, but couldn't get it to work either because the constants used are native key codes and not unicode characters. Therefore the numpad keys will be removed in the next commit.
2019-12-27 12:42:51 +01:00
Kovid Goyal
bcf847fe98 ... 2019-12-27 15:26:31 +05:30
Kovid Goyal
ee7a5eef99 Have read_shell_environment() not fail when no shell is present 2019-12-27 12:25:01 +05:30
Kovid Goyal
7bed66a458 Ensure ans is set in read_shell_environment
Fixes #2232
2019-12-27 12:20:06 +05:30
Kovid Goyal
b26229c44e Merge branch 'remove_release' of https://github.com/Luflosi/kitty 2019-12-26 08:48:20 +05:30
Luflosi
c497c0f96a Remove call to release on an automatically memory managed object
This call even reliably caused a crash for code I was trying to develop.
2019-12-25 20:29:07 +01:00
Kovid Goyal
6df64613f2 Merge branch 'replace_void_pointer' of https://github.com/Luflosi/kitty 2019-12-25 16:35:08 +05:30
Luflosi
46dd648380 Use the correct pointer type instead of void* 2019-12-25 11:51:40 +01:00
Kovid Goyal
4cd5de78c7 Merge branch 'generate_key_table' of https://github.com/Luflosi/kitty 2019-12-25 08:34:27 +05:30
Luflosi
32fa46d6eb Regenerate key table
Since `CIRCUMFLEX` and `^` were removed from `UN_SHIFTED_PRINTABLE` in b2d428618c by 3a2a16f54c and b5229ec73c, `generate_key_table()` wasn't yet run again.
2019-12-25 02:16:37 +01:00
Kovid Goyal
902c2f6c88 Merge branch 'update_comment' of https://github.com/Luflosi/kitty 2019-12-24 19:31:37 +05:30
Luflosi
2a5196873a Update comment to remove legacy way of starting kitty
Since 9135387cfa kitty should not be started with `python3 .` anymore.
2019-12-24 14:22:37 +01:00
Kovid Goyal
d2067141d3 Fix #2226 2019-12-24 17:10:33 +05:30
Kovid Goyal
b5229ec73c oops 2019-12-23 10:19:02 +05:30
Kovid Goyal
3a2a16f54c Merge branch 'add_circumflex_key' of https://github.com/Luflosi/kitty 2019-12-23 10:08:25 +05:30
Luflosi
b2d428618c Add circumflex (^) key 2019-12-22 18:41:07 +01:00
Kovid Goyal
97af84a063 version 0.15.1 2019-12-21 14:20:28 +05:30
Kovid Goyal
18faee6250 Merge branch 'glad2-regen' of https://github.com/Dav1dde/kitty 2019-12-20 20:19:54 +05:30
David Herberth
fd90a3ddc3 regenerates glad to fix missing APIENTRY 2019-12-20 15:04:23 +01:00
Kovid Goyal
a08931d84d Fix window not being rendered for the first time until some input has been received from child process
Fixes #2216
2019-12-20 08:46:50 +05:30
Kovid Goyal
2f0b6e24c9 Use pre-multiplied alpha when clearing windows
Apparently most systems expect this. See https://github.com/glfw/glfw/issues/1538
2019-12-20 08:16:10 +05:30
Kovid Goyal
33c5fc0fb6 typo 2019-12-20 07:59:55 +05:30
Kovid Goyal
71adb2dcf8 Merge branch 'new_os_window_key_macos' of https://github.com/Luflosi/kitty 2019-12-20 07:59:08 +05:30
Luflosi
1ae324691d Change keyboard shortcut selection algorithm for new_os_window on macOS
On macOS the keyboard shortcuts are visible in the menu bar. When the keyboard shortcut is used, the corresponding menu bar item flashes to indicate which action was just executed.
kitty allows defining multiple keyboard shortcuts for the same action but macOS allows only one, so kitty needs to decide which one should be handled by macOS. Currently it chooses the first keyboard shortcut with only the command key as a modifier key or the first shortcut when there are no shortcuts with only the command key as a modifier.
When a user tries to set their own keyboard shortcut (and doesn't use `clear_all_shortcuts yes`), this won't change the shortcut displayed in the menu bar since the first (default) shortcut with the command key is <kbd>⌘</kbd>+<kbd>n</kbd>.
I think simply choosing the last defined keyboard shortcut is better. This will even allow the user to specify modifier keys other than the command key while still changing the shortcut in the menu bar. This change will not change the default behaviour because all the macOS specific keyboard shortcuts are defined after the non-macOS specific ones.
2019-12-19 22:15:41 +01:00
Kovid Goyal
689d059517 Fix lines at the edge of the window at certain windows sizes when drawing images on a transparent window
Fixes #2079
Fixes #2214
2019-12-19 20:41:31 +05:30
Kovid Goyal
18f0ab9e02 Merge branch 'fix_typo' of https://github.com/Luflosi/kitty 2019-12-19 20:01:12 +05:30
Luflosi
088ab5f137 Fix typo 2019-12-19 13:40:08 +01:00
Kovid Goyal
3dd83975ba Dont cast double to monotonic_t for literals 2019-12-19 17:33:12 +05:30
Kovid Goyal
a796a6cbef Use exponential notation in monotonic.h 2019-12-19 17:22:33 +05:30
Kovid Goyal
4766d7de82 Merge branch 'glfw_upstream' of https://github.com/Luflosi/kitty 2019-12-19 17:19:42 +05:30
Luflosi
4a3686c16c X11: Cleanup
From upstream: 73a8ebb691.
2019-12-19 12:38:56 +01:00
Kovid Goyal
b49105495c Merge branch 'glfw_upstream' of https://github.com/Luflosi/kitty 2019-12-19 17:07:42 +05:30
Luflosi
ca2eda2c5b X11: Cleanup
From upstream: 4e70c95aa3.
2019-12-19 12:35:44 +01:00
Kovid Goyal
4fc7c4aafc Merge branch 'glfw_upstream' of https://github.com/Luflosi/kitty 2019-12-19 17:05:10 +05:30
Luflosi
0981828493 X11: Fix updating GLFW_FLOATING on a hidden window
From upstream: 9db156421f.
2019-12-19 12:31:31 +01:00
Kovid Goyal
6bc4f18a59 Merge branch 'glfw_upstream' of https://github.com/Luflosi/kitty 2019-12-19 16:59:26 +05:30
Luflosi
79532a315c X11: Fix invalid read when clearing GLFW_FLOATING
From upstream: 0b652a44d2.
2019-12-19 12:27:36 +01:00
Kovid Goyal
7472a992ed Merge branch 'glfw_upstream' of https://github.com/Luflosi/kitty 2019-12-19 16:56:48 +05:30
Luflosi
e40616a0db X11: Fix missing checks for EWMH attention atoms
From upstream: 9b6d68ec70.
2019-12-19 12:25:09 +01:00
Kovid Goyal
dd8b97a86c Merge branch 'glfw_upstream' of https://github.com/Luflosi/kitty 2019-12-19 16:53:38 +05:30
Luflosi
5eff3897de X11: Fix maximization of hidden windows
From upstream: 4837b78ffe.
2019-12-19 12:20:58 +01:00
Kovid Goyal
530cf2eb14 monotonic.h no longer depends on time.h 2019-12-19 16:48:35 +05:30
Kovid Goyal
2baa34beb8 Move a couple of functions to where they are actually needed 2019-12-19 16:43:51 +05:30
Kovid Goyal
87e2f7f86d Missed a couple of macOS timer calls 2019-12-19 16:34:47 +05:30
Kovid Goyal
e142083d53 Remove unused code
Strip out the GLFW timer code, since we use our own kitty based
monotonic clock.
2019-12-19 16:27:25 +05:30
Kovid Goyal
2e850a0d0d Merge branch 'glfw_upstream' of https://github.com/Luflosi/kitty 2019-12-19 07:56:04 +05:30
Luflosi
aec9c31bca Formatting
From upstream: 506a6aafde.
2019-12-18 18:34:55 +01:00
Kovid Goyal
598a147500 Merge branch 'glfw_upstream' of https://github.com/Luflosi/kitty 2019-12-18 22:51:17 +05:30
Luflosi
ba201c4c92 Add curly braces
From upstream: 9486ec0c02.

The upstream commit mainly changes some cmake stuff, which we don't use and only really adds curly braces to `egl_context.c` (and changes some formatting).
2019-12-18 18:12:48 +01:00
Kovid Goyal
5bc7cfaa43 Merge branch 'glfw_upstream' of https://github.com/Luflosi/kitty 2019-12-18 20:33:44 +05:30
Luflosi
2804e1ff81 Cocoa: Update outdated comment
From upstream: b3544ca43e.
2019-12-18 15:41:31 +01:00
Kovid Goyal
ae27d36902 Fix previous merge 2019-12-18 18:42:59 +05:30
Kovid Goyal
08182fbe4d Merge branch 'glfw_upstream' of https://github.com/Luflosi/kitty 2019-12-18 18:36:31 +05:30
Luflosi
778474f436 Wayland: Unset the cursor shape on border exit
From upstream: ef6189f348.
2019-12-18 14:01:29 +01:00
Kovid Goyal
c6698ce305 Merge branch 'comment' of https://github.com/Luflosi/kitty 2019-12-18 18:15:30 +05:30
Luflosi
21bc215313 Make comment more accurate
Since all the time values use `monotonic_t` now, `maximum_wait` is no longer measured in seconds. Instead of replacing seconds with nanoseconds, I removed it because the definition of `monotonic_t` is supposed to be changed easily, in which case this comment would not be accurate again.
2019-12-18 12:54:14 +01:00
Kovid Goyal
88a9cc42d2 Merge branch 'fix-panel' of https://github.com/natnat-mc/kitty 2019-12-18 07:32:25 +05:30
Kovid Goyal
28f33a67cf Merge branch 'fix_oserror' of https://github.com/Luflosi/kitty 2019-12-18 07:30:37 +05:30
Nathan DECHER
6742fabfba fix kitty +kitten panel -c <config> resulting in no config at all 2019-12-18 00:33:40 +01:00
Luflosi
b3806f4533 Fix OSError when failing to create config directory on read-only file system
When calling the completion code, kitty tries to access the config directory and create it if it does not exist. If kitty has no permission to create it, a temporary directory will be created instead. This will fail on a read-only file system because that raises an `OSError` and not a `PermissionError`.
In practice this happens when building kitty on macOS Catalina using Nix because `HOME` is set to `/homeless-shelter` for purity and `/` is a read-only filesystem.
2019-12-17 23:42:31 +01:00
Kovid Goyal
6d5fb4ccc6 Fix docs build warning 2019-12-17 20:44:32 +05:30
Kovid Goyal
2487f18f24 Add a new option active_tab_title_template to specify a different template for active tab titles
Fixes #2198
2019-12-17 20:39:46 +05:30
Kovid Goyal
f59afff1d1 Add a new option tab_bar_background to specify a different color for the tab bar
Fixes #2198
2019-12-17 20:08:33 +05:30
Kovid Goyal
b92f95b092 NSGL: Fix disabling of Retina resolution
From upstream: fa60269245
2019-12-15 20:54:21 +05:30
Kovid Goyal
d68ae01448 Make the active window history available when doing kitty @ ls
Fixes #2194
2019-12-13 18:17:13 +05:30
Kovid Goyal
87eda834d3 Use a token for github 2019-12-12 10:05:11 +05:30
Luflosi
c28ff5259a Finish implementing resize by increment 2019-12-09 08:38:41 +01:00
Anders Eurenius
4619259e26 Implement resize by increment 2019-12-09 08:33:32 +01:00
Kovid Goyal
7bf0afa621 Fix #2187 2019-12-08 22:37:47 +05:30
Kovid Goyal
e3e02c7271 Fix #2180 2019-12-01 22:34:56 +05:30
Kovid Goyal
24e17cb7d8 Fix background_opacity incorrectly applying to selected text and reverse video text
Fixes #2177
2019-12-01 15:14:15 +05:30
Kovid Goyal
769998adca Document valid values for pointer_shape_when_grabbed 2019-12-01 08:22:21 +05:30
Kovid Goyal
9b5d88e92d Fix choose item mapping 2019-11-30 17:18:02 +05:30
Kovid Goyal
6d7bebee3a Merge branch 'master' of https://github.com/l-yc/kitty 2019-11-30 16:58:28 +05:30
lyc
1c38654321 Fixed bug in loading libcanberra when falling back on alternative library names 2019-11-30 14:36:22 +08:00
Kovid Goyal
da7a78691f Merge branch 'simplify' of https://github.com/Luflosi/kitty 2019-11-29 09:21:32 +05:30
Luflosi
1eaf7083ef Simplify expression 2019-11-28 23:38:42 +01:00
Kovid Goyal
79a6fcdc5c Oops 2019-11-28 10:12:21 +05:30
Kovid Goyal
90bcbbf426 No need to add index to titles when using hits kitten to choose tab/os_window 2019-11-28 10:11:14 +05:30
Kovid Goyal
41049e2a40 Avoid traceback when cancelling tab selection 2019-11-28 09:42:55 +05:30
Kovid Goyal
c9b8510e9c Also use ascending order for os window selection 2019-11-28 09:23:08 +05:30
Kovid Goyal
d854fc1cd0 Better numbering when asking for tab to detach window to
Fixes #2174
2019-11-28 09:20:38 +05:30
Kovid Goyal
5f7bcae072 hints kitten: Add an option --ascending to control if the hints numbers increase or decrease from top to bottom 2019-11-28 09:20:02 +05:30
Kovid Goyal
652eec3033 Fix a crash/incorrect rendering when detaching a window in some circumstances
Fixes #2173

Ensure all cell related GPU data is resent
2019-11-28 09:01:40 +05:30
Kovid Goyal
a9928ec98a Merge branch 'format' of https://github.com/Luflosi/kitty 2019-11-28 07:24:06 +05:30
Luflosi
e1dfb608ca Format code in kitty/cocoa_window.m a little 2019-11-27 19:56:30 +01:00
Kovid Goyal
2cee3a8809 Better fix for getting clock_gettime() from time.h
Fixes #2169
2019-11-27 22:20:55 +05:30
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
Benoit de Chezelles
aadab38487 Fix compilation for macos 2019-09-24 22:03:55 +02:00
Benoit de Chezelles
53275c9137 Extract key event data to struct 2019-09-24 19:15:35 +02:00
277 changed files with 61881 additions and 46342 deletions

View File

@@ -1,104 +0,0 @@
version: 2
jobs:
lin-sys:
docker:
- image: kovidgoyal/kitty-test:latest
steps:
- checkout
- run: if grep -Inr '\s$' kitty kitty_tests kittens docs *.py *.asciidoc *.rst .gitattributes .gitignore; then echo Trailing whitespace found, aborting.; exit 1; fi
- run: python3 -m flake8 --count .
- run: python3 setup.py build --debug --verbose
- run: ./kitty/launcher/kitty +launch test.py
- run: make FAIL_WARN=-W man
- run: make FAIL_WARN=-W html
lin-package:
docker:
- image: kovidgoyal/kitty-test:latest
steps:
- checkout
- run: python3 setup.py linux-package --update-check-interval=0
lin-35:
docker:
- image: kovidgoyal/kitty-test:latest
environment:
CC: gcc
CFLAGS: -funsigned-char
LD_LIBRARY_PATH: /opt/py3.5/lib
ASAN_OPTIONS: leak_check_at_exit=0
steps:
- checkout
- run: /opt/py3.5/bin/python3 setup.py build --debug --verbose --sanitize
- run: ./kitty/launcher/kitty +launch test.py
lin-37:
docker:
- image: kovidgoyal/kitty-test:latest
environment:
CC: clang
LD_LIBRARY_PATH: /opt/py3.7/lib
ASAN_OPTIONS: leak_check_at_exit=0
steps:
- checkout
- run: /opt/py3.7/bin/python3 setup.py build --debug --verbose --sanitize
- run: ./kitty/launcher/kitty +launch test.py
lin-bundle:
docker:
- image: kovidgoyal/kitty-test:latest
environment:
ASAN_OPTIONS: leak_check_at_exit=0
steps:
- checkout
- run: echo "export LD_LIBRARY_PATH=$SW/lib" >> $BASH_ENV
- run: echo "export PKG_CONFIG_PATH=$SW/lib/pkgconfig" >> $BASH_ENV
- run: echo "export PYTHONHOME=$SW" >> $BASH_ENV
- run: $SW/bin/python3 setup.py build --debug --verbose
- run: ./kitty/launcher/kitty +launch test.py
mac-bundle:
macos:
xcode: "10.1.0"
environment:
LC_ALL: en_US.UTF-8
LANG: en_US.UTF-8
SW: /Users/Shared/buildbot/sw/sw
steps:
- checkout
- run: mkdir -p $SW
- run: curl https://download.calibre-ebook.com/travis/kitty/osx.tar.xz | tar xJ -C $SW
- run: echo "export PATH=$SW/bin:$PATH" >> $BASH_ENV
- run: python3 setup.py build --debug --verbose
- run: ./kitty/launcher/kitty +launch test.py
mac-brew:
macos:
xcode: "10.2.0"
environment:
LC_ALL: en_US.UTF-8
LANG: en_US.UTF-8
steps:
- checkout
- run: brew bundle
- run: python3 setup.py build --debug --verbose
- run: ./kitty/launcher/kitty +launch test.py
- run: echo "export PATH=/usr/local/opt/sphinx-doc/bin:$PATH" >> $BASH_ENV
- run: python3 setup.py linux-package --verbose
- run: python3 setup.py kitty.app --verbose
- run: kitty.app/Contents/MacOS/kitty +runpy "from kitty.constants import *; print(kitty_exe())"
workflows:
version: 2
all_jobs:
jobs:
- mac-bundle
- lin-sys
- lin-35
- lin-37
- lin-package
- lin-bundle
- mac-brew

View File

@@ -1,55 +0,0 @@
# When changing this file, go to
# https://cloud.docker.com/repository/docker/kovidgoyal/kitty-test/builds and
# click the "Trigger" button under Automated builds to rebuild
FROM ubuntu:latest
# make Apt non-interactive
ENV DEBIAN_FRONTEND=noninteractive
RUN echo 'APT::Get::Assume-Yes "true";' > /etc/apt/apt.conf.d/90circleci \
&& echo 'DPkg::Options "--force-confnew";' >> /etc/apt/apt.conf.d/90circleci \
&& echo 'Acquire::Languages "none";' >> /etc/apt/apt.conf.d/90circleci
# System setup
RUN apt-get update && mkdir -p /usr/share/man/man1 && apt-get install -y python3-flake8 python3-pip python3-pil clang git apt locales sudo openssh-client ca-certificates tar gzip parallel net-tools netcat unzip zip bzip2 gnupg curl wget build-essential apt-utils
# Setup circleci user
RUN groupadd --gid 3434 circleci \
&& useradd --uid 3434 --gid circleci --shell /bin/bash --create-home circleci \
&& echo 'circleci ALL=NOPASSWD: ALL' >> /etc/sudoers.d/50-circleci \
&& echo 'Defaults env_keep += "DEBIAN_FRONTEND"' >> /etc/sudoers.d/env_keep \
&& echo 'Defaults env_keep += "SW"' >> /etc/sudoers.d/env_keep \
&& echo 'Defaults env_keep += "LANG"' >> /etc/sudoers.d/env_keep
# Set timezone to UTC by default
RUN ln -sf /usr/share/zoneinfo/Etc/UTC /etc/localtime
# Use unicode
RUN locale-gen en_US.UTF-8 || true
ENV LANG=en_US.UTF-8
# Deps needed for building python
RUN apt-get install -y libreadline-dev zlib1g-dev libssl-dev libbz2-dev libsqlite3-dev libffi-dev
# kitty deps
RUN apt-get install -y libgl1-mesa-dev libxi-dev libxrandr-dev libxinerama-dev libxcursor-dev libxcb-xkb-dev libdbus-1-dev libxkbcommon-dev libharfbuzz-dev libpng-dev libfontconfig-dev libpython3-dev libxkbcommon-x11-dev python3-pygments libcanberra-dev
# Needed to build kitty docs
RUN pip3 install sphinx
# Install multiple pythons
ADD install-python.py /tmp/install-python.py
RUN python3 /tmp/install-python.py py3.5 https://www.python.org/ftp/python/3.5.6/Python-3.5.6.tar.xz
RUN python3 /tmp/install-python.py py3.7 https://www.python.org/ftp/python/3.7.2/Python-3.7.2.tar.xz
# Install kitty bundle
ENV SW=/home/circleci/sw
RUN python3 /tmp/install-python.py bundle https://download.calibre-ebook.com/travis/kitty/linux-64.tar.xz
RUN echo SW=$SW >> /etc/environment
# Clean unused files
RUN apt-get clean -y
USER circleci
LABEL com.circleci.preserve-entrypoint=true
ENTRYPOINT sleep 2h

View File

@@ -1,60 +0,0 @@
#!/usr/bin/env python3
# vim:fileencoding=utf-8
# License: GPLv3 Copyright: 2019, Kovid Goyal <kovid at kovidgoyal.net>
import io
import os
import shlex
import shutil
import subprocess
import sys
import tarfile
from urllib.request import urlopen
PY, URL = sys.argv[1], sys.argv[2]
if PY == 'bundle':
SW = os.environ['SW']
os.mkdir(SW)
os.chdir(SW)
else:
os.chdir('/usr/src')
def run(cmd):
cmd = shlex.split(cmd)
p = subprocess.Popen(cmd)
if p.wait() != 0:
raise SystemExit(p.returncode)
with urlopen(URL) as f:
data = f.read()
with tarfile.open(fileobj=io.BytesIO(data), mode='r:xz') as tf:
tf.extractall()
def replace_in_file(path, src, dest):
with open(path, 'r+') as f:
n = f.read().replace(src, dest)
f.seek(0), f.truncate()
f.write(n)
if PY == 'bundle':
replaced = 0
for dirpath, dirnames, filenames in os.walk(SW):
for f in filenames:
if f.endswith('.pc') or (f.endswith('.py') and f.startswith('_sysconfig')):
replace_in_file(os.path.join(dirpath, f), '/sw/sw', SW)
replaced += 1
if replaced < 2:
raise SystemExit('Failed to replace path to SW in bundle')
else:
src = os.path.abspath(tuple(os.listdir('.'))[0])
os.chdir(src)
run(f'./configure --prefix=/opt/{PY} --enable-shared --with-system-expat --without-ensurepip')
run(f'make -j {os.cpu_count()}')
run('make install')
os.chdir('/')
shutil.rmtree(src)

21
.editorconfig Normal file
View File

@@ -0,0 +1,21 @@
root = true
[*]
indent_style = spaces
indent_size = 4
end_of_line = lf
trim_trailing_whitespace = true
[{Makefile,*.terminfo}]
indent_style = tab
# Autogenerated files with tabs below this line.
[kitty/{unicode-data.c,emoji.h,wcwidth-std.h}]
indent_style = tab
[kittens/unicode_input/names.h]
indent_style = tab
[glfw/wayland-*-protocol.{c,h}]
indent_style = tab

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

34
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@@ -0,0 +1,34 @@
---
name: Bug report
about: Create a bug report
title: ''
labels: bug
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. XXX
2. YYY
3. ZZZ
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Enviroment details**
OS: Name and version of operating system(s)
```
Output of kitty --debug-config
```
**Additional context**
Try to reproduce the problem with `kitty --config NONE` if you cannot then post a minimal kitty.conf that reproduces the problem. If the problem involves interaction with some other terminal program post a minimal config for that program to reproduce the problem as well.

View File

@@ -0,0 +1,20 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: enhancement
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

125
.github/workflows/ci.py vendored Normal file
View File

@@ -0,0 +1,125 @@
#!/usr/bin/env python
# vim:fileencoding=utf-8
# License: GPLv3 Copyright: 2020, Kovid Goyal <kovid at kovidgoyal.net>
import io
import os
import shlex
import subprocess
import sys
import tarfile
from urllib.request import urlopen
is_bundle = os.environ.get('KITTY_BUNDLE') == '1'
is_macos = 'darwin' in sys.platform.lower()
SW = None
def run(*a):
if len(a) == 1:
a = shlex.split(a[0])
print(' '.join(map(shlex.quote, a)))
sys.stdout.flush()
ret = subprocess.Popen(a).wait()
if ret != 0:
raise SystemExit(ret)
def install_deps():
print('Installing kitty dependencies...')
sys.stdout.flush()
if is_macos:
items = (x.strip() for x in open('Brewfile').readlines() if not x.startswith('#'))
run('brew', 'install', *items)
else:
run('sudo apt-get update')
run('sudo apt-get install -y libgl1-mesa-dev libxi-dev libxrandr-dev libxinerama-dev'
' libxcursor-dev libxcb-xkb-dev libdbus-1-dev libxkbcommon-dev libharfbuzz-dev'
' libpng-dev libfontconfig-dev libxkbcommon-x11-dev libcanberra-dev')
if is_bundle:
install_bundle()
else:
run('pip install Pillow pygments')
def build_kitty():
python = 'python3' if is_bundle else sys.executable
cmd = '{} setup.py build --verbose'.format(python)
if os.environ.get('KITTY_SANITIZE') == '1':
cmd += ' --debug --sanitize'
run(cmd)
def test_kitty():
run('./kitty/launcher/kitty +launch test.py')
def package_kitty():
py = 'python3' if is_macos else 'python'
run(py + ' setup.py linux-package --update-check-interval=0 --verbose')
if is_macos:
run('python3 setup.py kitty.app --update-check-interval=0 --verbose')
run('kitty.app/Contents/MacOS/kitty +runpy "from kitty.constants import *; print(kitty_exe())"')
def replace_in_file(path, src, dest):
with open(path, 'r+') as f:
n = f.read().replace(src, dest)
f.seek(0), f.truncate()
f.write(n)
def setup_bundle_env():
global SW
os.environ['SW'] = SW = '/Users/Shared/buildbot/sw/sw' if is_macos else os.path.join(os.environ['GITHUB_WORKSPACE'], 'sw')
os.environ['PKG_CONFIG_PATH'] = SW + '/lib/pkgconfig'
if is_macos:
os.environ['PATH'] = '{}:{}'.format('/usr/local/opt/sphinx-doc/bin', os.environ['PATH'])
else:
os.environ['LD_LIBRARY_PATH'] = SW + '/lib'
os.environ['PYTHONHOME'] = SW
os.environ['PATH'] = '{}:{}'.format(os.path.join(SW, 'bin'), os.environ['PATH'])
def install_bundle():
cwd = os.getcwd()
os.makedirs(SW)
os.chdir(SW)
with urlopen('https://download.calibre-ebook.com/travis/kitty/{}.tar.xz'.format(
'osx' if is_macos else 'linux-64')) as f:
data = f.read()
with tarfile.open(fileobj=io.BytesIO(data), mode='r:xz') as tf:
tf.extractall()
if not is_macos:
replaced = 0
for dirpath, dirnames, filenames in os.walk('.'):
for f in filenames:
if f.endswith('.pc') or (f.endswith('.py') and f.startswith('_sysconfig')):
replace_in_file(os.path.join(dirpath, f), '/sw/sw', SW)
replaced += 1
if replaced < 2:
raise SystemExit('Failed to replace path to SW in bundle')
os.chdir(cwd)
def main():
if is_bundle:
setup_bundle_env()
else:
if not is_macos:
os.environ['LD_LIBRARY_PATH'] = '{}/lib'.format(os.environ['pythonLocation'])
action = sys.argv[-1]
if action in ('build', 'package'):
install_deps()
if action == 'build':
build_kitty()
elif action == 'package':
package_kitty()
elif action == 'test':
test_kitty()
else:
raise SystemExit('Unknown action: ' + action)
if __name__ == '__main__':
main()

132
.github/workflows/ci.yml vendored Normal file
View File

@@ -0,0 +1,132 @@
name: CI
on: [push, pull_request]
env:
CI: 'true'
ASAN_OPTIONS: leak_check_at_exit=0
LC_ALL: en_US.UTF-8
LANG: en_US.UTF-8
jobs:
linux:
name: Linux (python=${{ matrix.pyver }} cc=${{ matrix.cc }} sanitize=${{ matrix.sanitize }})
runs-on: ubuntu-latest
env:
CC: ${{ matrix.cc }}
KITTY_SANITIZE: ${{ matrix.sanitize }}
strategy:
matrix:
python: [a, b, c]
cc: [gcc, clang]
include:
- python: a
pyver: 3.6
sanitize: 0
- python: b
pyver: 3.7
sanitize: 1
- python: c
pyver: 3.8
sanitize: 1
exclude:
- python: a
cc: clang
- python: b
cc: clang
- python: c
cc: gcc
steps:
- name: Checkout source code
uses: actions/checkout@master
with:
fetch-depth: 10
- name: Set up Python ${{ matrix.pyver }}
uses: actions/setup-python@master
with:
python-version: ${{ matrix.pyver }}
- name: Build kitty
run: python .github/workflows/ci.py build
- name: Test kitty
run: python .github/workflows/ci.py test
linux-package:
name: Linux package
runs-on: ubuntu-latest
env:
CFLAGS: -funsigned-char
steps:
- name: Checkout source code
uses: actions/checkout@master
with:
fetch-depth: 10
- name: Test for trailing whitespace
run: if grep -Inr '\s$' kitty kitty_tests kittens docs *.py *.asciidoc *.rst .gitattributes .gitignore; then echo Trailing whitespace found, aborting.; exit 1; fi
- name: Set up Python
uses: actions/setup-python@master
with:
python-version: 3.8
- name: Install build-only deps
run: pip install flake8 mypy sphinx
- name: Run pyflakes
run: python -m flake8 --count .
- name: Build kitty package
run: python .github/workflows/ci.py package
- name: Run mypy
run: python test.py mypy
- name: Build man page
run: make FAIL_WARN=-W man
- name: Build HTML docs
run: make FAIL_WARN=-W html
bundle:
name: Bundle test (${{ matrix.os }})
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
env:
KITTY_BUNDLE: 1
steps:
- name: Checkout source code
uses: actions/checkout@master
with:
fetch-depth: 10
- name: Build kitty
run: which python3 && python3 .github/workflows/ci.py build
- name: Test kitty
run: python3 .github/workflows/ci.py test
brew:
name: macOS Brew
runs-on: macos-latest
steps:
- name: Checkout source code
uses: actions/checkout@master
with:
fetch-depth: 10
- name: Build kitty
run: python3 .github/workflows/ci.py build
- name: Test kitty
run: python3 .github/workflows/ci.py test
- name: Build kitty package
run: python3 .github/workflows/ci.py package

4
.gitignore vendored
View File

@@ -1,6 +1,8 @@
*.so
*.pyc
*.pyo
*_stub.pyi
/.dmypy.json
/tags
/build/
/linux-package/
@@ -14,4 +16,6 @@ __pycache__/
/glfw/wayland-*-client-protocol.[ch]
/docs/_build/
/docs/generated/
/.mypy_cache
.DS_Store
bypy/b

View File

@@ -1,5 +1,5 @@
brew 'pkg-config'
brew 'imagemagick'
brew 'harfbuzz'
brew 'python'
brew 'sphinx-doc'
pkg-config
python
imagemagick
harfbuzz
sphinx-doc

View File

@@ -1,7 +1,3 @@
To build from source:
To build from source: <https://sw.kovidgoyal.net/kitty/build.html>
https://sw.kovidgoyal.net/kitty/build.html
Pre-built binaries:
https://sw.kovidgoyal.net/kitty/binary.html
Pre-built binaries: <https://sw.kovidgoyal.net/kitty/binary.html>

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"]
image:https://github.com/kovidgoyal/kitty/workflows/CI/badge.svg["Build status", link="https://github.com/kovidgoyal/kitty/actions?query=workflow%3ACI"]

View File

@@ -4,54 +4,56 @@
import sys
import os
from typing import List
def icat(args):
from kittens.runner import run_kitten
def icat(args: List[str]) -> None:
from kittens.runner import run_kitten as rk
sys.argv = args
run_kitten('icat')
rk('icat')
def list_fonts(args):
from kitty.fonts.list import main
main(args)
def list_fonts(args: List[str]) -> None:
from kitty.fonts.list import main as list_main
list_main(args)
def remote_control(args):
from kitty.remote_control import main
main(args)
def remote_control(args: List[str]) -> None:
from kitty.remote_control import main as rc_main
rc_main(args)
def runpy(args):
def runpy(args: List[str]) -> None:
sys.argv = ['kitty'] + args[2:]
exec(args[1])
def hold(args):
def hold(args: List[str]) -> None:
import subprocess
ret = subprocess.Popen(args[1:]).wait()
sys.stdin.read()
raise SystemExit(ret)
def complete(args):
from kitty.complete import main
main(args[1:], entry_points, namespaced_entry_points)
def complete(args: List[str]) -> None:
from kitty.complete import main as complete_main
complete_main(args[1:], entry_points, namespaced_entry_points)
def launch(args):
def launch(args: List[str]) -> None:
import runpy
sys.argv = args[1:]
exe = args[1]
if exe.startswith(':'):
import shutil
exe = shutil.which(exe[1:])
if not exe:
q = shutil.which(exe[1:])
if not q:
raise SystemExit('{} not found in PATH'.format(args[1][1:]))
exe = q
runpy.run_path(exe, run_name='__main__')
def run_kitten(args):
def run_kitten(args: List[str]) -> None:
try:
kitten = args[1]
except IndexError:
@@ -59,11 +61,11 @@ def run_kitten(args):
list_kittens()
raise SystemExit(1)
sys.argv = args[1:]
from kittens.runner import run_kitten
run_kitten(kitten)
from kittens.runner import run_kitten as rk
rk(kitten)
def namespaced(args):
def namespaced(args: List[str]) -> None:
func = namespaced_entry_points[args[1]]
func(args[1:])
@@ -84,7 +86,7 @@ namespaced_entry_points['hold'] = hold
namespaced_entry_points['complete'] = complete
def setup_openssl_environment():
def setup_openssl_environment() -> None:
# Workaround for Linux distros that have still failed to get their heads
# out of their asses and implement a common location for SSL certificates.
# It's not that hard people, there exists a wonderful tool called the symlink
@@ -92,11 +94,13 @@ 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'
setattr(sys, 'kitty_ssl_env_var', 'SSL_CERT_FILE')
elif os.path.isdir('/etc/ssl/certs'):
os.environ['SSL_CERT_DIR'] = '/etc/ssl/certs'
setattr(sys, 'kitty_ssl_env_var', 'SSL_CERT_DIR')
def main():
def main() -> None:
if getattr(sys, 'frozen', False) and 'darwin' not in sys.platform.lower():
setup_openssl_environment()
first_arg = '' if len(sys.argv) < 2 else sys.argv[1]
@@ -107,8 +111,8 @@ def main():
elif first_arg.startswith('+'):
namespaced(['+', first_arg[1:]] + sys.argv[2:])
else:
from kitty.main import main
main()
from kitty.main import main as kitty_main
kitty_main()
else:
func(sys.argv[1:])

75
bypy/init_env.py Normal file
View File

@@ -0,0 +1,75 @@
#!/usr/bin/env python
# vim:fileencoding=utf-8
# License: GPLv3 Copyright: 2020, Kovid Goyal <kovid at kovidgoyal.net>
import os
import re
import shutil
import subprocess
import sys
from bypy.constants import (
LIBDIR, PREFIX, PYTHON, SRC as KITTY_DIR, ismacos, worker_env
)
from bypy.utils import run_shell
def read_src_file(name):
with open(os.path.join(KITTY_DIR, 'kitty', name), 'rb') as f:
return f.read().decode('utf-8')
def initialize_constants():
kitty_constants = {}
src = read_src_file('constants.py')
nv = re.search(r'Version\((\d+), (\d+), (\d+)\)', src)
kitty_constants['version'] = '%s.%s.%s' % (nv.group(1), nv.group(2), nv.group(3))
kitty_constants['appname'] = re.search(
r'appname: str\s+=\s+(u{0,1})[\'"]([^\'"]+)[\'"]', src
).group(2)
return kitty_constants
def run(*args, **extra_env):
env = os.environ.copy()
env.update(worker_env)
env.update(extra_env)
env['SW'] = PREFIX
env['LD_LIBRARY_PATH'] = LIBDIR
if ismacos:
env['PKGCONFIG_EXE'] = os.path.join(PREFIX, 'bin', 'pkg-config')
cwd = env.pop('cwd', KITTY_DIR)
return subprocess.call(list(args), env=env, cwd=cwd)
def build_c_extensions(ext_dir, args):
writeable_src_dir = os.path.join(ext_dir, 'src')
shutil.copytree(
KITTY_DIR, writeable_src_dir, symlinks=True,
ignore=shutil.ignore_patterns('b', 'build', 'dist', '*_commands.json', '*.o'))
cmd = [PYTHON, 'setup.py']
bundle = 'macos-freeze' if ismacos else 'linux-freeze'
cmd.append(bundle)
dest = kitty_constants['appname'] + ('.app' if ismacos else '')
dest = os.path.join(ext_dir, dest)
cmd += ['--prefix', dest]
if run(*cmd, cwd=writeable_src_dir) != 0:
print('Building of kitty package failed', file=sys.stderr)
os.chdir(KITTY_DIR)
run_shell()
raise SystemExit('Building of kitty package failed')
return ext_dir
def run_tests(path_to_kitty, cwd_on_failure):
ret = run(PYTHON, 'test.py', cwd=cwd_on_failure)
if ret != 0:
os.chdir(cwd_on_failure)
print(
'running kitty tests failed with return code:', ret, file=sys.stderr)
run_shell()
raise SystemExit('running kitty tests failed')
if __name__ == 'program':
kitty_constants = initialize_constants()

3
bypy/linux.conf Normal file
View File

@@ -0,0 +1,3 @@
image 'https://partner-images.canonical.com/core/xenial/current/ubuntu-xenial-core-cloudimg-{}-root.tar.gz'
deps 'bison flex libxcursor-dev libxrandr-dev libxi-dev libxinerama-dev libgl1-mesa-dev libxcb-xkb-dev libfontconfig1-dev libdbus-1-dev'

209
bypy/linux/__main__.py Normal file
View File

@@ -0,0 +1,209 @@
#!/usr/bin/env python
# vim:fileencoding=utf-8
# License: GPLv3 Copyright: 2020, Kovid Goyal <kovid at kovidgoyal.net>
import errno
import os
import shutil
import stat
import subprocess
import tarfile
import time
from bypy.constants import (
OUTPUT_DIR, PREFIX, is64bit, python_major_minor_version
)
from bypy.utils import get_dll_path, py_compile, walk
j = os.path.join
self_dir = os.path.dirname(os.path.abspath(__file__))
arch = 'x86_64' if is64bit else 'i686'
py_ver = '.'.join(map(str, python_major_minor_version()))
iv = globals()['init_env']
kitty_constants = iv['kitty_constants']
def binary_includes():
return tuple(map(get_dll_path, (
'expat', 'sqlite3', 'ffi', 'z', 'lzma', 'png16',
# dont include freetype because fontconfig is closely coupled to it
# and also distros often patch freetype
# 'iconv.so.2', 'pcre.so.1', 'graphite2.so.3', 'glib-2.0.so.0', 'freetype.so.6',
'harfbuzz', 'xkbcommon', 'xkbcommon-x11',
'ncursesw', 'readline',
))) + (
get_dll_path('bz2', 2), get_dll_path('ssl', 3), get_dll_path('crypto', 3),
get_dll_path('python' + py_ver, 2),
)
class Env:
def __init__(self, package_dir):
self.base = package_dir
self.lib_dir = j(self.base, 'lib')
self.py_dir = j(self.lib_dir, 'python' + py_ver)
os.makedirs(self.py_dir)
self.bin_dir = j(self.base, 'bin')
def ignore_in_lib(base, items, ignored_dirs=None):
ans = []
if ignored_dirs is None:
ignored_dirs = {'.svn', '.bzr', '.git', 'test', 'tests', 'testing'}
for name in items:
path = j(base, name)
if os.path.isdir(path):
if name in ignored_dirs or not os.path.exists(j(path, '__init__.py')):
if name != 'plugins':
ans.append(name)
else:
if name.rpartition('.')[-1] not in ('so', 'py'):
ans.append(name)
return ans
def import_site_packages(srcdir, dest):
if not os.path.exists(dest):
os.mkdir(dest)
for x in os.listdir(srcdir):
ext = x.rpartition('.')[-1]
f = j(srcdir, x)
if ext in ('py', 'so'):
shutil.copy2(f, dest)
elif ext == 'pth' and x != 'setuptools.pth':
for line in open(f, 'rb').read().splitlines():
src = os.path.abspath(j(srcdir, line))
if os.path.exists(src) and os.path.isdir(src):
import_site_packages(src, dest)
elif os.path.exists(j(f, '__init__.py')):
shutil.copytree(f, j(dest, x), ignore=ignore_in_lib)
def copy_libs(env):
print('Copying libs...')
for x in binary_includes():
dest = env.bin_dir if '/bin/' in x else env.lib_dir
shutil.copy2(x, dest)
def copy_python(env):
print('Copying python...')
srcdir = j(PREFIX, 'lib/python' + py_ver)
for x in os.listdir(srcdir):
y = j(srcdir, x)
ext = os.path.splitext(x)[1]
if os.path.isdir(y) and x not in ('test', 'hotshot', 'distutils', 'tkinter', 'turtledemo',
'site-packages', 'idlelib', 'lib2to3', 'dist-packages'):
shutil.copytree(y, j(env.py_dir, x), ignore=ignore_in_lib)
if os.path.isfile(y) and ext in ('.py', '.so'):
shutil.copy2(y, env.py_dir)
srcdir = j(srcdir, 'site-packages')
dest = j(env.py_dir, 'site-packages')
import_site_packages(srcdir, dest)
py_compile(env.py_dir)
py_compile(os.path.join(env.base, 'lib', 'kitty'))
def is_elf(path):
with open(path, 'rb') as f:
return f.read(4) == b'\x7fELF'
def fix_permissions(files):
for path in files:
os.chmod(path, 0o755)
STRIPCMD = ['strip']
def find_binaries(env):
files = {j(env.bin_dir, x) for x in os.listdir(env.bin_dir)} | {
x for x in {
j(os.path.dirname(env.bin_dir), x) for x in os.listdir(env.bin_dir)} if os.path.exists(x)}
for x in walk(env.lib_dir):
x = os.path.realpath(x)
if x not in files and is_elf(x):
files.add(x)
return files
def strip_files(files, argv_max=(256 * 1024)):
""" Strip a list of files """
while files:
cmd = list(STRIPCMD)
pathlen = sum(len(s) + 1 for s in cmd)
while pathlen < argv_max and files:
f = files.pop()
cmd.append(f)
pathlen += len(f) + 1
if len(cmd) > len(STRIPCMD):
all_files = cmd[len(STRIPCMD):]
unwritable_files = tuple(filter(None, (None if os.access(x, os.W_OK) else (x, os.stat(x).st_mode) for x in all_files)))
[os.chmod(x, stat.S_IWRITE | old_mode) for x, old_mode in unwritable_files]
subprocess.check_call(cmd)
[os.chmod(x, old_mode) for x, old_mode in unwritable_files]
def strip_binaries(files):
print('Stripping %d files...' % len(files))
before = sum(os.path.getsize(x) for x in files)
strip_files(files)
after = sum(os.path.getsize(x) for x in files)
print('Stripped %.1f MB' % ((before - after) / (1024 * 1024.)))
def create_tarfile(env, compression_level='9'):
print('Creating archive...')
base = OUTPUT_DIR
try:
shutil.rmtree(base)
except EnvironmentError as err:
if err.errno != errno.ENOENT:
raise
os.mkdir(base)
dist = os.path.join(base, '%s-%s-%s.tar' % (kitty_constants['appname'], kitty_constants['version'], arch))
with tarfile.open(dist, mode='w', format=tarfile.PAX_FORMAT) as tf:
cwd = os.getcwd()
os.chdir(env.base)
try:
for x in os.listdir('.'):
tf.add(x)
finally:
os.chdir(cwd)
print('Compressing archive...')
ans = dist.rpartition('.')[0] + '.txz'
start_time = time.time()
subprocess.check_call(['xz', '--threads=0', '-f', '-' + compression_level, dist])
secs = time.time() - start_time
print('Compressed in %d minutes %d seconds' % (secs // 60, secs % 60))
os.rename(dist + '.xz', ans)
print('Archive %s created: %.2f MB' % (
os.path.basename(ans), os.stat(ans).st_size / (1024.**2)))
def main():
args = globals()['args']
ext_dir = globals()['ext_dir']
if not args.skip_tests:
run_tests = iv['run_tests']
run_tests(None, os.path.join(ext_dir, 'src'))
env = Env(os.path.join(ext_dir, kitty_constants['appname']))
copy_libs(env)
copy_python(env)
files = find_binaries(env)
fix_permissions(files)
if not args.dont_strip:
strip_binaries(files)
create_tarfile(env, args.compression_level)
if __name__ == '__main__':
main()

6
bypy/macos.conf Normal file
View File

@@ -0,0 +1,6 @@
# Requires installation of XCode 10.3 and Python 3 and
# python3 -m pip install certifi
vm_name 'macos-kitty-build'
root '/Users/Shared/kitty-build'
python '/usr/local/bin/python3'

459
bypy/macos/__main__.py Normal file
View File

@@ -0,0 +1,459 @@
#!/usr/bin/env python
# vim:fileencoding=utf-8
# License: GPLv3 Copyright: 2020, Kovid Goyal <kovid at kovidgoyal.net>
import glob
import json
import os
import shutil
import stat
import subprocess
import sys
import tempfile
import zipfile
from bypy.constants import PREFIX, PYTHON, SW, python_major_minor_version
from bypy.macos_sign import (
codesign, create_entitlements_file, make_certificate_useable, notarize_app,
verify_signature
)
from bypy.utils import current_dir, py_compile, run_shell, timeit, walk
iv = globals()['init_env']
kitty_constants = iv['kitty_constants']
join = os.path.join
basename = os.path.basename
abspath = os.path.abspath
APPNAME = kitty_constants['appname']
VERSION = kitty_constants['version']
py_ver = '.'.join(map(str, python_major_minor_version()))
def flush(func):
def ff(*args, **kwargs):
sys.stdout.flush()
sys.stderr.flush()
ret = func(*args, **kwargs)
sys.stdout.flush()
sys.stderr.flush()
return ret
return ff
def flipwritable(fn, mode=None):
"""
Flip the writability of a file and return the old mode. Returns None
if the file is already writable.
"""
if os.access(fn, os.W_OK):
return None
old_mode = os.stat(fn).st_mode
os.chmod(fn, stat.S_IWRITE | old_mode)
return old_mode
STRIPCMD = ('/usr/bin/strip', '-x', '-S', '-')
def strip_files(files, argv_max=(256 * 1024)):
"""
Strip a list of files
"""
tostrip = [(fn, flipwritable(fn)) for fn in files if os.path.exists(fn)]
while tostrip:
cmd = list(STRIPCMD)
flips = []
pathlen = sum(len(s) + 1 for s in cmd)
while pathlen < argv_max:
if not tostrip:
break
added, flip = tostrip.pop()
pathlen += len(added) + 1
cmd.append(added)
flips.append((added, flip))
else:
cmd.pop()
tostrip.append(flips.pop())
os.spawnv(os.P_WAIT, cmd[0], cmd)
for args in flips:
flipwritable(*args)
def files_in(folder):
for record in os.walk(folder):
for f in record[-1]:
yield os.path.join(record[0], f)
def expand_dirs(items, exclude=lambda x: x.endswith('.so')):
items = set(items)
dirs = set(x for x in items if os.path.isdir(x))
items.difference_update(dirs)
for x in dirs:
items.update({y for y in files_in(x) if not exclude(y)})
return items
def do_sign(app_dir):
with current_dir(os.path.join(app_dir, 'Contents')):
# Sign all .so files
so_files = {x for x in files_in('.') if x.endswith('.so')}
codesign(so_files)
# Sign everything else in Frameworks
with current_dir('Frameworks'):
fw = set(glob.glob('*.framework'))
codesign(fw)
items = set(os.listdir('.')) - fw
codesign(expand_dirs(items))
# Now sign the main app
codesign(app_dir)
verify_signature(app_dir)
def sign_app(app_dir, notarize):
# Copied from iTerm2: https://github.com/gnachman/iTerm2/blob/master/iTerm2.entitlements
create_entitlements_file({
'com.apple.security.automation.apple-events': True,
'com.apple.security.cs.allow-jit': True,
'com.apple.security.device.audio-input': True,
'com.apple.security.device.camera': True,
'com.apple.security.personal-information.addressbook': True,
'com.apple.security.personal-information.calendars': True,
'com.apple.security.personal-information.location': True,
'com.apple.security.personal-information.photos-library': True,
})
with make_certificate_useable():
do_sign(app_dir)
if notarize:
notarize_app(app_dir)
class Freeze(object):
FID = '@executable_path/../Frameworks'
def __init__(self, build_dir, dont_strip=False, sign_installers=False, notarize=False):
self.build_dir = build_dir
self.sign_installers = sign_installers
self.notarize = notarize
self.dont_strip = dont_strip
self.contents_dir = join(self.build_dir, 'Contents')
self.resources_dir = join(self.contents_dir, 'Resources')
self.frameworks_dir = join(self.contents_dir, 'Frameworks')
self.to_strip = []
self.warnings = []
self.py_ver = py_ver
self.python_stdlib = join(self.resources_dir, 'Python', 'lib', 'python' + self.py_ver)
self.site_packages = self.python_stdlib # hack to avoid needing to add site-packages to path
self.run()
def run_shell(self):
with current_dir(self.contents_dir):
run_shell()
def run(self):
ret = 0
self.add_python_framework()
self.add_site_packages()
self.add_stdlib()
self.add_misc_libraries()
self.compile_py_modules()
self.fix_dependencies_in_kitty()
if not self.dont_strip:
self.strip_files()
# self.run_shell()
ret = self.makedmg(self.build_dir, APPNAME + '-' + VERSION)
return ret
@flush
def strip_files(self):
print('\nStripping files...')
strip_files(self.to_strip)
@flush
def set_id(self, path_to_lib, new_id):
old_mode = flipwritable(path_to_lib)
subprocess.check_call(
['install_name_tool', '-id', new_id, path_to_lib])
if old_mode is not None:
flipwritable(path_to_lib, old_mode)
@flush
def get_dependencies(self, path_to_lib):
install_name = subprocess.check_output(
['otool', '-D', path_to_lib]).decode('utf-8').splitlines()[-1].strip()
raw = subprocess.check_output(['otool', '-L', path_to_lib]).decode('utf-8')
for line in raw.splitlines():
if 'compatibility' not in line or line.strip().endswith(':'):
continue
idx = line.find('(')
path = line[:idx].strip()
yield path, path == install_name
@flush
def get_local_dependencies(self, path_to_lib):
for x, is_id in self.get_dependencies(path_to_lib):
for y in (PREFIX + '/lib/', PREFIX + '/python/Python.framework/'):
if x.startswith(y):
if y == PREFIX + '/python/Python.framework/':
y = PREFIX + '/python/'
yield x, x[len(y):], is_id
break
@flush
def change_dep(self, old_dep, new_dep, is_id, path_to_lib):
cmd = ['-id', new_dep] if is_id else ['-change', old_dep, new_dep]
subprocess.check_call(['install_name_tool'] + cmd + [path_to_lib])
@flush
def fix_dependencies_in_lib(self, path_to_lib):
self.to_strip.append(path_to_lib)
old_mode = flipwritable(path_to_lib)
for dep, bname, is_id in self.get_local_dependencies(path_to_lib):
ndep = self.FID + '/' + bname
self.change_dep(dep, ndep, is_id, path_to_lib)
ldeps = list(self.get_local_dependencies(path_to_lib))
if ldeps:
print('\nFailed to fix dependencies in', path_to_lib)
print('Remaining local dependencies:', ldeps)
raise SystemExit(1)
if old_mode is not None:
flipwritable(path_to_lib, old_mode)
@flush
def add_python_framework(self):
print('\nAdding Python framework')
src = join(PREFIX + '/python', 'Python.framework')
x = join(self.frameworks_dir, 'Python.framework')
curr = os.path.realpath(join(src, 'Versions', 'Current'))
currd = join(x, 'Versions', basename(curr))
rd = join(currd, 'Resources')
os.makedirs(rd)
shutil.copy2(join(curr, 'Resources', 'Info.plist'), rd)
shutil.copy2(join(curr, 'Python'), currd)
self.set_id(
join(currd, 'Python'),
self.FID + '/Python.framework/Versions/%s/Python' % basename(curr))
self.fix_dependencies_in_lib(join(self.contents_dir, 'MacOS', 'kitty'))
# The following is needed for codesign
with current_dir(x):
os.symlink(basename(curr), 'Versions/Current')
for y in ('Python', 'Resources'):
os.symlink('Versions/Current/%s' % y, y)
@flush
def install_dylib(self, path, set_id=True):
shutil.copy2(path, self.frameworks_dir)
if set_id:
self.set_id(
join(self.frameworks_dir, basename(path)),
self.FID + '/' + basename(path))
self.fix_dependencies_in_lib(join(self.frameworks_dir, basename(path)))
@flush
def add_misc_libraries(self):
for x in (
'sqlite3.0',
'z.1',
'harfbuzz.0',
'png16.16',
'crypto.1.0.0',
'ssl.1.0.0',
):
print('\nAdding', x)
x = 'lib%s.dylib' % x
src = join(PREFIX, 'lib', x)
shutil.copy2(src, self.frameworks_dir)
dest = join(self.frameworks_dir, x)
self.set_id(dest, self.FID + '/' + x)
self.fix_dependencies_in_lib(dest)
base = join(self.frameworks_dir, 'kitty')
for lib in walk(base):
if lib.endswith('.so'):
self.set_id(lib, self.FID + '/' + os.path.relpath(lib, self.frameworks_dir))
self.fix_dependencies_in_lib(lib)
@flush
def add_package_dir(self, x, dest=None):
def ignore(root, files):
ans = []
for y in files:
ext = os.path.splitext(y)[1]
if ext not in ('', '.py', '.so') or \
(not ext and not os.path.isdir(join(root, y))):
ans.append(y)
return ans
if dest is None:
dest = self.site_packages
dest = join(dest, basename(x))
shutil.copytree(x, dest, symlinks=True, ignore=ignore)
self.postprocess_package(x, dest)
for f in walk(dest):
if f.endswith('.so'):
self.fix_dependencies_in_lib(f)
@flush
def fix_dependencies_in_kitty(self):
for f in walk(join(self.resources_dir, 'kitty')):
if f.endswith('.so'):
self.fix_dependencies_in_lib(f)
@flush
def postprocess_package(self, src_path, dest_path):
pass
@flush
def add_stdlib(self):
print('\nAdding python stdlib')
src = PREFIX + '/python/Python.framework/Versions/Current/lib/python' + self.py_ver
dest = self.python_stdlib
if not os.path.exists(dest):
os.makedirs(dest)
for x in os.listdir(src):
if x in ('site-packages', 'config', 'test', 'lib2to3', 'lib-tk',
'lib-old', 'idlelib', 'plat-mac', 'plat-darwin',
'site.py', 'distutils', 'turtledemo', 'tkinter'):
continue
x = join(src, x)
if os.path.isdir(x):
self.add_package_dir(x, dest)
elif os.path.splitext(x)[1] in ('.so', '.py'):
shutil.copy2(x, dest)
dest2 = join(dest, basename(x))
if dest2.endswith('.so'):
self.fix_dependencies_in_lib(dest2)
@flush
def add_site_packages(self):
print('\nAdding site-packages')
os.makedirs(self.site_packages)
sys_path = json.loads(subprocess.check_output([
PYTHON, '-c', 'import sys, json; json.dump(sys.path, sys.stdout)']))
paths = reversed(tuple(map(abspath, [x for x in sys_path if x.startswith('/') and not x.startswith('/Library/')])))
upaths = []
for x in paths:
if x not in upaths and (x.endswith('.egg') or x.endswith('/site-packages')):
upaths.append(x)
for x in upaths:
print('\t', x)
tdir = None
try:
if not os.path.isdir(x):
zf = zipfile.ZipFile(x)
tdir = tempfile.mkdtemp()
zf.extractall(tdir)
x = tdir
self.add_modules_from_dir(x)
self.add_packages_from_dir(x)
finally:
if tdir is not None:
shutil.rmtree(tdir)
self.remove_bytecode(self.site_packages)
@flush
def add_modules_from_dir(self, src):
for x in glob.glob(join(src, '*.py')) + glob.glob(join(src, '*.so')):
shutil.copy2(x, self.site_packages)
if x.endswith('.so'):
self.fix_dependencies_in_lib(x)
@flush
def add_packages_from_dir(self, src):
for x in os.listdir(src):
x = join(src, x)
if os.path.isdir(x) and os.path.exists(join(x, '__init__.py')):
if self.filter_package(basename(x)):
continue
self.add_package_dir(x)
@flush
def filter_package(self, name):
return name in ('Cython', 'modulegraph', 'macholib', 'py2app',
'bdist_mpkg', 'altgraph')
@flush
def remove_bytecode(self, dest):
for x in os.walk(dest):
root = x[0]
for f in x[-1]:
if os.path.splitext(f) == '.pyc':
os.remove(join(root, f))
@flush
def compile_py_modules(self):
print('\nCompiling Python modules')
self.remove_bytecode(join(self.resources_dir, 'Python'))
py_compile(join(self.resources_dir, 'Python'))
self.remove_bytecode(join(self.resources_dir, 'kitty'))
py_compile(join(self.resources_dir, 'kitty'))
@flush
def makedmg(self, d, volname, internet_enable=True, format='ULFO'):
''' Copy a directory d into a dmg named volname '''
print('\nMaking dmg...')
sys.stdout.flush()
destdir = os.path.join(SW, 'dist')
try:
shutil.rmtree(destdir)
except FileNotFoundError:
pass
os.mkdir(destdir)
dmg = os.path.join(destdir, volname + '.dmg')
if os.path.exists(dmg):
os.unlink(dmg)
tdir = tempfile.mkdtemp()
appdir = os.path.join(tdir, os.path.basename(d))
shutil.copytree(d, appdir, symlinks=True)
if self.sign_installers:
with timeit() as times:
sign_app(appdir, self.notarize)
print('Signing completed in %d minutes %d seconds' % tuple(times))
os.symlink('/Applications', os.path.join(tdir, 'Applications'))
size_in_mb = int(
subprocess.check_output(['du', '-s', '-k', tdir]).decode('utf-8')
.split()[0]) / 1024.
cmd = [
'/usr/bin/hdiutil', 'create', '-srcfolder', tdir, '-volname',
volname, '-format', format
]
if 190 < size_in_mb < 250:
# We need -size 255m because of a bug in hdiutil. When the size of
# srcfolder is close to 200MB hdiutil fails with
# diskimages-helper: resize request is above maximum size allowed.
cmd += ['-size', '255m']
print('\nCreating dmg...')
with timeit() as times:
subprocess.check_call(cmd + [dmg])
if internet_enable:
subprocess.check_call(
['/usr/bin/hdiutil', 'internet-enable', '-yes', dmg])
print('dmg created in %d minutes and %d seconds' % tuple(times))
shutil.rmtree(tdir)
size = os.stat(dmg).st_size / (1024 * 1024.)
print('\nInstaller size: %.2fMB\n' % size)
return dmg
def main():
args = globals()['args']
ext_dir = globals()['ext_dir']
if not args.skip_tests:
run_tests = iv['run_tests']
run_tests(None, os.path.join(ext_dir, 'src'))
Freeze(
os.path.join(ext_dir, kitty_constants['appname'] + '.app'),
dont_strip=args.dont_strip,
sign_installers=args.sign_installers,
notarize=args.notarize
)
if __name__ == '__main__':
main()

1
bypy/rsync.conf Normal file
View File

@@ -0,0 +1 @@
to_vm_excludes '/build /dist /kitty/launcher/kitty /.build-cache /tags __pycache__ /*_commands.json *.so *.pyd *.pyc'

256
bypy/sources.json Normal file
View File

@@ -0,0 +1,256 @@
[
{
"name": "zlib",
"unix": {
"filename": "zlib-1.2.11.tar.xz",
"hash": "sha256:4ff941449631ace0d4d203e3483be9dbc9da454084111f97ea0a2114e19bf066",
"urls": ["https://zlib.net/{filename}"]
}
},
{
"name": "bzip2",
"os": "linux",
"unix": {
"filename": "bzip2-1.0.8.tar.gz",
"hash": "sha256:ab5a03176ee106d3f0fa90e381da478ddae405918153cca248e682cd0c4a2269",
"urls": ["https://www.sourceware.org/pub/bzip2/bzip2-latest.tar.gz"]
}
},
{
"name": "pkg-config",
"os": "macos",
"unix": {
"filename": "pkg-config-0.29.2.tar.gz",
"hash": "sha256:6fc69c01688c9458a57eb9a1664c9aba372ccda420a02bf4429fe610e7e7d591",
"urls": ["https://pkg-config.freedesktop.org/releases/{filename}"]
}
},
{
"name": "expat",
"unix": {
"filename": "expat-2.2.6.tar.bz2",
"hash": "sha256:17b43c2716d521369f82fc2dc70f359860e90fa440bea65b3b85f0b246ea81f2",
"urls": ["https://github.com/libexpat/libexpat/releases/download/R_2_2_6/{filename}"]
}
},
{
"name": "xkbcommon",
"os": "linux",
"unix": {
"filename": "libxkbcommon-0.10.0.tar.xz",
"hash": "sha256:57c3630cdc38fb4734cd57fa349e92244f5ae3862813e533cedbd86721a0b6f2",
"urls": ["http://xkbcommon.org/download/{filename}"]
}
},
{
"name": "sqlite",
"unix": {
"filename": "sqlite-autoconf-3310100.tar.gz",
"hash": "sha1:0c30f5b22152a8166aa3bebb0f4bc1f3e9cc508b",
"urls": ["https://www.sqlite.org/2020/{filename}"]
}
},
{
"name": "libffi",
"unix": {
"filename": "libffi-3.2.1.tar.gz",
"hash": "sha1:280c265b789e041c02e5c97815793dfc283fb1e6",
"urls": ["ftp://sourceware.org/pub/libffi/{filename}"]
}
},
{
"name": "openssl",
"unix": {
"filename": "openssl-1.0.2u.tar.gz",
"hash": "sha256:ecd0c6ffb493dd06707d38b14bb4d8c2288bb7033735606569d8f90f89669d16",
"urls": ["https://www.openssl.org/source/{filename}"]
}
},
{
"name": "ncurses",
"os": "linux",
"unix": {
"filename": "ncurses-6.2.tar.gz",
"hash": "sha256:30306e0c76e0f9f1f0de987cf1c82a5c21e1ce6568b9227f7da5b71cbea86c9d",
"urls": ["https://invisible-mirror.net/archives/ncurses/{filename}"]
}
},
{
"name": "readline",
"os": "linux",
"unix": {
"filename": "readline-8.0.tar.gz",
"hash": "sha256:e339f51971478d369f8a053a330a190781acb9864cf4c541060f12078948e461",
"urls": ["http://ftp.gnu.org/gnu/readline/{filename}"]
}
},
{
"name": "xz",
"os": "macos,linux",
"unix": {
"filename": "xz-5.2.5.tar.gz",
"hash": "sha256:f6f4910fd033078738bd82bfba4f49219d03b17eb0794eb91efbae419f4aba10",
"urls": ["https://tukaani.org/xz/{filename}"]
}
},
{
"name": "python",
"unix": {
"filename": "Python-3.8.3.tar.xz",
"hash": "sha256:dfab5ec723c218082fe3d5d7ae17ecbdebffa9a1aea4d64aa3a2ecdd2e795864",
"urls": ["https://www.python.org/ftp/python/3.8.3/{filename}"]
}
},
{
"name": "setuptools",
"unix": {
"filename": "setuptools-41.0.1.zip",
"hash": "sha256:a222d126f5471598053c9a77f4b5d4f26eaa1f150ad6e01dcf1a42e185d05613",
"urls": ["pypi"]
}
},
{
"name": "pygments",
"unix": {
"filename": "Pygments-2.6.1.tar.gz",
"hash": "sha256:647344a061c249a3b74e230c739f434d7ea4d8b1d5f3721bc0f3558049b38f44",
"urls": ["pypi"]
}
},
{
"name": "cmake",
"os": "macos",
"unix": {
"filename": "cmake-3.6.0.tar.gz",
"hash": "sha1:6b0d2d7d93c2e74f8890c4b8b824deb3b36d24b6",
"urls": ["https://cmake.org/files/v3.6/{filename}"]
}
},
{
"name": "libpng",
"unix": {
"filename": "libpng-1.6.37.tar.xz",
"hash": "sha256:505e70834d35383537b6491e7ae8641f1a4bed1876dbfe361201fc80868d88ca",
"urls": ["http://downloads.sourceforge.net/sourceforge/libpng/{filename}"]
}
},
{
"name": "graphite",
"os": "linux",
"unix": {
"filename": "graphite2-1.3.5.tgz",
"hash": "md5:5b8d22a8bbf031838e31432868c0109c",
"urls": ["http://downloads.sourceforge.net/silgraphite/{filename}"]
}
},
{
"name": "pcre",
"os": "linux",
"unix": {
"filename": "pcre-8.42.tar.bz2",
"hash": "md5:085b6aa253e0f91cae70b3cdbe8c1ac2",
"urls": ["https://ftp.pcre.org/pub/pcre/{filename}"]
}
},
{
"name": "iconv",
"os": "linux",
"unix": {
"filename": "libiconv-1.16.tar.gz",
"hash": "sha256:e6a1b1b589654277ee790cce3734f07876ac4ccfaecbee8afa0b649cf529cc04",
"urls": ["http://ftp.gnu.org/pub/gnu/libiconv/{filename}"]
}
},
{
"name": "glib",
"os": "linux",
"unix": {
"filename": "glib-2.57.1.tar.xz",
"hash": "sha256:d029e7c4536835f1f103472f7510332c28d58b9b7d6cd0e9f45c2653e670d9b4",
"urls": ["http://ftp.gnome.org/pub/GNOME/sources/glib/2.57/{filename}"]
}
},
{
"name": "freetype",
"os": "linux",
"unix": {
"filename": "freetype-2.9.1.tar.bz2",
"hash": "md5:60ef7d8160cd4bf8cb118ee9d65367ca",
"urls": ["https://download.savannah.gnu.org/releases/freetype/{filename}"]
}
},
{
"name": "fontconfig",
"os": "linux",
"unix": {
"filename": "fontconfig-2.12.0.tar.bz2",
"hash": "sha256:b433e4efff1f68fdd8aac221ed1df3ff1e580ffedbada020a703fe64017d8224",
"urls": ["http://www.fontconfig.org/release/{filename}"]
}
},
{
"name": "harfbuzz",
"unix": {
"filename": "harfbuzz-1.7.2.tar.bz2",
"hash": "sha256:a790585e35c1a87f0dcc23580c84b7cc2324e6f67a2946178d278c2a36c790cb",
"urls": ["https://www.freedesktop.org/software/harfbuzz/release/{filename}"]
}
},
{
"name": "libxml2",
"os": "linux",
"unix": {
"filename": "libxml2-2.9.4.tar.gz",
"hash": "sha1:958ae70baf186263a4bd801a81dd5d682aedd1db",
"urls": ["ftp://xmlsoft.org/libxml2/{filename}"]
}
},
{
"name": "wayland",
"os": "linux",
"unix": {
"filename": "wayland-1.18.0.tar.xz",
"hash": "sha256:4675a79f091020817a98fd0484e7208c8762242266967f55a67776936c2e294d",
"urls": ["https://wayland.freedesktop.org/releases/{filename}"]
}
},
{
"name": "wayland-protocols",
"os": "linux",
"unix": {
"filename": "wayland-protocols-1.20.tar.xz",
"hash": "sha256:9782b7a1a863d82d7c92478497d13c758f52e7da4f197aa16443f73de77e4de7",
"urls": ["https://wayland.freedesktop.org/releases/{filename}"]
}
}
]

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

@@ -46,7 +46,7 @@ particular desktop, but it should work for most major desktop environments.
# Place the kitty.desktop file somewhere it can be found by the OS
cp ~/.local/kitty.app/share/applications/kitty.desktop ~/.local/share/applications
# Update the path to the kitty icon in the kitty.desktop file
sed -i "s/Icon\=kitty/Icon\=\/home\/$USER\/.local\/kitty.app\/share\/icons\/hicolor\/256x256\/apps\/kitty.png/g" ~/.local/share/applications/kitty.desktop
sed -i "s|Icon=kitty|Icon=/home/$USER/.local/kitty.app/share/icons/hicolor/256x256/apps/kitty.png|g" ~/.local/share/applications/kitty.desktop

View File

@@ -1,9 +1,9 @@
Building kitty from source
==============================
.. image:: https://circleci.com/gh/kovidgoyal/kitty.svg?style=svg
.. image:: https://github.com/kovidgoyal/kitty/workflows/CI/badge.svg
:alt: Build status
:target: https://circleci.com/gh/kovidgoyal/kitty
:target: https://github.com/kovidgoyal/kitty/actions?query=workflow%3ACI
|kitty| is designed to run from source, for easy hackability. Make sure
@@ -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,403 @@ Changelog
|kitty| is a feature full, cross-platform, *fast*, GPU based terminal emulator.
To update |kitty|, :doc:`follow the instructions <binary>`.
0.18.1 [2020-06-23]
--------------------
- macOS: Fix for diff kitten not working with python 3.8 (:iss:`2780`)
0.18.0 [2020-06-20]
--------------------
- Allow multiple overlay windows per normal window
- Add an option :opt:`confirm_os_window_close` to ask for confirmation
when closing an OS window with multiple kitty windows.
- Tall and Fat layouts: Add a ``mirrored`` option to put the full size window
on the opposite edge of the screen (:iss:`2654`)
- Tall and Fat layouts: Add mappable actions to increase or decrease the number
of full size windows (:iss:`2688`)
- Allow sending arbitrary signals to the current foreground process in a window
using either a mapping in kitty.conf or via remote control (:iss:`2778`)
- Allow sending the back and forward mouse buttons to terminal applications
(:pull:`2742`)
- **Backwards incompatibility**: The numbers used to encode mouse buttons
for the ``send_mouse_event`` function that can be used in kittens have
been changed (see :ref:`send_mouse_event`).
- Add a new mappable ``quit`` action to quit kitty completely.
- Fix marks using different colors with regexes using only a single color
(:pull:`2663`)
- Linux: Workaround for broken Nvidia drivers for old cards (:iss:`456`)
- Wayland: Fix kitty being killed on some Wayland compositors if a hidden window
has a lot of output (:iss:`2329`)
- BSD: Fix controlling terminal not being established (:pull:`2686`)
- Add support for the CSI REP escape code (:pull:`2702`)
- Wayland: Fix mouse cursor rendering on HiDPI screens (:pull:`2709`)
- X11: Recompile keymaps on XkbNewKeyboardNotify events (:iss:`2726`)
- X11: Reduce startup time by ~25% by only querying GLX for framebuffer
configurations once (:iss:`2754`)
- macOS: Notarize the kitty application bundle (:iss:`2040`)
- Fix the kitty shell launched via a mapping needlessly requiring
:opt:`allow_remote_control` to be turned on.
0.17.4 [2020-05-09]
--------------------
- Allow showing the name of the current layout and the number of windows
in tab titles (:iss:`2634`)
- macOS: Fix a regression in the previous release that caused ligatures to be
not be centered horizontally (:iss:`2591`)
- By default, double clicking no longer considers the : as part of words, see
:opt:`select_by_word_characters` (:iss:`2602`)
- Fix a regression that caused clicking in the padding/margins of windows in
the stack layout to switch the window to the first window (:iss:`2604`)
- macOS: Fix a regression that broke drag and drop (:iss:`2605`)
- Report modifier key state when sending wheel events to the terminal program
- Fix kitty @ send-text not working with text larger than 1024 bytes when using
:option:`kitty --listen-on` (:iss:`2607`)
- Wayland: Fix OS window title not updating for hidden windows (:iss:`2629`)
- Fix :opt:`background_tint` making the window semi-transparent (:iss:`2618`)
0.17.3 [2020-04-23]
--------------------
- Allow individually setting margins and padding for each edge (left, right,
top, bottom). Margins can also be controlled per window via remote control
(:iss:`2546`)
- Fix reverse video not being rendered correctly when using transparency or a
background image (:iss:`2419`)
- Allow mapping arbitrary remote control commands to key presses in
:file:`kitty.conf`
- X11: Fix crash when doing drag and drop from some applications (:iss:`2505`)
- Fix :option:`launch --stdin-add-formatting` not working (:iss:`2512`)
- Update to Unicode 13.0 (:iss:`2513`)
- Render country flags designated by a pair of unicode codepoints
in two cells instead of four.
- diff kitten: New option to control the background color for filler lines in
the margin (:iss:`2518`)
- Fix specifying options for layouts in the startup session file not working
(:iss:`2520`)
- macOS: Fix incorrect horizontal positioning of some full-width East Asian characters
(:iss:`1457`)
- macOS: Render multi-cell PUA characters centered, matching behavior on other
platforms
- Linux: Ignore keys if they are designated as layout/group/mode switch keys
(:iss:`2519`)
- Marks: Fix marks not handling wide characters and tab characters correctly
(:iss:`2534`)
- Add a new :opt:`listen_on` option in kitty.conf to set :option:`kitty --listen-on`
globally. Also allow using environment variables in this option (:iss:`2569`).
- Allow sending mouse events in kittens (:pull:`2538`)
- icat kitten: Fix display of 16-bit depth images (:iss:`2542`)
- Add ncurses specific terminfo definitions for strikethrough (:pull:`2567`)
- Fix a regression in 0.17 that broke displaying graphics over SSH
(:iss:`2568`)
- Fix :option:`--title` not being applied at window creation time (:iss:`2570`)
0.17.2 [2020-03-29]
--------------------
- Add a :option:`launch --watcher` option that allows defining callbacks
that are called for various events in the window's life-cycle (:iss:`2440`)
- Fix a regression in 0.17 that broke drawing of borders with non-minimal
borders (:iss:`2474`)
- Hints kitten: Allow copying to primary selection as well as clipboard
(:pull:`2487`)
- Add a new mappable action ``close_other_windows_in_tab`` to close all but the
active window (:iss:`2484`)
- Hints kitten: Adjust the default regex used to detect line numbers to handle
line+column numbers (:iss:`2268`)
- Fix blank space at the start of tab bar in the powerline style when first tab is
inactive (:iss:`2478`)
- Fix regression causing incorrect rendering of separators in tab bar when
defining a tab bar background color (:pull:`2480`)
- Fix a regression in 0.17 that broke the kitty @ launch remote command and
also broke the --tab-title option when creating a new tab. (:iss:`2488`)
- Linux: Fix selection of fonts with multiple width variants not preferring
the normal width faces (:iss:`2491`)
0.17.1 [2020-03-24]
--------------------
- Fix :opt:`cursor_underline_thickness` not working (:iss:`2465`)
- Fix a regression in 0.17 that caused tab bar background to be rendered after
the last tab as well (:iss:`2464`)
- macOS: Fix a regression in 0.17 that caused incorrect variants to be
automatically selected for some fonts (:iss:`2462`)
- Fix a regression in 0.17 that caused kitty @ set-colors to require setting
cursor_text_color (:iss:`2470`)
0.17.0 [2020-03-24]
--------------------
- :ref:`splits_layout` to arrange windows in arbitrary splits
(:iss:`2308`)
- Add support for specifying a background image, see :opt:`background_image`
(:iss:`163` and :pull:`2326`; thanks to Fredrick Brennan.)
- A new :opt:`background_tint` option to darken the background under the text
area when using background images and/or transparent windows.
- Allow selection of single cells with the mouse. Also improve mouse selection
to follow semantics common to most programs (:iss:`945`)
- New options :opt:`cursor_beam_thickness` and :opt:`cursor_underline_thickness` to control the thickness of the
beam and underline cursors (:iss:`2337` and :pull:`2342`)
- When the application running in the terminal grabs the mouse, pass middle
clicks to the application unless :opt:`terminal_select_modifiers` are
pressed (:iss:`2368`)
- A new ``copy_and_clear_or_interrupt`` function (:iss:`2403`)
- X11: Fix arrow mouse cursor using right pointing instead of the default left
pointing arrow (:iss:`2341`)
- Allow passing the currently active kitty window id in the launch command
(:iss:`2391`)
- unicode input kitten: Allow pressing :kbd:`ctrl+tab` to change the input mode
(:iss:`2343`)
- Fix a bug that prevented using custom functions with the new marks feature
(:iss:`2344`)
- Make the set of URL prefixes that are recognized while hovering with the
mouse configurable (:iss:`2416`)
- Fix border/margin/padding sizes not being recalculated on DPI change
(:iss:`2346`)
- diff kitten: Fix directory diffing with removed binary files failing
(:iss:`2378`)
- macOS: Fix menubar title not updating on OS Window focus change (:iss:`2350`)
- Fix rendering of combining characters with fonts that have glyphs for
precomposed characters but not decomposed versions (:iss:`2365`)
- Fix incorrect rendering of selection when using rectangular select and
scrolling (:iss:`2351`)
- Allow setting WM_CLASS and WM_NAME when creating new OS windows with the
launch command (:option:`launch --os-window-class`)
- macOS: When switching input method while a pending multi-key input is in
progress, clear the pending input (:iss:`2358`)
- Fix a regression in the previous release that broke switching to neighboring windows
in the Grid layout when there are less than four windows (:iss:`2377`)
- Fix colors in scrollback pager off if the window has redefined terminal
colors using escape codes (:iss:`2381`)
- Fix selection not updating properly while scrolling (:iss:`2442`)
- Allow extending selections by dragging with right button pressed
(:iss:`2445`)
- Workaround for bug in less that causes colors to reset at wrapped lines
(:iss:`2381`)
- X11/Wayland: Allow drag and drop of text/plain in addition to text/uri-list
(:iss:`2441`)
- Dont strip :code:`&` and :code:`-` from the end of URLs (:iss:`2436`)
- Fix ``@selection`` placeholder not working with launch command (:iss:`2417`)
- Drop support for python 3.5
- Wayland: Fix a crash when drag and dropping into kitty (:iss:`2432`)
- diff kitten: Fix images lingering as blank rectangles after the kitten quits
(:iss:`2449`)
- diff kitten: Fix images losing position when scrolling using mouse
wheel/touchpad
0.16.0 [2020-01-28]
--------------------
- A new :doc:`marks` feature that allows highlighting and scrolling to arbitrary
text in the terminal window.
- hints kitten: Allow pressing :sc:`goto_file_line` to quickly open
the selected file at the selected line in vim or a configurable editor (:iss:`2268`)
- Allow having more than one full height window in the :code:`tall` layout
(:iss:`2276`)
- Allow choosing OpenType features for individual fonts via the
:opt:`font_features` option. (:pull:`2248`)
- Wayland: Fix a freeze in rare circumstances when having multiple OS Windows
(:iss:`2307` and :iss:`1722`)
- Wayland: Fix window titles being set to very long strings on the order of 8KB
causing a crash (:iss:`1526`)
- Add an option :opt:`force_ltr` to turn off the display of text in RTL scripts
in right-to-left order (:pull:`2293`)
- Allow opening new tabs/windows before the current tab/window as well as after
it with the :option:`launch --location` option.
- Add a :opt:`resize_in_steps` option that can be used to resize the OS window
in steps as large as character cells (:pull:`2131`)
- When triple-click+dragging to select multiple lines, extend the selection
of the first line to match the rest on the left (:pull:`2284`)
- macOS: Add a :code:`titlebar-only` setting to
:opt:`hide_window_decorations` to only hide the title bar (:pull:`2286`)
- Fix a segfault when using :option:`kitty --debug-config` with maps (:iss:`2270`)
- ``goto_tab`` now maps numbers larger than the last tab to the last tab
(:iss:`2291`)
- Fix URL detection not working for urls of the form scheme:///url
(:iss:`2292`)
- When windows are semi-transparent and all contain graphics, correctly render
them. (:iss:`2310`)
0.15.1 [2019-12-21]
--------------------
- Fix a crash/incorrect rendering when detaching a window in some circumstances
(:iss:`2173`)
- hints kitten: Add an option :option:`kitty +kitten hints --ascending` to
control if the hints numbers increase or decrease from top to bottom
- Fix :opt:`background_opacity` incorrectly applying to selected text and
reverse video text (:iss:`2177`)
- Add a new option :opt:`tab_bar_background` to specify a different color
for the tab bar (:iss:`2198`)
- Add a new option :opt:`active_tab_title_template` to specify a different
template for active tab titles (:iss:`2198`)
- Fix lines at the edge of the window at certain windows sizes when drawing
images on a transparent window (:iss:`2079`)
- Fix window not being rendered for the first time until some input has been
received from child process (:iss:`2216`)
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]
---------------------

View File

@@ -1,5 +1,5 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# vim:fileencoding=utf-8
#
# Configuration file for the Sphinx documentation builder.
#
@@ -7,28 +7,34 @@
# full list see the documentation:
# https://www.sphinx-doc.org/en/master/config
import importlib
import os
import re
import subprocess
import sys
import time
from functools import partial
from typing import (
Any, Callable, Dict, Iterable, List, Match, Optional, Sequence, Tuple,
Union
)
from docutils import nodes
from docutils.parsers.rst.roles import set_classes
from pygments.lexer import RegexLexer, bygroups
from pygments.token import (
from pygments.lexer import RegexLexer, bygroups # type: ignore
from pygments.token import ( # type: ignore
Comment, Keyword, Literal, Name, Number, String, Whitespace
)
from sphinx import addnodes
from sphinx.environment.adapters.toctree import TocTree
from sphinx.util.logging import getLogger
from sphinx import addnodes # type: ignore
from sphinx.environment.adapters.toctree import TocTree # type: ignore
from sphinx.util.logging import getLogger # type: ignore
kitty_src = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
if kitty_src not in sys.path:
sys.path.insert(0, kitty_src)
str_version = importlib.import_module('kitty.constants').str_version
from kitty.conf.definition import Option, Shortcut # noqa
from kitty.constants import str_version # noqa
# config {{{
# -- Project information -----------------------------------------------------
@@ -77,7 +83,7 @@ master_doc = 'index'
#
# This is also used if you do content translation via gettext catalogs.
# Usually you set "language" from the command line for these cases.
language = None
language: Optional[str] = None
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
@@ -184,7 +190,7 @@ texinfo_documents = [
# GitHub linking inline roles {{{
def num_role(which, name, rawtext, text, lineno, inliner, options={}, content=[]):
def num_role(which: str, name: str, rawtext: str, text: str, lineno: int, inliner: Any, options: Any = {}, content: Any = []) -> Tuple[List, List]:
' Link to a github issue '
try:
issue_num = int(text)
@@ -202,10 +208,11 @@ def num_role(which, name, rawtext, text, lineno, inliner, options={}, content=[]
return [node], []
def commit_role(name, rawtext, text, lineno, inliner, options={}, content=[]):
def commit_role(name: str, rawtext: str, text: str, lineno: int, inliner: Any, options: Any = {}, content: Any = []) -> Tuple[List, List]:
' Link to a github commit '
try:
commit_id = subprocess.check_output(f'git rev-list --max-count=1 --skip=# {text}'.split()).decode('utf-8').strip()
commit_id = subprocess.check_output(
f'git rev-list --max-count=1 --skip=# {text}'.split()).decode('utf-8').strip()
except Exception:
msg = inliner.reporter.error(
f'GitHub commit id "{text}" not recognized.', line=lineno)
@@ -213,21 +220,22 @@ def commit_role(name, rawtext, text, lineno, inliner, options={}, content=[]):
return [prb], [msg]
url = f'https://github.com/kovidgoyal/kitty/commit/{commit_id}'
set_classes(options)
short_id = subprocess.check_output(f'git rev-list --max-count=1 --abbrev-commit --skip=# {commit_id}'.split()).decode('utf-8').strip()
short_id = subprocess.check_output(
f'git rev-list --max-count=1 --abbrev-commit --skip=# {commit_id}'.split()).decode('utf-8').strip()
node = nodes.reference(rawtext, f'commit: {short_id}', refuri=url, **options)
return [node], []
# }}}
# Sidebar ToC {{{
def create_toc(app, pagename):
def create_toc(app: Any, pagename: str) -> Optional[Any]:
tt = TocTree(app.env)
toctree = tt.get_toc_for(pagename, app.builder)
if toctree is not None:
subtree = toctree[toctree.first_child_matching_class(nodes.list_item)]
bl = subtree.first_child_matching_class(nodes.bullet_list)
if bl is None:
return # Empty ToC
return None # Empty ToC
subtree = subtree[bl]
# for li in subtree.traverse(nodes.list_item):
# modify_li(li)
@@ -235,29 +243,40 @@ def create_toc(app, pagename):
return app.builder.render_partial(subtree)['fragment']
def add_html_context(app, pagename, templatename, context, *args):
def add_html_context(app: Any, pagename: str, templatename: str, context: Any, *args: Any) -> None:
if 'toc' in context:
context['toc'] = create_toc(app, pagename) or context['toc']
# }}}
# CLI docs {{{
def write_cli_docs(all_kitten_names):
def write_cli_docs(all_kitten_names: Iterable[str]) -> None:
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'))
as_rst = partial(option_spec_as_rst, heading_char='_')
from kitty.remote_control import global_options_spec, cli_msg, cmap, all_commands
from kitty.rc.base import all_command_names, command_for_name
from kitty.remote_control import global_options_spec, cli_msg
with open('generated/cli-kitty-at.rst', 'w') as f:
p = partial(print, file=f)
p('kitty @\n' + '-' * 80)
p('.. program::', 'kitty @')
p('\n\n' + as_rst(
global_options_spec, message=cli_msg, usage='command ...', appname='kitty @'))
from kitty.cmds import cli_params_for
for cmd_name in all_commands:
func = cmap[cmd_name]
from kitty.rc.base import cli_params_for
for cmd_name in sorted(all_command_names()):
func = command_for_name(cmd_name)
p(f'.. _at_{func.name}:\n')
p('kitty @', func.name + '\n' + '-' * 120)
p('.. program::', 'kitty @', func.name)
@@ -276,14 +295,14 @@ def write_cli_docs(all_kitten_names):
# }}}
def write_remote_control_protocol_docs(): # {{{
from kitty.cmds import cmap
def write_remote_control_protocol_docs() -> None: # {{{
from kitty.rc.base import all_command_names, command_for_name, RemoteCommand
field_pat = re.compile(r'\s*([a-zA-Z0-9_+]+)\s*:\s*(.+)')
def format_cmd(p, name, cmd):
def format_cmd(p: Callable, name: str, cmd: RemoteCommand) -> None:
p(name)
p('-' * 80)
lines = cmd.__doc__.strip().splitlines()
lines = (cmd.__doc__ or '').strip().splitlines()
fields = []
for line in lines:
m = field_pat.match(line)
@@ -307,10 +326,10 @@ def write_remote_control_protocol_docs(): # {{{
p(' ', desc), p()
p(), p()
with open(f'generated/rc.rst', 'w') as f:
with open('generated/rc.rst', 'w') as f:
p = partial(print, file=f)
for name in sorted(cmap):
cmd = cmap[name]
for name in sorted(all_command_names()):
cmd = command_for_name(name)
if not cmd.__doc__:
continue
name = name.replace('_', '-')
@@ -373,7 +392,7 @@ class SessionLexer(RegexLexer):
}
def link_role(name, rawtext, text, lineno, inliner, options={}, content=[]):
def link_role(name: str, rawtext: str, text: str, lineno: int, inliner: Any, options: Any = {}, content: Any = []) -> Tuple[List, List]:
m = re.match(r'(.+)\s+<(.+?)>', text)
if m is None:
msg = inliner.reporter.error(f'link "{text}" not recognized', line=lineno)
@@ -385,24 +404,24 @@ def link_role(name, rawtext, text, lineno, inliner, options={}, content=[]):
return [node], []
def expand_opt_references(conf_name, text):
def expand_opt_references(conf_name: str, text: str) -> str:
conf_name += '.'
def expand(m):
def expand(m: Match) -> str:
ref = m.group(1)
if '<' not in ref and '.' not in ref:
full_ref = conf_name + ref
return ':opt:`{} <{}>`'.format(ref, full_ref)
return m.group()
return str(m.group())
return re.sub(r':opt:`(.+?)`', expand, text)
opt_aliases = {}
shortcut_slugs = {}
opt_aliases: Dict[str, str] = {}
shortcut_slugs: Dict[str, Tuple[str, str]] = {}
def parse_opt_node(env, sig, signode):
def parse_opt_node(env: Any, sig: str, signode: Any) -> str:
"""Transform an option description into RST nodes."""
count = 0
firstname = ''
@@ -424,22 +443,22 @@ def parse_opt_node(env, sig, signode):
return firstname
def parse_shortcut_node(env, sig, signode):
def parse_shortcut_node(env: Any, sig: str, signode: Any) -> str:
"""Transform a shortcut description into RST nodes."""
conf_name, text = sig.split('.', 1)
signode += addnodes.desc_name(text, text)
return sig
def render_conf(conf_name, all_options):
from kitty.conf.definition import merged_opts, Option
def render_conf(conf_name: str, all_options: Iterable[Union['Option', Sequence['Shortcut']]]) -> str:
from kitty.conf.definition import merged_opts, Option, Group
ans = ['.. default-domain:: conf', '']
a = ans.append
current_group = None
all_options = list(all_options)
current_group: Optional[Group] = None
all_options_ = list(all_options)
kitty_mod = 'kitty_mod'
def render_group(group):
def render_group(group: Group) -> None:
a('')
a(f'.. _conf-{conf_name}-{group.name}:')
a('')
@@ -451,11 +470,12 @@ def render_conf(conf_name, all_options):
a(group.start_text)
a('')
def handle_group_end(group):
def handle_group_end(group: Group) -> None:
if group.end_text:
assert current_group is not None
a(''), a(current_group.end_text)
def handle_group(new_group, new_group_is_shortcut=False):
def handle_group(new_group: Group, new_group_is_shortcut: bool = False) -> None:
nonlocal current_group
if new_group is not current_group:
if current_group:
@@ -463,14 +483,14 @@ def render_conf(conf_name, all_options):
current_group = new_group
render_group(current_group)
def handle_option(i, opt):
def handle_option(i: int, opt: Option) -> None:
nonlocal kitty_mod
if not opt.long_text or not opt.add_to_docs:
return
handle_group(opt.group)
if opt.name == 'kitty_mod':
kitty_mod = opt.defval_as_string
mopts = list(merged_opts(all_options, opt, i))
mopts = list(merged_opts(all_options_, opt, i))
a('.. opt:: ' + ', '.join(conf_name + '.' + mo.name for mo in mopts))
a('.. code-block:: conf')
a('')
@@ -482,7 +502,7 @@ def render_conf(conf_name, all_options):
a(expand_opt_references(conf_name, opt.long_text))
a('')
def handle_shortcuts(shortcuts):
def handle_shortcuts(shortcuts: Sequence[Shortcut]) -> None:
sc = shortcuts[0]
handle_group(sc.group, True)
sc_text = f'{conf_name}.{sc.short_text}'
@@ -500,7 +520,7 @@ def render_conf(conf_name, all_options):
a(expand_opt_references(conf_name, sc.long_text))
a('')
for i, opt in enumerate(all_options):
for i, opt in enumerate(all_options_):
if isinstance(opt, Option):
handle_option(i, opt)
else:
@@ -511,7 +531,7 @@ def render_conf(conf_name, all_options):
return '\n'.join(ans)
def process_opt_link(env, refnode, has_explicit_title, title, target):
def process_opt_link(env: Any, refnode: Any, has_explicit_title: bool, title: str, target: str) -> Tuple[str, str]:
conf_name, opt = target.partition('.')[::2]
if not opt:
conf_name, opt = 'kitty', conf_name
@@ -519,7 +539,7 @@ def process_opt_link(env, refnode, has_explicit_title, title, target):
return title, opt_aliases.get(full_name, full_name)
def process_shortcut_link(env, refnode, has_explicit_title, title, target):
def process_shortcut_link(env: Any, refnode: Any, has_explicit_title: bool, title: str, target: str) -> Tuple[str, str]:
conf_name, slug = target.partition('.')[::2]
if not slug:
conf_name, slug = 'kitty', conf_name
@@ -534,7 +554,7 @@ def process_shortcut_link(env, refnode, has_explicit_title, title, target):
return title, target
def write_conf_docs(app, all_kitten_names):
def write_conf_docs(app: Any, all_kitten_names: Iterable[str]) -> None:
app.add_lexer('conf', ConfLexer())
app.add_object_type(
'opt', 'opt',
@@ -555,7 +575,7 @@ def write_conf_docs(app, all_kitten_names):
sc_role.warn_dangling = True
sc_role.process_link = process_shortcut_link
def generate_default_config(all_options, name):
def generate_default_config(all_options: Dict[str, Union[Option, Sequence[Shortcut]]], name: str) -> None:
from kitty.conf.definition import as_conf_file
with open(f'generated/conf-{name}.rst', 'w', encoding='utf-8') as f:
print('.. highlight:: conf\n', file=f)
@@ -577,13 +597,13 @@ def write_conf_docs(app, all_kitten_names):
# }}}
def setup(app):
def setup(app: Any) -> None:
os.makedirs('generated/conf', exist_ok=True)
from kittens.runner import all_kitten_names
all_kitten_names = all_kitten_names()
write_cli_docs(all_kitten_names)
kn = all_kitten_names()
write_cli_docs(kn)
write_remote_control_protocol_docs()
write_conf_docs(app, all_kitten_names)
write_conf_docs(app, kn)
app.add_lexer('session', SessionLexer())
app.add_role('link', link_role)
app.add_role('iss', partial(num_role, 'issues'))

View File

@@ -109,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>`_
@@ -164,7 +169,7 @@ 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 -e spacing=100 -e spacing=90
fc-list : family spacing outline scalable | grep -e spacing=100 -e spacing=90 | grep -e outline=True | grep -e scalable=True
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
@@ -174,7 +179,7 @@ following :file:`~/.config/fontconfig/fonts.conf`::
<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
<fontconfig>
<match target="scan">
<match target="font">
<test name="family">
<string>Your Font Family Name</string>
</test>
@@ -184,6 +189,11 @@ following :file:`~/.config/fontconfig/fonts.conf`::
</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``.

View File

@@ -30,10 +30,11 @@ alpha-blending and text over graphics.
Some programs that use the kitty graphics protocol:
* `termpdf <https://github.com/dsanson/termpdf>`_ - a terminal PDF/DJVU/CBR viewer
* `termpdf.py <https://github.com/dsanson/termpdf.py>`_ - a terminal PDF/DJVU/CBR viewer
* `ranger <https://github.com/ranger/ranger>`_ - a terminal file manager, with
image previews, see this `PR <https://github.com/ranger/ranger/pull/1077>`_
* :doc:`kitty-diff <kittens/diff>` - a side-by-side terminal diff program with support for images
* `pixcat <https://github.com/mirukana/pixcat>`_ - a third party CLI and python library that wraps the graphics protocol
* `neofetch <https://github.com/dylanaraps/neofetch>`_ - A command line system
information tool
@@ -262,8 +263,8 @@ received. Finally, terminals must not display anything, until the entire sequenc
received and validated.
Detecting available transmission mediums
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Querying support and available transmission mediums
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Since a client has no a-priori knowledge of whether it shares a filesystem/shared memory
with the terminal emulator, it can send an id with the control data, using the ``i`` key
@@ -289,6 +290,27 @@ use the *query action*, set ``a=q``. Then the terminal emulator will try to load
the image and respond with either OK or an error, as above, but it will not
replace an existing image with the same id, nor will it store the image.
While as of May 2020, kitty is the only terminal emulator to support this
graphics protocol, we intend that any terminal emulator that wishes to support
it can. To check if a terminal emulator supports the graphics protocol the best way
is to send the above *query action* followed by a request for the
`primary device attributes <https://vt100.net/docs/vt510-rm/DA1.html>`. If you
get back an answer for the device attributes without getting back an answer for
the *query action* the terminal emulator does not support the graphics
protocol.
This means that terminal emulators that support the graphics protocol, **must**
reply to *query actions* immediately without processing other input. Most
terminal emulators handle input in a FIFO manner, anyway.
So for example, you could send::
<ESC>_Gi=31,s=1,v=1,a=q,t=d,f=24;<NUL><NUL><NUL><ESC>\<ESC>[c
If you get back a response to the graphics query, the terminal emulator supports
the protocol, if you get back a response to the device attributes query without
a response to the graphics query, it does not.
Display images on screen
-----------------------------
@@ -334,7 +356,9 @@ Finally, you can specify the image *z-index*, i.e. the vertical stacking order.
placed in the same location with different z-index values will be blended if
they are semi-transparent. You can specify z-index values using the ``z`` key.
Negative z-index values mean that the images will be drawn under the text. This
allows rendering of text on top of images.
allows rendering of text on top of images. Negative z-index values below
INT32_MIN/2 (-1,073,741,824) will be drawn under cells with non-default background
colors.
Deleting images
---------------------
@@ -366,10 +390,10 @@ Value of ``d`` Meaning
Some examples::
<ESC>_Ga=d<ESC>\ # delete all visible images
<ESC>_Ga=d,i=10<ESC>\ # delete the image with id=10
<ESC>_Ga=Z,z=-1<ESC>\ # delete the images with z-index -1, also freeing up image data
<ESC>_Ga=P,x=3,y=4<ESC>\ # delete all images that intersect the cell at (3, 4)
<ESC>_Ga=d<ESC>\ # delete all visible images
<ESC>_Ga=d,d=i,i=10<ESC>\ # delete the image with id=10, without freeing data
<ESC>_Ga=d,d=Z,z=-1<ESC>\ # delete the images with z-index -1, also freeing up image data
<ESC>_Ga=d,d=p,x=3,y=4<ESC>\ # delete all images that intersect the cell at (3, 4), without freeing data
Image persistence and storage quotas
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -417,7 +441,7 @@ Key Value Default Description
``Y`` Positive integer ``0`` The y-offset within the first cell at which to start displaying the image
``c`` Positive integer ``0`` The number of columns to display the image over
``r`` Positive integer ``0`` The number of rows to display the image over
``z`` Integer ``0`` The *z-index* vertical stacking order of the image
``z`` 32-bit integer ``0`` The *z-index* vertical stacking order of the image
**Keys for deleting images**
-----------------------------------------------------------
``d`` Single character. ``a`` What to delete.

View File

@@ -53,19 +53,19 @@ Quickstart
--------------
Pre-built binaries of |kitty| are available for both macOS and Linux.
See the :doc:`binary install instructions </binary>`. You can also
See the :doc:`binary install instructions </binary>`. You can
:doc:`build from source </build>`.
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>`_,
`Arch Linux <https://www.archlinux.org/packages/community/x86_64/kitty/>`_,
`Gentoo <https://packages.gentoo.org/packages/x11-terms/kitty>`_,
`Fedora <https://copr.fedorainfracloud.org/coprs/gagbo/kitty-latest/>`_,
`Fedora <https://src.fedoraproject.org/rpms/kitty>`_,
`Void Linux <https://github.com/void-linux/void-packages/blob/master/srcpkgs/kitty/template>`_,
and `Solus <https://dev.getsol.us/source/kitty/>`_.
@@ -173,6 +173,30 @@ 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::
# moves the window into a new OS window
map ctrl+f2 detach_window
# moves the window into a new Tab
map ctrl+f3 detach_window new-tab
# asks which tab to move the window into
map ctrl+f4 detach_window ask
Similarly, you can detach the current tab, with::
# moves the tab into a new OS window
map ctrl+f2 detach_tab
# asks which OS Window to move the tab into
map ctrl+f4 detach_tab ask
Finally, you can define a shortcut to close all windows in a tab other than
the currently active window::
map f9 close_other_windows_in_tab
Other keyboard shortcuts
----------------------------------
@@ -206,55 +230,26 @@ Reset background opacity :sc:`reset_background_opacity`
Layouts
----------
A layout is an arrangement of multiple *windows*. You can create a new window
A layout is an arrangement of multiple kitty *windows* inside a top-level OS window. You can create a new window
using the :sc:`new_window` key combination.
Currently, there are five layouts available,
Currently, there are six layouts available:
* **Stack** -- Only a single maximized window is shown at a time
* **Tall** -- One window is shown full height on the left, the rest of the windows are shown one below the other on the right
* **Fat** -- One window is shown full width on the top, the rest of the windows are shown side-by-side on the bottom
* **Fat** -- One (or optionally more) windows are shown full width on the top, the rest of the windows are shown side-by-side on the bottom
* **Grid** -- All windows are shown in a grid
* **Horizontal** -- All windows are shown side-by-side
* **Splits** -- Windows arranged in arbitrary patterns created using horizontal and vertical splits
* **Stack** -- Only a single maximized window is shown at a time
* **Tall** -- One (or optionally more) windows are shown full height on the left, the rest of the windows are shown one below the other on the right
* **Vertical** -- All windows are shown one below the other
You can switch between layouts using the :sc:`next_layout` key combination. You can
also create shortcuts to select particular layouts, and choose which layouts
you want to enable/disable, see :ref:`conf-kitty-shortcuts.layout` for examples.
By default, all layouts are enabled and you can switch between layouts using
the :sc:`next_layout` key combination. You can also create shortcuts to select
particular layouts, and choose which layouts you want to enable/disable, see
:ref:`conf-kitty-shortcuts.layout` for examples. The first layout listed in
:opt:`enabled_layouts` becomes the default layout.
You can resize windows inside layouts. Press :sc:`start_resizing_window` (also :kbd:`⌘+r` on macOS) to
enter resizing mode and follow the on-screen instructions. In a given window
layout only some operations may be possible for a particular window. For
example, in the Tall layout you can make the first window wider/narrower, but
not taller/shorter. Note that what you are resizing is actually not a window,
but a row/column in the layout, all windows in that row/column will be resized.
You can also define shortcuts in :file:`kitty.conf` to make the active window
wider, narrower, taller, or shorter by mapping to the ``resize_window``
action, for example::
map ctrl+left resize_window narrower
map ctrl+right resize_window wider
map ctrl+up resize_window taller
map ctrl+down resize_window shorter 3
The ``resize_window`` action has a second, optional argument to control
the resizing increment (a positive integer that defaults to 1).
Some layouts take options to control their behavior. For example, the ``fat``
and ``tall`` layouts accept the ``bias`` option to control how the available
space is split up. To specify the option, in :opt:`kitty.conf <enabled_layouts>` use::
enabled_layouts tall:bias=70
This will make the tall window occupy ``70%`` of available width. ``bias`` can be
any number between 10 and 90.
Writing a new layout only requires about a hundred lines of code, so if there
is some layout you want, take a look at `layout.py
<https://github.com/kovidgoyal/kitty/blob/master/kitty/layout.py>`_ and submit
a pull request!
For more details on the layouts and how to use them see :doc:`layouts`.
.. _kittens:
@@ -365,11 +360,12 @@ Mouse features
* You can triple click to select a line and then drag to select more lines.
* You can right click to extend a previous selection.
* You can hold down :kbd:`ctrl+alt` and drag with the mouse to select in
columns.
columns (see also :opt:`rectangle_select_modifiers`).
* Selecting text automatically copies it to the primary clipboard (on
platforms with a primary clipboard).
* You can select text with kitty even when a terminal program has grabbed
the mouse by holding down the :kbd:`shift` key.
the mouse by holding down the :kbd:`shift` key (see also
:opt:`terminal_select_modifiers`).
Font control
@@ -402,7 +398,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.
@@ -428,6 +424,14 @@ internal buffer named ``a`` and :kbd:`F2` to paste from that buffer. The buffer
names are arbitrary strings, so you can define as many such buffers as you
need.
Marks
-------------
kitty has the ability to mark text on the screen based on regular expressions.
This can be useful to highlight words or phrases when browsing output from long
running programs or similar. To learn how this feature works, see :doc:`marks`.
Frequently Asked Questions
---------------------------------
@@ -435,6 +439,15 @@ The list of Frequently Asked Questions (*FAQ*) is :doc:`available here <faq>`.
.. _completion:
Cool integrations for kitty with other CLI tools
--------------------------------------------------
kitty provides extremely powerful interfaces such as :doc:`remote-control` and
:doc:`kittens/custom` and :doc:`kittens/icat`
that allow it to be integrated with other tools seamlessly. For a list of such
user created integrations, see: :doc:`integrations`.
Completion for kitty
---------------------------------
@@ -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

108
docs/integrations.rst Normal file
View File

@@ -0,0 +1,108 @@
Integrations with other tools
================================
kitty provides extremely powerful interfaces such as :doc:`remote-control` and
:doc:`kittens/custom` and :doc:`kittens/icat`
that allow it to be integrated with other tools seamlessly.
Image and document viewers
----------------------------
Powered by kitty's :doc:`graphics-protocol` there exist many tools for viewing
images and other types of documents directly in your terminal, even over SSH.
`termpdf.py <https://github.com/dsanson/termpdf.py>`_
a terminal PDF/DJVU/CBR viewer
`mdcat <https://github.com/lunaryorn/mdcat>`_
Display markdown files nicely formatted with images in the terminal
`ranger <https://github.com/ranger/ranger>`_
a terminal file manager, with previews of file contents powered by kitty's graphics protocol.
`nnn <https://github.com/jarun/nnn/>`_
another terminal file manager, with previews of file contents powered by kitty's graphics protocol.
`koneko <https://github.com/twenty5151/koneko>`_
browse images from the pixiv artist community directly in kitty
System and data visualisation tools
---------------------------------------
`neofetch <https://github.com/dylanaraps/neofetch>`_
A command line system information tool that shows images using kitty's graphics protocol
`matplotlib <https://github.com/jktr/matplotlib-backend-kitty>`_
show matplotlib plots directly in kitty
`KittyTerminalImages.jl <https://github.com/simonschoelly/KittyTerminalImages.jl>`_
show images from Julia directly in kitty
`gnuplot <http://www.gnuplot.info/>`_
a graphing and data visualization tool that can be made to display its
output in kitty with the following bash snippet::
function iplot {
cat <<EOF | gnuplot
set terminal pngcairo enhanced font 'Fira Sans,10'
set autoscale
set samples 1000
set output '|kitty +kitten icat --stdin yes'
set object 1 rectangle from screen 0,0 to screen 1,1 fillcolor rgb"#fdf6e3" behind
plot $@
set output '/dev/null'
EOF
}
Add this to bashrc and then to plot a function, simply do::
iplot 'sin(x*3)*exp(x*.2)'
Editor integration
-----------------------
kitty can be integrated into many different terminal editors to add features
such a split windows, previews, REPLs etc.
`kakoune <https://kakoune.org/>`_
integrates with kitty to use native kitty windows for its windows/panels and REPLs.
`vim-slime <https://github.com/jpalardy/vim-slime#kitty>`_
uses kitty remote control for a Lisp REPL.
`vim-kitty-navigator <https://github.com/knubie/vim-kitty-navigator>`_
allows you to navigate seamlessly between vim and kitty splits using a consistent set of hotkeys.
`vim-test <https://github.com/vim-test/vim-test>`_
allows easily running tests in a terminal window
Scrollback manipulation
-------------------------
`kitty-search <https://github.com/trygveaa/kitty-kitten-search>`_
Live incremental search of the scrollback buffer.
`kitty-grab <https://github.com/yurikhan/kitty_grab>`_
keyboard based text selection for the kitty scrollback buffer.
Miscellaneous
------------------
`kitty-smart-tab <https://github.com/yurikhan/kitty-smart-tab>`_
use keys to either control tabs or pass them onto running applications if
no tabs are present
`kitty-smart-scroll <https://github.com/yurikhan/kitty-smart-scroll>`_
use keys to either scroll or pass them onto running applications if
no scrollback buffer is present
`reload keybindings <https://github.com/kovidgoyal/kitty/issues/1292#issuecomment-582388769>`_
reload key bindings from :file:`kitty.conf` without needing to restart
kitty

View File

@@ -20,24 +20,24 @@ your machine).
.. code-block:: python
def main(args):
# this is the main entry point of the kitten, it will be executed in
# the overlay window when the kitten is launched
answer = input('Enter some text: ')
# whatever this function returns will be available in the
# handle_result() function
return answer
def main(args: List[str]) -> str:
# this is the main entry point of the kitten, it will be executed in
# the overlay window when the kitten is launched
answer = input('Enter some text: ')
# whatever this function returns will be available in the
# handle_result() function
return answer
def handle_result(args, answer, target_window_id, boss):
# get the kitty window into which to paste answer
w = boss.window_id_map.get(target_window_id)
if w is not None:
w.paste(answer)
def handle_result(args: List[str], answer: str, target_window_id: int, boss: kitty.boss.Boss) -> None:
# get the kitty window into which to paste answer
w = boss.window_id_map.get(target_window_id)
if w is not None:
w.paste(answer)
Now in :file:`kitty.conf` add the lines::
map ctrl+k kitten mykitten.py
map ctrl+k kitten mykitten.py
Start kitty and press :kbd:`ctrl+k` and you should see the kitten running.
@@ -53,7 +53,7 @@ Passing arguments to kittens
You can pass arguments to kittens by defining them in the map directive in
:file:`kitty.conf`. For example::
map ctrl+k kitten mykitten.py arg1 arg2
map ctrl+k kitten mykitten.py arg1 arg2
These will be available as the ``args`` parameter in the ``main()`` and
``handle_result()`` functions. Note also that the current working directory
@@ -70,17 +70,18 @@ function, telling kitty what kind of input your kitten would like. For example:
.. code-block:: py
# in main, STDIN is for the kitten process and will contain
# the contents of the screen
def main(args):
return sys.stdin.read()
# in main, STDIN is for the kitten process and will contain
# the contents of the screen
def main(args):
return sys.stdin.read()
# in handle_result, STDIN is for the kitty process itself, rather
# than the kitten process and should not be read from.
def handle_result(args, stdin_data, target_window_id, boss):
pass
# in handle_result, STDIN is for the kitty process itself, rather
# than the kitten process and should not be read from.
from kittens.tui.handler import result_handler
@result_handler(type_of_input='text')
def handle_result(args, stdin_data, target_window_id, boss):
pass
handle_result.type_of_input = 'text'
This will send the plain text of the active window to the kitten's
:file:`STDIN`. For text with formatting escape codes, use ``ansi``
@@ -103,23 +104,23 @@ Create a file in the kitty config folder, :file:`~/.config/kitty/zoom_toggle.py`
.. code-block:: py
def main(args):
pass
def main(args):
pass
def handle_result(args, answer, target_window_id, boss):
tab = boss.active_tab
if tab is not None:
if tab.current_layout.name == 'stack':
tab.last_used_layout()
else:
tab.goto_layout('stack')
handle_result.no_ui = True
from kittens.tui.handler import result_handler
@result_handler(no_ui=True)
def handle_result(args, answer, target_window_id, boss):
tab = boss.active_tab
if tab is not None:
if tab.current_layout.name == 'stack':
tab.last_used_layout()
else:
tab.goto_layout('stack')
Now in kitty.conf add::
map f11 kitten zoom_toggle.py
map f11 kitten zoom_toggle.py
Pressing :kbd:`F11` will now act as a zoom toggle function. You can get even
more fancy, switching the kitty OS window to fullscreen as well as changing the
@@ -128,7 +129,56 @@ layout, by simply adding the line::
boss.toggle_fullscreen()
to the ``handle_result()`` function, above.
To the ``handle_result()`` function, above.
.. _send_mouse_event:
Sending mouse events
--------------------
If the program running in a window is receiving mouse events you can simulate
those using::
from kitty.fast_data_types import send_mouse_event
send_mouse_event(screen, x, y, button, action, mods)
``screen`` is the ``screen`` attribute of the window you want to send the event
to. ``x`` and ``y`` are the 0-indexed coordinates. ``button`` is a number using
the same numbering as X11 (left: ``1``, middle: ``2``, right: ``3``, scroll up:
``4``, scroll down: ``5``, scroll left: ``6``, scroll right: ``7``, back:
``8``, forward: ``9``). ``action`` is one of ``PRESS``, ``RELEASE``, ``DRAG``
or ``MOVE``. ``mods`` is a bitmask of ``GLFW_MOD_{mod}`` where ``{mod}`` is one
of ``SHIFT``, ``CONTROL`` or ``ALT``. All the mentioned constants are imported
from ``kitty.fast_data_types``.
For example, to send a left click at position x: 2, y: 3 to the active window::
from kitty.fast_data_types import send_mouse_event, GLFW_MOUSE_BUTTON_LEFT, PRESS
send_mouse_event(boss.active_window.screen, 2, 3, GLFW_MOUSE_BUTTON_LEFT, PRESS, 0)
The function will only send the event if the program is receiving events of
that type, and will return ``True`` if it sent the event, and ``False`` if not.
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:
@@ -136,11 +186,11 @@ Kittens created by kitty users
---------------------------------------------
`vim-kitty-navigator <https://github.com/knubie/vim-kitty-navigator>`_
Allows you to navigate seamlessly between vim and kitty splits using a consistent set of hotkeys.
Allows you to navigate seamlessly between vim and kitty splits using a consistent set of hotkeys.
`smart-scroll <https://github.com/yurikhan/kitty-smart-scroll>`_
Makes the kitty scroll bindings work in full screen applications
Makes the kitty scroll bindings work in full screen applications
`insert password <https://github.com/kovidgoyal/kitty/issues/1222>`_
Insert a password from a CLI password manager, taking care to only do it at
a password prompt.
Insert a password from a CLI password manager, taking care to only do it at
a password prompt.

View File

@@ -18,11 +18,71 @@ select anything that looks like a path or filename and then insert it into the
terminal, very useful for picking files from the output of a ``git`` or ``ls`` command and
adding them to the command line for the next command.
You can also press :sc:`goto_file_line` to select anything that looks
like a path or filename followed by a colon and a line number and open
the file in vim at the specified line number. The patterns and editor
to be used can be modified using options passed to the kitten. For example::
map ctrl+g kitten hints --type=linenum --linenum-action=tab nvim +{line} {path}
will open the selected file in a new tab inside neovim when you press
:kbd:`ctrl+g`.
The hints kitten is very powerful to see more detailed help on its various
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

@@ -21,6 +21,12 @@ Then you can simply use ``icat image.png`` to view images.
`ImageMagick <https://www.imagemagick.org>`_ must be installed for ``icat`` to
work.
.. note::
kitty's image display protocol may not work when used within a terminal
multiplexer such as ``screen`` or ``tmux``, depending on whether the
multiplexer has added support for it or not.
.. program:: kitty +kitten icat

View File

@@ -22,3 +22,12 @@ 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.
You can switch between modes using either the function keys or by pressing
:kbd:`Ctrl+Tab` and :kbd:`Ctrl+Shift+Tab`.
Command Line Interface
-------------------------
.. include:: ../generated/cli-kitten-unicode_input.rst

96
docs/launch.rst Normal file
View File

@@ -0,0 +1,96 @@
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.
Special arguments
-------------------
There are a few special placeholder arguments that can be specified as part of
the command line. Namely ``@selection`` which is replaced by the current
selection and ``@active-kitty-window-id`` which is replaced by the id of the
currently active kitty window. For example::
map f1 launch my-program @active-kitty-window-id
Watching launched windows
---------------------------
The :option:`launch --watcher` option allows you to specify python functions
that will be called at specific events, such as when the window is resized or
closed. Simply specify the path to a python module that specifies callback
functions for the events you are interested in, for example:
.. code-block:: python
def on_resize(boss, window, data):
# Here data will contain old_geometry and new_geometry
def on_close(boss, window, data):
# called when window is closed, typically when the program running in
# it exits.
Every callback is passed a reference to the global ``Boss`` object as well as
the ``Window`` object the action is occurring on. The ``data`` object is
mapping that contains event dependent data. Some useful methods and attributes
for the ``Window`` object are: ``as_text(as_ans=False, add_history=False,
add_wrap_markers=False, alternate_screen=False)`` with which you can get the
contents of the window and its scrollback buffer. Similarly,
``window.child.pid`` is the PID of the processes that was launched
in the window and ``window.id`` is the internal kitty ``id`` of the
window.
Syntax reference
------------------
.. include:: /generated/launch.rst

258
docs/layouts.rst Normal file
View File

@@ -0,0 +1,258 @@
Layouts
============
kitty has the ability to define its own windows that can be tiled next to each
other in arbitrary arrangements, based on *Layouts*, see below for examples:
.. figure:: screenshots/screenshot.png
:alt: Screenshot, showing three programs in the 'Tall' layout
:align: center
:scale: 100%
Screenshot, showing vim, tig and git running in |kitty| with the 'Tall' layout
.. figure:: screenshots/splits.png
:alt: Screenshot, showing windows in the 'Splits' layout
:align: center
:scale: 100%
Screenshot, showing windows with arbitrary arrangement in the 'Splits'
layout
There are many different layouts available. They are all enabled by default,
you can switch layouts using :sc:`next_layout`. To control which layouts
are available use :opt:`enabled_layouts`, the first listed layout becomes
the default. Individual layouts and how to use them are described below.
.. contents::
The Stack Layout
------------------
This is the simplest layout it displays a single window using all available
space, other windows are hidden behind it. It has no options::
enabled_layouts stack
The Tall Layout
------------------
Displays one (or optionally more) full height windows on the left half of the
screen. Remaining windows are tiled vertically on the right half of the screen.
There are options to control how the screen is split horizontally ``bias``
(an integer between ``10`` and ``90``) and options to control how many
full-height windows there are ``full_size`` (a positive integer). The
``mirrored`` option when set to ``true`` will cause the short windows to be
on the left side of the screen instead of the right. The syntax
for the options is shown below::
enabled_layouts tall:bias=50;full_size=1;mirrored=false
┌──────────────┬───────────────┐
│ │ │
│ │ │
│ │ │
│ ├───────────────┤
│ │ │
│ │ │
│ │ │
│ ├───────────────┤
│ │ │
│ │ │
│ │ │
└──────────────┴───────────────┘
In addition, you can map keys to increase or decrease the number of full size
windows, for example::
map ctrl+[ layout_action decrease_num_full_size_windows
map ctrl+] layout_action increase_num_full_size_windows
The Fat Layout
----------------
Displays one (or optionally more) full width windows on the top half of the
screen. Remaining windows are tiled horizontally on the bottom half of the screen.
There are options to control how the screen is split vertically ``bias``
(an integer between ``10`` and ``90``) and options to control how many
full-height windows there are ``full_size`` (a positive integer). The
``mirrored`` option when set to ``true`` will cause the narrow windows to be
on the top of the screen instead of the bottom. The syntax for the options is
shown below::
enabled_layouts fat:bias=50;full_size=1;mirrored=false
┌──────────────────────────────┐
│ │
│ │
│ │
│ │
├─────────┬──────────┬─────────┤
│ │ │ │
│ │ │ │
│ │ │ │
│ │ │ │
│ │ │ │
└─────────┴──────────┴─────────┘
The Grid Layout
--------------------
Display windows in a balanced grid with all windows the same size except the
last column if there are not enough windows to fill the grid. Has no options::
enabled_layouts grid
┌─────────┬──────────┬─────────┐
│ │ │ │
│ │ │ │
│ │ │ │
│ │ │ │
├─────────┼──────────┼─────────┤
│ │ │ │
│ │ │ │
│ │ │ │
│ │ │ │
└─────────┴──────────┴─────────┘
.. _splits_layout:
The Splits Layout
--------------------
This is the most flexible layout. You can create any arrangement of windows
by splitting exiting windows repeatedly. To best use this layout you should
define a few extra keybindings in :file:`kitty.conf`::
map F5 launch --location=hsplit
map F6 launch --location=vsplit
map F7 layout_action rotate
map shift+up move_window up
map shift+left move_window left
map shift+right move_window right
map shift+down move_window down
map ctrl+left neighboring_window left
map ctrl+right neighboring_window right
map ctrl+up neighboring_window up
map ctrl+down neighboring_window down
Now you can create horizontal and vertical splits by using :kbd:`F5` and
:kbd:`F6`. You can move them around using :kbd:`shift+arrow keys`
and you can move focus to neighboring windows using :kbd:`ctrl+arrow keys`.
You can switch an existing split from horizontal to vertical and vice versa
using :kbd:`F7`. Finally, windows can be resized using :ref:`window_resizing`.
This layout takes one option, ``split_axis`` that controls whether new windows
are placed into vertical or horizontal splits, by default::
enabled_layouts splits:split_axis=horizontal
┌──────────────┬───────────────┐
│ │ │
│ │ │
│ │ │
│ ├───────┬───────┤
│ │ │ │
│ │ │ │
│ │ │ │
│ ├───────┴───────┤
│ │ │
│ │ │
│ │ │
└──────────────┴───────────────┘
The Horizontal Layout
------------------------
All windows are shown side by side. Has no options::
enabled_layouts horizontal
┌─────────┬──────────┬─────────┐
│ │ │ │
│ │ │ │
│ │ │ │
│ │ │ │
│ │ │ │
│ │ │ │
│ │ │ │
│ │ │ │
│ │ │ │
└─────────┴──────────┴─────────┘
The Vertical Layout
-----------------------
All windows are shown one below the other. Has no options::
enabled_layouts vertical
┌──────────────────────────────┐
│ │
│ │
│ │
├──────────────────────────────┤
│ │
│ │
│ │
├──────────────────────────────┤
│ │
│ │
│ │
└──────────────────────────────┘
.. _window_resizing:
Resizing windows
------------------
You can resize windows inside layouts. Press :sc:`start_resizing_window` (also
:kbd:`⌘+r` on macOS) to enter resizing mode and follow the on-screen
instructions. In a given window layout only some operations may be possible
for a particular window. For example, in the Tall layout you can make the first
window wider/narrower, but not taller/shorter. Note that what you are resizing
is actually not a window, but a row/column in the layout, all windows in that
row/column will be resized.
You can also define shortcuts in :file:`kitty.conf` to make the active window
wider, narrower, taller, or shorter by mapping to the ``resize_window``
action, for example::
map ctrl+left resize_window narrower
map ctrl+right resize_window wider
map ctrl+up resize_window taller
map ctrl+down resize_window shorter 3
The ``resize_window`` action has a second, optional argument to control
the resizing increment (a positive integer that defaults to 1).
Some layouts take options to control their behavior. For example, the ``fat``
and ``tall`` layouts accept the ``bias`` and ``full_size`` options to control
how the available space is split up.
To specify the option, in :opt:`kitty.conf <enabled_layouts>` use::
enabled_layouts tall:bias=70;full_size=2
This will have ``2`` instead of a single tall window, that occupy ``70%``
instead of ``50%`` of available width. ``bias`` can be any number between 10
and 90.
Writing a new layout only requires about two hundred lines of code, so if there
is some layout you want, take a look at one of the existing layouts in the
`layout <https://github.com/kovidgoyal/kitty/tree/master/kitty/layout>`_
package and submit a pull request!

125
docs/marks.rst Normal file
View File

@@ -0,0 +1,125 @@
Marks
=================
kitty has the ability to mark text on the screen based on regular expressions.
This can be useful to highlight words or phrases when browsing output from long
running programs or similar. Lets start with a few examples:
Suppose we want to be able to highlight the word ERROR in the current window.
Add the following to :file:`kitty.conf`::
map f1 toggle_marker text 1 ERROR
Now when you press :kbd:`F1` all instances of the word :code:`ERROR` will be
highlighted. To turn off the highlighting, press :kbd:`F1` again.
If you want to make it case-insensitive, use::
map f1 toggle_marker itext 1 ERROR
To make it match only complete words, use::
map f1 toggle_marker regex 1 \bERROR\b
Suppose you want to highlight both :code:`ERROR` and :code:`WARNING`, case
insensitively::
map f1 toggle_marker iregex 1 \bERROR\b 2 \bWARNING\b
kitty supports up to 3 mark groups (the numbers in the commands above). You
can control the colors used for these groups in :file:`kitty.conf` with::
mark1_foreground red
mark1_background gray
mark2_foreground green
...
.. note::
For performance reasons, matching is done per line only, and only when that line is
altered in any way. So you cannot match text that stretches across multiple
lines.
Creating markers dynamically
---------------------------------
If you want to create markers dynamically rather than pre-defining them in
:file:`kitty.conf` you can do so as follows::
map f1 create_marker
map f2 remove_marker
Then pressing :kbd:`F1` will allow you to enter the marker definition and set
it and pressing :kbd:`F2` will remove the marker. ``create_marker`` accepts
the same syntax as ``toggle_marker`` above. Note that while creating
markers, the prompt has history so you can easily re-use previous marker
expressions.
You can also use the facilities for :doc:`remote-control` to dynamically
add/remove markers.
Scrolling to marks
--------------------
kitty has an action to scroll to the next line that contains a mark. You can
use it by mapping it to some shortcut in :file:`kitty.conf`::
map ctrl+p scroll_to_mark prev
map ctrl+n scroll_to_mark next
Then pressing :kbd:`ctrl+p` will scroll to the first line in the scrollback
buffer above the current top line that contains a mark. Pressing :kbd:`ctrl+n`
will scroll to show the first line below the current last line that contains
a mark. If you wish to jump to a mark of a specific type, you can add that to
the mapping::
map ctrl+1 scroll_to_mark prev 1
Which will scroll only to marks of type 1.
The full syntax for creating marks
-------------------------------------
The syntax of the :code:`toggle_marker` command is::
toggle_marker <marker-type> <specification>
Here :code:`marker-type` is one of:
* :code:`text` - simple substring matching
* :code:`itext` - case-insensitive substring matching
* :code:`regex` - A python regular expression
* :code:`iregex` - A case-insensitive python regular expression
* :code:`function` - An arbitrary function defined in a python file, see
:ref:`marker_funcs`.
.. _marker_funcs:
Arbitrary marker functions
-----------------------------
You can create your own marker functions. Create a python file named
:file:`mymarker.py` and in it create a :code:`marker` function. This
function receives the text of the line as input and must yield three numbers,
the starting character position, the ending character position and the mark
group (1-3). For example:
.. code-block::
def marker(text):
# Function to highlight the letter X
for i, ch in enumerate(text):
if ch.lower() == 'x':
yield i, i, 3
Save this file somewhere and in :file:`kitty.conf`, use::
map f1 toggle_marker function /path/to/mymarker.py
If you save the file in the kitty config directory, you can use::
map f1 toggle_marker function mymarker.py

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

@@ -219,6 +219,11 @@ first, for example::
<ESC>]52;c;!<ESC>\
Here ``!`` is not valid base64 encoded text, so it clears the clipboard.
Further, since it is invalid, it should be ignored by terminal emulators
that do not support this extension, thereby making it safe to use, simply
always send it before starting a new OSC 52 paste, even if you aren't chunking
up large pastes, that way kitty wont concatenate your paste, and it will have
no ill-effects in other terminal emulators.
In case you're using software that can't be easily adapted to this
protocol extension, it can be disabled by specifying ``no-append`` to the

View File

@@ -21,7 +21,7 @@ In order for control to work, :opt:`allow_remote_control` must be enabled in
Now, in the new |kitty| window, enter the command::
kitty @ new-window --title Output --keep-focus cat
kitty @ launch --title Output --keep-focus cat
This will open a new window, running the ``cat`` program that will appear next
to the current window.
@@ -54,7 +54,7 @@ window. Type ``Ctrl+D`` when you are ready to stop.
Now, let's open a new tab::
kitty @ new-window --new-tab --tab-title "My Tab" --keep-focus bash
kitty @ launch --type=tab --tab-title "My Tab" --keep-focus bash
This will open a new tab running the bash shell with the title "My Tab".
We can change the title of the tab with::
@@ -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
@@ -134,6 +134,19 @@ still write to the pipes of any other program on the same computer and
therefore can control |kitty|. It can, however, be useful to block programs
running on other computers (for example, over ssh) or as other users.
Mapping key presses to remote control commands
--------------------------------------------------
If you wish to trigger a remote control command easily with just a keypress,
you can map it in :file:`kitty.conf`. For example::
map F1 remote_control set-spacing margin=30
Then pressing the :kbd:`F1` key will set the active window margins to 30.
The syntax for what follows :code:`remote_control` is exactly the same
as the syntax for what follows :code:`kitty @` above.
Documentation for the remote control protocol
-----------------------------------------------

BIN
docs/screenshots/splits.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

View File

@@ -4,18 +4,23 @@
import subprocess
from collections import defaultdict
from typing import Any, DefaultDict, Dict, FrozenSet, List, Tuple, Union
KeymapType = Dict[str, Tuple[str, Union[FrozenSet[str], str]]]
def resolve_keys(keymap):
ans = defaultdict(list)
def resolve_keys(keymap: KeymapType) -> DefaultDict[str, List[str]]:
ans: DefaultDict[str, List[str]] = defaultdict(list)
for ch, (attr, atype) in keymap.items():
if atype not in ('int', 'uint'):
atype = 'flag'
ans[atype].append(ch)
if isinstance(atype, str) and atype in ('int', 'uint'):
q = atype
else:
q = 'flag'
ans[q].append(ch)
return ans
def enum(keymap):
def enum(keymap: KeymapType) -> str:
lines = []
for ch, (attr, atype) in keymap.items():
lines.append(f"{attr}='{ch}'")
@@ -26,15 +31,15 @@ def enum(keymap):
'''.format(',\n'.join(lines))
def parse_key(keymap):
def parse_key(keymap: KeymapType) -> str:
lines = []
for attr, atype in keymap.values():
vs = atype.upper() if atype in ('uint', 'int') else 'FLAG'
vs = atype.upper() if isinstance(atype, str) and atype in ('uint', 'int') else 'FLAG'
lines.append(f'case {attr}: value_state = {vs}; break;')
return ' \n'.join(lines)
def parse_flag(keymap, type_map, command_class):
def parse_flag(keymap: KeymapType, type_map: Dict[str, Any], command_class: str) -> str:
lines = []
for ch in type_map['flag']:
attr, allowed_values = keymap[ch]
@@ -52,14 +57,14 @@ def parse_flag(keymap, type_map, command_class):
return ' \n'.join(lines)
def parse_number(keymap):
def parse_number(keymap: KeymapType) -> Tuple[str, str]:
int_keys = [f'I({attr})' for attr, atype in keymap.values() if atype == 'int']
uint_keys = [f'U({attr})' for attr, atype in keymap.values() if atype == 'uint']
return '; '.join(int_keys), '; '.join(uint_keys)
def cmd_for_report(report_name, keymap, type_map, payload_allowed):
def group(atype, conv):
def cmd_for_report(report_name: str, keymap: KeymapType, type_map: Dict[str, Any], payload_allowed: bool) -> str:
def group(atype: str, conv: str) -> Tuple[str, str]:
flag_fmt, flag_attrs = [], []
cv = {'flag': 'c', 'int': 'i', 'uint': 'I'}[atype]
for ch in type_map[atype]:
@@ -84,7 +89,15 @@ def cmd_for_report(report_name, keymap, type_map, payload_allowed):
return '\n'.join(ans)
def generate(function_name, callback_name, report_name, keymap, command_class, initial_key='a', payload_allowed=True):
def generate(
function_name: str,
callback_name: str,
report_name: str,
keymap: KeymapType,
command_class: str,
initial_key: str = 'a',
payload_allowed: bool = True
) -> str:
type_map = resolve_keys(keymap)
keys_enum = enum(keymap)
handle_key = parse_key(keymap)
@@ -124,6 +137,7 @@ static inline void
{parr}
{keys_enum}
enum KEYS key = '{initial_key}';
if (screen->parser_buf[pos] == ';') state = AFTER_VALUE;
while (pos < screen->parser_buf_pos) {{
switch(state) {{
@@ -225,7 +239,7 @@ static inline void
'''
def write_header(text, path):
def write_header(text: str, path: str) -> None:
with open(path, 'w') as f:
print(f'// This file is generated by {__file__} do not edit!', file=f, end='\n\n')
print('#pragma once', file=f)
@@ -233,9 +247,9 @@ def write_header(text, path):
subprocess.check_call(['clang-format', '-i', path])
def graphics_parser():
def graphics_parser() -> None:
flag = frozenset
keymap = {
keymap: KeymapType = {
'a': ('action', flag('tTqpd')),
'd': ('delete_action', flag('aAiIcCpPqQxXyYzZ')),
't': ('transmission_type', flag('dfts')),

View File

@@ -12,6 +12,10 @@ from functools import partial
from html.entities import html5
from itertools import groupby
from operator import itemgetter
from typing import (
Callable, DefaultDict, Dict, FrozenSet, Generator, Iterable, List,
Optional, Set, Tuple, Union
)
from urllib.request import urlopen
os.chdir(os.path.dirname(os.path.abspath(__file__)))
@@ -24,7 +28,7 @@ if len(non_characters) != 66:
emoji_skin_tone_modifiers = frozenset(range(0x1f3fb, 0x1F3FF + 1))
def get_data(fname, folder='UCD'):
def get_data(fname: str, folder: str = 'UCD') -> Iterable[str]:
url = f'https://www.unicode.org/Public/{folder}/latest/{fname}'
bn = os.path.basename(url)
local = os.path.join('/tmp', bn)
@@ -42,23 +46,25 @@ def get_data(fname, folder='UCD'):
# Map of class names to set of codepoints in class
class_maps = {}
name_map = {}
word_search_map = defaultdict(set)
class_maps: Dict[str, Set[int]] = {}
all_symbols: Set[int] = set()
name_map: Dict[int, str] = {}
word_search_map: DefaultDict[str, Set[int]] = defaultdict(set)
zwj = 0x200d
marks = set(emoji_skin_tone_modifiers) | {zwj}
flag_codepoints = frozenset(range(0x1F1E6, 0x1F1E6 + 26))
marks = set(emoji_skin_tone_modifiers) | {zwj} | flag_codepoints
not_assigned = set(range(0, sys.maxunicode))
def parse_ucd():
def parse_ucd() -> None:
def add_word(w, c):
def add_word(w: str, c: int) -> None:
if c <= 32 or c == 127 or 128 <= c <= 159:
return
if len(w) > 1:
word_search_map[w.lower()].add(c)
first = None
first: Optional[int] = None
for word, c in html5.items():
if len(c) == 1:
add_word(word.rstrip(';'), ord(c))
@@ -76,7 +82,7 @@ def parse_ucd():
category = parts[2]
s = class_maps.setdefault(category, set())
desc = parts[1]
codepoints = (codepoint,)
codepoints: Union[Tuple[int, ...], Iterable[int]] = (codepoint,)
if first is None:
if desc.endswith(', First>'):
first = codepoint
@@ -89,6 +95,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']
@@ -96,43 +104,97 @@ def parse_ucd():
word_search_map['lamda'] |= word_search_map['lambda']
def split_two(line):
spec, rest = line.split(';', 1)
spec, rest = spec.strip(), rest.strip().split(' ', 1)[0].strip()
def parse_range_spec(spec: str) -> Set[int]:
spec = spec.strip()
if '..' in spec:
chars = tuple(map(lambda x: int(x, 16), filter(None, spec.split('.'))))
chars = set(range(chars[0], chars[1] + 1))
chars_ = tuple(map(lambda x: int(x, 16), filter(None, spec.split('.'))))
chars = set(range(chars_[0], chars_[1] + 1))
else:
chars = {int(spec, 16)}
return chars, rest
return chars
all_emoji = set()
emoji_categories = {}
emoji_presentation_bases = set()
def split_two(line: str) -> Tuple[Set[int], str]:
spec, rest = line.split(';', 1)
spec, rest = spec.strip(), rest.strip().split(' ', 1)[0].strip()
return parse_range_spec(spec), rest
def parse_emoji():
for line in get_data('emoji-data.txt', 'emoji'):
chars, rest = split_two(line)
s = emoji_categories.setdefault(rest, set())
s.update(chars)
all_emoji.update(chars)
for line in get_data('emoji-variation-sequences.txt', 'emoji'):
base, var, *rest = line.split()
if base.startswith('#'):
all_emoji: Set[int] = set()
emoji_presentation_bases: Set[int] = set()
narrow_emoji: Set[int] = set()
wide_emoji: Set[int] = set()
flags: Dict[int, List[int]] = {}
def parse_basic_emoji(spec: str) -> None:
parts = list(filter(None, spec.split()))
has_emoji_presentation = len(parts) < 2
chars = parse_range_spec(parts[0])
all_emoji.update(chars)
emoji_presentation_bases.update(chars)
(wide_emoji if has_emoji_presentation else narrow_emoji).update(chars)
def parse_keycap_sequence(spec: str) -> None:
base, fe0f, cc = list(filter(None, spec.split()))
chars = parse_range_spec(base)
all_emoji.update(chars)
emoji_presentation_bases.update(chars)
narrow_emoji.update(chars)
def parse_flag_emoji_sequence(spec: str) -> None:
a, b = list(filter(None, spec.split()))
left, right = int(a, 16), int(b, 16)
chars = {left, right}
all_emoji.update(chars)
wide_emoji.update(chars)
emoji_presentation_bases.update(chars)
flags.setdefault(left, []).append(right)
def parse_emoji_tag_sequence(spec: str) -> None:
a = int(spec.split()[0], 16)
all_emoji.add(a)
wide_emoji.add(a)
emoji_presentation_bases.add(a)
def parse_emoji_modifier_sequence(spec: str) -> None:
a, b = list(filter(None, spec.split()))
char, mod = int(a, 16), int(b, 16)
mod
all_emoji.add(char)
wide_emoji.add(char)
emoji_presentation_bases.add(char)
def parse_emoji() -> None:
for line in get_data('emoji-sequences.txt', 'emoji'):
parts = [x.strip() for x in line.split(';')]
if len(parts) < 2:
continue
base = int(base, 16)
if var.upper() == 'FE0F':
emoji_presentation_bases.add(base)
data, etype = parts[:2]
if etype == 'Basic_Emoji':
parse_basic_emoji(data)
elif etype == 'Emoji_Keycap_Sequence':
parse_keycap_sequence(data)
elif etype == 'RGI_Emoji_Flag_Sequence':
parse_flag_emoji_sequence(data)
elif etype == 'RGI_Emoji_Tag_Sequence':
parse_emoji_tag_sequence(data)
elif etype == 'RGI_Emoji_Modifier_Sequence':
parse_emoji_modifier_sequence(data)
doublewidth, ambiguous = set(), set()
doublewidth: Set[int] = set()
ambiguous: Set[int] = set()
def parse_eaw():
def parse_eaw() -> None:
global doublewidth, ambiguous
seen = set()
seen: Set[int] = set()
for line in get_data('ucd/EastAsianWidth.txt'):
chars, eaw = split_two(line)
if eaw == 'A':
@@ -148,7 +210,7 @@ def parse_eaw():
doublewidth |= set(range(0x30000, 0x3FFFD + 1)) - seen
def get_ranges(items):
def get_ranges(items: List[int]) -> Generator[Union[int, Tuple[int, int]], None, None]:
items.sort()
for k, g in groupby(enumerate(items), lambda m: m[0]-m[1]):
group = tuple(map(itemgetter(1), g))
@@ -159,7 +221,7 @@ def get_ranges(items):
yield a, b
def write_case(spec, p):
def write_case(spec: Union[Tuple, int], p: Callable) -> None:
if isinstance(spec, tuple):
p('\t\tcase 0x{:x} ... 0x{:x}:'.format(*spec))
else:
@@ -167,7 +229,7 @@ def write_case(spec, p):
@contextmanager
def create_header(path, include_data_types=True):
def create_header(path: str, include_data_types: bool = True) -> Generator[Callable, None, None]:
with open(path, 'w') as f:
p = partial(print, file=f)
p('// unicode data, built from the unicode standard on:', date.today())
@@ -184,7 +246,7 @@ def create_header(path, include_data_types=True):
p('END_ALLOW_CASE_RANGE')
def gen_emoji():
def gen_emoji() -> None:
with create_header('kitty/emoji.h') as p:
p('static inline bool\nis_emoji(char_type code) {')
p('\tswitch(code) {')
@@ -194,9 +256,10 @@ 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('static inline bool\nis_symbol(char_type code) {')
p('\tswitch(code) {')
for spec in get_ranges(list(emoji_categories['Emoji_Modifier'])):
for spec in get_ranges(list(all_symbols)):
write_case(spec, p)
p('\t\t\treturn true;')
p('\t\tdefault: return false;')
@@ -204,9 +267,17 @@ def gen_emoji():
p('\treturn false;\n}')
def category_test(name, p, classes, comment, static=False, extra_chars=frozenset(), exclude=frozenset()):
static = 'static inline ' if static else ''
chars = set()
def category_test(
name: str,
p: Callable,
classes: Iterable[str],
comment: str,
use_static: bool = False,
extra_chars: Union[FrozenSet[int], Set[int]] = frozenset(),
exclude: Union[Set[int], FrozenSet[int]] = frozenset()
) -> None:
static = 'static inline ' if use_static else ''
chars: Set[int] = set()
for c in classes:
chars |= class_maps[c]
chars |= extra_chars
@@ -216,12 +287,12 @@ def category_test(name, p, classes, comment, static=False, extra_chars=frozenset
p('\tswitch(code) {')
for spec in get_ranges(list(chars)):
write_case(spec, p)
p(f'\t\t\treturn true;')
p('\t\t\treturn true;')
p('\t} // }}}\n')
p('\treturn false;\n}\n')
def codepoint_to_mark_map(p, mark_map):
def codepoint_to_mark_map(p: Callable, mark_map: List[int]) -> Dict[int, int]:
p('\tswitch(c) { // {{{')
rmap = {c: m for m, c in enumerate(mark_map)}
for spec in get_ranges(mark_map):
@@ -236,14 +307,14 @@ def codepoint_to_mark_map(p, mark_map):
return rmap
def classes_to_regex(classes, exclude=''):
chars = set()
def classes_to_regex(classes: Iterable[str], exclude: str = '') -> Iterable[str]:
chars: Set[int] = set()
for c in classes:
chars |= class_maps[c]
for c in map(ord, exclude):
chars.discard(c)
for x in map(ord, exclude):
chars.discard(x)
def as_string(codepoint):
def as_string(codepoint: int) -> str:
if codepoint < 256:
return r'\x{:02x}'.format(codepoint)
if codepoint <= 0xffff:
@@ -257,7 +328,7 @@ def classes_to_regex(classes, exclude=''):
yield as_string(spec)
def gen_ucd():
def gen_ucd() -> None:
cz = {c for c in class_maps if c[0] in 'CZ'}
with create_header('kitty/unicode-data.c') as p:
p('#include "unicode-data.h"')
@@ -285,7 +356,9 @@ def gen_ucd():
p('}\n')
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))
m = re.search(r'^#define VS15 (\d+)', unicode_data, re.M)
if m is not None:
expected = int(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]
@@ -294,7 +367,7 @@ def gen_ucd():
f.write("url_delimiters = '{}' # noqa".format(''.join(classes_to_regex(cz, exclude='\n'))))
def gen_names():
def gen_names() -> None:
with create_header('kittens/unicode_input/names.h') as p:
mark_to_cp = list(sorted(name_map))
cp_to_mark = {cp: m for m, cp in enumerate(mark_to_cp)}
@@ -348,29 +421,29 @@ def gen_names():
p('}; // }}}\n')
# The trie
p(f'typedef struct {{ uint32_t children_offset; uint32_t match_offset; }} word_trie;\n')
all_trie_nodes = []
p('typedef struct {{ uint32_t children_offset; uint32_t match_offset; }} word_trie;\n')
all_trie_nodes: List['TrieNode'] = [] # noqa
class TrieNode:
def __init__(self):
def __init__(self) -> None:
self.match_offset = 0
self.children_offset = 0
self.children = {}
self.children: Dict[int, int] = {}
def add_letter(self, letter):
def add_letter(self, letter: int) -> int:
if letter not in self.children:
self.children[letter] = len(all_trie_nodes)
all_trie_nodes.append(TrieNode())
return self.children[letter]
def __str__(self):
def __str__(self) -> str:
return f'{{ .children_offset={self.children_offset}, .match_offset={self.match_offset} }}'
root = TrieNode()
all_trie_nodes.append(root)
def add_word(word_idx, word):
def add_word(word_idx: int, word: str) -> None:
parent = root
for letter in map(ord, word):
idx = parent.add_letter(letter)
@@ -395,10 +468,10 @@ def gen_names():
p('}; // }}}\n')
def gen_wcwidth():
seen = set()
def gen_wcwidth() -> None:
seen: Set[int] = set()
def add(p, comment, chars_, ret):
def add(p: Callable, comment: str, chars_: Union[Set[int], FrozenSet[int]], ret: int) -> None:
chars = chars_ - seen
seen.update(chars)
p(f'\t\t// {comment} ({len(chars)} codepoints)' + ' {{' '{')
@@ -412,13 +485,14 @@ def gen_wcwidth():
p('\tswitch(code) {')
non_printing = class_maps['Cc'] | class_maps['Cf'] | class_maps['Cs']
add(p, 'Flags', flag_codepoints, 2)
add(p, 'Marks', marks | {0}, 0)
add(p, 'Non-printing characters', non_printing, -1)
add(p, 'Private use', class_maps['Co'], -3)
add(p, 'Text Presentation', emoji_categories['Emoji'] - emoji_categories['Emoji_Presentation'], 1)
add(p, 'Text Presentation', narrow_emoji, 1)
add(p, 'East Asian ambiguous width', ambiguous, -2)
add(p, 'East Asian double width', doublewidth, 2)
add(p, 'Emoji Presentation', emoji_categories['Emoji_Presentation'], 2)
add(p, 'Emoji Presentation', wide_emoji, 2)
add(p, 'Not assigned in the unicode character database', not_assigned, -4)

0
glfw/__init__.py Normal file
View File

114
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,22 +152,28 @@ 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;
}
return timeout;
}
static inline struct timespec
calc_time(monotonic_t nsec) {
struct timespec result;
result.tv_sec = nsec / (1000LL * 1000LL * 1000LL);
result.tv_nsec = nsec % (1000LL * 1000LL * 1000LL);
return result;
}
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 +191,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 +292,12 @@ finalizePollData(EventLoopData *eld) {
}
int
pollForEvents(EventLoopData *eld, double timeout) {
pollForEvents(EventLoopData *eld, monotonic_t timeout, watch_callback_func display_callback) {
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) {
@@ -312,6 +305,7 @@ pollForEvents(EventLoopData *eld, double timeout) {
errno = 0;
result = pollWithTimeout(eld->fds, eld->watches_count, timeout);
int saved_errno = errno;
if (display_callback) display_callback(result, eld->fds[0].revents && eld->watches[0].events, NULL);
dispatchTimers(eld);
if (result > 0) {
dispatchEvents(eld);
@@ -326,6 +320,7 @@ pollForEvents(EventLoopData *eld, double timeout) {
errno = 0;
result = poll(eld->fds, eld->watches_count, -1);
int saved_errno = errno;
if (display_callback) display_callback(result, eld->fds[0].revents && eld->watches[0].events, NULL);
dispatchTimers(eld);
if (result > 0) {
dispatchEvents(eld);
@@ -338,53 +333,20 @@ pollForEvents(EventLoopData *eld, double timeout) {
return read_ok;
}
// Splits and translates a text/uri-list into separate file paths
// NOTE: This function destroys the provided string
//
char** parseUriList(char* text, int* count)
{
const char* prefix = "file://";
char** paths = NULL;
char* line;
*count = 0;
while ((line = strtok(text, "\r\n")))
{
text = NULL;
if (line[0] == '#')
continue;
if (strncmp(line, prefix, strlen(prefix)) == 0)
{
line += strlen(prefix);
// TODO: Validate hostname
while (*line != '/')
line++;
}
(*count)++;
char* path = calloc(strlen(line) + 1, 1);
paths = realloc(paths, *count * sizeof(char*));
paths[*count - 1] = path;
while (*line)
{
if (line[0] == '%' && line[1] && line[2])
{
const char digits[3] = { line[1], line[2], '\0' };
*path = strtol(digits, NULL, 16);
line += 2;
}
else
*path = *line;
path++;
line++;
// Duplicate a UTF-8 encoded string
// but cut it so that it has at most max_length bytes plus the null byte.
// This does not take combining characters into account.
GLFWAPI char* utf_8_strndup(const char* source, size_t max_length) {
if (!source) return NULL;
size_t length = strnlen(source, max_length);
if (length >= max_length) {
for (length = max_length; length > 0; length--) {
if ((source[length] & 0xC0) != 0x80) break;
}
}
return paths;
char* result = malloc(length + 1);
memcpy(result, source, length);
result[length] = 0;
return result;
}

15
glfw/backend_utils.h vendored
View File

@@ -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,16 +83,16 @@ 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, watch_callback_func);
unsigned dispatchTimers(EventLoopData *eld);
void finalizePollData(EventLoopData *eld);
bool initPollData(EventLoopData *eld, int display_fd);
char** parseUriList(char* text, int* count);
void wakeupEventLoop(EventLoopData *eld);
char* utf_8_strndup(const char* source, size_t max_length);

View File

@@ -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,98 @@ static bool initializeTIS(void)
@end // GLFWHelper
// Delegate for application related notifications {{{
@interface GLFWApplicationDelegate : NSObject <NSApplicationDelegate>
@end
@implementation GLFWApplicationDelegate
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
{
(void)sender;
if (_glfw.callbacks.application_close) _glfw.callbacks.application_close(0);
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 and finishLaunching
// 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;
@@ -313,6 +525,32 @@ static bool initializeTIS(void)
@end
//////////////////////////////////////////////////////////////////////////
////// GLFW internal API //////
//////////////////////////////////////////////////////////////////////////
void* _glfwLoadLocalVulkanLoaderNS(void)
{
CFBundleRef bundle = CFBundleGetMainBundle();
if (!bundle)
return NULL;
CFURLRef url =
CFBundleCopyAuxiliaryExecutableURL(bundle, CFSTR("libvulkan.1.dylib"));
if (!url)
return NULL;
char path[PATH_MAX];
void* handle = NULL;
if (CFURLGetFileSystemRepresentation(url, true, (UInt8*) path, sizeof(path) - 1))
handle = _glfw_dlopen(path);
CFRelease(url);
return handle;
}
//////////////////////////////////////////////////////////////////////////
////// GLFW platform API //////
//////////////////////////////////////////////////////////////////////////
@@ -335,6 +573,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 +595,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 +648,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:)
@@ -402,7 +669,6 @@ int _glfwPlatformInit(void)
if (!initializeTIS())
return false;
_glfwInitTimerNS();
_glfwInitJoysticksNS();
_glfwPollMonitorsNS();
@@ -531,7 +797,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 +817,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 +828,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 +854,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

@@ -146,7 +146,7 @@ static bool modeIsGood(CGDisplayModeRef mode)
// Convert Core Graphics display mode to GLFW video mode
//
static GLFWvidmode vidmodeFromCGDisplayMode(CGDisplayModeRef mode,
CVDisplayLinkRef link)
double fallbackRefreshRate)
{
GLFWvidmode result;
result.width = (int) CGDisplayModeGetWidth(mode);
@@ -154,11 +154,7 @@ static GLFWvidmode vidmodeFromCGDisplayMode(CGDisplayModeRef mode,
result.refreshRate = (int) round(CGDisplayModeGetRefreshRate(mode));
if (result.refreshRate == 0)
{
const CVTime time = CVDisplayLinkGetNominalOutputVideoRefreshPeriod(link);
if (!(time.flags & kCVTimeIsIndefinite))
result.refreshRate = (int) (time.timeScale / (double) time.timeValue);
}
result.refreshRate = (int) round(fallbackRefreshRate);
#if MAC_OS_X_VERSION_MAX_ALLOWED <= 101100
CFStringRef format = CGDisplayModeCopyPixelEncoding(mode);
@@ -240,6 +236,69 @@ static bool refreshMonitorScreen(_GLFWmonitor* monitor)
return false;
}
// Returns the display refresh rate queried from the I/O registry
//
static double getFallbackRefreshRate(CGDirectDisplayID displayID)
{
double refreshRate = 60.0;
io_iterator_t it;
io_service_t service;
if (IOServiceGetMatchingServices(kIOMasterPortDefault,
IOServiceMatching("IOFramebuffer"),
&it) != 0)
{
return refreshRate;
}
while ((service = IOIteratorNext(it)) != 0)
{
const CFNumberRef indexRef =
IORegistryEntryCreateCFProperty(service,
CFSTR("IOFramebufferOpenGLIndex"),
kCFAllocatorDefault,
kNilOptions);
if (!indexRef)
continue;
uint32_t index = 0;
CFNumberGetValue(indexRef, kCFNumberIntType, &index);
CFRelease(indexRef);
if (CGOpenGLDisplayMaskToDisplayID(1 << index) != displayID)
continue;
const CFNumberRef clockRef =
IORegistryEntryCreateCFProperty(service,
CFSTR("IOFBCurrentPixelClock"),
kCFAllocatorDefault,
kNilOptions);
const CFNumberRef countRef =
IORegistryEntryCreateCFProperty(service,
CFSTR("IOFBCurrentPixelCount"),
kCFAllocatorDefault,
kNilOptions);
if (!clockRef || !countRef)
break;
uint32_t clock = 0, count = 0;
CFNumberGetValue(clockRef, kCFNumberIntType, &clock);
CFNumberGetValue(countRef, kCFNumberIntType, &count);
CFRelease(clockRef);
CFRelease(countRef);
if (clock > 0 && count > 0)
refreshRate = clock / (double) count;
break;
}
IOObjectRelease(it);
return refreshRate;
}
//////////////////////////////////////////////////////////////////////////
////// GLFW internal API //////
//////////////////////////////////////////////////////////////////////////
@@ -328,13 +387,18 @@ 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);
free(name);
CGDisplayModeRef mode = CGDisplayCopyDisplayMode(displays[i]);
if (CGDisplayModeGetRefreshRate(mode) == 0.0)
monitor->ns.fallbackRefreshRate = getFallbackRefreshRate(displays[i]);
CGDisplayModeRelease(mode);
_glfwInputMonitor(monitor, GLFW_CONNECTED, _GLFW_INSERT_LAST);
}
@@ -354,14 +418,12 @@ 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;
CVDisplayLinkRef link;
CVDisplayLinkCreateWithCGDisplay(monitor->ns.displayID, &link);
CFArrayRef modes = CGDisplayCopyAllDisplayModes(monitor->ns.displayID, NULL);
const CFIndex count = CFArrayGetCount(modes);
CGDisplayModeRef native = NULL;
@@ -372,7 +434,8 @@ void _glfwSetVideoModeNS(_GLFWmonitor* monitor, const GLFWvidmode* desired)
if (!modeIsGood(dm))
continue;
const GLFWvidmode mode = vidmodeFromCGDisplayMode(dm, link);
const GLFWvidmode mode =
vidmodeFromCGDisplayMode(dm, monitor->ns.fallbackRefreshRate);
if (_glfwCompareVideoModes(best, &mode) == 0)
{
native = dm;
@@ -391,7 +454,6 @@ void _glfwSetVideoModeNS(_GLFWmonitor* monitor, const GLFWvidmode* desired)
}
CFRelease(modes);
CVDisplayLinkRelease(link);
}
// Restore the previously saved (original) video mode
@@ -454,13 +516,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;
}
@@ -468,9 +530,6 @@ GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count)
{
*count = 0;
CVDisplayLinkRef link;
CVDisplayLinkCreateWithCGDisplay(monitor->ns.displayID, &link);
CFArrayRef modes = CGDisplayCopyAllDisplayModes(monitor->ns.displayID, NULL);
const CFIndex found = CFArrayGetCount(modes);
GLFWvidmode* result = calloc(found, sizeof(GLFWvidmode));
@@ -481,7 +540,8 @@ GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count)
if (!modeIsGood(dm))
continue;
const GLFWvidmode mode = vidmodeFromCGDisplayMode(dm, link);
const GLFWvidmode mode =
vidmodeFromCGDisplayMode(dm, monitor->ns.fallbackRefreshRate);
for (CFIndex j = 0; j < *count; j++)
{
@@ -498,21 +558,14 @@ GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count)
}
CFRelease(modes);
CVDisplayLinkRelease(link);
return result;
}
void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode *mode)
{
CVDisplayLinkRef link;
CVDisplayLinkCreateWithCGDisplay(monitor->ns.displayID, &link);
CGDisplayModeRef native = CGDisplayCopyDisplayMode(monitor->ns.displayID);
*mode = vidmodeFromCGDisplayMode(native, link);
*mode = vidmodeFromCGDisplayMode(native, monitor->ns.fallbackRefreshRate);
CGDisplayModeRelease(native);
CVDisplayLinkRelease(link);
}
bool _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp)

34
glfw/cocoa_platform.h vendored
View File

@@ -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
@@ -62,12 +65,15 @@ typedef void* CVDisplayLinkRef;
#endif
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 VkFlags VkMacOSSurfaceCreateFlagsMVK;
typedef VkFlags VkMetalSurfaceCreateFlagsEXT;
typedef struct VkMacOSSurfaceCreateInfoMVK
{
VkStructureType sType;
@@ -76,7 +82,16 @@ typedef struct VkMacOSSurfaceCreateInfoMVK
const void* pView;
} VkMacOSSurfaceCreateInfoMVK;
typedef struct VkMetalSurfaceCreateInfoEXT
{
VkStructureType sType;
const void* pNext;
VkMetalSurfaceCreateFlagsEXT flags;
const void* pLayer;
} VkMetalSurfaceCreateInfoEXT;
typedef VkResult (APIENTRY *PFN_vkCreateMacOSSurfaceMVK)(VkInstance,const VkMacOSSurfaceCreateInfoMVK*,const VkAllocationCallbacks*,VkSurfaceKHR*);
typedef VkResult (APIENTRY *PFN_vkCreateMetalSurfaceEXT)(VkInstance,const VkMetalSurfaceCreateInfoEXT*,const VkAllocationCallbacks*,VkSurfaceKHR*);
#include "posix_thread.h"
#include "cocoa_joystick.h"
@@ -88,7 +103,7 @@ typedef VkResult (APIENTRY *PFN_vkCreateMacOSSurfaceMVK)(VkInstance,const VkMacO
#define _glfw_dlclose(handle) dlclose(handle)
#define _glfw_dlsym(handle, name) dlsym(handle, name)
#define _GLFW_EGL_NATIVE_WINDOW ((EGLNativeWindowType) window->ns.view)
#define _GLFW_EGL_NATIVE_WINDOW ((EGLNativeWindowType) window->ns.layer)
#define _GLFW_EGL_NATIVE_DISPLAY EGL_DEFAULT_DISPLAY
#define _GLFW_PLATFORM_WINDOW_STATE _GLFWwindowNS ns
@@ -144,7 +159,7 @@ typedef struct _GLFWDisplayLinkNS
{
CVDisplayLinkRef displayLink;
CGDirectDisplayID displayID;
double lastRenderFrameRequestedAt;
monotonic_t lastRenderFrameRequestedAt;
} _GLFWDisplayLinkNS;
// Cocoa-specific global data
@@ -153,6 +168,7 @@ typedef struct _GLFWlibraryNS
{
CGEventSourceRef eventSource;
id delegate;
bool finishedLaunching;
bool cursorHidden;
TISInputSourceRef inputSource;
IOHIDManagerRef hidManager;
@@ -160,11 +176,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
@@ -195,6 +212,7 @@ typedef struct _GLFWmonitorNS
CGDisplayModeRef previousMode;
uint32_t unitNumber;
id screen;
double fallbackRefreshRate;
} _GLFWmonitorNS;
@@ -215,14 +233,14 @@ typedef struct _GLFWtimerNS
} _GLFWtimerNS;
void _glfwInitTimerNS(void);
void _glfwPollMonitorsNS(void);
void _glfwSetVideoModeNS(_GLFWmonitor* monitor, const GLFWvidmode* desired);
void _glfwRestoreVideoModeNS(_GLFWmonitor* monitor);
float _glfwTransformYNS(float y);
void* _glfwLoadLocalVulkanLoaderNS(void);
void _glfwClearDisplayLinks(void);
void _glfwRestartDisplayLinks(void);
void _glfwDispatchTickCallback(void);

62
glfw/cocoa_time.c vendored
View File

@@ -1,62 +0,0 @@
//========================================================================
// GLFW 3.4 macOS - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2009-2016 Camilla Löwy <elmindreda@glfw.org>
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would
// be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source
// distribution.
//
//========================================================================
// It is fine to use C99 in this file because it will not be built with VS
//========================================================================
#include "internal.h"
#include <mach/mach_time.h>
//////////////////////////////////////////////////////////////////////////
////// GLFW internal API //////
//////////////////////////////////////////////////////////////////////////
// Initialise timer
//
void _glfwInitTimerNS(void)
{
mach_timebase_info_data_t info;
mach_timebase_info(&info);
_glfw.timer.ns.frequency = (info.denom * 1e9) / info.numer;
}
//////////////////////////////////////////////////////////////////////////
////// GLFW platform API //////
//////////////////////////////////////////////////////////////////////////
uint64_t _glfwPlatformGetTimerValue(void)
{
return mach_absolute_time();
}
uint64_t _glfwPlatformGetTimerFrequency(void)
{
return _glfw.timer.ns.frequency;
}

File diff suppressed because it is too large Load Diff

168
glfw/context.c vendored
View File

@@ -173,174 +173,6 @@ bool _glfwIsValidContextConfig(const _GLFWctxconfig* ctxconfig)
return true;
}
// Chooses the framebuffer config that best matches the desired one
//
const _GLFWfbconfig* _glfwChooseFBConfig(const _GLFWfbconfig* desired,
const _GLFWfbconfig* alternatives,
unsigned int count)
{
unsigned int i;
unsigned int missing, leastMissing = UINT_MAX;
unsigned int colorDiff, leastColorDiff = UINT_MAX;
unsigned int extraDiff, leastExtraDiff = UINT_MAX;
const _GLFWfbconfig* current;
const _GLFWfbconfig* closest = NULL;
for (i = 0; i < count; i++)
{
current = alternatives + i;
if (desired->stereo > 0 && current->stereo == 0)
{
// Stereo is a hard constraint
continue;
}
if (desired->doublebuffer != current->doublebuffer)
{
// Double buffering is a hard constraint
continue;
}
// Count number of missing buffers
{
missing = 0;
if (desired->alphaBits > 0 && current->alphaBits == 0)
missing++;
if (desired->depthBits > 0 && current->depthBits == 0)
missing++;
if (desired->stencilBits > 0 && current->stencilBits == 0)
missing++;
if (desired->auxBuffers > 0 &&
current->auxBuffers < desired->auxBuffers)
{
missing += desired->auxBuffers - current->auxBuffers;
}
if (desired->samples > 0 && current->samples == 0)
{
// Technically, several multisampling buffers could be
// involved, but that's a lower level implementation detail and
// not important to us here, so we count them as one
missing++;
}
if (desired->transparent != current->transparent)
missing++;
}
// These polynomials make many small channel size differences matter
// less than one large channel size difference
// Calculate color channel size difference value
{
colorDiff = 0;
if (desired->redBits != GLFW_DONT_CARE)
{
colorDiff += (desired->redBits - current->redBits) *
(desired->redBits - current->redBits);
}
if (desired->greenBits != GLFW_DONT_CARE)
{
colorDiff += (desired->greenBits - current->greenBits) *
(desired->greenBits - current->greenBits);
}
if (desired->blueBits != GLFW_DONT_CARE)
{
colorDiff += (desired->blueBits - current->blueBits) *
(desired->blueBits - current->blueBits);
}
}
// Calculate non-color channel size difference value
{
extraDiff = 0;
if (desired->alphaBits != GLFW_DONT_CARE)
{
extraDiff += (desired->alphaBits - current->alphaBits) *
(desired->alphaBits - current->alphaBits);
}
if (desired->depthBits != GLFW_DONT_CARE)
{
extraDiff += (desired->depthBits - current->depthBits) *
(desired->depthBits - current->depthBits);
}
if (desired->stencilBits != GLFW_DONT_CARE)
{
extraDiff += (desired->stencilBits - current->stencilBits) *
(desired->stencilBits - current->stencilBits);
}
if (desired->accumRedBits != GLFW_DONT_CARE)
{
extraDiff += (desired->accumRedBits - current->accumRedBits) *
(desired->accumRedBits - current->accumRedBits);
}
if (desired->accumGreenBits != GLFW_DONT_CARE)
{
extraDiff += (desired->accumGreenBits - current->accumGreenBits) *
(desired->accumGreenBits - current->accumGreenBits);
}
if (desired->accumBlueBits != GLFW_DONT_CARE)
{
extraDiff += (desired->accumBlueBits - current->accumBlueBits) *
(desired->accumBlueBits - current->accumBlueBits);
}
if (desired->accumAlphaBits != GLFW_DONT_CARE)
{
extraDiff += (desired->accumAlphaBits - current->accumAlphaBits) *
(desired->accumAlphaBits - current->accumAlphaBits);
}
if (desired->samples != GLFW_DONT_CARE)
{
extraDiff += (desired->samples - current->samples) *
(desired->samples - current->samples);
}
if (desired->sRGB && !current->sRGB)
extraDiff++;
}
// Figure out if the current one is better than the best one found so far
// Least number of missing buffers is the most important heuristic,
// then color buffer size match and lastly size match for other buffers
if (missing < leastMissing)
closest = current;
else if (missing == leastMissing)
{
if ((colorDiff < leastColorDiff) ||
(colorDiff == leastColorDiff && extraDiff < leastExtraDiff))
{
closest = current;
}
}
if (current == closest)
{
leastMissing = missing;
leastColorDiff = colorDiff;
leastExtraDiff = extraDiff;
}
}
return closest;
}
// Retrieves the attributes of the current context
//
bool _glfwRefreshContextAttribs(_GLFWwindow* window,

3
glfw/dbus_glfw.c vendored
View File

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

143
glfw/egl_context.c vendored
View File

@@ -76,6 +76,7 @@ static const char* getEGLErrorString(EGLint error)
}
}
#ifdef _GLFW_X11
// Returns the specified attribute of the specified EGLConfig
//
static int getEGLConfigAttrib(EGLConfig config, int attrib)
@@ -84,6 +85,7 @@ static int getEGLConfigAttrib(EGLConfig config, int attrib)
eglGetConfigAttrib(_glfw.egl.display, config, attrib, &value);
return value;
}
#endif
// Return the EGLConfig most closely matching the specified hints
//
@@ -91,101 +93,70 @@ static bool chooseEGLConfig(const _GLFWctxconfig* ctxconfig,
const _GLFWfbconfig* desired,
EGLConfig* result)
{
EGLConfig* nativeConfigs;
_GLFWfbconfig* usableConfigs;
const _GLFWfbconfig* closest;
int i, nativeCount, usableCount;
EGLConfig configs[512];
int i = 0, nativeCount = 0, ans_idx = 0;
EGLint attributes[64];
#define ATTR(k, v) { attributes[i++] = k; attributes[i++] = v; }
ATTR(EGL_COLOR_BUFFER_TYPE, EGL_RGB_BUFFER);
ATTR(EGL_SURFACE_TYPE, EGL_WINDOW_BIT);
if (ctxconfig->client == GLFW_OPENGL_ES_API) {
if (ctxconfig->major == 1) ATTR(EGL_RENDERABLE_TYPE, EGL_OPENGL_ES_BIT)
else ATTR(EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT);
}
else if (ctxconfig->client == GLFW_OPENGL_API) ATTR(EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT);
if (desired->samples > 0) ATTR(EGL_SAMPLES, desired->samples);
if (desired->depthBits > 0) ATTR(EGL_DEPTH_SIZE, desired->depthBits);
if (desired->stencilBits > 0) ATTR(EGL_STENCIL_SIZE, desired->stencilBits);
if (desired->redBits > 0) ATTR(EGL_RED_SIZE, desired->redBits);
if (desired->greenBits > 0) ATTR(EGL_GREEN_SIZE, desired->greenBits);
if (desired->blueBits > 0) ATTR(EGL_BLUE_SIZE, desired->blueBits);
if (desired->alphaBits > 0) ATTR(EGL_ALPHA_SIZE, desired->alphaBits);
ATTR(EGL_NONE, EGL_NONE);
#undef ATTR
if (!eglChooseConfig(_glfw.egl.display, attributes, configs, sizeof(configs)/sizeof(configs[0]), &nativeCount)) {
_glfwInputError(GLFW_API_UNAVAILABLE, "EGL: eglChooseConfig failed");
return false;
}
eglGetConfigs(_glfw.egl.display, NULL, 0, &nativeCount);
if (!nativeCount)
{
_glfwInputError(GLFW_API_UNAVAILABLE, "EGL: No EGLConfigs returned");
return false;
}
nativeConfigs = calloc(nativeCount, sizeof(EGLConfig));
eglGetConfigs(_glfw.egl.display, nativeConfigs, nativeCount, &nativeCount);
usableConfigs = calloc(nativeCount, sizeof(_GLFWfbconfig));
usableCount = 0;
for (i = 0; i < nativeCount; i++)
{
const EGLConfig n = nativeConfigs[i];
_GLFWfbconfig* u = usableConfigs + usableCount;
// Only consider RGB(A) EGLConfigs
if (getEGLConfigAttrib(n, EGL_COLOR_BUFFER_TYPE) != EGL_RGB_BUFFER)
continue;
// Only consider window EGLConfigs
if (!(getEGLConfigAttrib(n, EGL_SURFACE_TYPE) & EGL_WINDOW_BIT))
continue;
#if defined(_GLFW_X11)
XVisualInfo vi = {0};
// Only consider EGLConfigs with associated Visuals
vi.visualid = getEGLConfigAttrib(n, EGL_NATIVE_VISUAL_ID);
if (!vi.visualid)
continue;
if (desired->transparent)
{
int count;
XVisualInfo* vis = XGetVisualInfo(_glfw.x11.display,
VisualIDMask, &vi,
&count);
if (vis)
const EGLConfig n = configs[i];
XVisualInfo vi = {0};
// Only consider EGLConfigs with associated Visuals
vi.visualid = getEGLConfigAttrib(n, EGL_NATIVE_VISUAL_ID);
if (!vi.visualid)
continue;
if (desired->transparent)
{
u->transparent = _glfwIsVisualTransparentX11(vis[0].visual);
XFree(vis);
int count;
XVisualInfo* vis =
XGetVisualInfo(_glfw.x11.display, VisualIDMask, &vi, &count);
if (vis)
{
bool transparent = _glfwIsVisualTransparentX11(vis[0].visual);
XFree(vis);
if (!transparent) continue;
}
}
}
#endif // _GLFW_X11
if (ctxconfig->client == GLFW_OPENGL_ES_API)
{
if (ctxconfig->major == 1)
{
if (!(getEGLConfigAttrib(n, EGL_RENDERABLE_TYPE) & EGL_OPENGL_ES_BIT))
continue;
}
else
{
if (!(getEGLConfigAttrib(n, EGL_RENDERABLE_TYPE) & EGL_OPENGL_ES2_BIT))
continue;
}
}
else if (ctxconfig->client == GLFW_OPENGL_API)
{
if (!(getEGLConfigAttrib(n, EGL_RENDERABLE_TYPE) & EGL_OPENGL_BIT))
continue;
}
u->redBits = getEGLConfigAttrib(n, EGL_RED_SIZE);
u->greenBits = getEGLConfigAttrib(n, EGL_GREEN_SIZE);
u->blueBits = getEGLConfigAttrib(n, EGL_BLUE_SIZE);
u->alphaBits = getEGLConfigAttrib(n, EGL_ALPHA_SIZE);
u->depthBits = getEGLConfigAttrib(n, EGL_DEPTH_SIZE);
u->stencilBits = getEGLConfigAttrib(n, EGL_STENCIL_SIZE);
u->samples = getEGLConfigAttrib(n, EGL_SAMPLES);
u->doublebuffer = true;
u->handle = (uintptr_t) n;
usableCount++;
ans_idx = i;
break;
}
closest = _glfwChooseFBConfig(desired, usableConfigs, usableCount);
if (closest)
*result = (EGLConfig) closest->handle;
free(nativeConfigs);
free(usableConfigs);
return closest != NULL;
*result = configs[ans_idx];
return true;
}
static void makeContextCurrentEGL(_GLFWwindow* window)
@@ -339,6 +310,7 @@ bool _glfwInitEGL(void)
glfw_dlsym(_glfw.egl.GetConfigAttrib, _glfw.egl.handle, "eglGetConfigAttrib");
glfw_dlsym(_glfw.egl.GetConfigs, _glfw.egl.handle, "eglGetConfigs");
glfw_dlsym(_glfw.egl.ChooseConfig, _glfw.egl.handle, "eglChooseConfig");
glfw_dlsym(_glfw.egl.GetDisplay, _glfw.egl.handle, "eglGetDisplay");
glfw_dlsym(_glfw.egl.GetError, _glfw.egl.handle, "eglGetError");
glfw_dlsym(_glfw.egl.Initialize, _glfw.egl.handle, "eglInitialize");
@@ -356,6 +328,7 @@ bool _glfwInitEGL(void)
if (!_glfw.egl.GetConfigAttrib ||
!_glfw.egl.GetConfigs ||
!_glfw.egl.ChooseConfig ||
!_glfw.egl.GetDisplay ||
!_glfw.egl.GetError ||
!_glfw.egl.Initialize ||
@@ -571,18 +544,16 @@ bool _glfwCreateContextEGL(_GLFWwindow* window,
}
// Set up attributes for surface creation
index = 0;
if (fbconfig->sRGB)
{
int index = 0;
if (fbconfig->sRGB)
{
if (_glfw.egl.KHR_gl_colorspace)
setAttrib(EGL_GL_COLORSPACE_KHR, EGL_GL_COLORSPACE_SRGB_KHR);
}
setAttrib(EGL_NONE, EGL_NONE);
if (_glfw.egl.KHR_gl_colorspace)
setAttrib(EGL_GL_COLORSPACE_KHR, EGL_GL_COLORSPACE_SRGB_KHR);
}
setAttrib(EGL_NONE, EGL_NONE);
window->context.egl.surface =
eglCreateWindowSurface(_glfw.egl.display,
config,

3
glfw/egl_context.h vendored
View File

@@ -120,6 +120,7 @@ typedef void* EGLSurface;
// EGL function pointer typedefs
typedef EGLBoolean (EGLAPIENTRY * PFN_eglGetConfigAttrib)(EGLDisplay,EGLConfig,EGLint,EGLint*);
typedef EGLBoolean (EGLAPIENTRY * PFN_eglGetConfigs)(EGLDisplay,EGLConfig*,EGLint,EGLint*);
typedef EGLBoolean (EGLAPIENTRY * PFN_eglChooseConfig)(EGLDisplay,EGLint const*,EGLConfig*,EGLint,EGLint*);
typedef EGLDisplay (EGLAPIENTRY * PFN_eglGetDisplay)(EGLNativeDisplayType);
typedef EGLint (EGLAPIENTRY * PFN_eglGetError)(void);
typedef EGLBoolean (EGLAPIENTRY * PFN_eglInitialize)(EGLDisplay,EGLint*,EGLint*);
@@ -136,6 +137,7 @@ typedef const char* (EGLAPIENTRY * PFN_eglQueryString)(EGLDisplay,EGLint);
typedef GLFWglproc (EGLAPIENTRY * PFN_eglGetProcAddress)(const char*);
#define eglGetConfigAttrib _glfw.egl.GetConfigAttrib
#define eglGetConfigs _glfw.egl.GetConfigs
#define eglChooseConfig _glfw.egl.ChooseConfig
#define eglGetDisplay _glfw.egl.GetDisplay
#define eglGetError _glfw.egl.GetError
#define eglInitialize _glfw.egl.Initialize
@@ -185,6 +187,7 @@ typedef struct _GLFWlibraryEGL
PFN_eglGetConfigAttrib GetConfigAttrib;
PFN_eglGetConfigs GetConfigs;
PFN_eglChooseConfig ChooseConfig;
PFN_eglGetDisplay GetDisplay;
PFN_eglGetError GetError;
PFN_eglInitialize Initialize;

View File

@@ -6,20 +6,57 @@ import json
import os
import re
import sys
from typing import Callable, Dict, List, Optional, Tuple
_plat = sys.platform.lower()
is_linux = 'linux' in _plat
base = os.path.dirname(os.path.abspath(__file__))
def wayland_protocol_file_name(base, ext='c'):
class Env:
cc: str = ''
cppflags: List[str] = []
cflags: List[str] = []
ldflags: List[str] = []
library_paths: Dict[str, List[str]] = {}
ldpaths: List[str] = []
ccver: Tuple[int, int]
# glfw stuff
all_headers: List[str] = []
sources: List[str] = []
wayland_packagedir: str = ''
wayland_scanner: str = ''
wayland_scanner_code: str = ''
wayland_protocols: Tuple[str, ...] = ()
def __init__(
self, cc: str = '', cppflags: List[str] = [], cflags: List[str] = [], ldflags: List[str] = [],
library_paths: Dict[str, List[str]] = {}, ldpaths: Optional[List[str]] = None, ccver: Tuple[int, int] = (0, 0)
):
self.cc, self.cppflags, self.cflags, self.ldflags, self.library_paths = cc, cppflags, cflags, ldflags, library_paths
self.ldpaths, self.ccver = [] if ldpaths is None else ldpaths, ccver
def copy(self) -> 'Env':
ans = Env(self.cc, list(self.cppflags), list(self.cflags), list(self.ldflags), dict(self.library_paths), list(self.ldpaths), self.ccver)
ans.all_headers = list(self.all_headers)
ans.sources = list(self.sources)
ans.wayland_packagedir = self.wayland_packagedir
ans.wayland_scanner = self.wayland_scanner
ans.wayland_scanner_code = self.wayland_scanner_code
ans.wayland_protocols = self.wayland_protocols
return ans
def wayland_protocol_file_name(base: str, ext: str = 'c') -> str:
base = os.path.basename(base).rpartition('.')[0]
return 'wayland-{}-client-protocol.{}'.format(base, ext)
def init_env(env, pkg_config, at_least_version, test_compile, module='x11'):
def init_env(env: Env, pkg_config: Callable, at_least_version: Callable, test_compile: Callable, module: str = 'x11') -> Env:
ans = env.copy()
ans.cflags.append('-fpic')
ans.cflags.append('-fPIC')
ans.cppflags.append('-D_GLFW_' + module.upper())
ans.cppflags.append('-D_GLFW_BUILD_DLL')
@@ -46,8 +83,8 @@ def init_env(env, pkg_config, at_least_version, test_compile, module='x11'):
elif module == 'cocoa':
ans.cppflags.append('-DGL_SILENCE_DEPRECATION')
for f in 'Cocoa IOKit CoreFoundation CoreVideo'.split():
ans.ldpaths.extend(('-framework', f))
for f_ in 'Cocoa IOKit CoreFoundation CoreVideo'.split():
ans.ldpaths.extend(('-framework', f_))
elif module == 'wayland':
at_least_version('wayland-protocols', *sinfo['wayland_protocols'])
@@ -59,7 +96,7 @@ def init_env(env, pkg_config, at_least_version, test_compile, module='x11'):
for p in ans.wayland_protocols:
ans.sources.append(wayland_protocol_file_name(p))
ans.all_headers.append(wayland_protocol_file_name(p, 'h'))
for dep in 'wayland-egl wayland-client wayland-cursor xkbcommon dbus-1'.split():
for dep in 'wayland-client wayland-cursor xkbcommon dbus-1'.split():
ans.cflags.extend(pkg_config(dep, '--cflags-only-I'))
ans.ldpaths.extend(pkg_config(dep, '--libs'))
has_memfd_create = test_compile(env.cc, '-Werror', src='''#define _GNU_SOURCE
@@ -74,7 +111,7 @@ def init_env(env, pkg_config, at_least_version, test_compile, module='x11'):
return ans
def build_wayland_protocols(env, Command, parallel_run, emphasis, newer, dest_dir):
def build_wayland_protocols(env: Env, Command: Callable, parallel_run: Callable, emphasis: Callable, newer: Callable, dest_dir: str) -> None:
items = []
for protocol in env.wayland_protocols:
src = os.path.join(env.wayland_packagedir, protocol)
@@ -95,7 +132,7 @@ def build_wayland_protocols(env, Command, parallel_run, emphasis, newer, dest_di
class Arg:
def __init__(self, decl):
def __init__(self, decl: str):
self.type, self.name = decl.rsplit(' ', 1)
self.type = self.type.strip()
self.name = self.name.strip()
@@ -103,13 +140,13 @@ class Arg:
self.name = self.name[1:]
self.type = self.type + '*'
def __repr__(self):
def __repr__(self) -> str:
return 'Arg({}, {})'.format(self.type, self.name)
class Function:
def __init__(self, declaration, check_fail=True):
def __init__(self, declaration: str, check_fail: bool = True):
self.check_fail = check_fail
m = re.match(
r'(.+?)\s+(glfw[A-Z][a-zA-Z0-9]+)[(](.+)[)]$', declaration
@@ -128,14 +165,14 @@ class Function:
if not self.args:
self.args = [Arg('void v')]
def declaration(self):
return 'typedef {restype} (*{name}_func)({args});\n{name}_func {name}_impl;\n#define {name} {name}_impl'.format(
def declaration(self) -> str:
return 'typedef {restype} (*{name}_func)({args});\nGFW_EXTERN {name}_func {name}_impl;\n#define {name} {name}_impl'.format(
restype=self.restype,
name=self.name,
args=', '.join(a.type for a in self.args)
)
def load(self):
def load(self) -> str:
ans = '*(void **) (&{name}_impl) = dlsym(handle, "{name}");'.format(
name=self.name
)
@@ -146,7 +183,7 @@ class Function:
return ans
def generate_wrappers(glfw_header):
def generate_wrappers(glfw_header: str) -> None:
with open(glfw_header) as f:
src = f.read()
functions = []
@@ -165,13 +202,14 @@ def generate_wrappers(glfw_header):
GLFWcocoatextinputfilterfun glfwSetCocoaTextInputFilter(GLFWwindow* window, GLFWcocoatextinputfilterfun callback)
GLFWcocoatogglefullscreenfun glfwSetCocoaToggleFullscreenIntercept(GLFWwindow *window, GLFWcocoatogglefullscreenfun callback)
GLFWapplicationshouldhandlereopenfun glfwSetApplicationShouldHandleReopen(GLFWapplicationshouldhandlereopenfun callback)
void glfwGetCocoaKeyEquivalent(int glfw_key, int glfw_mods, void* cocoa_key, void* cocoa_mods)
GLFWapplicationwillfinishlaunchingfun glfwSetApplicationWillFinishLaunching(GLFWapplicationwillfinishlaunchingfun callback)
void glfwGetCocoaKeyEquivalent(int glfw_key, int glfw_mods, char* cocoa_key, size_t key_sz, int* 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)
@@ -185,15 +223,26 @@ 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"
#ifndef GFW_EXTERN
#define GFW_EXTERN extern
#endif
{}
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*);
@@ -206,6 +255,7 @@ const char* load_glfw(const char* path);
f.write(header)
code = '''
#define GFW_EXTERN
#include "data-types.h"
#include "glfw-wrapper.h"
#include <dlfcn.h>
@@ -235,7 +285,7 @@ unload_glfw(void) {
f.write(code)
def main():
def main() -> None:
os.chdir(os.path.dirname(os.path.abspath(__file__)))
generate_wrappers('glfw3.h')

927
glfw/glfw3.h vendored

File diff suppressed because it is too large Load Diff

111
glfw/glx_context.c vendored
View File

@@ -47,99 +47,87 @@ static int getGLXFBConfigAttrib(GLXFBConfig fbconfig, int attrib)
return value;
}
static GLXFBConfig*
choose_fb_config(const _GLFWfbconfig* desired, bool trust_window_bit, int *nelements) {
int attrib_list[64];
int pos = 0;
#define ATTR(x, y) { attrib_list[pos++] = x; attrib_list[pos++] = y; }
ATTR(GLX_DOUBLEBUFFER, desired->doublebuffer ? True : False);
if (desired->stereo > 0) ATTR(GLX_STEREO, desired->stereo ? True : False);
if (desired->auxBuffers > 0) ATTR(GLX_AUX_BUFFERS, desired->auxBuffers);
if (_glfw.glx.ARB_multisample && desired->samples > 0) ATTR(GLX_SAMPLES, desired->samples);
if (desired->depthBits != GLFW_DONT_CARE) ATTR(GLX_DEPTH_SIZE, desired->depthBits);
if (desired->stencilBits != GLFW_DONT_CARE) ATTR(GLX_STENCIL_SIZE, desired->stencilBits);
if (desired->redBits != GLFW_DONT_CARE) ATTR(GLX_RED_SIZE, desired->redBits);
if (desired->greenBits != GLFW_DONT_CARE) ATTR(GLX_GREEN_SIZE, desired->greenBits);
if (desired->blueBits != GLFW_DONT_CARE) ATTR(GLX_BLUE_SIZE, desired->blueBits);
if (desired->alphaBits != GLFW_DONT_CARE) ATTR(GLX_ALPHA_SIZE, desired->alphaBits);
if (desired->accumRedBits != GLFW_DONT_CARE) ATTR(GLX_ACCUM_RED_SIZE, desired->accumRedBits);
if (desired->accumGreenBits != GLFW_DONT_CARE) ATTR(GLX_ACCUM_GREEN_SIZE, desired->accumGreenBits);
if (desired->accumBlueBits != GLFW_DONT_CARE) ATTR(GLX_ACCUM_BLUE_SIZE, desired->accumBlueBits);
if (desired->accumAlphaBits != GLFW_DONT_CARE) ATTR(GLX_ACCUM_ALPHA_SIZE, desired->accumAlphaBits);
if (!trust_window_bit) ATTR(GLX_DRAWABLE_TYPE, 0);
ATTR(None, None);
return glXChooseFBConfig(_glfw.x11.display, _glfw.x11.screen, attrib_list, nelements);
#undef ATTR
}
// Return the GLXFBConfig most closely matching the specified hints
//
static bool chooseGLXFBConfig(const _GLFWfbconfig* desired,
GLXFBConfig* result)
{
GLXFBConfig* nativeConfigs;
_GLFWfbconfig* usableConfigs;
const _GLFWfbconfig* closest;
int i, nativeCount, usableCount;
int i, nativeCount, ans_idx = 0;
const char* vendor;
bool trustWindowBit = true;
static _GLFWfbconfig prev_desired = {0};
static GLXFBConfig prev_result = 0;
if (prev_result != 0 && memcmp(&prev_desired, desired, sizeof(_GLFWfbconfig)) == 0) {
*result = prev_result;
return true;
}
prev_desired = *desired;
// HACK: This is a (hopefully temporary) workaround for Chromium
// (VirtualBox GL) not setting the window bit on any GLXFBConfigs
vendor = glXGetClientString(_glfw.x11.display, GLX_VENDOR);
if (vendor && strcmp(vendor, "Chromium") == 0)
trustWindowBit = false;
nativeConfigs =
glXGetFBConfigs(_glfw.x11.display, _glfw.x11.screen, &nativeCount);
nativeConfigs = choose_fb_config(desired, trustWindowBit, &nativeCount);
if (!nativeConfigs || !nativeCount)
{
_glfwInputError(GLFW_API_UNAVAILABLE, "GLX: No GLXFBConfigs returned");
return false;
}
usableConfigs = calloc(nativeCount, sizeof(_GLFWfbconfig));
usableCount = 0;
for (i = 0; i < nativeCount; i++)
{
const GLXFBConfig n = nativeConfigs[i];
_GLFWfbconfig* u = usableConfigs + usableCount;
// Only consider RGBA GLXFBConfigs
if (!(getGLXFBConfigAttrib(n, GLX_RENDER_TYPE) & GLX_RGBA_BIT))
continue;
// Only consider window GLXFBConfigs
if (!(getGLXFBConfigAttrib(n, GLX_DRAWABLE_TYPE) & GLX_WINDOW_BIT))
{
if (trustWindowBit)
continue;
}
if (desired->transparent)
{
bool transparency_matches = true, srgb_matches = true;
if (desired->transparent) {
transparency_matches = false;
XVisualInfo* vi = glXGetVisualFromFBConfig(_glfw.x11.display, n);
if (vi)
{
u->transparent = _glfwIsVisualTransparentX11(vi->visual);
XFree(vi);
}
if (vi && _glfwIsVisualTransparentX11(vi->visual)) transparency_matches = true;
}
u->redBits = getGLXFBConfigAttrib(n, GLX_RED_SIZE);
u->greenBits = getGLXFBConfigAttrib(n, GLX_GREEN_SIZE);
u->blueBits = getGLXFBConfigAttrib(n, GLX_BLUE_SIZE);
if (desired->sRGB && (_glfw.glx.ARB_framebuffer_sRGB || _glfw.glx.EXT_framebuffer_sRGB)) {
srgb_matches = getGLXFBConfigAttrib(n, GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB) ? true : false;
}
u->alphaBits = getGLXFBConfigAttrib(n, GLX_ALPHA_SIZE);
u->depthBits = getGLXFBConfigAttrib(n, GLX_DEPTH_SIZE);
u->stencilBits = getGLXFBConfigAttrib(n, GLX_STENCIL_SIZE);
if (transparency_matches && srgb_matches) {
ans_idx = i; break;
}
u->accumRedBits = getGLXFBConfigAttrib(n, GLX_ACCUM_RED_SIZE);
u->accumGreenBits = getGLXFBConfigAttrib(n, GLX_ACCUM_GREEN_SIZE);
u->accumBlueBits = getGLXFBConfigAttrib(n, GLX_ACCUM_BLUE_SIZE);
u->accumAlphaBits = getGLXFBConfigAttrib(n, GLX_ACCUM_ALPHA_SIZE);
u->auxBuffers = getGLXFBConfigAttrib(n, GLX_AUX_BUFFERS);
if (getGLXFBConfigAttrib(n, GLX_STEREO))
u->stereo = true;
if (getGLXFBConfigAttrib(n, GLX_DOUBLEBUFFER))
u->doublebuffer = true;
if (_glfw.glx.ARB_multisample)
u->samples = getGLXFBConfigAttrib(n, GLX_SAMPLES);
if (_glfw.glx.ARB_framebuffer_sRGB || _glfw.glx.EXT_framebuffer_sRGB)
u->sRGB = getGLXFBConfigAttrib(n, GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB);
u->handle = (uintptr_t) n;
usableCount++;
}
closest = _glfwChooseFBConfig(desired, usableConfigs, usableCount);
if (closest)
*result = (GLXFBConfig) closest->handle;
*result = nativeConfigs[ans_idx];
prev_result = nativeConfigs[ans_idx];
XFree(nativeConfigs);
free(usableConfigs);
return closest != NULL;
return true;
}
// Create the OpenGL context using legacy API
@@ -287,6 +275,7 @@ bool _glfwInitGLX(void)
glfw_dlsym(_glfw.glx.GetFBConfigs, _glfw.glx.handle, "glXGetFBConfigs");
glfw_dlsym(_glfw.glx.GetFBConfigAttrib, _glfw.glx.handle, "glXGetFBConfigAttrib");
glfw_dlsym(_glfw.glx.ChooseFBConfig, _glfw.glx.handle, "glXChooseFBConfig");
glfw_dlsym(_glfw.glx.GetClientString, _glfw.glx.handle, "glXGetClientString");
glfw_dlsym(_glfw.glx.QueryExtension, _glfw.glx.handle, "glXQueryExtension");
glfw_dlsym(_glfw.glx.QueryVersion, _glfw.glx.handle, "glXQueryVersion");

3
glfw/glx_context.h vendored
View File

@@ -73,6 +73,7 @@ typedef struct __GLXcontext* GLXContext;
typedef void (*__GLXextproc)(void);
typedef int (*PFNGLXGETFBCONFIGATTRIBPROC)(Display*,GLXFBConfig,int,int*);
typedef GLXFBConfig* (*PFNGLXCHOOSEFBCONFIGPROC)(Display*,int,const int*,int*);
typedef const char* (*PFNGLXGETCLIENTSTRINGPROC)(Display*,int);
typedef Bool (*PFNGLXQUERYEXTENSIONPROC)(Display*,int*,int*);
typedef Bool (*PFNGLXQUERYVERSIONPROC)(Display*,int*,int*);
@@ -95,6 +96,7 @@ typedef GLXContext (*PFNGLXCREATECONTEXTATTRIBSARBPROC)(Display*,GLXFBConfig,GLX
// libGL.so function pointer typedefs
#define glXGetFBConfigs _glfw.glx.GetFBConfigs
#define glXGetFBConfigAttrib _glfw.glx.GetFBConfigAttrib
#define glXChooseFBConfig _glfw.glx.ChooseFBConfig
#define glXGetClientString _glfw.glx.GetClientString
#define glXQueryExtension _glfw.glx.QueryExtension
#define glXQueryVersion _glfw.glx.QueryVersion
@@ -134,6 +136,7 @@ typedef struct _GLFWlibraryGLX
// GLX 1.3 functions
PFNGLXGETFBCONFIGSPROC GetFBConfigs;
PFNGLXGETFBCONFIGATTRIBPROC GetFBConfigAttrib;
PFNGLXCHOOSEFBCONFIGPROC ChooseFBConfig;
PFNGLXGETCLIENTSTRINGPROC GetClientString;
PFNGLXQUERYEXTENSIONPROC QueryExtension;
PFNGLXQUERYVERSIONPROC QueryVersion;

29
glfw/ibus_glfw.c vendored
View File

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

15
glfw/ibus_glfw.h vendored
View File

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

21
glfw/init.c vendored
View File

@@ -168,6 +168,10 @@ void _glfwInputError(int code, const char* format, ...)
strcpy(description, "The requested format is unavailable");
else if (code == GLFW_NO_WINDOW_CONTEXT)
strcpy(description, "The specified window has no context");
else if (code == GLFW_FEATURE_UNAVAILABLE)
strcpy(description, "The requested feature cannot be implemented for this platform");
else if (code == GLFW_FEATURE_UNIMPLEMENTED)
strcpy(description, "The requested feature has not yet been implemented for this platform");
else
strcpy(description, "ERROR: UNKNOWN GLFW ERROR");
}
@@ -201,7 +205,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 +218,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;
@@ -239,7 +244,6 @@ GLFWAPI int glfwInit(void)
_glfwPlatformSetTls(&_glfw.errorSlot, &_glfwMainThreadError);
_glfw.initialized = true;
_glfw.timer.offset = _glfwPlatformGetTimerValue();
glfwDefaultWindowHints();
@@ -350,16 +354,23 @@ 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);
}
GLFWAPI void glfwRemoveTimer(unsigned long long timer_id) {
_glfwPlatformRemoveTimer(timer_id);
}
GLFWAPI GLFWapplicationclosefun glfwSetApplicationCloseCallback(GLFWapplicationclosefun cbfun)
{
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
_GLFW_SWAP_POINTERS(_glfw.callbacks.application_close, cbfun);
return cbfun;
}

121
glfw/input.c vendored
View File

@@ -28,6 +28,7 @@
//========================================================================
#include "internal.h"
#include "../kitty/monotonic.h"
#include <assert.h>
#include <float.h>
@@ -256,42 +257,53 @@ 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);
}
}
// Notifies shared code of a scroll event
//
void _glfwInputScroll(_GLFWwindow* window, double xoffset, double yoffset, int flags)
void _glfwInputScroll(_GLFWwindow* window, double xoffset, double yoffset, int flags, int mods)
{
if (window->callbacks.scroll)
window->callbacks.scroll((GLFWwindow*) window, xoffset, yoffset, flags);
window->callbacks.scroll((GLFWwindow*) window, xoffset, yoffset, flags, mods);
}
// Notifies shared code of a mouse button click event
@@ -338,10 +350,11 @@ void _glfwInputCursorEnter(_GLFWwindow* window, bool entered)
// Notifies shared code of files or directories dropped on a window
//
void _glfwInputDrop(_GLFWwindow* window, int count, const char** paths)
int _glfwInputDrop(_GLFWwindow* window, const char *mime, const char *text, size_t sz)
{
if (window->callbacks.drop)
window->callbacks.drop((GLFWwindow*) window, count, paths);
return window->callbacks.drop((GLFWwindow*) window, mime, text, sz);
return 0;
}
// Notifies shared code of a joystick connection or disconnection
@@ -498,6 +511,7 @@ const char* _glfwGetKeyName(int key)
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_CIRCUMFLEX: return "CIRCUMFLEX";
case GLFW_KEY_UNDERSCORE: return "UNDERSCORE";
case GLFW_KEY_GRAVE_ACCENT: return "GRAVE_ACCENT";
case GLFW_KEY_WORLD_1: return "WORLD_1";
@@ -661,6 +675,8 @@ GLFWAPI int glfwGetInputMode(GLFWwindow* handle, int mode)
return window->stickyMouseButtons;
case GLFW_LOCK_KEY_MODS:
return window->lockKeyMods;
case GLFW_RAW_MOUSE_MOTION:
return window->rawMouseMotion;
}
_glfwInputError(GLFW_INVALID_ENUM, "Invalid input mode 0x%08X", mode);
@@ -740,11 +756,33 @@ GLFWAPI void glfwSetInputMode(GLFWwindow* handle, int mode, int value)
{
window->lockKeyMods = value ? true : false;
}
else if (mode == GLFW_RAW_MOUSE_MOTION)
{
if (!_glfwPlatformRawMouseMotionSupported())
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Raw mouse motion is not supported on this system");
return;
}
value = value ? true : false;
if (window->rawMouseMotion == value)
return;
window->rawMouseMotion = value;
_glfwPlatformSetRawMouseMotion(window, value);
}
else
_glfwInputError(GLFW_INVALID_ENUM, "Invalid input mode 0x%08X", mode);
}
GLFWAPI const char* glfwGetKeyName(int key, int scancode)
GLFWAPI int glfwRawMouseMotionSupported(void)
{
_GLFW_REQUIRE_INIT_OR_RETURN(false);
return _glfwPlatformRawMouseMotionSupported();
}
GLFWAPI const char* glfwGetKeyName(int key, int native_key)
{
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
@@ -757,13 +795,13 @@ GLFWAPI const char* glfwGetKeyName(int key, int scancode)
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);
@@ -773,7 +811,7 @@ GLFWAPI int glfwGetKeyScancode(int key)
return GLFW_RELEASE;
}
return _glfwPlatformGetKeyScancode(key);
return _glfwPlatformGetNativeKeyForKey(key);
}
GLFWAPI int glfwGetKey(GLFWwindow* handle, int key)
@@ -1398,8 +1436,18 @@ GLFWAPI int glfwGetGamepadState(int jid, GLFWgamepadstate* state)
if (e->type == _GLFW_JOYSTICK_AXIS)
{
const float value = js->axes[e->index] * e->axisScale + e->axisOffset;
if (value > 0.f)
state->buttons[i] = GLFW_PRESS;
// HACK: This should be baked into the value transform
// TODO: Bake into transform when implementing output modifiers
if (e->axisOffset < 0 || (e->axisOffset == 0 && e->axisScale > 0))
{
if (value >= 0.f)
state->buttons[i] = GLFW_PRESS;
}
else
{
if (value <= 0.f)
state->buttons[i] = GLFW_PRESS;
}
}
else if (e->type == _GLFW_JOYSTICK_HATBIT)
{
@@ -1466,35 +1514,8 @@ GLFWAPI const char* glfwGetPrimarySelectionString(GLFWwindow* handle UNUSED)
}
#endif
GLFWAPI double glfwGetTime(void)
{
_GLFW_REQUIRE_INIT_OR_RETURN(0.0);
return (double) (_glfwPlatformGetTimerValue() - _glfw.timer.offset) /
_glfwPlatformGetTimerFrequency();
}
GLFWAPI void glfwSetTime(double time)
{
_GLFW_REQUIRE_INIT();
if (time != time || time < 0.0 || time > 18446744073.0)
{
_glfwInputError(GLFW_INVALID_VALUE, "Invalid time %f", time);
return;
}
_glfw.timer.offset = _glfwPlatformGetTimerValue() -
(uint64_t) (time * _glfwPlatformGetTimerFrequency());
}
GLFWAPI uint64_t glfwGetTimerValue(void)
GLFWAPI monotonic_t glfwGetTime(void)
{
_GLFW_REQUIRE_INIT_OR_RETURN(0);
return _glfwPlatformGetTimerValue();
}
GLFWAPI uint64_t glfwGetTimerFrequency(void)
{
_GLFW_REQUIRE_INIT_OR_RETURN(0);
return _glfwPlatformGetTimerFrequency();
return monotonic();
}

42
glfw/internal.h vendored
View File

@@ -27,6 +27,8 @@
#pragma once
#include "../kitty/monotonic.h"
#if defined(_GLFW_USE_CONFIG_H)
#include "glfw_config.h"
#endif
@@ -130,6 +132,7 @@ typedef enum VkStructureType
VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR = 1000006000,
VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR = 1000009000,
VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK = 1000123000,
VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT = 1000217000,
VK_STRUCTURE_TYPE_MAX_ENUM = 0x7FFFFFFF
} VkStructureType;
@@ -416,6 +419,7 @@ struct _GLFWwindow
int minwidth, minheight;
int maxwidth, maxheight;
int numer, denom;
int widthincr, heightincr;
bool stickyKeys;
bool stickyMouseButtons;
@@ -425,6 +429,7 @@ struct _GLFWwindow
char keys[GLFW_KEY_LAST + 1];
// Virtual cursor position when cursor is disabled
double virtualCursorPosX, virtualCursorPosY;
bool rawMouseMotion;
_GLFWcontext context;
@@ -572,12 +577,6 @@ struct _GLFWlibrary
_GLFWtls contextSlot;
_GLFWmutex errorLock;
struct {
uint64_t offset;
// This is defined in the platform's time.h
_GLFW_PLATFORM_LIBRARY_TIMER_STATE;
} timer;
struct {
bool available;
void* handle;
@@ -591,6 +590,7 @@ struct _GLFWlibrary
bool KHR_win32_surface;
#elif defined(_GLFW_COCOA)
bool MVK_macos_surface;
bool EXT_metal_surface;
#elif defined(_GLFW_X11)
bool KHR_xlib_surface;
bool KHR_xcb_surface;
@@ -602,8 +602,10 @@ struct _GLFWlibrary
struct {
GLFWmonitorfun monitor;
GLFWjoystickfun joystick;
GLFWapplicationclosefun application_close;
} callbacks;
// This is defined in the window API's platform.h
_GLFW_PLATFORM_LIBRARY_WINDOW_STATE;
// This is defined in the context API's context.h
@@ -632,14 +634,16 @@ const char* _glfwPlatformGetVersionString(void);
void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos);
void _glfwPlatformSetCursorPos(_GLFWwindow* window, double xpos, double ypos);
void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode);
void _glfwPlatformSetRawMouseMotion(_GLFWwindow *window, bool enabled);
bool _glfwPlatformRawMouseMotionSupported(void);
int _glfwPlatformCreateCursor(_GLFWcursor* cursor,
const GLFWimage* image, int xhot, int yhot, int count);
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);
@@ -661,9 +665,6 @@ const char* _glfwPlatformGetPrimarySelectionString(void);
int _glfwPlatformPollJoystick(_GLFWjoystick* js, int mode);
void _glfwPlatformUpdateGamepadGUID(char* guid);
uint64_t _glfwPlatformGetTimerValue(void);
uint64_t _glfwPlatformGetTimerFrequency(void);
int _glfwPlatformCreateWindow(_GLFWwindow* window,
const _GLFWwndconfig* wndconfig,
const _GLFWctxconfig* ctxconfig,
@@ -680,6 +681,7 @@ void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window,
int minwidth, int minheight,
int maxwidth, int maxheight);
void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window, int numer, int denom);
void _glfwPlatformSetWindowSizeIncrements(_GLFWwindow* window, int widthincr, int heightincr);
void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* height);
void _glfwInputLiveResize(_GLFWwindow* window, bool started);
void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window,
@@ -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,12 +758,13 @@ 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 _glfwInputScroll(_GLFWwindow* window, double xoffset, double yoffset, int flags);
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, int mods);
void _glfwInputMouseClick(_GLFWwindow* window, int button, int action, int mods);
void _glfwInputCursorPos(_GLFWwindow* window, double xpos, double ypos);
void _glfwInputCursorEnter(_GLFWwindow* window, bool entered);
void _glfwInputDrop(_GLFWwindow* window, int count, const char** names);
int _glfwInputDrop(_GLFWwindow* window, const char *mime, const char *text, size_t sz);
void _glfwInputJoystick(_GLFWjoystick* js, int event);
void _glfwInputJoystickAxis(_GLFWjoystick* js, int axis, float value);
void _glfwInputJoystickButton(_GLFWjoystick* js, int button, char value);
@@ -791,9 +794,6 @@ void _glfwDebug(const char* format, ...);
//////////////////////////////////////////////////////////////////////////
bool _glfwStringInExtensionString(const char* string, const char* extensions);
const _GLFWfbconfig* _glfwChooseFBConfig(const _GLFWfbconfig* desired,
const _GLFWfbconfig* alternatives,
unsigned int count);
bool _glfwRefreshContextAttribs(_GLFWwindow* window,
const _GLFWctxconfig* ctxconfig);
bool _glfwIsValidContextConfig(const _GLFWctxconfig* ctxconfig);
@@ -823,8 +823,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);

View File

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

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);
}

10
glfw/monotonic.c vendored Normal file
View File

@@ -0,0 +1,10 @@
/*
* monotonic.c
* Copyright (C) 2019 Kovid Goyal <kovid at kovidgoyal.net>
*
* Distributed under terms of the GPL3 license.
*/
#define _POSIX_C_SOURCE 200809L
#define MONOTONIC_IMPLEMENTATION
#include "../kitty/monotonic.h"

4
glfw/nsgl_context.h vendored
View File

@@ -32,8 +32,8 @@
//
typedef struct _GLFWcontextNSGL
{
id pixelFormat;
id object;
id pixelFormat;
id object;
} _GLFWcontextNSGL;

View File

@@ -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;
@@ -293,8 +293,7 @@ bool _glfwCreateContextNSGL(_GLFWwindow* window,
forParameter:NSOpenGLContextParameterSurfaceOpacity];
}
if (window->ns.retina)
[window->ns.view setWantsBestResolutionOpenGLSurface:YES];
[window->ns.view setWantsBestResolutionOpenGLSurface:window->ns.retina];
GLint interval = 0;
[window->context.nsgl.object setValues:&interval
@@ -325,7 +324,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;

7
glfw/null_init.c vendored
View File

@@ -29,6 +29,8 @@
#include "internal.h"
#include <stdlib.h>
//////////////////////////////////////////////////////////////////////////
////// GLFW platform API //////
@@ -36,12 +38,14 @@
int _glfwPlatformInit(void)
{
_glfwInitTimerPOSIX();
_glfwPollMonitorsNull();
return true;
}
void _glfwPlatformTerminate(void)
{
free(_glfw.null.clipboardString);
_glfwTerminateOSMesa();
}
@@ -49,4 +53,3 @@ const char* _glfwPlatformGetVersionString(void)
{
return _GLFW_VERSION_NUMBER " null OSMesa";
}

96
glfw/null_monitor.c vendored
View File

@@ -29,13 +29,45 @@
#include "internal.h"
#include <stdlib.h>
#include <string.h>
#include <math.h>
// The the sole (fake) video mode of our (sole) fake monitor
//
static GLFWvidmode getVideoMode(void)
{
GLFWvidmode mode;
mode.width = 1920;
mode.height = 1080;
mode.redBits = 8;
mode.greenBits = 8;
mode.blueBits = 8;
mode.refreshRate = 60;
return mode;
}
//////////////////////////////////////////////////////////////////////////
////// GLFW internal API //////
//////////////////////////////////////////////////////////////////////////
void _glfwPollMonitorsNull(void)
{
const float dpi = 141.f;
const GLFWvidmode mode = getVideoMode();
_GLFWmonitor* monitor = _glfwAllocMonitor("Null SuperNoop 0",
(int) (mode.width * 25.4f / dpi),
(int) (mode.height * 25.4f / dpi));
_glfwInputMonitor(monitor, GLFW_CONNECTED, _GLFW_INSERT_FIRST);
}
//////////////////////////////////////////////////////////////////////////
////// GLFW platform API //////
//////////////////////////////////////////////////////////////////////////
void _glfwPlatformFreeMonitor(_GLFWmonitor* monitor UNUSED)
void _glfwPlatformFreeMonitor(_GLFWmonitor* monitor)
{
_glfwFreeGammaArrays(&monitor->null.ramp);
}
void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor UNUSED, int* xpos UNUSED, int* ypos UNUSED)
@@ -52,26 +84,72 @@ void _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor UNUSED,
}
void _glfwPlatformGetMonitorWorkarea(_GLFWmonitor* monitor UNUSED,
int* xpos UNUSED, int* ypos UNUSED,
int* width UNUSED, int* height UNUSED)
int* xpos, int* ypos,
int* width, int* height)
{
const GLFWvidmode mode = getVideoMode();
if (xpos)
*xpos = 10;
if (ypos)
ypos = 0;
if (width)
*width = mode.width;
if (height)
*height = mode.height - 10;
}
GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor UNUSED, int* found UNUSED)
GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor UNUSED, int* found)
{
return NULL;
GLFWvidmode* mode = calloc(1, sizeof(GLFWvidmode));
*mode = getVideoMode();
*found = 1;
return mode;
}
void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor UNUSED, GLFWvidmode* mode UNUSED)
void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor UNUSED, GLFWvidmode* mode)
{
*mode = getVideoMode();
}
bool _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor UNUSED, GLFWgammaramp* ramp UNUSED)
bool _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
{
return false;
if (!monitor->null.ramp.size)
{
_glfwAllocGammaArrays(&monitor->null.ramp, 256);
for (unsigned int i = 0; i < monitor->null.ramp.size; i++)
{
const float gamma = 2.2f;
float value;
value = i / (float) (monitor->null.ramp.size - 1);
value = powf(value, 1.f / gamma) * 65535.f + 0.5f;
value = _glfw_fminf(value, 65535.f);
monitor->null.ramp.red[i] = (unsigned short) value;
monitor->null.ramp.green[i] = (unsigned short) value;
monitor->null.ramp.blue[i] = (unsigned short) value;
}
}
_glfwAllocGammaArrays(ramp, monitor->null.ramp.size);
memcpy(ramp->red, monitor->null.ramp.red, sizeof(short) * ramp->size);
memcpy(ramp->green, monitor->null.ramp.green, sizeof(short) * ramp->size);
memcpy(ramp->blue, monitor->null.ramp.blue, sizeof(short) * ramp->size);
return true;
}
void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor UNUSED, const GLFWgammaramp* ramp UNUSED)
void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp)
{
if (monitor->null.ramp.size != ramp->size)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Null: Gamma ramp size must match current ramp size");
return;
}
memcpy(monitor->null.ramp.red, ramp->red, sizeof(short) * ramp->size);
memcpy(monitor->null.ramp.green, ramp->green, sizeof(short) * ramp->size);
memcpy(monitor->null.ramp.blue, ramp->blue, sizeof(short) * ramp->size);
}

39
glfw/null_platform.h vendored
View File

@@ -27,12 +27,12 @@
#include <dlfcn.h>
#define _GLFW_PLATFORM_WINDOW_STATE _GLFWwindowNull null
#define _GLFW_PLATFORM_WINDOW_STATE _GLFWwindowNull null
#define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryNull null
#define _GLFW_PLATFORM_MONITOR_STATE _GLFWmonitorNull null
#define _GLFW_PLATFORM_CONTEXT_STATE
#define _GLFW_PLATFORM_MONITOR_STATE
#define _GLFW_PLATFORM_CURSOR_STATE
#define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE
#define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE
#define _GLFW_EGL_CONTEXT_STATE
#define _GLFW_EGL_LIBRARY_CONTEXT_STATE
@@ -56,7 +56,36 @@
//
typedef struct _GLFWwindowNull
{
int width;
int height;
int xpos;
int ypos;
int width;
int height;
char* title;
bool visible;
bool iconified;
bool maximized;
bool resizable;
bool decorated;
bool floating;
bool transparent;
float opacity;
} _GLFWwindowNull;
// Null-specific per-monitor data
//
typedef struct _GLFWmonitorNull
{
GLFWgammaramp ramp;
} _GLFWmonitorNull;
// Null-specific global data
//
typedef struct _GLFWlibraryNull
{
int xcursor;
int ycursor;
char* clipboardString;
_GLFWwindow* focusedWindow;
} _GLFWlibraryNull;
void _glfwPollMonitorsNull(void);

507
glfw/null_window.c vendored
View File

@@ -28,13 +28,73 @@
//========================================================================
#include "internal.h"
#include "../kitty/monotonic.h"
#include <stdlib.h>
static void applySizeLimits(_GLFWwindow* window, int* width, int* height)
{
if (window->numer != GLFW_DONT_CARE && window->denom != GLFW_DONT_CARE)
{
const float ratio = (float) window->numer / (float) window->denom;
*height = (int) (*width / ratio);
}
if (window->minwidth != GLFW_DONT_CARE && *width < window->minwidth)
*width = window->minwidth;
else if (window->maxwidth != GLFW_DONT_CARE && *width > window->maxwidth)
*width = window->maxwidth;
if (window->minheight != GLFW_DONT_CARE && *height < window->minheight)
*height = window->minheight;
else if (window->maxheight != GLFW_DONT_CARE && *height > window->maxheight)
*height = window->maxheight;
}
static void fitToMonitor(_GLFWwindow* window)
{
GLFWvidmode mode;
_glfwPlatformGetVideoMode(window->monitor, &mode);
_glfwPlatformGetMonitorPos(window->monitor,
&window->null.xpos,
&window->null.ypos);
window->null.width = mode.width;
window->null.height = mode.height;
}
static void acquireMonitor(_GLFWwindow* window)
{
_glfwInputMonitorWindow(window->monitor, window);
}
static void releaseMonitor(_GLFWwindow* window)
{
if (window->monitor->window != window)
return;
_glfwInputMonitorWindow(window->monitor, NULL);
}
static int createNativeWindow(_GLFWwindow* window,
const _GLFWwndconfig* wndconfig)
const _GLFWwndconfig* wndconfig,
const _GLFWfbconfig* fbconfig)
{
window->null.width = wndconfig->width;
window->null.height = wndconfig->height;
if (window->monitor)
fitToMonitor(window);
else
{
window->null.xpos = 17;
window->null.ypos = 17;
window->null.width = wndconfig->width;
window->null.height = wndconfig->height;
}
window->null.visible = wndconfig->visible;
window->null.decorated = wndconfig->decorated;
window->null.maximized = wndconfig->maximized;
window->null.floating = wndconfig->floating;
window->null.transparent = fbconfig->transparent;
window->null.opacity = 1.f;
return true;
}
@@ -49,7 +109,7 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window,
const _GLFWctxconfig* ctxconfig,
const _GLFWfbconfig* fbconfig)
{
if (!createNativeWindow(window, wndconfig))
if (!createNativeWindow(window, wndconfig, fbconfig))
return false;
if (ctxconfig->client != GLFW_NO_API)
@@ -69,11 +129,24 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window,
}
}
if (window->monitor)
{
_glfwPlatformShowWindow(window);
_glfwPlatformFocusWindow(window);
acquireMonitor(window);
}
return true;
}
void _glfwPlatformDestroyWindow(_GLFWwindow* window)
{
if (window->monitor)
releaseMonitor(window);
if (_glfw.null.focusedWindow == window)
_glfw.null.focusedWindow = NULL;
if (window->context.destroy)
window->context.destroy(window);
}
@@ -87,20 +160,60 @@ void _glfwPlatformSetWindowIcon(_GLFWwindow* window UNUSED, int count UNUSED,
{
}
void _glfwPlatformSetWindowMonitor(_GLFWwindow* window UNUSED,
_GLFWmonitor* monitor UNUSED,
int xpos UNUSED, int ypos UNUSED,
int width UNUSED, int height UNUSED,
void _glfwPlatformSetWindowMonitor(_GLFWwindow* window,
_GLFWmonitor* monitor,
int xpos, int ypos,
int width, int height,
int refreshRate UNUSED)
{
if (window->monitor == monitor)
{
if (!monitor)
{
_glfwPlatformSetWindowPos(window, xpos, ypos);
_glfwPlatformSetWindowSize(window, width, height);
}
return;
}
if (window->monitor)
releaseMonitor(window);
_glfwInputWindowMonitor(window, monitor);
if (window->monitor)
{
window->null.visible = true;
acquireMonitor(window);
fitToMonitor(window);
}
else
{
_glfwPlatformSetWindowPos(window, xpos, ypos);
_glfwPlatformSetWindowSize(window, width, height);
}
}
void _glfwPlatformGetWindowPos(_GLFWwindow* window UNUSED, int* xpos UNUSED, int* ypos UNUSED)
void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos)
{
if (xpos)
*xpos = window->null.xpos;
if (ypos)
*ypos = window->null.ypos;
}
void _glfwPlatformSetWindowPos(_GLFWwindow* window UNUSED, int xpos UNUSED, int ypos UNUSED)
void _glfwPlatformSetWindowPos(_GLFWwindow* window, int xpos, int ypos)
{
if (window->monitor)
return;
if (window->null.xpos != xpos || window->null.ypos != ypos)
{
window->null.xpos = xpos;
window->null.ypos = ypos;
_glfwInputWindowPos(window, xpos, ypos);
}
}
void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height)
@@ -113,17 +226,37 @@ void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height)
void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height)
{
window->null.width = width;
window->null.height = height;
if (window->monitor)
return;
if (window->null.width != width || window->null.height != height)
{
window->null.width = width;
window->null.height = height;
_glfwInputWindowSize(window, width, height);
_glfwInputFramebufferSize(window, width, height);
}
}
void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window UNUSED,
void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window,
int minwidth UNUSED, int minheight UNUSED,
int maxwidth UNUSED, int maxheight UNUSED)
{
int width = window->null.width;
int height = window->null.height;
applySizeLimits(window, &width, &height);
_glfwPlatformSetWindowSize(window, width, height);
}
void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window UNUSED, int n UNUSED, int d UNUSED)
void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window, int n UNUSED, int d UNUSED)
{
int width = window->null.width;
int height = window->null.height;
applySizeLimits(window, &width, &height);
_glfwPlatformSetWindowSize(window, width, height);
}
void _glfwPlatformSetWindowSizeIncrements(_GLFWwindow* window UNUSED, int widthincr UNUSED, int heightincr UNUSED)
{
}
@@ -135,10 +268,17 @@ void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* heigh
*height = window->null.height;
}
void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window UNUSED,
int* left UNUSED, int* top UNUSED,
int* right UNUSED, int* bottom UNUSED)
void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window,
int* left, int* top,
int* right, int* bottom)
{
if (window->null.decorated && !window->monitor)
{
*left = 1;
*top = 10;
*right = 1;
*bottom = 1;
}
}
void _glfwPlatformGetWindowContentScale(_GLFWwindow* window UNUSED,
@@ -150,64 +290,112 @@ void _glfwPlatformGetWindowContentScale(_GLFWwindow* window UNUSED,
*yscale = 1.f;
}
double _glfwPlatformGetDoubleClickInterval(_GLFWwindow* window UNUSED)
monotonic_t _glfwPlatformGetDoubleClickInterval(_GLFWwindow* window UNUSED)
{
return 0.5;
return ms_to_monotonic_t(500ll);
}
void _glfwPlatformIconifyWindow(_GLFWwindow* window UNUSED)
void _glfwPlatformIconifyWindow(_GLFWwindow* window)
{
if (_glfw.null.focusedWindow == window)
{
_glfw.null.focusedWindow = NULL;
_glfwInputWindowFocus(window, false);
}
if (!window->null.iconified)
{
window->null.iconified = true;
_glfwInputWindowIconify(window, true);
if (window->monitor)
releaseMonitor(window);
}
}
void _glfwPlatformRestoreWindow(_GLFWwindow* window)
{
if (window->null.iconified)
{
window->null.iconified = false;
_glfwInputWindowIconify(window, false);
if (window->monitor)
acquireMonitor(window);
}
else if (window->null.maximized)
{
window->null.maximized = false;
_glfwInputWindowMaximize(window, false);
}
}
void _glfwPlatformMaximizeWindow(_GLFWwindow* window)
{
if (!window->null.maximized)
{
window->null.maximized = true;
_glfwInputWindowMaximize(window, true);
}
}
int _glfwPlatformWindowMaximized(_GLFWwindow* window)
{
return window->null.maximized;
}
int _glfwPlatformWindowHovered(_GLFWwindow* window)
{
return _glfw.null.xcursor >= window->null.xpos &&
_glfw.null.ycursor >= window->null.ypos &&
_glfw.null.xcursor <= window->null.xpos + window->null.width - 1 &&
_glfw.null.ycursor <= window->null.ypos + window->null.height - 1;
}
int _glfwPlatformFramebufferTransparent(_GLFWwindow* window)
{
return window->null.transparent;
}
void _glfwPlatformSetWindowResizable(_GLFWwindow* window, bool enabled)
{
window->null.resizable = enabled;
}
void _glfwPlatformSetWindowDecorated(_GLFWwindow* window, bool enabled)
{
window->null.decorated = enabled;
}
void _glfwPlatformSetWindowFloating(_GLFWwindow* window, bool enabled)
{
window->null.floating = enabled;
}
float _glfwPlatformGetWindowOpacity(_GLFWwindow* window)
{
return window->null.opacity;
}
void _glfwPlatformSetWindowOpacity(_GLFWwindow* window, float opacity)
{
window->null.opacity = opacity;
}
void _glfwPlatformSetRawMouseMotion(_GLFWwindow *window UNUSED, bool enabled UNUSED)
{
}
void _glfwPlatformRestoreWindow(_GLFWwindow* window UNUSED)
bool _glfwPlatformRawMouseMotionSupported(void)
{
return true;
}
void _glfwPlatformMaximizeWindow(_GLFWwindow* window UNUSED)
void _glfwPlatformShowWindow(_GLFWwindow* window)
{
window->null.visible = true;
}
int _glfwPlatformWindowMaximized(_GLFWwindow* window UNUSED)
{
return false;
}
int _glfwPlatformWindowHovered(_GLFWwindow* window UNUSED)
{
return false;
}
int _glfwPlatformFramebufferTransparent(_GLFWwindow* window UNUSED)
{
return false;
}
void _glfwPlatformSetWindowResizable(_GLFWwindow* window UNUSED, bool enabled UNUSED)
{
}
void _glfwPlatformSetWindowDecorated(_GLFWwindow* window UNUSED, bool enabled UNUSED)
{
}
void _glfwPlatformSetWindowFloating(_GLFWwindow* window UNUSED, bool enabled UNUSED)
{
}
float _glfwPlatformGetWindowOpacity(_GLFWwindow* window UNUSED)
{
return 1.f;
}
void _glfwPlatformSetWindowOpacity(_GLFWwindow* window UNUSED, float opacity UNUSED)
{
}
void _glfwPlatformShowWindow(_GLFWwindow* window UNUSED)
{
}
void _glfwPlatformRequestWindowAttention(_GLFWwindow* window UNUSED)
{
}
@@ -217,21 +405,41 @@ int _glfwPlatformWindowBell(_GLFWwindow* window UNUSED)
return false;
}
void _glfwPlatformUnhideWindow(_GLFWwindow* window UNUSED)
void _glfwPlatformHideWindow(_GLFWwindow* window)
{
if (_glfw.null.focusedWindow == window)
{
_glfw.null.focusedWindow = NULL;
_glfwInputWindowFocus(window, false);
}
window->null.visible = false;
}
void _glfwPlatformHideWindow(_GLFWwindow* window UNUSED)
void _glfwPlatformFocusWindow(_GLFWwindow* window)
{
if (_glfw.null.focusedWindow == window)
return;
if (!window->null.visible)
return;
_GLFWwindow* previous = _glfw.null.focusedWindow;
_glfw.null.focusedWindow = window;
if (previous)
{
_glfwInputWindowFocus(previous, false);
if (previous->monitor && previous->autoIconify)
_glfwPlatformIconifyWindow(previous);
}
_glfwInputWindowFocus(window, true);
}
void _glfwPlatformFocusWindow(_GLFWwindow* window UNUSED)
int _glfwPlatformWindowFocused(_GLFWwindow* window)
{
}
int _glfwPlatformWindowFocused(_GLFWwindow* window UNUSED)
{
return false;
return _glfw.null.focusedWindow == window;
}
int _glfwPlatformWindowOccluded(_GLFWwindow* window UNUSED)
@@ -239,14 +447,14 @@ int _glfwPlatformWindowOccluded(_GLFWwindow* window UNUSED)
return false;
}
int _glfwPlatformWindowIconified(_GLFWwindow* window UNUSED)
int _glfwPlatformWindowIconified(_GLFWwindow* window)
{
return false;
return window->null.iconified;
}
int _glfwPlatformWindowVisible(_GLFWwindow* window UNUSED)
int _glfwPlatformWindowVisible(_GLFWwindow* window)
{
return false;
return window->null.visible;
}
void _glfwPlatformPollEvents(void)
@@ -257,7 +465,7 @@ void _glfwPlatformWaitEvents(void)
{
}
void _glfwPlatformWaitEventsTimeout(double timeout UNUSED)
void _glfwPlatformWaitEventsTimeout(monotonic_t timeout UNUSED)
{
}
@@ -265,12 +473,18 @@ void _glfwPlatformPostEmptyEvent(void)
{
}
void _glfwPlatformGetCursorPos(_GLFWwindow* window UNUSED, double* xpos UNUSED, double* ypos UNUSED)
void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos)
{
if (xpos)
*xpos = _glfw.null.xcursor - window->null.xpos;
if (ypos)
*ypos = _glfw.null.ycursor - window->null.ypos;
}
void _glfwPlatformSetCursorPos(_GLFWwindow* window UNUSED, double x UNUSED, double y UNUSED)
void _glfwPlatformSetCursorPos(_GLFWwindow* window, double x, double y)
{
_glfw.null.xcursor = window->null.xpos + (int) x;
_glfw.null.ycursor = window->null.ypos + (int) y;
}
void _glfwPlatformSetCursorMode(_GLFWwindow* window UNUSED, int mode UNUSED)
@@ -297,23 +511,142 @@ void _glfwPlatformSetCursor(_GLFWwindow* window UNUSED, _GLFWcursor* cursor UNUS
{
}
void _glfwPlatformSetClipboardString(const char* string UNUSED)
void _glfwPlatformSetClipboardString(const char* string)
{
char* copy = _glfw_strdup(string);
free(_glfw.null.clipboardString);
_glfw.null.clipboardString = copy;
}
const char* _glfwPlatformGetClipboardString(void)
{
return _glfw.null.clipboardString;
}
const char* _glfwPlatformGetNativeKeyName(int native_key)
{
switch (scancode)
{
case GLFW_KEY_APOSTROPHE:
return "'";
case GLFW_KEY_COMMA:
return ",";
case GLFW_KEY_MINUS:
case GLFW_KEY_KP_SUBTRACT:
return "-";
case GLFW_KEY_PERIOD:
case GLFW_KEY_KP_DECIMAL:
return ".";
case GLFW_KEY_SLASH:
case GLFW_KEY_KP_DIVIDE:
return "/";
case GLFW_KEY_SEMICOLON:
return ";";
case GLFW_KEY_EQUAL:
case GLFW_KEY_KP_EQUAL:
return "=";
case GLFW_KEY_LEFT_BRACKET:
return "[";
case GLFW_KEY_RIGHT_BRACKET:
return "]";
case GLFW_KEY_KP_MULTIPLY:
return "*";
case GLFW_KEY_KP_ADD:
return "+";
case GLFW_KEY_BACKSLASH:
case GLFW_KEY_WORLD_1:
case GLFW_KEY_WORLD_2:
return "\\";
case GLFW_KEY_0:
case GLFW_KEY_KP_0:
return "0";
case GLFW_KEY_1:
case GLFW_KEY_KP_1:
return "1";
case GLFW_KEY_2:
case GLFW_KEY_KP_2:
return "2";
case GLFW_KEY_3:
case GLFW_KEY_KP_3:
return "3";
case GLFW_KEY_4:
case GLFW_KEY_KP_4:
return "4";
case GLFW_KEY_5:
case GLFW_KEY_KP_5:
return "5";
case GLFW_KEY_6:
case GLFW_KEY_KP_6:
return "6";
case GLFW_KEY_7:
case GLFW_KEY_KP_7:
return "7";
case GLFW_KEY_8:
case GLFW_KEY_KP_8:
return "8";
case GLFW_KEY_9:
case GLFW_KEY_KP_9:
return "9";
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";
}
return NULL;
}
const char* _glfwPlatformGetScancodeName(int scancode UNUSED)
int _glfwPlatformGetNativeKeyForKey(int key)
{
return "";
}
int _glfwPlatformGetKeyScancode(int key UNUSED)
{
return -1;
return key;
}
void _glfwPlatformGetRequiredInstanceExtensions(char** extensions UNUSED)
@@ -333,6 +666,6 @@ VkResult _glfwPlatformCreateWindowSurface(VkInstance instance UNUSED,
VkSurfaceKHR* surface UNUSED)
{
// This seems like the most appropriate error to return here
return VK_ERROR_INITIALIZATION_FAILED;
return VK_ERROR_EXTENSION_NOT_PRESENT;
}

87
glfw/posix_time.c vendored
View File

@@ -1,87 +0,0 @@
//========================================================================
// GLFW 3.4 POSIX - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2017 Camilla Löwy <elmindreda@glfw.org>
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would
// be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source
// distribution.
//
//========================================================================
// It is fine to use C99 in this file because it will not be built with VS
//========================================================================
#include "internal.h"
#include <sys/time.h>
#include <time.h>
//////////////////////////////////////////////////////////////////////////
////// GLFW internal API //////
//////////////////////////////////////////////////////////////////////////
// Initialise timer
//
void _glfwInitTimerPOSIX(void)
{
#if defined(CLOCK_MONOTONIC)
struct timespec ts;
if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0)
{
_glfw.timer.posix.monotonic = true;
_glfw.timer.posix.frequency = 1000000000;
}
else
#endif
{
_glfw.timer.posix.monotonic = false;
_glfw.timer.posix.frequency = 1000000;
}
}
//////////////////////////////////////////////////////////////////////////
////// GLFW platform API //////
//////////////////////////////////////////////////////////////////////////
uint64_t _glfwPlatformGetTimerValue(void)
{
#if defined(CLOCK_MONOTONIC)
if (_glfw.timer.posix.monotonic)
{
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return (uint64_t) ts.tv_sec * (uint64_t) 1000000000 + (uint64_t) ts.tv_nsec;
}
else
#endif
{
struct timeval tv;
gettimeofday(&tv, NULL);
return (uint64_t) tv.tv_sec * (uint64_t) 1000000 + (uint64_t) tv.tv_usec;
}
}
uint64_t _glfwPlatformGetTimerFrequency(void)
{
return _glfw.timer.posix.frequency;
}

44
glfw/posix_time.h vendored
View File

@@ -1,44 +0,0 @@
//========================================================================
// GLFW 3.4 POSIX - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2017 Camilla Löwy <elmindreda@glfw.org>
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would
// be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source
// distribution.
//
//========================================================================
#define _GLFW_PLATFORM_LIBRARY_TIMER_STATE _GLFWtimerPOSIX posix
#include <stdint.h>
// POSIX-specific global timer data
//
typedef struct _GLFWtimerPOSIX
{
bool monotonic;
uint64_t frequency;
} _GLFWtimerPOSIX;
void _glfwInitTimerPOSIX(void);

View File

@@ -13,7 +13,6 @@
"cocoa_joystick.m",
"cocoa_monitor.m",
"cocoa_window.m",
"cocoa_time.c",
"posix_thread.c",
"nsgl_context.m",
"egl_context.c",
@@ -31,6 +30,7 @@
"input.c",
"monitor.c",
"vulkan.c",
"monotonic.c",
"window.c"
]
},
@@ -38,7 +38,6 @@
"headers": [
"null_platform.h",
"null_joystick.h",
"posix_time.h",
"posix_thread.h",
"osmesa_context.h"
],
@@ -47,7 +46,6 @@
"null_monitor.c",
"null_window.c",
"null_joystick.c",
"posix_time.c",
"posix_thread.c",
"osmesa_context.c"
]
@@ -55,8 +53,8 @@
"wayland": {
"headers": [
"wl_platform.h",
"posix_time.h",
"posix_thread.h",
"wl_cursors.h",
"xkb_glfw.h",
"dbus_glfw.h",
"ibus_glfw.h",
@@ -81,7 +79,7 @@
"wl_init.c",
"wl_monitor.c",
"wl_window.c",
"posix_time.c",
"wl_cursors.c",
"posix_thread.c",
"xkb_glfw.c",
"dbus_glfw.c",
@@ -125,7 +123,6 @@
"dbus_glfw.h",
"ibus_glfw.h",
"backend_utils.h",
"posix_time.h",
"posix_thread.h",
"glx_context.h",
"egl_context.h",
@@ -142,7 +139,6 @@
"xkb_glfw.c",
"dbus_glfw.c",
"ibus_glfw.c",
"posix_time.c",
"posix_thread.c",
"glx_context.c",
"egl_context.c",

4
glfw/vulkan.c vendored
View File

@@ -57,6 +57,8 @@ bool _glfwInitVulkan(int mode)
_glfw.vk.handle = _glfw_dlopen("vulkan-1.dll");
#elif defined(_GLFW_COCOA)
_glfw.vk.handle = _glfw_dlopen("libvulkan.1.dylib");
if (!_glfw.vk.handle)
_glfw.vk.handle = _glfwLoadLocalVulkanLoaderNS();
#else
_glfw.vk.handle = _glfw_dlopen("libvulkan.so.1");
#endif
@@ -130,6 +132,8 @@ bool _glfwInitVulkan(int mode)
#elif defined(_GLFW_COCOA)
else if (strcmp(ep[i].extensionName, "VK_MVK_macos_surface") == 0)
_glfw.vk.MVK_macos_surface = true;
else if (strcmp(ep[i].extensionName, "VK_EXT_metal_surface") == 0)
_glfw.vk.EXT_metal_surface = true;
#elif defined(_GLFW_X11)
else if (strcmp(ep[i].extensionName, "VK_KHR_xlib_surface") == 0)
_glfw.vk.KHR_xlib_surface = true;

27
glfw/window.c vendored
View File

@@ -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);
}
}
@@ -251,6 +254,8 @@ GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height,
window->maxheight = GLFW_DONT_CARE;
window->numer = GLFW_DONT_CARE;
window->denom = GLFW_DONT_CARE;
window->widthincr = GLFW_DONT_CARE;
window->heightincr = GLFW_DONT_CARE;
// Open the actual window and create its context
if (!_glfwPlatformCreateWindow(window, &wndconfig, &ctxconfig, &fbconfig))
@@ -687,6 +692,20 @@ GLFWAPI void glfwSetWindowAspectRatio(GLFWwindow* handle, int numer, int denom)
_glfwPlatformSetWindowAspectRatio(window, numer, denom);
}
GLFWAPI void glfwSetWindowSizeIncrements(GLFWwindow* handle, int widthincr, int heightincr)
{
_GLFWwindow* window = (_GLFWwindow*) handle;
assert(window != NULL);
assert(widthincr >= 0);
assert(heightincr >= 0);
_GLFW_REQUIRE_INIT();
window->widthincr = widthincr;
window->heightincr = heightincr;
_glfwPlatformSetWindowSizeIncrements(window, window->widthincr, window->heightincr);
}
GLFWAPI void glfwGetFramebufferSize(GLFWwindow* handle, int* width, int* height)
{
_GLFWwindow* window = (_GLFWwindow*) handle;
@@ -736,12 +755,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);
}

164
glfw/wl_cursors.c vendored Normal file
View File

@@ -0,0 +1,164 @@
// Future devs supporting whatever Wayland protocol stabilizes for cursor selection: see _themeAdd.
#include "wl_cursors.h"
#include "internal.h"
#include <assert.h>
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
typedef struct {
struct wl_cursor_theme *theme;
int px;
int refcount;
} _themeData;
struct _wlCursorThemeManager {
size_t count;
/** Pointer to the head of an unsorted array of themes with no sentinel.
*
* The lack of sort (and thus forcing a linear search) is intentional;
* in most cases, users are likely to have 1-2 different cursor sizes loaded.
* For those cases, we get no benefit from sorting and added constant overheads.
*
* Don't change this to a flexible array member because that complicates growing/shrinking.
*/
_themeData *themes;
};
static void
_themeInit(_themeData *dest, const char *name, int px) {
dest->px = px;
dest->refcount = 1;
if (_glfw.wl.shm) {
dest->theme = wl_cursor_theme_load(name, px, _glfw.wl.shm);
if(!dest->theme) {
_glfwInputError(GLFW_PLATFORM_ERROR,
"Wayland: Unable to load cursor theme");
}
} else {
dest->theme = NULL;
}
}
static struct wl_cursor_theme*
_themeAdd(int px, _wlCursorThemeManager *manager) {
++manager->count;
_themeData *temp = realloc(manager->themes, sizeof(_themeData)*manager->count);
if (!temp) {
_glfwInputError(GLFW_OUT_OF_MEMORY,
"OOM during cursor theme management.");
return NULL;
} else {
manager->themes = temp;
_themeInit(manager->themes + manager->count-1,
getenv("XCURSOR_THEME"),
px);
return manager->themes[manager->count-1].theme;
}
}
//WARNING: No input safety checks.
static inline void _themeInc(_themeData
*theme) {
++(theme->refcount);
}
// WARNING: No input safety checks.
// In particular, doesn't check if theme is actually managed by the manager.
static void
_themeDec(_themeData *theme, _wlCursorThemeManager *manager) {
if (--(theme->refcount) == 0) {
wl_cursor_theme_destroy(theme->theme);
if (--(manager->count) > 0) {
const _themeData *last_theme = (manager->themes)+(manager->count);
*theme = *last_theme;
_themeData *temp = realloc(manager->themes, (manager->count)*sizeof(_themeData));
// We're shrinking here, so it's not catastrophic if realloc fails.
if (temp) manager->themes = temp;
} else {
free(manager->themes);
manager->themes = NULL;
}
}
}
static _wlCursorThemeManager _default = {0};
_wlCursorThemeManager*
_wlCursorThemeManagerDefault() {
return &_default;
}
void
_wlCursorThemeManagerDestroy(_wlCursorThemeManager *manager) {
if (manager) {
for (size_t i = 0; i < manager->count; ++i) {
wl_cursor_theme_destroy(manager->themes[i].theme);
}
free(manager->themes);
}
}
static struct wl_cursor_theme*
_wlCursorThemeManagerGet(_wlCursorThemeManager *manager, int px) {
_themeData *themedata = NULL;
for (size_t i = 0; i < manager->count; ++i) {
_themeData *temp = manager->themes+i;
if (temp->px == px) {
themedata = temp;
break;
}
}
if (themedata != NULL) {
_themeInc(themedata);
return themedata->theme;
}
return _themeAdd(px, manager);
}
struct wl_cursor_theme*
_wlCursorThemeManage(_wlCursorThemeManager *manager, struct wl_cursor_theme *theme, int px) {
//WARNING: Multiple returns.
if (manager == NULL) {
return NULL;
}
if (theme != NULL) {
// Search for the provided theme in the manager.
_themeData *themedata = NULL;
for (size_t i = 0; i < manager->count; ++i) {
_themeData *temp = manager->themes+i;
if (temp->theme == theme) {
themedata = temp;
break;
}
}
if (themedata != NULL) {
// Search succeeded. Check if we can avoid unnecessary operations.
if (themedata->px == px) return theme;
_themeDec(themedata, manager);
} else {
_glfwInputError(GLFW_PLATFORM_ERROR,
"Wayland internal: managed theme isn't in the provided manager");
return theme;
//^ This is probably the sanest behavior for this situation: do nothing.
}
}
return px > 0 ? _wlCursorThemeManagerGet(manager, px) : NULL;
}
int
_wlCursorPxFromScale(int scale) {
const char *envStr = getenv("XCURSOR_SIZE");
if(envStr != NULL) {
const int retval = atoi(envStr);
//^ atoi here is fine since 0 is an invalid value.
if(retval > 0 && retval <= INT_MAX/scale) {
return retval*scale;
}
}
return 32*scale;
}

30
glfw/wl_cursors.h vendored Normal file
View File

@@ -0,0 +1,30 @@
// Declarations for a HiDPI-aware cursor theme manager.
#include <wayland-cursor.h>
typedef struct _wlCursorThemeManager _wlCursorThemeManager;
/** Returns a pointer to a wlCursorThemeManagerInstance.
* Repeatedly calling this function will return the same instance.
*
* The retrieved instance must be destroyed with _wlCursorThemeManagerDestroy.
*/
_wlCursorThemeManager* _wlCursorThemeManagerDefault(void);
/** Set a wl_cursor_theme pointer variable to a pointer to a managed cursor theme.
* Pass the desired px as the third argument.
* Returns a pointer to a managed theme, or NULL if the desired px is 0 or an error occurs.
*
* The passed theme pointer must either be NULL or a pointer to a theme managed by the passed manager.
* The provided pointer may be invalidated if it's non-NULL.
*/
struct wl_cursor_theme*
_wlCursorThemeManage(_wlCursorThemeManager*, struct wl_cursor_theme*, int);
void _wlCursorThemeManagerDestroy(_wlCursorThemeManager*);
/** Helper method to determine the appropriate size in pixels for a given scale.
*
* Reads XCURSOR_SIZE if it's set and is valid, else defaults to 32*scale.
*/
int _wlCursorPxFromScale(int);

127
glfw/wl_init.c vendored
View File

@@ -29,6 +29,7 @@
#define _GNU_SOURCE
#include "internal.h"
#include "backend_utils.h"
#include "../kitty/monotonic.h"
#include <assert.h>
#include <errno.h>
@@ -112,7 +113,7 @@ static void pointerHandleEnter(void* data UNUSED,
}
window->wl.decorations.focus = focus;
_glfw.wl.pointerSerial = serial;
_glfw.wl.serial = serial;
_glfw.wl.pointerFocus = window;
window->wl.hovered = true;
@@ -133,19 +134,26 @@ static void pointerHandleLeave(void* data UNUSED,
window->wl.hovered = false;
_glfw.wl.pointerSerial = serial;
_glfw.wl.serial = serial;
_glfw.wl.pointerFocus = NULL;
_glfwInputCursorEnter(window, false);
_glfw.wl.cursorPreviousShape = GLFW_INVALID_CURSOR;
}
static void setCursor(GLFWCursorShape shape)
static void setCursor(GLFWCursorShape shape, _GLFWwindow* window)
{
struct wl_buffer* buffer;
struct wl_cursor* cursor;
struct wl_cursor_image* image;
struct wl_surface* surface = _glfw.wl.cursorSurface;
const int scale = window->wl.scale;
cursor = _glfwLoadCursor(shape);
window->wl.cursorTheme = _wlCursorThemeManage(
_glfw.wl.cursorThemeManager,
window->wl.cursorTheme,
_wlCursorPxFromScale(scale)
);
cursor = _glfwLoadCursor(shape, window->wl.cursorTheme);
if (!cursor) return;
// TODO: handle animated cursors too.
image = cursor->images[0];
@@ -156,14 +164,16 @@ static void setCursor(GLFWCursorShape shape)
buffer = wl_cursor_image_get_buffer(image);
if (!buffer)
return;
wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.pointerSerial,
wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.serial,
surface,
image->hotspot_x,
image->hotspot_y);
image->hotspot_x / scale,
image->hotspot_y / scale);
wl_surface_set_buffer_scale(surface, scale);
wl_surface_attach(surface, buffer, 0, 0);
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 +184,46 @@ 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);
_glfw.wl.cursorPreviousShape = GLFW_INVALID_CURSOR;
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 +231,8 @@ static void pointerHandleMotion(void* data UNUSED,
default:
assert(0);
}
setCursor(cursorShape);
if (_glfw.wl.cursorPreviousShape != cursorShape)
setCursor(cursorShape, window);
}
static void pointerHandleButton(void* data UNUSED,
@@ -284,8 +298,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;
}
}
@@ -294,7 +308,7 @@ static void pointerHandleButton(void* data UNUSED,
if (window->wl.decorations.focus != mainWindow)
return;
_glfw.wl.pointerSerial = serial;
_glfw.wl.serial = serial;
/* Makes left, right and middle 0, 1 and 2. Overall order follows evdev
* codes. */
@@ -327,7 +341,7 @@ static void pointerHandleAxis(void* data UNUSED,
else if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL)
y = wl_fixed_to_double(value) * -1;
_glfwInputScroll(window, x, y, 1);
_glfwInputScroll(window, x, y, 1, _glfw.wl.xkb.states.modifiers);
}
static const struct wl_pointer_listener pointerListener = {
@@ -365,9 +379,9 @@ static void keyboardHandleKeymap(void* data UNUSED,
static void keyboardHandleEnter(void* data UNUSED,
struct wl_keyboard* keyboard UNUSED,
uint32_t serial UNUSED,
uint32_t serial,
struct wl_surface* surface,
struct wl_array* keys UNUSED)
struct wl_array* keys)
{
// Happens in the case we just destroyed the surface.
if (!surface)
@@ -381,13 +395,23 @@ static void keyboardHandleEnter(void* data UNUSED,
return;
}
_glfw.wl.serial = serial;
_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,
struct wl_keyboard* keyboard UNUSED,
uint32_t serial UNUSED,
uint32_t serial,
struct wl_surface* surface UNUSED)
{
_GLFWwindow* window = _glfw.wl.keyboardFocus;
@@ -395,22 +419,24 @@ static void keyboardHandleLeave(void* data UNUSED,
if (!window)
return;
_glfw.wl.serial = serial;
_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);
}
static void keyboardHandleKey(void* data UNUSED,
struct wl_keyboard* keyboard UNUSED,
uint32_t serial UNUSED,
uint32_t serial,
uint32_t time UNUSED,
uint32_t key,
uint32_t state)
@@ -419,8 +445,11 @@ static void keyboardHandleKey(void* data UNUSED,
if (!window)
return;
int action = state == WL_KEYBOARD_KEY_STATE_PRESSED ? GLFW_PRESS : GLFW_RELEASE;
_glfw.wl.serial = serial;
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,19 +458,20 @@ 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);
}
static void keyboardHandleModifiers(void* data UNUSED,
struct wl_keyboard* keyboard UNUSED,
uint32_t serial UNUSED,
uint32_t serial,
uint32_t modsDepressed,
uint32_t modsLatched,
uint32_t modsLocked,
uint32_t group)
{
_glfw.wl.serial = serial;
glfw_xkb_update_modifiers(&_glfw.wl.xkb, modsDepressed, modsLatched, modsLocked, 0, 0, group);
}
@@ -454,7 +484,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 +637,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 +757,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);
@@ -749,7 +778,6 @@ int _glfwPlatformInit(void)
}
#endif
_glfwInitTimerPOSIX();
if (!_glfw.wl.wmBase)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
@@ -759,26 +787,14 @@ int _glfwPlatformInit(void)
if (_glfw.wl.shm)
{
const char *cursorTheme = getenv("XCURSOR_THEME"), *cursorSizeStr = getenv("XCURSOR_SIZE");
char *cursorSizeEnd;
int cursorSize = 32;
if (cursorSizeStr)
{
errno = 0;
long cursorSizeLong = strtol(cursorSizeStr, &cursorSizeEnd, 10);
if (!*cursorSizeEnd && !errno && cursorSizeLong > 0 && cursorSizeLong <= INT_MAX)
cursorSize = (int)cursorSizeLong;
}
_glfw.wl.cursorTheme = wl_cursor_theme_load(cursorTheme, cursorSize, _glfw.wl.shm);
if (!_glfw.wl.cursorTheme)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Wayland: Unable to load default cursor theme");
return false;
}
_glfw.wl.cursorSurface =
_glfw.wl.cursorThemeManager = _wlCursorThemeManagerDefault();
_glfw.wl.cursorSurface =
wl_compositor_create_surface(_glfw.wl.compositor);
}
else
{
_glfw.wl.cursorThemeManager = NULL;
}
return true;
}
@@ -798,8 +814,6 @@ void _glfwPlatformTerminate(void)
glfw_xkb_release(&_glfw.wl.xkb);
glfw_dbus_terminate(&_glfw.wl.dbus);
if (_glfw.wl.cursorTheme)
wl_cursor_theme_destroy(_glfw.wl.cursorTheme);
if (_glfw.wl.cursor.handle)
{
_glfw_dlclose(_glfw.wl.cursor.handle);
@@ -808,6 +822,9 @@ void _glfwPlatformTerminate(void)
if (_glfw.wl.cursorSurface)
wl_surface_destroy(_glfw.wl.cursorSurface);
if (_glfw.wl.cursorThemeManager) {
_wlCursorThemeManagerDestroy(_glfw.wl.cursorThemeManager);
}
if (_glfw.wl.subcompositor)
wl_subcompositor_destroy(_glfw.wl.subcompositor);
if (_glfw.wl.compositor)
@@ -836,7 +853,7 @@ void _glfwPlatformTerminate(void)
wl_data_source_destroy(_glfw.wl.dataSourceForClipboard);
for (size_t doi=0; doi < arraysz(_glfw.wl.dataOffers); doi++) {
if (_glfw.wl.dataOffers[doi].id) {
wl_data_offer_destroy(_glfw.wl.dataOffers[doi].id);
destroy_data_offer(&_glfw.wl.dataOffers[doi]);
}
}
if (_glfw.wl.dataDevice)

4
glfw/wl_monitor.c vendored
View File

@@ -202,7 +202,7 @@ void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode)
bool _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor UNUSED, GLFWgammaramp* ramp UNUSED)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
_glfwInputError(GLFW_FEATURE_UNAVAILABLE,
"Wayland: Gamma ramp access is not available");
return false;
}
@@ -210,7 +210,7 @@ bool _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor UNUSED, GLFWgammaramp* ramp
void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor UNUSED,
const GLFWgammaramp* ramp UNUSED)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
_glfwInputError(GLFW_FEATURE_UNAVAILABLE,
"Wayland: Gamma ramp access is not available");
}

57
glfw/wl_platform.h vendored
View File

@@ -43,7 +43,6 @@ typedef VkResult (APIENTRY *PFN_vkCreateWaylandSurfaceKHR)(VkInstance,const VkWa
typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR)(VkPhysicalDevice,uint32_t,struct wl_display*);
#include "posix_thread.h"
#include "posix_time.h"
#ifdef __linux__
#include "linux_joystick.h"
#else
@@ -53,6 +52,7 @@ typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR
#include "xkb_glfw.h"
#include "egl_context.h"
#include "osmesa_context.h"
#include "wl_cursors.h"
#include "wayland-xdg-shell-client-protocol.h"
#include "wayland-viewporter-client-protocol.h"
@@ -77,18 +77,6 @@ typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR
#define _GLFW_PLATFORM_CONTEXT_STATE
#define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE
struct wl_cursor_image {
uint32_t width;
uint32_t height;
uint32_t hotspot_x;
uint32_t hotspot_y;
uint32_t delay;
};
struct wl_cursor {
unsigned int image_count;
struct wl_cursor_image** images;
char* name;
};
typedef struct wl_cursor_theme* (* PFN_wl_cursor_theme_load)(const char*, int, struct wl_shm*);
typedef void (* PFN_wl_cursor_theme_destroy)(struct wl_cursor_theme*);
typedef struct wl_cursor* (* PFN_wl_cursor_theme_get_cursor)(struct wl_cursor_theme*, const char*);
@@ -149,6 +137,7 @@ typedef struct _GLFWwindowWayland
_GLFWcursor* currentCursor;
double cursorPosX, cursorPosY;
struct wl_cursor_theme* cursorTheme;
char* title;
char appId[256];
@@ -156,6 +145,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;
@@ -195,28 +185,19 @@ typedef enum _GLFWWaylandOfferType
typedef struct _GLFWWaylandDataOffer
{
struct wl_data_offer *id;
const char *mime;
void *id;
_GLFWWaylandOfferType offer_type;
size_t idx;
int is_self_offer;
int has_uri_list;
bool is_self_offer;
bool is_primary;
const char *plain_text_mime, *mime_for_drop;
uint32_t source_actions;
uint32_t dnd_action;
struct wl_surface *surface;
const char **mimes;
size_t mimes_capacity, mimes_count;
} _GLFWWaylandDataOffer;
typedef struct _GLFWWaylandPrimaryOffer
{
struct zwp_primary_selection_offer_v1 *id;
const char *mime;
_GLFWWaylandOfferType offer_type;
size_t idx;
int is_self_offer;
int has_uri_list;
struct wl_surface *surface;
} _GLFWWaylandPrimaryOffer;
// Wayland-specific global data
//
typedef struct _GLFWlibraryWayland
@@ -245,12 +226,12 @@ typedef struct _GLFWlibraryWayland
int compositorVersion;
int seatVersion;
struct wl_cursor_theme* cursorTheme;
struct wl_surface* cursorSurface;
uint32_t pointerSerial;
GLFWCursorShape cursorPreviousShape;
uint32_t serial;
int32_t keyboardRepeatRate;
int32_t keyboardRepeatDelay;
monotonic_t keyboardRepeatDelay;
struct {
uint32_t key;
id_type keyRepeatTimer;
@@ -286,8 +267,8 @@ typedef struct _GLFWlibraryWayland
size_t dataOffersCounter;
_GLFWWaylandDataOffer dataOffers[8];
char* primarySelectionString;
size_t primarySelectionOffersCounter;
_GLFWWaylandPrimaryOffer primarySelectionOffers[8];
_wlCursorThemeManager* cursorThemeManager;
} _GLFWlibraryWayland;
// Wayland-specific per-monitor data
@@ -301,8 +282,7 @@ typedef struct _GLFWmonitorWayland
int x;
int y;
int scale;
} _GLFWmonitorWayland;
} _GLFWmonitorWayland;
// Wayland-specific per-cursor data
//
@@ -313,6 +293,10 @@ typedef struct _GLFWcursorWayland
int width, height;
int xhot, yhot;
int currentImage;
/** The scale of the cursor, or 0 if the cursor should be loaded late, or -1 if the cursor variable itself is unused. */
int scale;
/** Cursor shape stored to allow late cursor loading in setCursorImage. */
GLFWCursorShape shape;
} _GLFWcursorWayland;
@@ -320,4 +304,5 @@ void _glfwAddOutputWayland(uint32_t name, uint32_t version);
void _glfwSetupWaylandDataDevice(void);
void _glfwSetupWaylandPrimarySelectionDevice(void);
void animateCursorImage(id_type timer_id, void *data);
struct wl_cursor* _glfwLoadCursor(GLFWCursorShape);
struct wl_cursor* _glfwLoadCursor(GLFWCursorShape, struct wl_cursor_theme*);
void destroy_data_offer(_GLFWWaylandDataOffer*);

565
glfw/wl_window.c vendored

File diff suppressed because it is too large Load Diff

71
glfw/x11_init.c vendored
View File

@@ -42,11 +42,11 @@
#include <unistd.h>
// Check whether the specified atom is supported
// Return the atom ID only if it is listed in the specified array
//
static Atom getSupportedAtom(Atom* supportedAtoms,
unsigned long atomCount,
const char* atomName)
static Atom getAtomIfSupported(Atom* supportedAtoms,
unsigned long atomCount,
const char* atomName)
{
const Atom atom = XInternAtom(_glfw.x11.display, atomName, False);
@@ -64,9 +64,8 @@ static Atom getSupportedAtom(Atom* supportedAtoms,
static void detectEWMH(void)
{
// First we read the _NET_SUPPORTING_WM_CHECK property on the root window
Window* windowFromRoot = NULL;
// Then we look for the _NET_SUPPORTING_WM_CHECK property of the root window
Window* windowFromRoot = NULL;
if (!_glfwGetWindowPropertyX11(_glfw.x11.root,
_glfw.x11.NET_SUPPORTING_WM_CHECK,
XA_WINDOW,
@@ -93,6 +92,7 @@ static void detectEWMH(void)
_glfwReleaseErrorHandlerX11();
// If the property exists, it should contain the XID of the window
if (*windowFromRoot != *windowFromChild)
{
XFree(windowFromRoot);
@@ -103,49 +103,50 @@ static void detectEWMH(void)
XFree(windowFromRoot);
XFree(windowFromChild);
// We are now fairly sure that an EWMH-compliant window manager is running
// We are now fairly sure that an EWMH-compliant WM is currently running
// We can now start querying the WM about what features it supports by
// looking in the _NET_SUPPORTED property on the root window
// It should contain a list of supported EWMH protocol and state atoms
Atom* supportedAtoms = NULL;
const unsigned long atomCount = _glfwGetWindowPropertyX11(_glfw.x11.root,
_glfw.x11.NET_SUPPORTED,
XA_ATOM,
(unsigned char**) &supportedAtoms);
const unsigned long atomCount =
_glfwGetWindowPropertyX11(_glfw.x11.root,
_glfw.x11.NET_SUPPORTED,
XA_ATOM,
(unsigned char**) &supportedAtoms);
if (!supportedAtoms)
return;
// See which of the atoms we support that are supported by the WM
_glfw.x11.NET_WM_STATE =
getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE");
getAtomIfSupported(supportedAtoms, atomCount, "_NET_WM_STATE");
_glfw.x11.NET_WM_STATE_ABOVE =
getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE_ABOVE");
getAtomIfSupported(supportedAtoms, atomCount, "_NET_WM_STATE_ABOVE");
_glfw.x11.NET_WM_STATE_FULLSCREEN =
getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE_FULLSCREEN");
getAtomIfSupported(supportedAtoms, atomCount, "_NET_WM_STATE_FULLSCREEN");
_glfw.x11.NET_WM_STATE_MAXIMIZED_VERT =
getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE_MAXIMIZED_VERT");
getAtomIfSupported(supportedAtoms, atomCount, "_NET_WM_STATE_MAXIMIZED_VERT");
_glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ =
getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE_MAXIMIZED_HORZ");
getAtomIfSupported(supportedAtoms, atomCount, "_NET_WM_STATE_MAXIMIZED_HORZ");
_glfw.x11.NET_WM_STATE_DEMANDS_ATTENTION =
getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE_DEMANDS_ATTENTION");
getAtomIfSupported(supportedAtoms, atomCount, "_NET_WM_STATE_DEMANDS_ATTENTION");
_glfw.x11.NET_WM_FULLSCREEN_MONITORS =
getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_FULLSCREEN_MONITORS");
getAtomIfSupported(supportedAtoms, atomCount, "_NET_WM_FULLSCREEN_MONITORS");
_glfw.x11.NET_WM_WINDOW_TYPE =
getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_WINDOW_TYPE");
getAtomIfSupported(supportedAtoms, atomCount, "_NET_WM_WINDOW_TYPE");
_glfw.x11.NET_WM_WINDOW_TYPE_NORMAL =
getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_WINDOW_TYPE_NORMAL");
getAtomIfSupported(supportedAtoms, atomCount, "_NET_WM_WINDOW_TYPE_NORMAL");
_glfw.x11.NET_WORKAREA =
getSupportedAtom(supportedAtoms, atomCount, "_NET_WORKAREA");
getAtomIfSupported(supportedAtoms, atomCount, "_NET_WORKAREA");
_glfw.x11.NET_CURRENT_DESKTOP =
getSupportedAtom(supportedAtoms, atomCount, "_NET_CURRENT_DESKTOP");
getAtomIfSupported(supportedAtoms, atomCount, "_NET_CURRENT_DESKTOP");
_glfw.x11.NET_ACTIVE_WINDOW =
getSupportedAtom(supportedAtoms, atomCount, "_NET_ACTIVE_WINDOW");
getAtomIfSupported(supportedAtoms, atomCount, "_NET_ACTIVE_WINDOW");
_glfw.x11.NET_FRAME_EXTENTS =
getSupportedAtom(supportedAtoms, atomCount, "_NET_FRAME_EXTENTS");
getAtomIfSupported(supportedAtoms, atomCount, "_NET_FRAME_EXTENTS");
_glfw.x11.NET_REQUEST_FRAME_EXTENTS =
getSupportedAtom(supportedAtoms, atomCount, "_NET_REQUEST_FRAME_EXTENTS");
getAtomIfSupported(supportedAtoms, atomCount, "_NET_REQUEST_FRAME_EXTENTS");
XFree(supportedAtoms);
}
@@ -384,7 +385,6 @@ static bool initExtensions(void)
_glfw.x11.XdndFinished = XInternAtom(_glfw.x11.display, "XdndFinished", False);
_glfw.x11.XdndSelection = XInternAtom(_glfw.x11.display, "XdndSelection", False);
_glfw.x11.XdndTypeList = XInternAtom(_glfw.x11.display, "XdndTypeList", False);
_glfw.x11.text_uri_list = XInternAtom(_glfw.x11.display, "text/uri-list", False);
// ICCCM, EWMH and Motif window property atoms
// These can be set safely even without WM support
@@ -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);
@@ -505,8 +503,11 @@ static Window createHelperWindow(void)
// X error handler
//
static int errorHandler(Display *display UNUSED, XErrorEvent* event)
static int errorHandler(Display *display, XErrorEvent* event)
{
if (_glfw.x11.display != display)
return 0;
_glfw.x11.errorCode = event->error_code;
return 0;
}
@@ -637,8 +638,6 @@ int _glfwPlatformInit(void)
}
#endif
_glfwInitTimerPOSIX();
_glfwPollMonitorsX11();
return true;
}

37
glfw/x11_monitor.c vendored
View File

@@ -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;
@@ -231,7 +241,8 @@ void _glfwSetVideoModeX11(_GLFWmonitor* monitor, const GLFWvidmode* desired)
if (_glfwCompareVideoModes(&current, best) == 0)
return;
XRRScreenResources* sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root);
XRRScreenResources* sr =
XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root);
XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc);
XRROutputInfo* oi = XRRGetOutputInfo(_glfw.x11.display, sr, monitor->x11.output);
@@ -279,7 +290,8 @@ void _glfwRestoreVideoModeX11(_GLFWmonitor* monitor)
if (monitor->x11.oldMode == None)
return;
XRRScreenResources* sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root);
XRRScreenResources* sr =
XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root);
XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc);
XRRSetCrtcConfig(_glfw.x11.display,
@@ -311,9 +323,10 @@ void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos)
{
if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken)
{
XRRScreenResources* sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root);
XRRScreenResources* sr =
XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root);
XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc);
if (ci)
{
if (xpos)
@@ -323,6 +336,7 @@ void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos)
XRRFreeCrtcInfo(ci);
}
XRRFreeScreenResources(sr);
}
}
@@ -342,8 +356,8 @@ void _glfwPlatformGetMonitorWorkarea(_GLFWmonitor* monitor, int* xpos, int* ypos
if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken)
{
XRRScreenResources* sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root);
XRRScreenResources* sr =
XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root);
XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc);
areaX = ci->x;
@@ -436,7 +450,8 @@ GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count)
if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken)
{
XRRScreenResources* sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root);
XRRScreenResources* sr =
XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root);
XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc);
XRROutputInfo* oi = XRRGetOutputInfo(_glfw.x11.display, sr, monitor->x11.output);
@@ -483,17 +498,19 @@ void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode)
{
if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken)
{
XRRScreenResources* sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root);
XRRScreenResources* sr =
XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root);
XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc);
if (ci) {
if (ci)
{
const XRRModeInfo* mi = getModeInfo(sr, ci->mode);
if (mi) // mi can be NULL if the monitor has been disconnected
*mode = vidmodeFromModeInfo(mi, ci);
XRRFreeCrtcInfo(ci);
}
XRRFreeScreenResources(sr);
}
else

6
glfw/x11_platform.h vendored
View File

@@ -152,7 +152,6 @@ typedef VkResult (APIENTRY *PFN_vkCreateXcbSurfaceKHR)(VkInstance,const VkXcbSur
typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR)(VkPhysicalDevice,uint32_t,xcb_connection_t*,xcb_visualid_t);
#include "posix_thread.h"
#include "posix_time.h"
#include "glx_context.h"
#include "egl_context.h"
#include "osmesa_context.h"
@@ -181,6 +180,7 @@ typedef struct _GLFWwindowX11
{
Colormap colormap;
Window handle;
Window parent;
bool iconified;
bool maximized;
@@ -266,7 +266,6 @@ typedef struct _GLFWlibraryX11
Atom XdndFinished;
Atom XdndSelection;
Atom XdndTypeList;
Atom text_uri_list;
// Selection (clipboard) atoms
Atom TARGETS;
@@ -327,7 +326,8 @@ typedef struct _GLFWlibraryX11
struct {
int version;
Window source;
Atom format;
char format[128];
int format_priority;
} xdnd;
struct {

503
glfw/x11_window.c vendored
View File

@@ -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,9 +66,9 @@
static unsigned _glfwDispatchX11Events(void);
static void
handleEvents(double timeout) {
EVDBG("starting handleEvents(%.2f)", timeout);
int display_read_ok = pollForEvents(&_glfw.x11.eventLoopData, timeout);
handleEvents(monotonic_t timeout) {
EVDBG("starting handleEvents(%.2f)", monotonic_t_to_s_double(timeout));
int display_read_ok = pollForEvents(&_glfw.x11.eventLoopData, timeout, NULL);
EVDBG("display_read_ok: %d", display_read_ok);
if (display_read_ok) {
unsigned dispatched = _glfwDispatchX11Events();
@@ -77,9 +82,9 @@ handleEvents(double timeout) {
}
static bool
waitForX11Event(double timeout) {
waitForX11Event(monotonic_t timeout) {
// returns true if there is X11 data waiting to be read, does not run watches and timers
double end_time = glfwGetTime() + timeout;
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;
}
@@ -250,6 +255,14 @@ static void updateNormalHints(_GLFWwindow* window, int width, int height)
hints->min_aspect.x = hints->max_aspect.x = window->numer;
hints->min_aspect.y = hints->max_aspect.y = window->denom;
}
if (window->widthincr != GLFW_DONT_CARE &&
window->heightincr != GLFW_DONT_CARE)
{
hints->flags |= PResizeInc;
hints->width_inc = window->widthincr;
hints->height_inc = window->heightincr;
}
}
else
{
@@ -442,22 +455,41 @@ static void updateCursorImage(_GLFWwindow* window)
}
}
// Enable XI2 raw mouse motion events
//
static void enableRawMouseMotion(_GLFWwindow* window UNUSED)
{
XIEventMask em;
unsigned char mask[XIMaskLen(XI_RawMotion)] = { 0 };
em.deviceid = XIAllMasterDevices;
em.mask_len = sizeof(mask);
em.mask = mask;
XISetMask(mask, XI_RawMotion);
XISelectEvents(_glfw.x11.display, _glfw.x11.root, &em, 1);
}
// Disable XI2 raw mouse motion events
//
static void disableRawMouseMotion(_GLFWwindow* window UNUSED)
{
XIEventMask em;
unsigned char mask[] = { 0 };
em.deviceid = XIAllMasterDevices;
em.mask_len = sizeof(mask);
em.mask = mask;
XISelectEvents(_glfw.x11.display, _glfw.x11.root, &em, 1);
}
// Apply disabled cursor mode to a focused window
//
static void disableCursor(_GLFWwindow* window)
{
if (_glfw.x11.xi.available)
{
XIEventMask em;
unsigned char mask[XIMaskLen(XI_RawMotion)] = { 0 };
em.deviceid = XIAllMasterDevices;
em.mask_len = sizeof(mask);
em.mask = mask;
XISetMask(mask, XI_RawMotion);
XISelectEvents(_glfw.x11.display, _glfw.x11.root, &em, 1);
}
if (window->rawMouseMotion)
enableRawMouseMotion(window);
_glfw.x11.disabledCursorWindow = window;
_glfwPlatformGetCursorPos(window,
@@ -477,17 +509,8 @@ static void disableCursor(_GLFWwindow* window)
//
static void enableCursor(_GLFWwindow* window)
{
if (_glfw.x11.xi.available)
{
XIEventMask em;
unsigned char mask[] = { 0 };
em.deviceid = XIAllMasterDevices;
em.mask_len = sizeof(mask);
em.mask = mask;
XISelectEvents(_glfw.x11.display, _glfw.x11.root, &em, 1);
}
if (window->rawMouseMotion)
disableRawMouseMotion(window);
_glfw.x11.disabledCursorWindow = NULL;
XUngrabPointer(_glfw.x11.display, CurrentTime);
@@ -508,8 +531,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
@@ -520,46 +543,41 @@ static bool createNativeWindow(_GLFWwindow* window,
window->x11.transparent = _glfwIsVisualTransparentX11(visual);
// Create the actual window
XSetWindowAttributes wa = { 0 };
wa.colormap = window->x11.colormap;
wa.event_mask = StructureNotifyMask | KeyPressMask | KeyReleaseMask |
PointerMotionMask | ButtonPressMask | ButtonReleaseMask |
ExposureMask | FocusChangeMask | VisibilityChangeMask |
EnterWindowMask | LeaveWindowMask | PropertyChangeMask;
_glfwGrabErrorHandlerX11();
window->x11.parent = _glfw.x11.root;
window->x11.handle = XCreateWindow(_glfw.x11.display,
_glfw.x11.root,
0, 0, // Position
width, height,
0, // Border width
depth, // Color depth
InputOutput,
visual,
CWBorderPixel | CWColormap | CWEventMask,
&wa);
_glfwReleaseErrorHandlerX11();
if (!window->x11.handle)
{
XSetWindowAttributes wa;
const unsigned long wamask = CWBorderPixel | CWColormap | CWEventMask;
wa.colormap = window->x11.colormap;
wa.border_pixel = 0;
wa.event_mask = StructureNotifyMask | KeyPressMask | KeyReleaseMask |
PointerMotionMask | ButtonPressMask | ButtonReleaseMask |
ExposureMask | FocusChangeMask | VisibilityChangeMask |
EnterWindowMask | LeaveWindowMask | PropertyChangeMask;
_glfwGrabErrorHandlerX11();
window->x11.handle = XCreateWindow(_glfw.x11.display,
_glfw.x11.root,
0, 0,
width, height,
0, // Border width
depth, // Color depth
InputOutput,
visual,
wamask,
&wa);
_glfwReleaseErrorHandlerX11();
if (!window->x11.handle)
{
_glfwInputErrorX11(GLFW_PLATFORM_ERROR,
"X11: Failed to create window");
return false;
}
XSaveContext(_glfw.x11.display,
window->x11.handle,
_glfw.x11.context,
(XPointer) window);
_glfwInputErrorX11(GLFW_PLATFORM_ERROR,
"X11: Failed to create window");
return false;
}
XSaveContext(_glfw.x11.display,
window->x11.handle,
_glfw.x11.context,
(XPointer) window);
if (!wndconfig->decorated)
_glfwPlatformSetWindowDecorated(window, false);
@@ -589,7 +607,7 @@ static bool createNativeWindow(_GLFWwindow* window,
{
XChangeProperty(_glfw.x11.display, window->x11.handle,
_glfw.x11.NET_WM_STATE, XA_ATOM, 32,
PropModeReplace, (unsigned char*) &states, count);
PropModeReplace, (unsigned char*) states, count);
}
}
@@ -880,7 +898,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 +913,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 +953,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);
@@ -1067,6 +1085,21 @@ static void onConfigChange(void)
}
}
static void
get_atom_names(Atom *atoms, int count, char **atom_names) {
_glfwGrabErrorHandlerX11();
XGetAtomNames(_glfw.x11.display, atoms, count, atom_names);
_glfwReleaseErrorHandlerX11();
if (_glfw.x11.errorCode != Success) {
for (int i = 0; i < count; i++) {
_glfwGrabErrorHandlerX11();
atom_names[i] = XGetAtomName(_glfw.x11.display, atoms[i]);
_glfwReleaseErrorHandlerX11();
if (_glfw.x11.errorCode != Success) atom_names[i] = NULL;
}
}
}
// Process the specified X event
//
static void processEvent(XEvent *event)
@@ -1099,6 +1132,7 @@ static void processEvent(XEvent *event)
_GLFWwindow* window = _glfw.x11.disabledCursorWindow;
if (window &&
window->rawMouseMotion &&
event->xcookie.extension == _glfw.x11.xi.majorOpcode &&
XGetEventData(_glfw.x11.display, &event->xcookie) &&
event->xcookie.evtype == XI_RawMotion)
@@ -1143,8 +1177,11 @@ static void processEvent(XEvent *event)
{
XkbEvent *kb_event = (XkbEvent*)event;
switch(kb_event->any.xkb_type) {
case XkbNewKeyboardNotify:
if(!glfw_xkb_update_x11_keyboard_id(&_glfw.x11.xkb)) return;
case XkbNewKeyboardNotify: {
int32_t old_id = _glfw.x11.xkb.keyboard_device_id;
if (!glfw_xkb_update_x11_keyboard_id(&_glfw.x11.xkb)) return;
if (old_id != _glfw.x11.xkb.keyboard_device_id) keymap_dirty = true;
}
/* fallthrough */
case XkbMapNotify:
{
@@ -1177,6 +1214,12 @@ static void processEvent(XEvent *event)
switch (event->type)
{
case ReparentNotify:
{
window->x11.parent = event->xreparent.parent;
return;
}
case KeyPress:
{
UPDATE_KEYMAP_IF_NEEDED;
@@ -1236,13 +1279,13 @@ static void processEvent(XEvent *event)
// Modern X provides scroll events as mouse button presses
else if (event->xbutton.button == Button4)
_glfwInputScroll(window, 0.0, 1.0, 0);
_glfwInputScroll(window, 0.0, 1.0, 0, mods);
else if (event->xbutton.button == Button5)
_glfwInputScroll(window, 0.0, -1.0, 0);
_glfwInputScroll(window, 0.0, -1.0, 0, mods);
else if (event->xbutton.button == Button6)
_glfwInputScroll(window, 1.0, 0.0, 0);
_glfwInputScroll(window, 1.0, 0.0, 0, mods);
else if (event->xbutton.button == Button7)
_glfwInputScroll(window, -1.0, 0.0, 0);
_glfwInputScroll(window, -1.0, 0.0, 0, mods);
else
{
@@ -1334,7 +1377,7 @@ static void processEvent(XEvent *event)
{
if (_glfw.x11.disabledCursorWindow != window)
return;
if (_glfw.x11.xi.available)
if (window->rawMouseMotion)
return;
const int dx = x - window->x11.lastCursorPosX;
@@ -1370,20 +1413,36 @@ static void processEvent(XEvent *event)
window->x11.height = event->xconfigure.height;
}
if (event->xconfigure.x != window->x11.xpos ||
event->xconfigure.y != window->x11.ypos)
{
if (event->xany.send_event)
{
_glfwInputWindowPos(window,
event->xconfigure.x,
event->xconfigure.y);
int xpos = event->xconfigure.x;
int ypos = event->xconfigure.y;
window->x11.xpos = event->xconfigure.x;
window->x11.ypos = event->xconfigure.y;
// NOTE: ConfigureNotify events from the server are in local
// coordinates, so if we are reparented we need to translate
// the position into root (screen) coordinates
if (!event->xany.send_event && window->x11.parent != _glfw.x11.root)
{
Window dummy;
_glfwGrabErrorHandlerX11();
XTranslateCoordinates(_glfw.x11.display,
window->x11.parent,
_glfw.x11.root,
xpos, ypos,
&xpos, &ypos,
&dummy);
_glfwReleaseErrorHandlerX11();
if (_glfw.x11.errorCode != Success) {
_glfwInputError(GLFW_PLATFORM_ERROR, "X11: Failed to translate ConfigureNotiy co-ords for reparented window");
return;
}
}
if (xpos != window->x11.xpos || ypos != window->x11.ypos)
{
_glfwInputWindowPos(window, xpos, ypos);
window->x11.xpos = xpos;
window->x11.ypos = ypos;
}
return;
}
@@ -1430,7 +1489,8 @@ static void processEvent(XEvent *event)
_glfw.x11.xdnd.source = event->xclient.data.l[0];
_glfw.x11.xdnd.version = event->xclient.data.l[1] >> 24;
_glfw.x11.xdnd.format = None;
memset(_glfw.x11.xdnd.format, 0, sizeof(_glfw.x11.xdnd.format));
_glfw.x11.xdnd.format_priority = 0;
if (_glfw.x11.xdnd.version > _GLFW_XDND_VERSION)
return;
@@ -1447,14 +1507,22 @@ static void processEvent(XEvent *event)
count = 3;
formats = (Atom*) event->xclient.data.l + 2;
}
char **atom_names = calloc(count, sizeof(char**));
if (atom_names) {
get_atom_names(formats, count, atom_names);
for (i = 0; i < count; i++)
{
if (formats[i] == _glfw.x11.text_uri_list)
for (i = 0; i < count; i++)
{
_glfw.x11.xdnd.format = _glfw.x11.text_uri_list;
break;
if (atom_names[i]) {
int prio = _glfwInputDrop(window, atom_names[i], NULL, 0);
if (prio > _glfw.x11.xdnd.format_priority) {
_glfw.x11.xdnd.format_priority = prio;
strncpy(_glfw.x11.xdnd.format, atom_names[i], arraysz(_glfw.x11.xdnd.format) - 1);
}
XFree(atom_names[i]);
}
}
free(atom_names);
}
if (list && formats)
@@ -1468,7 +1536,7 @@ static void processEvent(XEvent *event)
if (_glfw.x11.xdnd.version > _GLFW_XDND_VERSION)
return;
if (_glfw.x11.xdnd.format)
if (_glfw.x11.xdnd.format_priority > 0)
{
if (_glfw.x11.xdnd.version >= 1)
time = event->xclient.data.l[2];
@@ -1476,7 +1544,7 @@ static void processEvent(XEvent *event)
// Request the chosen format from the source window
XConvertSelection(_glfw.x11.display,
_glfw.x11.XdndSelection,
_glfw.x11.xdnd.format,
XInternAtom(_glfw.x11.display, _glfw.x11.xdnd.format, 0),
_glfw.x11.XdndSelection,
window->x11.handle,
time);
@@ -1502,17 +1570,21 @@ static void processEvent(XEvent *event)
const int xabs = (event->xclient.data.l[2] >> 16) & 0xffff;
const int yabs = (event->xclient.data.l[2]) & 0xffff;
Window dummy;
int xpos, ypos;
int xpos = 0, ypos = 0;
if (_glfw.x11.xdnd.version > _GLFW_XDND_VERSION)
return;
_glfwGrabErrorHandlerX11();
XTranslateCoordinates(_glfw.x11.display,
_glfw.x11.root,
window->x11.handle,
xabs, yabs,
&xpos, &ypos,
&dummy);
_glfwReleaseErrorHandlerX11();
if (_glfw.x11.errorCode != Success)
_glfwInputError(GLFW_PLATFORM_ERROR, "X11: Failed to get DND event position");
_glfwInputCursorPos(window, xpos, ypos);
@@ -1524,7 +1596,7 @@ static void processEvent(XEvent *event)
reply.xclient.data.l[2] = 0; // Specify an empty rectangle
reply.xclient.data.l[3] = 0;
if (_glfw.x11.xdnd.format)
if (_glfw.x11.xdnd.format_priority > 0)
{
// Reply that we are ready to copy the dragged data
reply.xclient.data.l[1] = 1; // Accept with no rectangle
@@ -1554,14 +1626,7 @@ static void processEvent(XEvent *event)
if (result)
{
int i, count;
char** paths = parseUriList(data, &count);
_glfwInputDrop(window, count, (const char**) paths);
for (i = 0; i < count; i++)
free(paths[i]);
free(paths);
_glfwInputDrop(window, _glfw.x11.xdnd.format, data, result);
}
if (data)
@@ -1774,7 +1839,7 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window,
const _GLFWctxconfig* ctxconfig,
const _GLFWfbconfig* fbconfig)
{
Visual* visual;
Visual* visual = NULL;
int depth;
if (ctxconfig->client != GLFW_NO_API)
@@ -1800,8 +1865,7 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window,
}
}
if (ctxconfig->client == GLFW_NO_API ||
ctxconfig->source == GLFW_OSMESA_CONTEXT_API)
if (!visual)
{
visual = DefaultVisual(_glfw.x11.display, _glfw.x11.screen);
depth = DefaultDepth(_glfw.x11.display, _glfw.x11.screen);
@@ -1947,10 +2011,14 @@ void _glfwPlatformSetWindowIcon(_GLFWwindow* window,
void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos)
{
Window dummy;
int x, y;
int x = 0, y = 0;
_glfwGrabErrorHandlerX11();
XTranslateCoordinates(_glfw.x11.display, window->x11.handle, _glfw.x11.root,
0, 0, &x, &y, &dummy);
_glfwReleaseErrorHandlerX11();
if (_glfw.x11.errorCode != Success)
_glfwInputError(GLFW_PLATFORM_ERROR, "X11: Failed to get window position");
if (xpos)
*xpos = x;
@@ -2029,6 +2097,14 @@ void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window, int numer UNUSED, in
XFlush(_glfw.x11.display);
}
void _glfwPlatformSetWindowSizeIncrements(_GLFWwindow* window, int widthincr UNUSED, int heightincr UNUSED)
{
int width, height;
_glfwPlatformGetWindowSize(window, &width, &height);
updateNormalHints(window, width, height);
XFlush(_glfw.x11.display);
}
void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* height)
{
_glfwPlatformGetWindowSize(window, width, height);
@@ -2066,7 +2142,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 +2179,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)
@@ -2141,18 +2217,67 @@ void _glfwPlatformRestoreWindow(_GLFWwindow* window)
void _glfwPlatformMaximizeWindow(_GLFWwindow* window)
{
if (_glfw.x11.NET_WM_STATE &&
_glfw.x11.NET_WM_STATE_MAXIMIZED_VERT &&
_glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ)
if (!_glfw.x11.NET_WM_STATE ||
!_glfw.x11.NET_WM_STATE_MAXIMIZED_VERT ||
!_glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ)
{
return;
}
if (_glfwPlatformWindowVisible(window))
{
sendEventToWM(window,
_glfw.x11.NET_WM_STATE,
_NET_WM_STATE_ADD,
_glfw.x11.NET_WM_STATE_MAXIMIZED_VERT,
_glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ,
1, 0);
XFlush(_glfw.x11.display);
_glfw.x11.NET_WM_STATE,
_NET_WM_STATE_ADD,
_glfw.x11.NET_WM_STATE_MAXIMIZED_VERT,
_glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ,
1, 0);
}
else
{
Atom* states = NULL;
unsigned long count =
_glfwGetWindowPropertyX11(window->x11.handle,
_glfw.x11.NET_WM_STATE,
XA_ATOM,
(unsigned char**) &states);
// NOTE: We don't check for failure as this property may not exist yet
// and that's fine (and we'll create it implicitly with append)
Atom missing[2] =
{
_glfw.x11.NET_WM_STATE_MAXIMIZED_VERT,
_glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ
};
unsigned long missingCount = 2;
for (unsigned long i = 0; i < count; i++)
{
for (unsigned long j = 0; j < missingCount; j++)
{
if (states[i] == missing[j])
{
missing[j] = missing[missingCount - 1];
missingCount--;
}
}
}
if (states)
XFree(states);
if (!missingCount)
return;
XChangeProperty(_glfw.x11.display, window->x11.handle,
_glfw.x11.NET_WM_STATE, XA_ATOM, 32,
PropModeAppend,
(unsigned char*) missing,
missingCount);
}
XFlush(_glfw.x11.display);
}
void _glfwPlatformShowWindow(_GLFWwindow* window)
@@ -2172,6 +2297,9 @@ void _glfwPlatformHideWindow(_GLFWwindow* window)
void _glfwPlatformRequestWindowAttention(_GLFWwindow* window)
{
if (!_glfw.x11.NET_WM_STATE || !_glfw.x11.NET_WM_STATE_DEMANDS_ATTENTION)
return;
sendEventToWM(window,
_glfw.x11.NET_WM_STATE,
_NET_WM_STATE_ADD,
@@ -2188,7 +2316,7 @@ void _glfwPlatformFocusWindow(_GLFWwindow* window)
{
if (_glfw.x11.NET_ACTIVE_WINDOW)
sendEventToWM(window, _glfw.x11.NET_ACTIVE_WINDOW, 1, 0, 0, 0, 0);
else
else if (_glfwPlatformWindowVisible(window))
{
XRaiseWindow(_glfw.x11.display, window->x11.handle);
XSetInputFocus(_glfw.x11.display, window->x11.handle,
@@ -2289,6 +2417,7 @@ int _glfwPlatformWindowMaximized(_GLFWwindow* window)
{
return maximized;
}
const unsigned long count =
_glfwGetWindowPropertyX11(window->x11.handle,
_glfw.x11.NET_WM_STATE,
@@ -2350,33 +2479,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)
@@ -2386,7 +2506,7 @@ void _glfwPlatformSetWindowFloating(_GLFWwindow* window, bool enabled)
if (_glfwPlatformWindowVisible(window))
{
const Atom action = enabled ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
const long action = enabled ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
sendEventToWM(window,
_glfw.x11.NET_WM_STATE,
action,
@@ -2395,15 +2515,16 @@ void _glfwPlatformSetWindowFloating(_GLFWwindow* window, bool enabled)
}
else
{
Atom* states;
Atom* states = NULL;
unsigned long i, count;
count = _glfwGetWindowPropertyX11(window->x11.handle,
_glfw.x11.NET_WM_STATE,
XA_ATOM,
(unsigned char**) &states);
if (!states)
return;
// NOTE: We don't check for failure as this property may not exist yet
// and that's fine (and we'll create it implicitly with append)
if (enabled)
{
@@ -2413,32 +2534,36 @@ void _glfwPlatformSetWindowFloating(_GLFWwindow* window, bool enabled)
break;
}
if (i == count)
{
XChangeProperty(_glfw.x11.display, window->x11.handle,
_glfw.x11.NET_WM_STATE, XA_ATOM, 32,
PropModeAppend,
(unsigned char*) &_glfw.x11.NET_WM_STATE_ABOVE,
1);
}
if (i < count)
return;
XChangeProperty(_glfw.x11.display, window->x11.handle,
_glfw.x11.NET_WM_STATE, XA_ATOM, 32,
PropModeAppend,
(unsigned char*) &_glfw.x11.NET_WM_STATE_ABOVE,
1);
}
else
else if (states)
{
for (i = 0; i < count; i++)
{
if (states[i] == _glfw.x11.NET_WM_STATE_ABOVE)
{
states[i] = states[count - 1];
count--;
}
break;
}
if (i == count)
return;
states[i] = states[count - 1];
count--;
XChangeProperty(_glfw.x11.display, window->x11.handle,
_glfw.x11.NET_WM_STATE, XA_ATOM, 32,
PropModeReplace, (unsigned char*) &states, count);
PropModeReplace, (unsigned char*) states, count);
}
XFree(states);
if (states)
XFree(states);
}
XFlush(_glfw.x11.display);
@@ -2519,6 +2644,25 @@ _glfwDispatchX11Events(void) {
return dispatched;
}
void _glfwPlatformSetRawMouseMotion(_GLFWwindow *window, bool enabled)
{
if (!_glfw.x11.xi.available)
return;
if (_glfw.x11.disabledCursorWindow != window)
return;
if (enabled)
enableRawMouseMotion(window);
else
disableRawMouseMotion(window);
}
bool _glfwPlatformRawMouseMotionSupported(void)
{
return _glfw.x11.xi.available;
}
void _glfwPlatformPollEvents(void)
{
_glfwDispatchX11Events();
@@ -2527,11 +2671,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 +2729,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);
}
@@ -2612,7 +2756,7 @@ int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, GLFWCursorShape shape
int native = 0;
#define C(name, val) case name: native = val; break;
switch(shape) {
C(GLFW_ARROW_CURSOR, XC_arrow);
C(GLFW_ARROW_CURSOR, XC_left_ptr);
C(GLFW_IBEAM_CURSOR, XC_xterm);
C(GLFW_CROSSHAIR_CURSOR, XC_crosshair);
C(GLFW_HAND_CURSOR, XC_hand2);
@@ -2655,8 +2799,9 @@ void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor UNUSED)
void _glfwPlatformSetClipboardString(const char* string)
{
char* copy = _glfw_strdup(string);
free(_glfw.x11.clipboardString);
_glfw.x11.clipboardString = _glfw_strdup(string);
_glfw.x11.clipboardString = copy;
XSetSelectionOwner(_glfw.x11.display,
_glfw.x11.CLIPBOARD,
@@ -2870,7 +3015,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);
}

123
glfw/xkb_glfw.c vendored
View File

@@ -61,6 +61,7 @@ START_ALLOW_CASE_RANGE
S(bracketleft, LEFT_BRACKET); \
S(backslash, BACKSLASH); \
S(bracketright, RIGHT_BRACKET); \
S(asciicircum, CIRCUMFLEX); \
S(underscore, UNDERSCORE); \
S(grave, GRAVE_ACCENT); \
R(a, z, A, Z); \
@@ -437,24 +438,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:
@@ -534,11 +533,14 @@ 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
@@ -547,53 +549,58 @@ glfw_xkb_key_from_ime(KeyEvent *ev, bool handled_by_ime, bool failed) {
// 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
@@ -601,37 +608,61 @@ 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);
if (xkb_sym == XKB_KEY_ISO_First_Group || xkb_sym == XKB_KEY_ISO_Last_Group || xkb_sym == XKB_KEY_ISO_Next_Group || xkb_sym == XKB_KEY_ISO_Prev_Group || xkb_sym == XKB_KEY_Mode_switch) {
return;
}
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);
}
}

6
glfw/xkb_glfw.h vendored
View File

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

@@ -3,28 +3,36 @@
# License: GPL v3 Copyright: 2018, Kovid Goyal <kovid at kovidgoyal.net>
import os
import sys
from contextlib import suppress
from typing import TYPE_CHECKING, List, Optional, Tuple
from kitty.cli import parse_args
from kitty.cli_stub import AskCLIOptions
from kitty.constants import cache_dir
from kitty.typing import BossType
from ..tui.operations import alternate_screen, styled
from ..tui.handler import result_handler
from ..tui.operations import alternate_screen, set_cursor_visible, styled
readline = None
if TYPE_CHECKING:
import readline
else:
readline = None
def get_history_items():
def get_history_items() -> List[str]:
return list(map(readline.get_history_item, range(1, readline.get_current_history_length() + 1)))
def sort_key(item):
def sort_key(item: str) -> Tuple[int, str]:
return len(item), item.lower()
class HistoryCompleter:
def __init__(self, name=None):
self.matches = []
def __init__(self, name: Optional[str] = None):
self.matches: List[str] = []
self.history_path = None
if name:
ddir = os.path.join(cache_dir(), 'ask')
@@ -32,7 +40,7 @@ class HistoryCompleter:
os.makedirs(ddir)
self.history_path = os.path.join(ddir, name)
def complete(self, text, state):
def complete(self, text: str, state: int) -> Optional[str]:
response = None
if state == 0:
history_values = get_history_items()
@@ -47,22 +55,22 @@ class HistoryCompleter:
response = None
return response
def __enter__(self):
def __enter__(self) -> 'HistoryCompleter':
if self.history_path:
with suppress(Exception):
readline.read_history_file(self.history_path)
readline.set_completer(self.complete)
return self
def __exit__(self, *a):
def __exit__(self, *a: object) -> None:
if self.history_path:
readline.write_history_file(self.history_path)
def option_text():
def option_text() -> str:
return '''\
--type -t
choices=line
choices=line,yesno
default=line
Type of input. Defaults to asking for a line of text.
@@ -78,44 +86,77 @@ be used for completions and via the browse history readline bindings.
'''
def main(args):
try:
from typing import TypedDict
except ImportError:
TypedDict = dict
class Response(TypedDict):
items: List[str]
response: Optional[str]
def yesno(cli_opts: AskCLIOptions, items: List[str]) -> Response:
import tty
with alternate_screen():
if cli_opts.message:
print(styled(cli_opts.message, bold=True))
print()
print(' ', styled('Y', fg='green') + 'es', ' ', styled('N', fg='red') + 'o', set_cursor_visible(False))
sys.stdout.flush()
tty.setraw(sys.stdin.fileno())
try:
response = sys.stdin.buffer.read(1)
yes = response in (b'y', b'Y', b'\r', b'\n' b' ')
return {'items': items, 'response': 'y' if yes else 'n'}
finally:
sys.stdout.write(set_cursor_visible(True))
tty.setcbreak(sys.stdin.fileno())
sys.stdout.flush()
def main(args: List[str]) -> Response:
# For some reason importing readline in a key handler in the main kitty process
# causes a crash of the python interpreter, probably because of some global
# lock
global readline
import readline as rl
readline = rl
from kitty.shell import init_readline
msg = 'Ask the user for input'
try:
args, items = parse_args(args[1:], option_text, '', msg, 'kitty ask')
cli_opts, items = parse_args(args[1:], option_text, '', msg, 'kitty ask', result_class=AskCLIOptions)
except SystemExit as e:
if e.code != 0:
print(e.args[0])
input('Press enter to quit...')
raise SystemExit(e.code)
init_readline(readline)
ans = {'items': items}
if cli_opts.type == 'yesno':
return yesno(cli_opts, items)
with alternate_screen(), HistoryCompleter(args.name):
if args.message:
print(styled(args.message, bold=True))
import readline as rl
readline = rl
from kitty.shell import init_readline
init_readline(readline)
response = None
with alternate_screen(), HistoryCompleter(cli_opts.name):
if cli_opts.message:
print(styled(cli_opts.message, bold=True))
prompt = '> '
with suppress(KeyboardInterrupt, EOFError):
ans['response'] = input(prompt)
return ans
response = input(prompt)
return {'items': items, 'response': response}
def handle_result(args, data, target_window_id, boss):
if 'response' in data:
@result_handler()
def handle_result(args: List[str], data: Response, target_window_id: int, boss: BossType) -> None:
if data['response'] is not None:
func, *args = data['items']
getattr(boss, func)(data['response'], *args)
if __name__ == '__main__':
import sys
ans = main(sys.argv)
if ans:
print(ans)

View File

@@ -3,39 +3,40 @@
# License: GPL v3 Copyright: 2018, Kovid Goyal <kovid at kovidgoyal.net>
import sys
from typing import Iterable, List, Union
from kitty.key_encoding import KeyEvent
from . import subseq_matcher
from ..tui.handler import Handler
from ..tui.loop import Loop
from . import subseq_matcher
def match(
input_data,
query,
threads=0,
positions=False,
level1='/',
level2='-_0123456789',
level3='.',
limit=0,
mark_before='',
mark_after='',
delimiter='\n'
):
input_data: Union[str, bytes, Iterable[Union[str, bytes]]],
query: str,
threads: int = 0,
positions: bool = False,
level1: str = '/',
level2: str = '-_0123456789',
level3: str = '.',
limit: int = 0,
mark_before: str = '',
mark_after: str = '',
delimiter: str = '\n'
) -> List[str]:
if isinstance(input_data, str):
input_data = input_data.encode('utf-8')
if isinstance(input_data, bytes):
input_data = input_data.split(delimiter.encode('utf-8'))
idata = [x.encode('utf-8') for x in input_data.split(delimiter)]
elif isinstance(input_data, bytes):
idata = input_data.split(delimiter.encode('utf-8'))
else:
input_data = [x.encode('utf-8') if isinstance(x, str) else x for x in input_data]
idata = [x.encode('utf-8') if isinstance(x, str) else x for x in input_data]
query = query.lower()
level1 = level1.lower()
level2 = level2.lower()
level3 = level3.lower()
data = subseq_matcher.match(
input_data, (level1, level2, level3), query,
idata, (level1, level2, level3), query,
positions, limit, threads,
mark_before, mark_after, delimiter)
if data is None:
@@ -45,23 +46,23 @@ def match(
class ChooseHandler(Handler):
def initialize(self):
def initialize(self) -> None:
pass
def on_text(self, text, in_bracketed_paste=False):
def on_text(self, text: str, in_bracketed_paste: bool = False) -> None:
pass
def on_key(self, key_event):
def on_key(self, key_event: KeyEvent) -> None:
pass
def on_interrupt(self):
def on_interrupt(self) -> None:
self.quit_loop(1)
def on_eot(self):
def on_eot(self) -> None:
self.quit_loop(1)
def main(args):
def main(args: List[str]) -> None:
loop = Loop()
handler = ChooseHandler()
loop.loop(handler)

View File

@@ -0,0 +1,9 @@
from typing import List, Optional, Tuple
def match(
lines: List[bytes], levels: Tuple[str, str, str], needle: str,
output_positions: bool, limit: int, num_threads: int, mark_before: str,
mark_after: str, delimiter: str
) -> Optional[str]:
pass

View File

@@ -4,8 +4,10 @@
import os
import sys
from typing import List, NoReturn, Optional
from kitty.cli import parse_args
from kitty.cli_stub import ClipboardCLIOptions
from ..tui.handler import Handler
from ..tui.loop import Loop
@@ -13,12 +15,12 @@ from ..tui.loop import Loop
class Clipboard(Handler):
def __init__(self, data_to_send, args):
def __init__(self, data_to_send: Optional[bytes], args: ClipboardCLIOptions):
self.args = args
self.clipboard_contents = None
self.clipboard_contents: Optional[str] = None
self.data_to_send = data_to_send
def initialize(self):
def initialize(self) -> None:
if self.data_to_send is not None:
self.cmd.write_to_clipboard(self.data_to_send, self.args.use_primary)
if not self.args.get_clipboard:
@@ -32,17 +34,17 @@ class Clipboard(Handler):
return
self.cmd.request_from_clipboard(self.args.use_primary)
def on_clipboard_response(self, text, from_primary=False):
def on_clipboard_response(self, text: str, from_primary: bool = False) -> None:
self.clipboard_contents = text
self.quit_loop(0)
def on_capability_response(self, name, val):
def on_capability_response(self, name: str, val: str) -> None:
self.quit_loop(0)
def on_interrupt(self):
def on_interrupt(self) -> None:
self.quit_loop(1)
def on_eot(self):
def on_eot(self) -> None:
self.quit_loop(1)
@@ -80,16 +82,16 @@ To set the clipboard text, pipe in the new text on stdin. Use the
usage = ''
def main(args):
args, items = parse_args(args[1:], OPTIONS, usage, help_text, 'kitty +kitten clipboard')
def main(args: List[str]) -> NoReturn:
cli_opts, items = parse_args(args[1:], OPTIONS, usage, help_text, 'kitty +kitten clipboard', result_class=ClipboardCLIOptions)
if items:
raise SystemExit('Unrecognized extra command line arguments')
data = None
data: Optional[bytes] = None
if not sys.stdin.isatty():
data = sys.stdin.buffer.read()
sys.stdin = open(os.ctermid(), 'r')
loop = Loop()
handler = Clipboard(data, args)
handler = Clipboard(data, cli_opts)
loop.loop(handler)
if loop.return_code == 0 and handler.clipboard_contents:
sys.stdout.write(handler.clipboard_contents)
@@ -100,6 +102,7 @@ def main(args):
if __name__ == '__main__':
main(sys.argv)
elif __name__ == '__doc__':
sys.cli_docs['usage'] = usage
sys.cli_docs['options'] = OPTIONS
sys.cli_docs['help_text'] = help_text
cd = sys.cli_docs # type: ignore
cd['usage'] = usage
cd['options'] = OPTIONS
cd['help_text'] = help_text

View File

@@ -0,0 +1,8 @@
class GlobalData:
def __init__(self) -> None:
self.title = ''
self.cmd = ''
global_data = GlobalData

View File

@@ -4,86 +4,94 @@
import os
import re
from contextlib import suppress
from functools import lru_cache
from hashlib import md5
from mimetypes import guess_type
from contextlib import suppress
from typing import TYPE_CHECKING, Dict, List, Set, Optional, Iterator, Tuple, Union
path_name_map = {}
if TYPE_CHECKING:
from .highlight import DiffHighlight # noqa
path_name_map: Dict[str, str] = {}
class Segment:
__slots__ = ('start', 'end', 'start_code', 'end_code')
def __init__(self, start, start_code):
def __init__(self, start: int, start_code: str):
self.start = start
self.start_code = start_code
self.end: Optional[int] = None
self.end_code: Optional[str] = None
def __repr__(self):
def __repr__(self) -> str:
return 'Segment(start={!r}, start_code={!r}, end={!r}, end_code={!r})'.format(
self.start, self.start_code, getattr(self, 'end', None), getattr(self, 'end_code', None)
)
self.start, self.start_code, self.end, self.end_code)
class Collection:
def __init__(self):
self.changes = {}
self.renames = {}
self.adds = set()
self.removes = set()
self.all_paths = []
self.type_map = {}
def __init__(self) -> None:
self.changes: Dict[str, str] = {}
self.renames: Dict[str, str] = {}
self.adds: Set[str] = set()
self.removes: Set[str] = set()
self.all_paths: List[str] = []
self.type_map: Dict[str, str] = {}
self.added_count = self.removed_count = 0
def add_change(self, left_path, right_path):
def add_change(self, left_path: str, right_path: str) -> None:
self.changes[left_path] = right_path
self.all_paths.append(left_path)
self.type_map[left_path] = 'diff'
def add_rename(self, left_path, right_path):
def add_rename(self, left_path: str, right_path: str) -> None:
self.renames[left_path] = right_path
self.all_paths.append(left_path)
self.type_map[left_path] = 'rename'
def add_add(self, right_path):
def add_add(self, right_path: str) -> None:
self.adds.add(right_path)
self.all_paths.append(right_path)
self.type_map[right_path] = 'add'
if isinstance(data_for_path(right_path), str):
self.added_count += len(lines_for_path(right_path))
def add_removal(self, left_path):
def add_removal(self, left_path: str) -> None:
self.removes.add(left_path)
self.all_paths.append(left_path)
self.type_map[left_path] = 'removal'
if isinstance(data_for_path(left_path), str):
self.removed_count += len(lines_for_path(left_path))
def finalize(self):
def finalize(self) -> None:
self.all_paths.sort(key=path_name_map.get)
def __iter__(self):
def __iter__(self) -> Iterator[Tuple[str, str, Optional[str]]]:
for path in self.all_paths:
typ = self.type_map[path]
if typ == 'diff':
data = self.changes[path]
data: Optional[str] = self.changes[path]
elif typ == 'rename':
data = self.renames[path]
else:
data = None
yield path, typ, data
def __len__(self):
def __len__(self) -> int:
return len(self.all_paths)
def collect_files(collection, left, right):
left_names, right_names = set(), set()
left_path_map, right_path_map = {}, {}
def collect_files(collection: Collection, left: str, right: str) -> None:
left_names: Set[str] = set()
right_names: Set[str] = set()
left_path_map: Dict[str, str] = {}
right_path_map: Dict[str, str] = {}
def walk(base, names, pmap):
def walk(base: str, names: Set[str], pmap: Dict[str, str]) -> None:
for dirpath, dirnames, filenames in os.walk(base):
for filename in filenames:
path = os.path.abspath(os.path.join(dirpath, filename))
@@ -91,7 +99,8 @@ def collect_files(collection, left, right):
names.add(name)
pmap[name] = path
walk(left, left_names, left_path_map), walk(right, right_names, right_path_map)
walk(left, left_names, left_path_map)
walk(right, right_names, right_path_map)
common_names = left_names & right_names
changed_names = {n for n in common_names if data_for_path(left_path_map[n]) != data_for_path(right_path_map[n])}
for n in changed_names:
@@ -117,50 +126,56 @@ def collect_files(collection, left, right):
sanitize_pat = re.compile('[\x00-\x09\x0b-\x1f\x7f\x80-\x9f]')
def sanitize(text):
def sanitize(text: str) -> str:
ntext = text.replace('\r\n', '\n')
return sanitize_pat.sub('', ntext)
@lru_cache(maxsize=1024)
def mime_type_for_path(path):
def mime_type_for_path(path: str) -> str:
return guess_type(path)[0] or 'application/octet-stream'
@lru_cache(maxsize=1024)
def raw_data_for_path(path):
def raw_data_for_path(path: str) -> bytes:
with open(path, 'rb') as f:
return f.read()
def is_image(path):
return mime_type_for_path(path).startswith('image/')
def is_image(path: Optional[str]) -> bool:
return mime_type_for_path(path).startswith('image/') if path else False
@lru_cache(maxsize=1024)
def data_for_path(path):
ans = raw_data_for_path(path)
def data_for_path(path: str) -> Union[str, bytes]:
raw_bytes = raw_data_for_path(path)
if not is_image(path) and not os.path.samefile(path, os.devnull):
with suppress(UnicodeDecodeError):
ans = ans.decode('utf-8')
return ans
return raw_bytes.decode('utf-8')
return raw_bytes
class LinesForPath:
replace_tab_by = ' ' * 4
@lru_cache(maxsize=1024)
def __call__(self, path: str) -> Tuple[str, ...]:
data = data_for_path(path)
assert isinstance(data, str)
data = data.replace('\t', self.replace_tab_by)
return tuple(sanitize(data).splitlines())
lines_for_path = LinesForPath()
@lru_cache(maxsize=1024)
def lines_for_path(path):
data = data_for_path(path).replace('\t', lines_for_path.replace_tab_by)
return tuple(sanitize(data).splitlines())
lines_for_path.replace_tab_by = ' ' * 4
@lru_cache(maxsize=1024)
def hash_for_path(path):
def hash_for_path(path: str) -> bytes:
return md5(raw_data_for_path(path)).digest()
def create_collection(left, right):
def create_collection(left: str, right: str) -> Collection:
collection = Collection()
if os.path.isdir(left):
collect_files(collection, left, right)
@@ -173,13 +188,13 @@ def create_collection(left, right):
return collection
highlight_data = {}
highlight_data: Dict[str, 'DiffHighlight'] = {}
def set_highlight_data(data):
def set_highlight_data(data: Dict[str, 'DiffHighlight']) -> None:
global highlight_data
highlight_data = data
def highlights_for_path(path):
def highlights_for_path(path: str) -> 'DiffHighlight':
return highlight_data.get(path, [])

View File

@@ -3,27 +3,30 @@
# License: GPL v3 Copyright: 2018, Kovid Goyal <kovid at kovidgoyal.net>
import os
from typing import Any, Dict, Iterable, Optional, Tuple, Type, Union
from kitty.conf.utils import (
init_config as _init_config, key_func, load_config as _load_config, merge_dicts,
parse_config_base, parse_kittens_key, resolve_config
)
from kitty.conf.definition import config_lines
from kitty.conf.utils import (
init_config as _init_config, key_func, load_config as _load_config,
merge_dicts, parse_config_base, parse_kittens_key, resolve_config
)
from kitty.constants import config_dir
from kitty.options_stub import DiffOptions
from kitty.cli_stub import DiffCLIOptions
from kitty.rgb import color_as_sgr
from .config_data import type_map, all_options
from .config_data import all_options, type_convert
defaults = None
defaults: Optional[DiffOptions] = None
formats = {
formats: Dict[str, str] = {
'title': '',
'margin': '',
'text': '',
}
def set_formats(opts):
def set_formats(opts: DiffOptions) -> None:
formats['text'] = '48' + color_as_sgr(opts.background)
formats['title'] = '38' + color_as_sgr(opts.title_fg) + ';48' + color_as_sgr(opts.title_bg) + ';1'
formats['margin'] = '38' + color_as_sgr(opts.margin_fg) + ';48' + color_as_sgr(opts.margin_bg)
@@ -32,6 +35,7 @@ def set_formats(opts):
formats['added'] = '48' + color_as_sgr(opts.added_bg)
formats['removed'] = '48' + color_as_sgr(opts.removed_bg)
formats['filler'] = '48' + color_as_sgr(opts.filler_bg)
formats['margin_filler'] = '48' + color_as_sgr(opts.margin_filler_bg or opts.filler_bg)
formats['hunk_margin'] = '38' + color_as_sgr(opts.margin_fg) + ';48' + color_as_sgr(opts.hunk_margin_bg)
formats['hunk'] = '38' + color_as_sgr(opts.margin_fg) + ';48' + color_as_sgr(opts.hunk_bg)
formats['removed_highlight'] = '48' + color_as_sgr(opts.highlight_removed_bg)
@@ -42,7 +46,7 @@ func_with_args, args_funcs = key_func()
@func_with_args('scroll_by')
def parse_scroll_by(func, rest):
def parse_scroll_by(func: str, rest: str) -> Tuple[str, int]:
try:
return func, int(rest)
except Exception:
@@ -50,7 +54,7 @@ def parse_scroll_by(func, rest):
@func_with_args('scroll_to')
def parse_scroll_to(func, rest):
def parse_scroll_to(func: str, rest: str) -> Tuple[str, str]:
rest = rest.lower()
if rest not in {'start', 'end', 'next-change', 'prev-change', 'next-page', 'prev-page', 'next-match', 'prev-match'}:
rest = 'start'
@@ -58,7 +62,7 @@ def parse_scroll_to(func, rest):
@func_with_args('change_context')
def parse_change_context(func, rest):
def parse_change_context(func: str, rest: str) -> Tuple[str, Union[int, str]]:
rest = rest.lower()
if rest in {'all', 'default'}:
return func, rest
@@ -70,26 +74,29 @@ def parse_change_context(func, rest):
@func_with_args('start_search')
def parse_start_search(func, rest):
rest = rest.lower().split()
is_regex = rest and rest[0] == 'regex'
is_backward = len(rest) > 1 and rest[1] == 'backward'
def parse_start_search(func: str, rest: str) -> Tuple[str, Tuple[bool, bool]]:
rest_ = rest.lower().split()
is_regex = bool(rest_ and rest_[0] == 'regex')
is_backward = bool(len(rest_) > 1 and rest_[1] == 'backward')
return func, (is_regex, is_backward)
def special_handling(key, val, ans):
def special_handling(key: str, val: str, ans: Dict) -> bool:
if key == 'map':
action, *key_def = parse_kittens_key(val, args_funcs)
ans['key_definitions'][tuple(key_def)] = action
return True
x = parse_kittens_key(val, args_funcs)
if x is not None:
action, key_def = x
ans['key_definitions'][key_def] = action
return True
return False
def parse_config(lines, check_keys=True):
ans = {'key_definitions': {}}
def parse_config(lines: Iterable[str], check_keys: bool = True) -> Dict[str, Any]:
ans: Dict[str, Any] = {'key_definitions': {}}
parse_config_base(
lines,
defaults,
type_map,
type_convert,
special_handling,
ans,
check_keys=check_keys
@@ -97,7 +104,7 @@ def parse_config(lines, check_keys=True):
return ans
def merge_configs(defaults, vals):
def merge_configs(defaults: Dict, vals: Dict) -> Dict:
ans = {}
for k, v in defaults.items():
if isinstance(v, dict):
@@ -108,14 +115,16 @@ def merge_configs(defaults, vals):
return ans
def parse_defaults(lines, check_keys=False):
def parse_defaults(lines: Iterable[str], check_keys: bool = False) -> Dict[str, Any]:
return parse_config(lines, check_keys)
Options, defaults = _init_config(config_lines(all_options), parse_defaults)
x = _init_config(config_lines(all_options), parse_defaults)
Options: Type[DiffOptions] = x[0]
defaults = x[1]
def load_config(*paths, overrides=None):
def load_config(*paths: str, overrides: Optional[Iterable[str]] = None) -> DiffOptions:
return _load_config(Options, defaults, parse_config, merge_configs, *paths, overrides=overrides)
@@ -123,7 +132,7 @@ SYSTEM_CONF = '/etc/xdg/kitty/diff.conf'
defconf = os.path.join(config_dir, 'diff.conf')
def init_config(args):
def init_config(args: DiffCLIOptions) -> DiffOptions:
config = tuple(resolve_config(SYSTEM_CONF, defconf, args.config))
overrides = (a.replace('=', ' ', 1) for a in args.override or ())
opts = load_config(*config, overrides=overrides)

View File

@@ -4,17 +4,18 @@
# Utils {{{
from gettext import gettext as _
from functools import partial
from gettext import gettext as _
from typing import Any, Dict, Sequence, Union
from kitty.conf.definition import option_func
from kitty.conf.definition import Option, Shortcut, option_func
from kitty.conf.utils import (
positive_int, python_string, to_color
positive_int, python_string, to_color, to_color_or_none
)
# }}}
all_options = {}
all_options: Dict[str, Union[Option, Sequence[Shortcut]]] = {}
o, k, g, all_groups = option_func(all_options, {
'colors': [_('Colors')],
'diff': [_('Diffing'), ],
@@ -25,7 +26,7 @@ o, k, g, all_groups = option_func(all_options, {
g('diff')
def syntax_aliases(raw):
def syntax_aliases(raw: str) -> Dict[str, str]:
ans = {}
for x in raw.split():
a, b = x.partition(':')[::2]
@@ -34,7 +35,7 @@ def syntax_aliases(raw):
return ans
o('syntax_aliases', 'pyj:py recipe:py', option_type=syntax_aliases, long_text=_('''
o('syntax_aliases', 'pyj:py pyi:py recipe:py', option_type=syntax_aliases, long_text=_('''
File extension aliases for syntax highlight
For example, to syntax highlight :file:`file.xyz` as
:file:`file.abc` use a setting of :code:`xyz:abc`
@@ -79,6 +80,8 @@ c('highlight_added_bg', '#acf2bd')
c('added_margin_bg', '#cdffd8')
c('filler_bg', '#fafbfc', long_text=_('Filler (empty) line background'))
c('margin_filler_bg', 'none', option_type=to_color_or_none, long_text=_(
'Filler (empty) line background in margins, defaults to the filler background'))
c('hunk_margin_bg', '#dbedff', long_text=_('Hunk header colors'))
c('hunk_bg', '#f1f8ff')
@@ -121,4 +124,9 @@ k('prev_match', '<', 'scroll_to prev-match', _('Scroll to previous search match'
k('search_forward_simple', 'f', 'start_search substring forward', _('Search forward (no regex)'))
k('search_backward_simple', 'b', 'start_search substring backward', _('Search backward (no regex)'))
type_map = {o.name: o.option_type for o in all_options.values() if hasattr(o, 'option_type')}
def type_convert(name: str, val: Any) -> Any:
o = all_options.get(name)
if isinstance(o, Option):
val = o.option_type(val)
return val

View File

@@ -0,0 +1,14 @@
from typing import List, Optional, Tuple
from .collect import Segment
def split_with_highlights(
line: str, truncate_points: List[int], fg_highlights: List,
bg_highlight: Optional[Segment]
) -> List:
pass
def changed_center(left_prefix: str, right_postfix: str) -> Tuple[int, int]:
pass

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