Compare commits
420 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
97af84a063 | ||
|
|
18faee6250 | ||
|
|
fd90a3ddc3 | ||
|
|
a08931d84d | ||
|
|
2f0b6e24c9 | ||
|
|
33c5fc0fb6 | ||
|
|
71adb2dcf8 | ||
|
|
1ae324691d | ||
|
|
689d059517 | ||
|
|
18f0ab9e02 | ||
|
|
088ab5f137 | ||
|
|
3dd83975ba | ||
|
|
a796a6cbef | ||
|
|
4766d7de82 | ||
|
|
4a3686c16c | ||
|
|
b49105495c | ||
|
|
ca2eda2c5b | ||
|
|
4fc7c4aafc | ||
|
|
0981828493 | ||
|
|
6bc4f18a59 | ||
|
|
79532a315c | ||
|
|
7472a992ed | ||
|
|
e40616a0db | ||
|
|
dd8b97a86c | ||
|
|
5eff3897de | ||
|
|
530cf2eb14 | ||
|
|
2baa34beb8 | ||
|
|
87e2f7f86d | ||
|
|
e142083d53 | ||
|
|
2e850a0d0d | ||
|
|
aec9c31bca | ||
|
|
598a147500 | ||
|
|
ba201c4c92 | ||
|
|
5bc7cfaa43 | ||
|
|
2804e1ff81 | ||
|
|
ae27d36902 | ||
|
|
08182fbe4d | ||
|
|
778474f436 | ||
|
|
c6698ce305 | ||
|
|
21bc215313 | ||
|
|
88a9cc42d2 | ||
|
|
28f33a67cf | ||
|
|
6742fabfba | ||
|
|
b3806f4533 | ||
|
|
6d5fb4ccc6 | ||
|
|
2487f18f24 | ||
|
|
f59afff1d1 | ||
|
|
b92f95b092 | ||
|
|
d68ae01448 | ||
|
|
87eda834d3 | ||
|
|
7bf0afa621 | ||
|
|
e3e02c7271 | ||
|
|
24e17cb7d8 | ||
|
|
769998adca | ||
|
|
9b5d88e92d | ||
|
|
6d7bebee3a | ||
|
|
1c38654321 | ||
|
|
da7a78691f | ||
|
|
1eaf7083ef | ||
|
|
79a6fcdc5c | ||
|
|
90bcbbf426 | ||
|
|
41049e2a40 | ||
|
|
c9b8510e9c | ||
|
|
d854fc1cd0 | ||
|
|
5f7bcae072 | ||
|
|
652eec3033 | ||
|
|
a9928ec98a | ||
|
|
e1dfb608ca | ||
|
|
2cee3a8809 | ||
|
|
804f72b31a | ||
|
|
e106dcc83b | ||
|
|
9347be639b | ||
|
|
ffc0c42a63 | ||
|
|
f5e855b3ad | ||
|
|
9af4dc4bff | ||
|
|
6f6180c34a | ||
|
|
6ddd751713 | ||
|
|
2c72b06012 | ||
|
|
88854c1aa4 | ||
|
|
5ad704469f | ||
|
|
c140e17a6f | ||
|
|
4fc733a9c8 | ||
|
|
c5c59e4c55 | ||
|
|
e0edef6719 | ||
|
|
0f46ce49e2 | ||
|
|
f9fd39b8c1 | ||
|
|
bd75157428 | ||
|
|
f987f3ba77 | ||
|
|
1c16806efd | ||
|
|
29155fef23 | ||
|
|
c05cbed5b2 | ||
|
|
4f85d4db71 | ||
|
|
468468ab9f | ||
|
|
1b4a6da577 | ||
|
|
aed7a197c7 | ||
|
|
c257b7ecfd | ||
|
|
d6072f6218 | ||
|
|
4ea72a2892 | ||
|
|
89b07a1c6b | ||
|
|
db0cd61807 | ||
|
|
6feb906953 | ||
|
|
7cbf8c63bc | ||
|
|
fae51d4e00 | ||
|
|
c510584afd | ||
|
|
738878c2ff | ||
|
|
d5682fe49a | ||
|
|
d8dd22048a | ||
|
|
737d8b96b6 | ||
|
|
c8627c9713 | ||
|
|
65fa7da24a | ||
|
|
c4c6ef799f | ||
|
|
0d18b91895 | ||
|
|
42089aaadc | ||
|
|
432d0f3318 | ||
|
|
4ade6587e8 | ||
|
|
1724f11429 | ||
|
|
75d66d1048 | ||
|
|
feccef67b9 | ||
|
|
a7d30a199d | ||
|
|
37bbfb11d3 | ||
|
|
79c80b4043 | ||
|
|
18a1402ae2 | ||
|
|
5d639b91b0 | ||
|
|
080c09d22e | ||
|
|
00c2670039 | ||
|
|
f113184165 | ||
|
|
d69f8af107 | ||
|
|
ad2bd1bf63 | ||
|
|
059786ab66 | ||
|
|
72dfa5e5e6 | ||
|
|
d84da6b7b8 | ||
|
|
6aa82d82ad | ||
|
|
a649eb2a48 | ||
|
|
83932c8099 | ||
|
|
95e36cece1 | ||
|
|
7075a7f1c0 | ||
|
|
3093610d26 | ||
|
|
86eed7f895 | ||
|
|
5dc14c5861 | ||
|
|
cab87f6fb2 | ||
|
|
fb3acd1f4a | ||
|
|
b247cef85c | ||
|
|
70445f33e9 | ||
|
|
cadb4f1389 | ||
|
|
bf75a4de61 | ||
|
|
400ab584ac | ||
|
|
9edad62144 | ||
|
|
e94205098f | ||
|
|
35ab7eb472 | ||
|
|
18619b14ac | ||
|
|
97e0b9b65a | ||
|
|
5175d9f4a6 | ||
|
|
a5aed0f4ab | ||
|
|
14d693a8ff | ||
|
|
645963cc24 | ||
|
|
20751c2807 | ||
|
|
dda886b97c | ||
|
|
b796ceecdd | ||
|
|
4def89ebb5 | ||
|
|
bd1c1839dd | ||
|
|
8739f698f9 | ||
|
|
b8c8482f20 | ||
|
|
4348ca8cc5 | ||
|
|
d1aa59080f | ||
|
|
bf0ffa80be | ||
|
|
2a89a0c87e | ||
|
|
de84489a20 | ||
|
|
40901778ad | ||
|
|
c1febea659 | ||
|
|
b42f4ac288 | ||
|
|
fae57a5868 | ||
|
|
7a02d09508 | ||
|
|
8ec6fe960d | ||
|
|
61a77e19ef | ||
|
|
82e88b54c7 | ||
|
|
ab8975f4da | ||
|
|
5e7fd21c8d | ||
|
|
30cd9b2ae4 | ||
|
|
4f7d12f3fd | ||
|
|
62da158823 | ||
|
|
2d19b87208 | ||
|
|
54ca775006 | ||
|
|
a64a0d64cb | ||
|
|
6634dc81fe | ||
|
|
a2d5eef398 | ||
|
|
8184ba246a | ||
|
|
54ad1d103a | ||
|
|
d92f8a90ef | ||
|
|
d33c287344 | ||
|
|
782eebf976 | ||
|
|
0fbf75b95a | ||
|
|
5781facf4b | ||
|
|
b710ffc403 | ||
|
|
7d8edccb04 | ||
|
|
3750d70173 | ||
|
|
025e0bb546 | ||
|
|
033367de91 | ||
|
|
f93b605b75 | ||
|
|
7b4141b0c8 | ||
|
|
90acef72dc | ||
|
|
43f200be77 | ||
|
|
2fbb167803 | ||
|
|
2b396262f0 | ||
|
|
74deca52b9 | ||
|
|
058d956464 | ||
|
|
0f38dc1bd1 | ||
|
|
576b03c047 | ||
|
|
59cb1ad1e0 | ||
|
|
f77acdce14 | ||
|
|
43a98a1df1 | ||
|
|
d1cf771c14 | ||
|
|
10e5fcc375 | ||
|
|
2112932d04 | ||
|
|
be505ce6e0 | ||
|
|
4d6472128c | ||
|
|
26b7b1ec63 | ||
|
|
9a8f0a9b5a | ||
|
|
16dbbf3a1e | ||
|
|
8492d0a264 | ||
|
|
d8f8f1f590 | ||
|
|
b762e81da0 | ||
|
|
8b3b68ea69 | ||
|
|
28525766a5 | ||
|
|
d8fc23c38f | ||
|
|
8cae70fa36 | ||
|
|
7f2b98fad7 | ||
|
|
2b6dde2ac5 | ||
|
|
0c254fa7c7 | ||
|
|
fe7375becc | ||
|
|
b6ee88056e | ||
|
|
96f691ad64 | ||
|
|
8cf3380a77 | ||
|
|
e8d7e3e98b | ||
|
|
8af0a8476f | ||
|
|
2de4248f76 | ||
|
|
8c73ab6afb | ||
|
|
ee9bd77dc4 | ||
|
|
81f31ca215 | ||
|
|
51eff372f8 | ||
|
|
087376b44d | ||
|
|
e49047ef7d | ||
|
|
c117f36009 | ||
|
|
5ec83ee759 | ||
|
|
410165c14d | ||
|
|
973ef9fcda | ||
|
|
396bfb8540 | ||
|
|
aaf597bffd | ||
|
|
63c4f64bf5 | ||
|
|
5745dc34f7 | ||
|
|
114b8cff93 | ||
|
|
261571bb69 | ||
|
|
497e2c9163 | ||
|
|
ac01ffaa54 | ||
|
|
eb9fe06d10 | ||
|
|
506f2f7db7 | ||
|
|
f476c56f91 | ||
|
|
474688888d | ||
|
|
7ddbb613fe | ||
|
|
adc1c06089 | ||
|
|
1f8631cc99 | ||
|
|
f9e4e71285 | ||
|
|
5529194c8d | ||
|
|
5b008163af | ||
|
|
802da7087c | ||
|
|
53ab7617ca | ||
|
|
4369255a25 | ||
|
|
b709ee6842 | ||
|
|
4a8f9efe79 | ||
|
|
19d36fbe69 | ||
|
|
d37e73db54 | ||
|
|
a8f6615380 | ||
|
|
97fe38fbbc | ||
|
|
3378175450 | ||
|
|
9f60d2aea3 | ||
|
|
46d49e18c0 | ||
|
|
43fc335be2 | ||
|
|
f68339c571 | ||
|
|
0d68b7078c | ||
|
|
2e71dde780 | ||
|
|
51ddd584d6 | ||
|
|
4b090259cd | ||
|
|
f3b9ff5f9f | ||
|
|
4ec1a8d9c3 | ||
|
|
350cfeb7ef | ||
|
|
97d379b13e | ||
|
|
2154d555e5 | ||
|
|
1389c36657 | ||
|
|
bd1e7d6942 | ||
|
|
aadab38487 | ||
|
|
91299a279b | ||
|
|
53275c9137 | ||
|
|
fb1c318a09 | ||
|
|
2a07b3f46a | ||
|
|
ffc4e99717 | ||
|
|
fe807dd66f | ||
|
|
40ce5db812 | ||
|
|
649a9f4a6f | ||
|
|
e17ce875be | ||
|
|
415701c58a | ||
|
|
f16f80b459 | ||
|
|
628e6cc87f | ||
|
|
8f9a225c3a | ||
|
|
7b41bc95e1 | ||
|
|
2d06ee5822 | ||
|
|
40b4fb966f | ||
|
|
be696a9d76 | ||
|
|
1ffe9bef35 | ||
|
|
ed70d95c44 | ||
|
|
49bf876f73 | ||
|
|
e512b4d3e3 | ||
|
|
e78b6c7c7c | ||
|
|
a7403c0005 | ||
|
|
5bed0dddaa | ||
|
|
bc302dad23 | ||
|
|
41b0f8852f | ||
|
|
2fadd3e7ba | ||
|
|
dcfd2b8d60 | ||
|
|
7fe63a7aad | ||
|
|
67f2ec2421 | ||
|
|
8e7a23a7b9 | ||
|
|
8e96a27d51 | ||
|
|
b337d4d9d5 | ||
|
|
d9404c0362 | ||
|
|
e4ba5f449f | ||
|
|
17fd749e8d | ||
|
|
f3be5b5e57 | ||
|
|
e619eb9cbb | ||
|
|
a65ee155c5 | ||
|
|
4037480d2b | ||
|
|
97e6978ed8 | ||
|
|
f05eefcc20 | ||
|
|
3f926dfd8b | ||
|
|
59f64c5e33 | ||
|
|
87059a2004 | ||
|
|
7c52dd2bd8 | ||
|
|
70c2765a6e | ||
|
|
3618f4d642 | ||
|
|
698569536d | ||
|
|
c398d3d16e | ||
|
|
9dbc54aad6 | ||
|
|
931cb223cd | ||
|
|
336ee53fea | ||
|
|
34350af61c | ||
|
|
72f7cb3b7d | ||
|
|
481047a446 | ||
|
|
3bf1d73b07 | ||
|
|
b3b830bb5f | ||
|
|
def0c55df3 | ||
|
|
b995e00850 | ||
|
|
32dfc94909 | ||
|
|
20f7118432 | ||
|
|
37e6c3f0cb | ||
|
|
0459dda5c2 | ||
|
|
a10c816c05 | ||
|
|
c0c7cfacc2 | ||
|
|
8cdb6647ed | ||
|
|
b68e3c85b9 | ||
|
|
ef25d5bbd5 | ||
|
|
278bf6e897 | ||
|
|
90a985b73a | ||
|
|
b016353809 | ||
|
|
bc222af2e2 | ||
|
|
44599c9460 | ||
|
|
902fc22670 | ||
|
|
d84e22fbf1 | ||
|
|
6cc720a350 | ||
|
|
c905978874 | ||
|
|
bfe595a8e8 | ||
|
|
94d56d1a9e | ||
|
|
bd3f0b5363 | ||
|
|
6fae3545c7 | ||
|
|
297963f6ab | ||
|
|
a0ceba407e | ||
|
|
35fa91fba2 | ||
|
|
a5d6cd169e | ||
|
|
06c2263657 | ||
|
|
472c6f6b8d | ||
|
|
afcaca85da | ||
|
|
2575349ec2 | ||
|
|
77054f688d | ||
|
|
c5cb24378f | ||
|
|
d66123dd14 | ||
|
|
4ef8f11f9e | ||
|
|
599be7ddc9 | ||
|
|
685497fc8c | ||
|
|
57542fc204 | ||
|
|
8d9323aec6 | ||
|
|
4984a25b19 | ||
|
|
3bdcb29e01 | ||
|
|
b9ab8e6348 | ||
|
|
4a851701e9 | ||
|
|
eafd8af937 | ||
|
|
28bb123be8 | ||
|
|
8e1ed2f8c3 | ||
|
|
4a0fcb3cff | ||
|
|
b5c2163238 | ||
|
|
d0ecdfb330 | ||
|
|
bdf7d98a36 | ||
|
|
e4b0980d15 | ||
|
|
d99c57aeae | ||
|
|
5f855ce547 | ||
|
|
68f3b6fbeb | ||
|
|
dc6d14943e | ||
|
|
05f7334db9 | ||
|
|
cd707e9335 | ||
|
|
505ed5e43b | ||
|
|
9dc8bf5f62 | ||
|
|
f8098662b6 | ||
|
|
de7a0e86c4 | ||
|
|
ca55438fda | ||
|
|
a4b60e7eef | ||
|
|
5d22e07738 | ||
|
|
bdade7e151 | ||
|
|
6958ded4c4 | ||
|
|
cc06104be6 | ||
|
|
059c34c345 | ||
|
|
9cbb726566 | ||
|
|
e8b4356a88 | ||
|
|
634138cd3b | ||
|
|
3f6b07de81 |
4
.gitattributes
vendored
4
.gitattributes
vendored
@@ -3,11 +3,11 @@ kitty/emoji.h linguist-generated=true
|
|||||||
kitty/keys.h linguist-generated=true
|
kitty/keys.h linguist-generated=true
|
||||||
kitty/charsets.c linguist-generated=true
|
kitty/charsets.c linguist-generated=true
|
||||||
kitty/key_encoding.py 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/rgb.py linguist-generated=true
|
||||||
kitty/gl-wrapper.* linguist-generated=true
|
kitty/gl-wrapper.* linguist-generated=true
|
||||||
kitty/khrplatform.h linguist-generated=true
|
|
||||||
kitty/glfw-wrapper.* linguist-generated=true
|
kitty/glfw-wrapper.* linguist-generated=true
|
||||||
|
kitty/parse-graphics-command.h linguist-generated=true
|
||||||
glfw/*.c linguist-vendored=true
|
glfw/*.c linguist-vendored=true
|
||||||
glfw/*.h linguist-vendored=true
|
glfw/*.h linguist-vendored=true
|
||||||
kittens/unicode_input/names.h linguist-generated=true
|
kittens/unicode_input/names.h linguist-generated=true
|
||||||
|
|||||||
3
.github/FUNDING.yml
vendored
Normal file
3
.github/FUNDING.yml
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
patreon: kovidgoyal
|
||||||
|
liberapay: kovidgoyal
|
||||||
|
custom: https://sw.kovidgoyal.net/kitty/support.html
|
||||||
27
.gitignore
vendored
27
.gitignore
vendored
@@ -1,18 +1,17 @@
|
|||||||
*.so
|
*.so
|
||||||
*.pyc
|
*.pyc
|
||||||
*.pyo
|
*.pyo
|
||||||
tags
|
/tags
|
||||||
build
|
/build/
|
||||||
linux-package
|
/linux-package/
|
||||||
kitty.app
|
/kitty.app/
|
||||||
compile_commands.json
|
/compile_commands.json
|
||||||
link_commands.json
|
/link_commands.json
|
||||||
glad/out
|
/glad/out/
|
||||||
kitty/launcher
|
/kitty/launcher/
|
||||||
*.dSYM
|
/*.dSYM/
|
||||||
dev
|
__pycache__/
|
||||||
__pycache__
|
/glfw/wayland-*-client-protocol.[ch]
|
||||||
glfw/wayland-*-client-protocol.[ch]
|
/docs/_build/
|
||||||
docs/_build
|
/docs/generated/
|
||||||
docs/generated
|
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
|||||||
6
Makefile
6
Makefile
@@ -1,8 +1,8 @@
|
|||||||
ifdef V
|
ifdef V
|
||||||
VVAL=--verbose
|
VVAL=--verbose
|
||||||
endif
|
endif
|
||||||
ifdef VERBOSE
|
ifdef VERBOSE
|
||||||
VVAL=--verbose
|
VVAL=--verbose
|
||||||
endif
|
endif
|
||||||
|
|
||||||
all:
|
all:
|
||||||
@@ -28,7 +28,7 @@ asan:
|
|||||||
profile:
|
profile:
|
||||||
python3 setup.py build $(VVAL) --profile
|
python3 setup.py build $(VVAL) --profile
|
||||||
|
|
||||||
app:
|
app:
|
||||||
python3 setup.py kitty.app $(VVAL)
|
python3 setup.py kitty.app $(VVAL)
|
||||||
|
|
||||||
man:
|
man:
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
= kitty - the fast, featureful, GPU based, terminal emulator
|
= 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://circleci.com/gh/kovidgoyal/kitty.svg?style=svg["Build status", link="https://circleci.com/gh/kovidgoyal/kitty"]
|
||||||
|
|||||||
@@ -92,8 +92,10 @@ def setup_openssl_environment():
|
|||||||
if 'SSL_CERT_FILE' not in os.environ and 'SSL_CERT_DIR' not in os.environ:
|
if '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):
|
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'
|
os.environ['SSL_CERT_FILE'] = '/etc/pki/tls/certs/ca-bundle.crt'
|
||||||
|
sys.kitty_ssl_env_var = 'SSL_CERT_FILE'
|
||||||
elif os.path.isdir('/etc/ssl/certs'):
|
elif os.path.isdir('/etc/ssl/certs'):
|
||||||
os.environ['SSL_CERT_DIR'] = '/etc/ssl/certs'
|
os.environ['SSL_CERT_DIR'] = '/etc/ssl/certs'
|
||||||
|
sys.kitty_ssl_env_var = 'SSL_CERT_DIR'
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
|||||||
@@ -1,2 +1,27 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env python
|
||||||
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
|
|
||||||
|
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())
|
||||||
|
|||||||
2
docs/_static/custom.css
vendored
2
docs/_static/custom.css
vendored
@@ -78,6 +78,8 @@ body div.document {
|
|||||||
div.sphinxsidebar {
|
div.sphinxsidebar {
|
||||||
font-size: inherit;
|
font-size: inherit;
|
||||||
line-height: inherit;
|
line-height: inherit;
|
||||||
|
max-height: 100%;
|
||||||
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
#sidebartoc li {
|
#sidebartoc li {
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ Build-time dependencies:
|
|||||||
* gcc or clang
|
* gcc or clang
|
||||||
* pkg-config
|
* pkg-config
|
||||||
* For building on Linux in addition to the above dependencies you might also need to install the ``-dev`` packages for:
|
* 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.
|
if they are not already installed by your distro.
|
||||||
|
|
||||||
Install and run from source
|
Install and run from source
|
||||||
|
|||||||
@@ -4,6 +4,153 @@ Changelog
|
|||||||
|kitty| is a feature full, cross-platform, *fast*, GPU based terminal emulator.
|
|kitty| is a feature full, cross-platform, *fast*, GPU based terminal emulator.
|
||||||
To update |kitty|, :doc:`follow the instructions <binary>`.
|
To update |kitty|, :doc:`follow the instructions <binary>`.
|
||||||
|
|
||||||
|
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]
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
- macOS: Fix a regression in the previous release that caused a crash when
|
||||||
|
pressing a unprintable key, such as the POWER key (:iss:`1997`)
|
||||||
|
|
||||||
|
- Fix a regression in the previous release that caused kitty to not always
|
||||||
|
respond to DPI changes (:pull:`1999`)
|
||||||
|
|
||||||
|
|
||||||
|
0.14.5 [2019-09-23]
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
- Implement a hack to (mostly) preserve tabs when cat-ting a file with them and then
|
||||||
|
copying the text or passing screen contents to another program (:iss:`1829`)
|
||||||
|
|
||||||
|
- When all visible windows have the same background color, use that as the
|
||||||
|
color for the global padding, instead of the configured background color
|
||||||
|
(:iss:`1957`)
|
||||||
|
|
||||||
|
- When resetting the terminal, also reset parser state, this allows easy
|
||||||
|
recovery from incomplete escape codes (:iss:`1961`)
|
||||||
|
|
||||||
|
- Allow mapping keys commonly found on European keyboards (:pull:`1928`)
|
||||||
|
|
||||||
|
- Fix incorrect rendering of some symbols when followed by a space while using
|
||||||
|
the PowerLine font which does not have a space glyph (:iss:`1225`)
|
||||||
|
|
||||||
|
- Linux: Allow using fonts with spacing=90 in addition to fonts with
|
||||||
|
spacing=100 (:iss:`1968`)
|
||||||
|
|
||||||
|
- Use selection foreground color for underlines as well (:iss:`1982`)
|
||||||
|
|
||||||
|
0.14.4 [2019-08-31]
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
- hints kitten: Add a :option:`kitty +kitten hints --alphabet` option to
|
||||||
|
control what alphabets are used for hints (:iss:`1879`)
|
||||||
|
|
||||||
|
- hints kitten: Allow specifying :option:`kitty +kitten hints --program`
|
||||||
|
multiple times to run multiple programs (:iss:`1879`)
|
||||||
|
|
||||||
|
- Add a :opt:`kitten_alias` option that can be used to alias kitten invocation
|
||||||
|
for brevity and to change kitten option defaults globally (:iss:`1879`)
|
||||||
|
|
||||||
|
- macOS: Add an option :opt:`macos_show_window_title_in` to control
|
||||||
|
showing the window title in the menubar/titlebar (:pull:`1837`)
|
||||||
|
|
||||||
|
- macOS: Allow drag and drop of text from other applications into kitty
|
||||||
|
(:pull:`1921`)
|
||||||
|
|
||||||
|
- When running kittens, use the colorscheme of the current window
|
||||||
|
rather than the configured colorscheme (:iss:`1906`)
|
||||||
|
|
||||||
|
- Don't fail to start if running the shell to read the EDITOR env var fails
|
||||||
|
(:iss:`1869`)
|
||||||
|
|
||||||
|
- Disable the ``liga`` and ``dlig`` OpenType features for broken fonts
|
||||||
|
such as Nimbus Mono.
|
||||||
|
|
||||||
|
- Fix a regression that broke setting background_opacity via remote control
|
||||||
|
(:iss:`1895`)
|
||||||
|
|
||||||
|
- Fix piping PNG images into the icat kitten not working (:iss:`1920`)
|
||||||
|
|
||||||
|
- When the OS returns a fallback font that does not actually contain glyphs
|
||||||
|
for the text, do not exhaust the list of fallback fonts (:iss:`1918`)
|
||||||
|
|
||||||
|
- Fix formatting attributes not reset across line boundaries when passing
|
||||||
|
buffer as ANSI (:iss:`1924`)
|
||||||
|
|
||||||
|
|
||||||
0.14.3 [2019-07-29]
|
0.14.3 [2019-07-29]
|
||||||
---------------------
|
---------------------
|
||||||
|
|
||||||
@@ -192,7 +339,7 @@ To update |kitty|, :doc:`follow the instructions <binary>`.
|
|||||||
|
|
||||||
- macOS: Fix :kbd:`cmd+period` key not working (:iss:`1318`)
|
- macOS: Fix :kbd:`cmd+period` key not working (:iss:`1318`)
|
||||||
|
|
||||||
- macOS: Add an option :opt:`macos_show_window_title_in_menubar` to not
|
- macOS: Add an option `macos_show_window_title_in_menubar` to not
|
||||||
show the current window title in the menu-bar (:iss:`1066`)
|
show the current window title in the menu-bar (:iss:`1066`)
|
||||||
|
|
||||||
- macOS: Workaround for cocoa bug that could cause the mouse cursor to become
|
- macOS: Workaround for cocoa bug that could cause the mouse cursor to become
|
||||||
|
|||||||
12
docs/conf.py
12
docs/conf.py
@@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
# vim:fileencoding=utf-8
|
||||||
#
|
#
|
||||||
# Configuration file for the Sphinx documentation builder.
|
# Configuration file for the Sphinx documentation builder.
|
||||||
#
|
#
|
||||||
@@ -243,7 +243,17 @@ def add_html_context(app, pagename, templatename, context, *args):
|
|||||||
|
|
||||||
# CLI docs {{{
|
# CLI docs {{{
|
||||||
def write_cli_docs(all_kitten_names):
|
def write_cli_docs(all_kitten_names):
|
||||||
|
from kitty.launch import options_spec as launch_options_spec
|
||||||
from kitty.cli import option_spec_as_rst
|
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:
|
with open('generated/cli-kitty.rst', 'w') as f:
|
||||||
f.write(option_spec_as_rst(appname='kitty').replace(
|
f.write(option_spec_as_rst(appname='kitty').replace(
|
||||||
'kitty --to', 'kitty @ --to'))
|
'kitty --to', 'kitty @ --to'))
|
||||||
|
|||||||
50
docs/faq.rst
50
docs/faq.rst
@@ -63,6 +63,18 @@ Really, the correct solution for this is to convince the OpenSSH maintainers to
|
|||||||
have ssh do this automatically, if possible, when connecting to a server, so that
|
have ssh do this automatically, if possible, when connecting to a server, so that
|
||||||
all terminals work transparently.
|
all terminals work transparently.
|
||||||
|
|
||||||
|
If the server is running FreeBSD, or another system that relies on termcap
|
||||||
|
rather than terminfo, you will need to convert the terminfo file on your local
|
||||||
|
machine by running (on local machine with |kitty|)::
|
||||||
|
|
||||||
|
infocmp -C xterm-kitty
|
||||||
|
|
||||||
|
The output of this command is the termcap description, which should be appended
|
||||||
|
to :file:`/usr/share/misc/termcap` on the remote server. Then run the following
|
||||||
|
command to apply your change (on the server)::
|
||||||
|
|
||||||
|
cap_mkdb /usr/share/misc/termcap
|
||||||
|
|
||||||
|
|
||||||
Keys such as arrow keys, backspace, delete, home/end, etc. do not work when using su or sudo?
|
Keys such as arrow keys, backspace, delete, home/end, etc. do not work when using su or sudo?
|
||||||
-------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------
|
||||||
@@ -97,8 +109,13 @@ How do I change the colors in a running kitty instance?
|
|||||||
|
|
||||||
You can either use the
|
You can either use the
|
||||||
`OSC terminal escape codes <https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Operating-System-Commands>`_
|
`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>`
|
to set colors or you can define keyboard shortcuts to set colors, for example::
|
||||||
for |kitty| and use :ref:`at_set-colors`.
|
|
||||||
|
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:
|
A list of pre-made color themes for kitty is available at:
|
||||||
`kitty-themes <https://github.com/dexpota/kitty-themes>`_
|
`kitty-themes <https://github.com/dexpota/kitty-themes>`_
|
||||||
@@ -152,7 +169,32 @@ only monospace fonts, since every cell in the grid has to be the same size. If
|
|||||||
your font is not listed in ``kitty list-fonts`` it means that it is not
|
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::
|
monospace. On Linux you can list all monospace fonts with::
|
||||||
|
|
||||||
fc-list : family spacing | grep spacing=100
|
fc-list : family spacing | grep -e spacing=100 -e spacing=90
|
||||||
|
|
||||||
|
Note that the spacing property is calculated by fontconfig based on actual
|
||||||
|
glyph widths in the font. If for some reason fontconfig concludes your favorite
|
||||||
|
monospace font does not have ``spacing=100`` you can override it by using the
|
||||||
|
following :file:`~/.config/fontconfig/fonts.conf`::
|
||||||
|
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
|
||||||
|
<fontconfig>
|
||||||
|
<match target="scan">
|
||||||
|
<test name="family">
|
||||||
|
<string>Your Font Family Name</string>
|
||||||
|
</test>
|
||||||
|
<edit name="spacing">
|
||||||
|
<int>100</int>
|
||||||
|
</edit>
|
||||||
|
</match>
|
||||||
|
</fontconfig>
|
||||||
|
|
||||||
|
After creating (or modifying) this file, you may need to run the following
|
||||||
|
command to rebuild your fontconfig cache::
|
||||||
|
|
||||||
|
fc-cache -r
|
||||||
|
|
||||||
|
Then, the font will be available in ``kitty list-fonts``.
|
||||||
|
|
||||||
|
|
||||||
How can I assign a single global shortcut to bring up the kitty terminal?
|
How can I assign a single global shortcut to bring up the kitty terminal?
|
||||||
@@ -172,7 +214,7 @@ For example::
|
|||||||
|
|
||||||
map alt+s send_text all \x13
|
map alt+s send_text all \x13
|
||||||
|
|
||||||
This maps :kbd:`alt+s`` to :kbd:`ctrl+s`. To figure out what bytes to use for
|
This maps :kbd:`alt+s` to :kbd:`ctrl+s`. To figure out what bytes to use for
|
||||||
the :sc:`send_text <send_text>` you can use the ``showkey`` utility. Run::
|
the :sc:`send_text <send_text>` you can use the ``showkey`` utility. Run::
|
||||||
|
|
||||||
showkey -a
|
showkey -a
|
||||||
|
|||||||
@@ -107,7 +107,8 @@ features of the graphics protocol:
|
|||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
cmd.clear()
|
cmd.clear()
|
||||||
|
|
||||||
write_chunked({'a': 'T', 'f': 100}, open(sys.argv[-1], 'rb').read())
|
with open(sys.argv[-1], 'rb') as f:
|
||||||
|
write_chunked({'a': 'T', 'f': 100}, f.read())
|
||||||
|
|
||||||
|
|
||||||
Save this script as :file:`png.py`, then you can use it to display any PNG
|
Save this script as :file:`png.py`, then you can use it to display any PNG
|
||||||
@@ -255,7 +256,10 @@ sequence of escape codes to the terminal emulator::
|
|||||||
Note that only the first escape code needs to have the full set of control
|
Note that only the first escape code needs to have the full set of control
|
||||||
codes such as width, height, format etc. Subsequent chunks must have
|
codes such as width, height, format etc. Subsequent chunks must have
|
||||||
only the ``m`` key. The client **must** finish sending all chunks for a single image
|
only the ``m`` key. The client **must** finish sending all chunks for a single image
|
||||||
before sending any other graphics related escape codes.
|
before sending any other graphics related escape codes. Note that the cursor
|
||||||
|
position used to display the image **must** be the position when the final chunk is
|
||||||
|
received. Finally, terminals must not display anything, until the entire sequence is
|
||||||
|
received and validated.
|
||||||
|
|
||||||
|
|
||||||
Detecting available transmission mediums
|
Detecting available transmission mediums
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ See the :doc:`binary install instructions </binary>`. You can also
|
|||||||
You can also use your favorite package manager to install the |kitty| package.
|
You can also use your favorite package manager to install the |kitty| package.
|
||||||
|kitty| packages are available for:
|
|kitty| packages are available for:
|
||||||
`macOS with Homebrew (Cask) <https://formulae.brew.sh/cask/kitty>`_,
|
`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>`_,
|
`Ubuntu <https://launchpad.net/ubuntu/+source/kitty>`_,
|
||||||
`Debian <https://packages.debian.org/buster/kitty>`_,
|
`Debian <https://packages.debian.org/buster/kitty>`_,
|
||||||
`openSUSE <https://build.opensuse.org/package/show/X11:terminals/kitty>`_,
|
`openSUSE <https://build.opensuse.org/package/show/X11:terminals/kitty>`_,
|
||||||
@@ -173,6 +173,19 @@ You can also define a shortcut to switch to the previously active window::
|
|||||||
``nth_window`` will focus the nth window for positive numbers and the
|
``nth_window`` will focus the nth window for positive numbers and the
|
||||||
previously active windows for negative numbers.
|
previously active windows for negative numbers.
|
||||||
|
|
||||||
|
.. _detach_window:
|
||||||
|
|
||||||
|
You can define shortcuts to detach the current window and
|
||||||
|
move it to another tab or another OS window::
|
||||||
|
|
||||||
|
map ctrl+f2 detach_window # moves the window into a new OS window
|
||||||
|
map ctrl+f3 detach_window new-tab # moves the window into a new Tab
|
||||||
|
map ctrl+f4 detach_window ask # asks which tab to move the window into
|
||||||
|
|
||||||
|
Similarly, you can detach the current tab, with::
|
||||||
|
|
||||||
|
map ctrl+f2 detach_tab # moves the tab into a new OS window
|
||||||
|
map ctrl+f4 detach_tab ask # asks which OS Window to move the tab into
|
||||||
|
|
||||||
Other keyboard shortcuts
|
Other keyboard shortcuts
|
||||||
----------------------------------
|
----------------------------------
|
||||||
@@ -402,7 +415,7 @@ comfortably within the pager.
|
|||||||
Additionally, you can pipe the contents of the scrollback buffer to an
|
Additionally, you can pipe the contents of the scrollback buffer to an
|
||||||
arbitrary, command running in a new window, tab or overlay, for example::
|
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`
|
Would open the scrollback buffer in a new window when you press the :kbd:`F1`
|
||||||
key. See :sc:`show_scrollback` for details.
|
key. See :sc:`show_scrollback` for details.
|
||||||
@@ -478,7 +491,8 @@ completions happens after the call to :file:`compinit`.
|
|||||||
fish
|
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
|
.. code-block:: sh
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,10 @@ import tempfile
|
|||||||
py3 = sys.version_info[0] > 2
|
py3 = sys.version_info[0] > 2
|
||||||
is64bit = platform.architecture()[0] == '64bit'
|
is64bit = platform.architecture()[0] == '64bit'
|
||||||
is_macos = 'darwin' in sys.platform.lower()
|
is_macos = 'darwin' in sys.platform.lower()
|
||||||
|
if is_macos:
|
||||||
|
mac_ver = tuple(map(int, platform.mac_ver()[0].split('.')))
|
||||||
|
if mac_ver[:2] < (10, 12):
|
||||||
|
raise SystemExit('Your version of macOS is too old, at least 10.12 is required')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
__file__
|
__file__
|
||||||
@@ -225,7 +229,8 @@ def script_launch():
|
|||||||
|
|
||||||
def update_intaller_wrapper():
|
def update_intaller_wrapper():
|
||||||
# To run: python3 -c "import runpy; runpy.run_path('installer.py', run_name='update_wrapper')" installer.sh
|
# To run: python3 -c "import runpy; runpy.run_path('installer.py', run_name='update_wrapper')" installer.sh
|
||||||
src = open(__file__, 'rb').read().decode('utf-8')
|
with open(__file__, 'rb') as f:
|
||||||
|
src = f.read().decode('utf-8')
|
||||||
wrapper = sys.argv[-1]
|
wrapper = sys.argv[-1]
|
||||||
with open(wrapper, 'r+b') as f:
|
with open(wrapper, 'r+b') as f:
|
||||||
raw = f.read().decode('utf-8')
|
raw = f.read().decode('utf-8')
|
||||||
|
|||||||
@@ -128,7 +128,27 @@ layout, by simply adding the line::
|
|||||||
boss.toggle_fullscreen()
|
boss.toggle_fullscreen()
|
||||||
|
|
||||||
|
|
||||||
to the ``handle_result()`` function, above.
|
To the ``handle_result()`` function, above.
|
||||||
|
|
||||||
|
|
||||||
|
Debugging kittens
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
The part of the kitten that runs in ``main()`` is just a normal program and
|
||||||
|
the output of print statements will be visible in the kitten window. Or
|
||||||
|
alternately, you can use::
|
||||||
|
|
||||||
|
from kittens.tui.loop import debug
|
||||||
|
debug('whatever')
|
||||||
|
|
||||||
|
The ``debug()`` function is just like ``print()`` except that the output
|
||||||
|
will appear in the ``STDOUT`` of the kitty process inside which the kitten is
|
||||||
|
running.
|
||||||
|
|
||||||
|
The ``handle_result()`` part of the kitten runs inside the kitty process.
|
||||||
|
The output of print statements will go to the ``STDOUT`` of the kitty process.
|
||||||
|
So if you run kitty from another kitty instance, the output will be visible
|
||||||
|
in the first kitty instance.
|
||||||
|
|
||||||
.. _external_kittens:
|
.. _external_kittens:
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,56 @@ options and modes of operation, see below. You can use these options to
|
|||||||
create mappings in :file:`kitty.conf` to select various different text
|
create mappings in :file:`kitty.conf` to select various different text
|
||||||
snippets. See :sc:`insert_selected_path` for examples.
|
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
|
Command Line Interface
|
||||||
-------------------------
|
-------------------------
|
||||||
|
|
||||||
|
|||||||
@@ -22,3 +22,8 @@ In :guilabel:`Name` mode you instead type words from the character name and use
|
|||||||
keys/tab to select the character from the displayed matches. You can also type
|
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
|
a leading period and the index for the match if you don't like to use arrow
|
||||||
keys.
|
keys.
|
||||||
|
|
||||||
|
Command Line Interface
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
.. include:: ../generated/cli-kitten-unicode_input.rst
|
||||||
|
|||||||
56
docs/launch.rst
Normal file
56
docs/launch.rst
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
Launching programs in new windows/tabs
|
||||||
|
========================================
|
||||||
|
|
||||||
|
.. program:: launch
|
||||||
|
|
||||||
|
|
||||||
|
|kitty| has a :code:`launch` action that can be used to run arbitrary programs
|
||||||
|
in news windows/tabs. It can be mapped to user defined shortcuts in kitty.conf.
|
||||||
|
It is very powerful and allows sending the contents of
|
||||||
|
the current window to the launched program, as well as many other options.
|
||||||
|
|
||||||
|
In the simplest form, you can use it to open a new kitty window running the
|
||||||
|
shell, as shown below::
|
||||||
|
|
||||||
|
map f1 launch
|
||||||
|
|
||||||
|
To run a different program simply pass the command line as arguments to
|
||||||
|
launch::
|
||||||
|
|
||||||
|
map f1 launch vim path/to/some/file
|
||||||
|
|
||||||
|
|
||||||
|
To open a new window with the same working directory as the currently
|
||||||
|
active window::
|
||||||
|
|
||||||
|
map f1 launch --cwd=current
|
||||||
|
|
||||||
|
To open the new window in a new tab::
|
||||||
|
|
||||||
|
map f1 launch --type=tab
|
||||||
|
|
||||||
|
To pass the contents of the current screen and scrollback to the started process::
|
||||||
|
|
||||||
|
map f1 launch --stdin-source=@screen_scrollback less
|
||||||
|
|
||||||
|
There are many more powerful options, refer to the complete list below.
|
||||||
|
|
||||||
|
The piping environment
|
||||||
|
--------------------------
|
||||||
|
|
||||||
|
When using :option:`launch --stdin-source`, the program to which the data is
|
||||||
|
piped has a special environment variable declared, ``KITTY_PIPE_DATA`` whose
|
||||||
|
contents are::
|
||||||
|
|
||||||
|
KITTY_PIPE_DATA={scrolled_by}:{cursor_x},{cursor_y}:{lines},{columns}
|
||||||
|
|
||||||
|
where ``scrolled_by`` is the number of lines kitty is currently scrolled by,
|
||||||
|
``cursor_(x|y)`` is the position of the cursor on the screen with ``(1,1)``
|
||||||
|
being the top left corner and ``{lines},{columns}`` being the number of rows
|
||||||
|
and columns of the screen.
|
||||||
|
|
||||||
|
|
||||||
|
Syntax reference
|
||||||
|
------------------
|
||||||
|
|
||||||
|
.. include:: /generated/launch.rst
|
||||||
@@ -1,6 +1,9 @@
|
|||||||
Working with the screen and history buffer contents
|
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
|
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
|
: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
|
There are various different kinds of placeholders
|
||||||
|
|
||||||
|
``@selection``
|
||||||
|
Plain text, currently selected text
|
||||||
|
|
||||||
``@text``
|
``@text``
|
||||||
Plain text, current screen + scrollback buffer
|
Plain text, current screen + scrollback buffer
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ Documentation for the kitty remote control protocol
|
|||||||
======================================================
|
======================================================
|
||||||
|
|
||||||
The kitty remote control protocol is a simple protocol that involves sending
|
The kitty remote control protocol is a simple protocol that involves sending
|
||||||
data to kitty in the form of JSON. Any individual command ot kitty has the
|
data to kitty in the form of JSON. Any individual command of kitty has the
|
||||||
form::
|
form::
|
||||||
|
|
||||||
<ESC>P@kitty-cmd<JSON object><ESC>\
|
<ESC>P@kitty-cmd<JSON object><ESC>\
|
||||||
@@ -21,7 +21,7 @@ standalone client, use the kitty version that you are developing against. Using
|
|||||||
a version greater than the version of the kitty instance you are talking to,
|
a version greater than the version of the kitty instance you are talking to,
|
||||||
will cause a failure.
|
will cause a failure.
|
||||||
|
|
||||||
Set ``no_response`` to True if you dont want a response from kitty.
|
Set ``no_response`` to True if you don't want a response from kitty.
|
||||||
|
|
||||||
The optional payload is a JSON object that is specific to the actual command being sent.
|
The optional payload is a JSON object that is specific to the actual command being sent.
|
||||||
The fields in the object for every command are documented below.
|
The fields in the object for every command are documented below.
|
||||||
|
|||||||
@@ -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
|
enable remote control for only some |kitty| windows. Simply create a shortcut
|
||||||
such as::
|
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 @``
|
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
|
to control kitty. Note that any program with the right level of permissions can
|
||||||
|
|||||||
@@ -29,10 +29,12 @@ def get_data(fname, folder='UCD'):
|
|||||||
bn = os.path.basename(url)
|
bn = os.path.basename(url)
|
||||||
local = os.path.join('/tmp', bn)
|
local = os.path.join('/tmp', bn)
|
||||||
if os.path.exists(local):
|
if os.path.exists(local):
|
||||||
data = open(local, 'rb').read()
|
with open(local, 'rb') as f:
|
||||||
|
data = f.read()
|
||||||
else:
|
else:
|
||||||
data = urlopen(url).read()
|
data = urlopen(url).read()
|
||||||
open(local, 'wb').write(data)
|
with open(local, 'wb') as f:
|
||||||
|
f.write(data)
|
||||||
for line in data.decode('utf-8').splitlines():
|
for line in data.decode('utf-8').splitlines():
|
||||||
line = line.strip()
|
line = line.strip()
|
||||||
if line and not line.startswith('#'):
|
if line and not line.startswith('#'):
|
||||||
@@ -41,6 +43,7 @@ def get_data(fname, folder='UCD'):
|
|||||||
|
|
||||||
# Map of class names to set of codepoints in class
|
# Map of class names to set of codepoints in class
|
||||||
class_maps = {}
|
class_maps = {}
|
||||||
|
all_symbols = set()
|
||||||
name_map = {}
|
name_map = {}
|
||||||
word_search_map = defaultdict(set)
|
word_search_map = defaultdict(set)
|
||||||
zwj = 0x200d
|
zwj = 0x200d
|
||||||
@@ -87,6 +90,8 @@ def parse_ucd():
|
|||||||
not_assigned.discard(codepoint)
|
not_assigned.discard(codepoint)
|
||||||
if category.startswith('M'):
|
if category.startswith('M'):
|
||||||
marks.add(codepoint)
|
marks.add(codepoint)
|
||||||
|
elif category.startswith('S'):
|
||||||
|
all_symbols.add(codepoint)
|
||||||
|
|
||||||
# Some common synonyms
|
# Some common synonyms
|
||||||
word_search_map['bee'] |= word_search_map['honeybee']
|
word_search_map['bee'] |= word_search_map['honeybee']
|
||||||
@@ -166,21 +171,20 @@ def write_case(spec, p):
|
|||||||
|
|
||||||
@contextmanager
|
@contextmanager
|
||||||
def create_header(path, include_data_types=True):
|
def create_header(path, include_data_types=True):
|
||||||
f = open(path, 'w')
|
with open(path, 'w') as f:
|
||||||
p = partial(print, file=f)
|
p = partial(print, file=f)
|
||||||
p('// unicode data, built from the unicode standard on:', date.today())
|
p('// unicode data, built from the unicode standard on:', date.today())
|
||||||
p('// see gen-wcwidth.py')
|
p('// see gen-wcwidth.py')
|
||||||
if path.endswith('.h'):
|
if path.endswith('.h'):
|
||||||
p('#pragma once')
|
p('#pragma once')
|
||||||
if include_data_types:
|
if include_data_types:
|
||||||
p('#include "data-types.h"\n')
|
p('#include "data-types.h"\n')
|
||||||
p('START_ALLOW_CASE_RANGE')
|
p('START_ALLOW_CASE_RANGE')
|
||||||
p()
|
p()
|
||||||
yield p
|
yield p
|
||||||
p()
|
p()
|
||||||
if include_data_types:
|
if include_data_types:
|
||||||
p('END_ALLOW_CASE_RANGE')
|
p('END_ALLOW_CASE_RANGE')
|
||||||
f.close()
|
|
||||||
|
|
||||||
|
|
||||||
def gen_emoji():
|
def gen_emoji():
|
||||||
@@ -193,6 +197,7 @@ def gen_emoji():
|
|||||||
p('\t\tdefault: return false;')
|
p('\t\tdefault: return false;')
|
||||||
p('\t}')
|
p('\t}')
|
||||||
p('\treturn false;\n}')
|
p('\treturn false;\n}')
|
||||||
|
|
||||||
p('static inline bool\nis_emoji_modifier(char_type code) {')
|
p('static inline bool\nis_emoji_modifier(char_type code) {')
|
||||||
p('\tswitch(code) {')
|
p('\tswitch(code) {')
|
||||||
for spec in get_ranges(list(emoji_categories['Emoji_Modifier'])):
|
for spec in get_ranges(list(emoji_categories['Emoji_Modifier'])):
|
||||||
@@ -202,6 +207,15 @@ def gen_emoji():
|
|||||||
p('\t}')
|
p('\t}')
|
||||||
p('\treturn false;\n}')
|
p('\treturn false;\n}')
|
||||||
|
|
||||||
|
p('static inline bool\nis_symbol(char_type code) {')
|
||||||
|
p('\tswitch(code) {')
|
||||||
|
for spec in get_ranges(list(all_symbols)):
|
||||||
|
write_case(spec, p)
|
||||||
|
p('\t\t\treturn true;')
|
||||||
|
p('\t\tdefault: return false;')
|
||||||
|
p('\t}')
|
||||||
|
p('\treturn false;\n}')
|
||||||
|
|
||||||
|
|
||||||
def category_test(name, p, classes, comment, static=False, extra_chars=frozenset(), exclude=frozenset()):
|
def category_test(name, p, classes, comment, static=False, extra_chars=frozenset(), exclude=frozenset()):
|
||||||
static = 'static inline ' if static else ''
|
static = 'static inline ' if static else ''
|
||||||
@@ -282,7 +296,9 @@ def gen_ucd():
|
|||||||
p('combining_type mark_for_codepoint(char_type c) {')
|
p('combining_type mark_for_codepoint(char_type c) {')
|
||||||
rmap = codepoint_to_mark_map(p, mark_map)
|
rmap = codepoint_to_mark_map(p, mark_map)
|
||||||
p('}\n')
|
p('}\n')
|
||||||
expected = int(re.search(r'^#define VS15 (\d+)', open('kitty/unicode-data.h').read(), re.M).group(1))
|
with open('kitty/unicode-data.h') as f:
|
||||||
|
unicode_data = f.read()
|
||||||
|
expected = int(re.search(r'^#define VS15 (\d+)', unicode_data, re.M).group(1))
|
||||||
if rmap[0xfe0e] != expected:
|
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(
|
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]
|
rmap[0xfe0e], rmap[0xfe0f]
|
||||||
|
|||||||
53
glfw/backend_utils.c
vendored
53
glfw/backend_utils.c
vendored
@@ -22,19 +22,6 @@
|
|||||||
#define ppoll pollts
|
#define ppoll pollts
|
||||||
#endif
|
#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
|
void
|
||||||
update_fds(EventLoopData *eld) {
|
update_fds(EventLoopData *eld) {
|
||||||
for (nfds_t i = 0; i < eld->watches_count; i++) {
|
for (nfds_t i = 0; i < eld->watches_count; i++) {
|
||||||
@@ -109,7 +96,7 @@ update_timers(EventLoopData *eld) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
id_type
|
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])) {
|
if (eld->timers_count >= sizeof(eld->timers)/sizeof(eld->timers[0])) {
|
||||||
_glfwInputError(GLFW_PLATFORM_ERROR, "Too many timers added");
|
_glfwInputError(GLFW_PLATFORM_ERROR, "Too many timers added");
|
||||||
return 0;
|
return 0;
|
||||||
@@ -117,7 +104,7 @@ addTimer(EventLoopData *eld, const char *name, double interval, int enabled, boo
|
|||||||
Timer *t = eld->timers + eld->timers_count++;
|
Timer *t = eld->timers + eld->timers_count++;
|
||||||
t->interval = interval;
|
t->interval = interval;
|
||||||
t->name = name;
|
t->name = name;
|
||||||
t->trigger_at = enabled ? monotonic() + interval : DBL_MAX;
|
t->trigger_at = enabled ? monotonic() + interval : MONOTONIC_T_MAX;
|
||||||
t->repeats = repeats;
|
t->repeats = repeats;
|
||||||
t->callback = cb;
|
t->callback = cb;
|
||||||
t->callback_data = cb_data;
|
t->callback_data = cb_data;
|
||||||
@@ -144,7 +131,7 @@ void
|
|||||||
toggleTimer(EventLoopData *eld, id_type timer_id, int enabled) {
|
toggleTimer(EventLoopData *eld, id_type timer_id, int enabled) {
|
||||||
for (nfds_t i = 0; i < eld->timers_count; i++) {
|
for (nfds_t i = 0; i < eld->timers_count; i++) {
|
||||||
if (eld->timers[i].id == timer_id) {
|
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) {
|
if (trigger_at != eld->timers[i].trigger_at) {
|
||||||
eld->timers[i].trigger_at = trigger_at;
|
eld->timers[i].trigger_at = trigger_at;
|
||||||
update_timers(eld);
|
update_timers(eld);
|
||||||
@@ -155,7 +142,7 @@ toggleTimer(EventLoopData *eld, id_type timer_id, int enabled) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
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++) {
|
for (nfds_t i = 0; i < eld->timers_count; i++) {
|
||||||
if (eld->timers[i].id == timer_id) {
|
if (eld->timers[i].id == timer_id) {
|
||||||
eld->timers[i].interval = interval;
|
eld->timers[i].interval = interval;
|
||||||
@@ -165,22 +152,28 @@ changeTimerInterval(EventLoopData *eld, id_type timer_id, double interval) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
double
|
monotonic_t
|
||||||
prepareForPoll(EventLoopData *eld, double timeout) {
|
prepareForPoll(EventLoopData *eld, monotonic_t timeout) {
|
||||||
for (nfds_t i = 0; i < eld->watches_count; i++) eld->fds[i].revents = 0;
|
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;
|
if (!eld->timers_count || eld->timers[0].trigger_at == MONOTONIC_T_MAX) return timeout;
|
||||||
double now = monotonic(), next_repeat_at = eld->timers[0].trigger_at;
|
monotonic_t now = monotonic(), next_repeat_at = eld->timers[0].trigger_at;
|
||||||
if (timeout < 0 || now + timeout > next_repeat_at) {
|
if (timeout < 0 || now + timeout > next_repeat_at) {
|
||||||
timeout = next_repeat_at <= now ? 0 : next_repeat_at - now;
|
timeout = next_repeat_at <= now ? 0 : next_repeat_at - now;
|
||||||
}
|
}
|
||||||
return timeout;
|
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
|
int
|
||||||
pollWithTimeout(struct pollfd *fds, nfds_t nfds, double timeout) {
|
pollWithTimeout(struct pollfd *fds, nfds_t nfds, monotonic_t timeout) {
|
||||||
const long seconds = (long) timeout;
|
struct timespec tv = calc_time(timeout);
|
||||||
const long nanoseconds = (long) ((timeout - seconds) * 1e9);
|
|
||||||
struct timespec tv = { seconds, nanoseconds };
|
|
||||||
return ppoll(fds, nfds, &tv, NULL);
|
return ppoll(fds, nfds, &tv, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -198,10 +191,10 @@ dispatchEvents(EventLoopData *eld) {
|
|||||||
|
|
||||||
unsigned
|
unsigned
|
||||||
dispatchTimers(EventLoopData *eld) {
|
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])];
|
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;
|
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++) {
|
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;
|
eld->timers[i].trigger_at = now + eld->timers[i].interval;
|
||||||
dispatches[num_dispatches].func = eld->timers[i].callback;
|
dispatches[num_dispatches].func = eld->timers[i].callback;
|
||||||
@@ -299,12 +292,12 @@ finalizePollData(EventLoopData *eld) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
pollForEvents(EventLoopData *eld, double timeout) {
|
pollForEvents(EventLoopData *eld, monotonic_t timeout) {
|
||||||
int read_ok = 0;
|
int read_ok = 0;
|
||||||
timeout = prepareForPoll(eld, timeout);
|
timeout = prepareForPoll(eld, timeout);
|
||||||
EVDBG("pollForEvents final timeout: %.3f", timeout);
|
EVDBG("pollForEvents final timeout: %.3f", monotonic_t_to_s_double(timeout));
|
||||||
int result;
|
int result;
|
||||||
double end_time = monotonic() + timeout;
|
monotonic_t end_time = monotonic() + timeout;
|
||||||
eld->wakeup_fd_ready = false;
|
eld->wakeup_fd_ready = false;
|
||||||
|
|
||||||
while(1) {
|
while(1) {
|
||||||
|
|||||||
15
glfw/backend_utils.h
vendored
15
glfw/backend_utils.h
vendored
@@ -1,5 +1,5 @@
|
|||||||
//========================================================================
|
//========================================================================
|
||||||
// GLFW 3.3 Wayland - www.glfw.org
|
// GLFW 3.4 Wayland - www.glfw.org
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
// Copyright (c) 2014 Jonas Ådahl <jadahl@gmail.com>
|
// Copyright (c) 2014 Jonas Ådahl <jadahl@gmail.com>
|
||||||
//
|
//
|
||||||
@@ -25,6 +25,7 @@
|
|||||||
//========================================================================
|
//========================================================================
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
#include "../kitty/monotonic.h"
|
||||||
#include <poll.h>
|
#include <poll.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
@@ -55,7 +56,7 @@ typedef struct {
|
|||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
id_type id;
|
id_type id;
|
||||||
double interval, trigger_at;
|
monotonic_t interval, trigger_at;
|
||||||
timer_callback_func callback;
|
timer_callback_func callback;
|
||||||
void *callback_data;
|
void *callback_data;
|
||||||
GLFWuserdatafreefun free;
|
GLFWuserdatafreefun free;
|
||||||
@@ -82,14 +83,14 @@ void check_for_wakeup_events(EventLoopData *eld);
|
|||||||
id_type addWatch(EventLoopData *eld, const char *name, int fd, int events, int enabled, watch_callback_func cb, void *cb_data);
|
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 removeWatch(EventLoopData *eld, id_type watch_id);
|
||||||
void toggleWatch(EventLoopData *eld, id_type watch_id, int enabled);
|
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 removeTimer(EventLoopData *eld, id_type timer_id);
|
||||||
void removeAllTimers(EventLoopData *eld);
|
void removeAllTimers(EventLoopData *eld);
|
||||||
void toggleTimer(EventLoopData *eld, id_type timer_id, int enabled);
|
void toggleTimer(EventLoopData *eld, id_type timer_id, int enabled);
|
||||||
void changeTimerInterval(EventLoopData *eld, id_type timer_id, double interval);
|
void changeTimerInterval(EventLoopData *eld, id_type timer_id, monotonic_t interval);
|
||||||
double prepareForPoll(EventLoopData *eld, double timeout);
|
monotonic_t prepareForPoll(EventLoopData *eld, monotonic_t timeout);
|
||||||
int pollWithTimeout(struct pollfd *fds, nfds_t nfds, double timeout);
|
int pollWithTimeout(struct pollfd *fds, nfds_t nfds, monotonic_t timeout);
|
||||||
int pollForEvents(EventLoopData *eld, double timeout);
|
int pollForEvents(EventLoopData *eld, monotonic_t timeout);
|
||||||
unsigned dispatchTimers(EventLoopData *eld);
|
unsigned dispatchTimers(EventLoopData *eld);
|
||||||
void finalizePollData(EventLoopData *eld);
|
void finalizePollData(EventLoopData *eld);
|
||||||
bool initPollData(EventLoopData *eld, int display_fd);
|
bool initPollData(EventLoopData *eld, int display_fd);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
//========================================================================
|
//========================================================================
|
||||||
// GLFW 3.3 macOS - www.glfw.org
|
// GLFW 3.4 macOS - www.glfw.org
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
// Copyright (c) 2009-2019 Camilla Löwy <elmindreda@glfw.org>
|
// Copyright (c) 2009-2019 Camilla Löwy <elmindreda@glfw.org>
|
||||||
//
|
//
|
||||||
@@ -27,9 +27,13 @@
|
|||||||
//========================================================================
|
//========================================================================
|
||||||
|
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
|
#include "../kitty/monotonic.h"
|
||||||
#include <sys/param.h> // For MAXPATHLEN
|
#include <sys/param.h> // For MAXPATHLEN
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
|
|
||||||
|
// Needed for _NSGetProgname
|
||||||
|
#include <crt_externs.h>
|
||||||
|
|
||||||
// Change to our application bundle's resources directory, if present
|
// Change to our application bundle's resources directory, if present
|
||||||
//
|
//
|
||||||
static void changeToResourcesDirectory(void)
|
static void changeToResourcesDirectory(void)
|
||||||
@@ -66,14 +70,119 @@ static void changeToResourcesDirectory(void)
|
|||||||
chdir(resourcesPath);
|
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
|
// Create key code translation tables
|
||||||
//
|
//
|
||||||
static void createKeyTables(void)
|
static void createKeyTables(void)
|
||||||
{
|
{
|
||||||
int scancode;
|
int keycode;
|
||||||
|
|
||||||
memset(_glfw.ns.keycodes, -1, sizeof(_glfw.ns.keycodes));
|
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[0x1D] = GLFW_KEY_0;
|
||||||
_glfw.ns.keycodes[0x12] = GLFW_KEY_1;
|
_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[0x43] = GLFW_KEY_KP_MULTIPLY;
|
||||||
_glfw.ns.keycodes[0x4E] = GLFW_KEY_KP_SUBTRACT;
|
_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
|
// Store the reverse translation for faster key name lookup
|
||||||
if (_glfw.ns.keycodes[scancode] >= 0)
|
if (_glfw.ns.keycodes[keycode] >= 0)
|
||||||
_glfw.ns.scancodes[_glfw.ns.keycodes[scancode]] = scancode;
|
_glfw.ns.key_to_keycode[_glfw.ns.keycodes[keycode]] = keycode;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -276,6 +385,17 @@ static bool initializeTIS(void)
|
|||||||
return updateUnicodeDataNS();
|
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
|
@interface GLFWHelper : NSObject
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@@ -294,6 +414,102 @@ static bool initializeTIS(void)
|
|||||||
|
|
||||||
@end // GLFWHelper
|
@end // GLFWHelper
|
||||||
|
|
||||||
|
// Delegate for application related notifications {{{
|
||||||
|
|
||||||
|
@interface GLFWApplicationDelegate : NSObject <NSApplicationDelegate>
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation GLFWApplicationDelegate
|
||||||
|
|
||||||
|
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
|
||||||
|
{
|
||||||
|
(void)sender;
|
||||||
|
_GLFWwindow* window;
|
||||||
|
|
||||||
|
for (window = _glfw.windowListHead; window; window = window->next)
|
||||||
|
_glfwInputWindowCloseRequest(window);
|
||||||
|
|
||||||
|
return NSTerminateCancel;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GLFWapplicationshouldhandlereopenfun handle_reopen_callback = NULL;
|
||||||
|
|
||||||
|
- (BOOL)applicationShouldHandleReopen:(NSApplication *)sender hasVisibleWindows:(BOOL)flag
|
||||||
|
{
|
||||||
|
(void)sender;
|
||||||
|
if (!handle_reopen_callback) return YES;
|
||||||
|
if (handle_reopen_callback(flag)) return YES;
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)applicationDidChangeScreenParameters:(NSNotification *) notification
|
||||||
|
{
|
||||||
|
(void)notification;
|
||||||
|
_GLFWwindow* window;
|
||||||
|
|
||||||
|
for (window = _glfw.windowListHead; window; window = window->next)
|
||||||
|
{
|
||||||
|
if (window->context.client != GLFW_NO_API)
|
||||||
|
[window->context.nsgl.object update];
|
||||||
|
}
|
||||||
|
|
||||||
|
_glfwPollMonitorsNS();
|
||||||
|
}
|
||||||
|
|
||||||
|
static GLFWapplicationwillfinishlaunchingfun finish_launching_callback = NULL;
|
||||||
|
|
||||||
|
- (void)applicationWillFinishLaunching:(NSNotification *)notification
|
||||||
|
{
|
||||||
|
(void)notification;
|
||||||
|
if (_glfw.hints.init.ns.menubar)
|
||||||
|
{
|
||||||
|
// In case we are unbundled, make us a proper UI application
|
||||||
|
[NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
|
||||||
|
|
||||||
|
// Menu bar setup must go between sharedApplication 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
|
@interface GLFWApplication : NSApplication
|
||||||
- (void)tick_callback;
|
- (void)tick_callback;
|
||||||
- (void)render_frame_received:(id)displayIDAsID;
|
- (void)render_frame_received:(id)displayIDAsID;
|
||||||
@@ -335,6 +551,18 @@ is_cmd_period(NSEvent *event, NSEventModifierFlags modifierFlags) {
|
|||||||
return false;
|
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)
|
int _glfwPlatformInit(void)
|
||||||
{
|
{
|
||||||
@autoreleasepool {
|
@autoreleasepool {
|
||||||
@@ -345,8 +573,21 @@ int _glfwPlatformInit(void)
|
|||||||
toTarget:_glfw.ns.helper
|
toTarget:_glfw.ns.helper
|
||||||
withObject:nil];
|
withObject:nil];
|
||||||
|
|
||||||
|
if (NSApp)
|
||||||
|
_glfw.ns.finishedLaunching = true;
|
||||||
|
|
||||||
[GLFWApplication sharedApplication];
|
[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)
|
NSEvent* (^keydown_block)(NSEvent*) = ^ NSEvent* (NSEvent* event)
|
||||||
{
|
{
|
||||||
NSEventModifierFlags modifierFlags = [event modifierFlags] & NSEventModifierFlagDeviceIndependentFlagsMask;
|
NSEventModifierFlags modifierFlags = [event modifierFlags] & NSEventModifierFlagDeviceIndependentFlagsMask;
|
||||||
@@ -385,6 +626,10 @@ int _glfwPlatformInit(void)
|
|||||||
if (_glfw.hints.init.ns.chdir)
|
if (_glfw.hints.init.ns.chdir)
|
||||||
changeToResourcesDirectory();
|
changeToResourcesDirectory();
|
||||||
|
|
||||||
|
// Press and Hold prevents some keys from emitting repeated characters
|
||||||
|
NSDictionary* defaults = @{@"ApplePressAndHoldEnabled":@NO};
|
||||||
|
[[NSUserDefaults standardUserDefaults] registerDefaults:defaults];
|
||||||
|
|
||||||
[[NSNotificationCenter defaultCenter]
|
[[NSNotificationCenter defaultCenter]
|
||||||
addObserver:_glfw.ns.helper
|
addObserver:_glfw.ns.helper
|
||||||
selector:@selector(selectedKeyboardInputSourceChanged:)
|
selector:@selector(selectedKeyboardInputSourceChanged:)
|
||||||
@@ -402,7 +647,6 @@ int _glfwPlatformInit(void)
|
|||||||
if (!initializeTIS())
|
if (!initializeTIS())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
_glfwInitTimerNS();
|
|
||||||
_glfwInitJoysticksNS();
|
_glfwInitJoysticksNS();
|
||||||
|
|
||||||
_glfwPollMonitorsNS();
|
_glfwPollMonitorsNS();
|
||||||
@@ -531,7 +775,7 @@ typedef struct {
|
|||||||
NSTimer *os_timer;
|
NSTimer *os_timer;
|
||||||
unsigned long long id;
|
unsigned long long id;
|
||||||
bool repeats;
|
bool repeats;
|
||||||
double interval;
|
monotonic_t interval;
|
||||||
GLFWuserdatafun callback;
|
GLFWuserdatafun callback;
|
||||||
void *callback_data;
|
void *callback_data;
|
||||||
GLFWuserdatafun free_callback_data;
|
GLFWuserdatafun free_callback_data;
|
||||||
@@ -551,7 +795,7 @@ remove_timer_at(size_t idx) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void schedule_timer(Timer *t) {
|
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++) {
|
for (size_t i = 0; i < num_timers; i++) {
|
||||||
if (timers[i].os_timer == os_timer) {
|
if (timers[i].os_timer == os_timer) {
|
||||||
timers[i].callback(timers[i].id, timers[i].callback_data);
|
timers[i].callback(timers[i].id, timers[i].callback_data);
|
||||||
@@ -562,7 +806,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;
|
static unsigned long long timer_counter = 0;
|
||||||
if (num_timers >= sizeof(timers)/sizeof(timers[0]) - 1) {
|
if (num_timers >= sizeof(timers)/sizeof(timers[0]) - 1) {
|
||||||
_glfwInputError(GLFW_PLATFORM_ERROR, "Too many timers added");
|
_glfwInputError(GLFW_PLATFORM_ERROR, "Too many timers added");
|
||||||
@@ -588,7 +832,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++) {
|
for (size_t i = 0; i < num_timers; i++) {
|
||||||
if (timers[i].id == timer_id) {
|
if (timers[i].id == timer_id) {
|
||||||
Timer *t = timers + i;
|
Timer *t = timers + i;
|
||||||
|
|||||||
2
glfw/cocoa_joystick.h
vendored
2
glfw/cocoa_joystick.h
vendored
@@ -1,5 +1,5 @@
|
|||||||
//========================================================================
|
//========================================================================
|
||||||
// GLFW 3.3 Cocoa - www.glfw.org
|
// GLFW 3.4 Cocoa - www.glfw.org
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
// Copyright (c) 2006-2017 Camilla Löwy <elmindreda@glfw.org>
|
// Copyright (c) 2006-2017 Camilla Löwy <elmindreda@glfw.org>
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
//========================================================================
|
//========================================================================
|
||||||
// GLFW 3.3 Cocoa - www.glfw.org
|
// GLFW 3.4 Cocoa - www.glfw.org
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
// Copyright (c) 2009-2019 Camilla Löwy <elmindreda@glfw.org>
|
// Copyright (c) 2009-2019 Camilla Löwy <elmindreda@glfw.org>
|
||||||
// Copyright (c) 2012 Torsten Walluhn <tw@mad-cad.net>
|
// Copyright (c) 2012 Torsten Walluhn <tw@mad-cad.net>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
//========================================================================
|
//========================================================================
|
||||||
// GLFW 3.3 macOS - www.glfw.org
|
// GLFW 3.4 macOS - www.glfw.org
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||||
// Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
|
// Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
|
||||||
@@ -328,7 +328,7 @@ void _glfwPollMonitorsNS(void)
|
|||||||
if (!name)
|
if (!name)
|
||||||
name = _glfw_strdup("Unknown");
|
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.displayID = displays[i];
|
||||||
monitor->ns.unitNumber = unitNumber;
|
monitor->ns.unitNumber = unitNumber;
|
||||||
createDisplayLink(monitor->ns.displayID);
|
createDisplayLink(monitor->ns.displayID);
|
||||||
@@ -354,8 +354,9 @@ void _glfwPollMonitorsNS(void)
|
|||||||
void _glfwSetVideoModeNS(_GLFWmonitor* monitor, const GLFWvidmode* desired)
|
void _glfwSetVideoModeNS(_GLFWmonitor* monitor, const GLFWvidmode* desired)
|
||||||
{
|
{
|
||||||
GLFWvidmode current;
|
GLFWvidmode current;
|
||||||
const GLFWvidmode* best = _glfwChooseVideoMode(monitor, desired);
|
|
||||||
_glfwPlatformGetVideoMode(monitor, ¤t);
|
_glfwPlatformGetVideoMode(monitor, ¤t);
|
||||||
|
|
||||||
|
const GLFWvidmode* best = _glfwChooseVideoMode(monitor, desired);
|
||||||
if (_glfwCompareVideoModes(¤t, best) == 0)
|
if (_glfwCompareVideoModes(¤t, best) == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -454,13 +455,13 @@ void _glfwPlatformGetMonitorWorkarea(_GLFWmonitor* monitor,
|
|||||||
const NSRect frameRect = [monitor->ns.screen visibleFrame];
|
const NSRect frameRect = [monitor->ns.screen visibleFrame];
|
||||||
|
|
||||||
if (xpos)
|
if (xpos)
|
||||||
*xpos = frameRect.origin.x;
|
*xpos = (int)frameRect.origin.x;
|
||||||
if (ypos)
|
if (ypos)
|
||||||
*ypos = _glfwTransformYNS(frameRect.origin.y + frameRect.size.height - 1);
|
*ypos = (int)_glfwTransformYNS(frameRect.origin.y + frameRect.size.height - 1);
|
||||||
if (width)
|
if (width)
|
||||||
*width = frameRect.size.width;
|
*width = (int)frameRect.size.width;
|
||||||
if (height)
|
if (height)
|
||||||
*height = frameRect.size.height;
|
*height = (int)frameRect.size.height;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -505,7 +506,6 @@ GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count)
|
|||||||
void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode *mode)
|
void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode *mode)
|
||||||
{
|
{
|
||||||
CVDisplayLinkRef link;
|
CVDisplayLinkRef link;
|
||||||
|
|
||||||
CVDisplayLinkCreateWithCGDisplay(monitor->ns.displayID, &link);
|
CVDisplayLinkCreateWithCGDisplay(monitor->ns.displayID, &link);
|
||||||
|
|
||||||
CGDisplayModeRef native = CGDisplayCopyDisplayMode(monitor->ns.displayID);
|
CGDisplayModeRef native = CGDisplayCopyDisplayMode(monitor->ns.displayID);
|
||||||
|
|||||||
18
glfw/cocoa_platform.h
vendored
18
glfw/cocoa_platform.h
vendored
@@ -1,5 +1,5 @@
|
|||||||
//========================================================================
|
//========================================================================
|
||||||
// GLFW 3.3 macOS - www.glfw.org
|
// GLFW 3.4 macOS - www.glfw.org
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
// Copyright (c) 2009-2019 Camilla Löwy <elmindreda@glfw.org>
|
// Copyright (c) 2009-2019 Camilla Löwy <elmindreda@glfw.org>
|
||||||
//
|
//
|
||||||
@@ -36,6 +36,9 @@ typedef void* id;
|
|||||||
typedef void* CVDisplayLinkRef;
|
typedef void* CVDisplayLinkRef;
|
||||||
#endif
|
#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
|
#if MAC_OS_X_VERSION_MAX_ALLOWED < 101200
|
||||||
#define NSBitmapFormatAlphaNonpremultiplied NSAlphaNonpremultipliedBitmapFormat
|
#define NSBitmapFormatAlphaNonpremultiplied NSAlphaNonpremultipliedBitmapFormat
|
||||||
#define NSEventMaskAny NSAnyEventMask
|
#define NSEventMaskAny NSAnyEventMask
|
||||||
@@ -64,8 +67,9 @@ typedef void* CVDisplayLinkRef;
|
|||||||
|
|
||||||
typedef VkFlags VkMacOSSurfaceCreateFlagsMVK;
|
typedef VkFlags VkMacOSSurfaceCreateFlagsMVK;
|
||||||
typedef int (* GLFWcocoatextinputfilterfun)(int,int,unsigned int, unsigned long);
|
typedef int (* GLFWcocoatextinputfilterfun)(int,int,unsigned int, unsigned long);
|
||||||
typedef int (* GLFWapplicationshouldhandlereopenfun)(int);
|
typedef bool (* GLFWapplicationshouldhandlereopenfun)(int);
|
||||||
typedef int (* GLFWcocoatogglefullscreenfun)(GLFWwindow*);
|
typedef void (* GLFWapplicationwillfinishlaunchingfun)(void);
|
||||||
|
typedef bool (* GLFWcocoatogglefullscreenfun)(GLFWwindow*);
|
||||||
typedef void (* GLFWcocoarenderframefun)(GLFWwindow*);
|
typedef void (* GLFWcocoarenderframefun)(GLFWwindow*);
|
||||||
|
|
||||||
typedef struct VkMacOSSurfaceCreateInfoMVK
|
typedef struct VkMacOSSurfaceCreateInfoMVK
|
||||||
@@ -144,7 +148,7 @@ typedef struct _GLFWDisplayLinkNS
|
|||||||
{
|
{
|
||||||
CVDisplayLinkRef displayLink;
|
CVDisplayLinkRef displayLink;
|
||||||
CGDirectDisplayID displayID;
|
CGDirectDisplayID displayID;
|
||||||
double lastRenderFrameRequestedAt;
|
monotonic_t lastRenderFrameRequestedAt;
|
||||||
} _GLFWDisplayLinkNS;
|
} _GLFWDisplayLinkNS;
|
||||||
|
|
||||||
// Cocoa-specific global data
|
// Cocoa-specific global data
|
||||||
@@ -153,6 +157,7 @@ typedef struct _GLFWlibraryNS
|
|||||||
{
|
{
|
||||||
CGEventSourceRef eventSource;
|
CGEventSourceRef eventSource;
|
||||||
id delegate;
|
id delegate;
|
||||||
|
bool finishedLaunching;
|
||||||
bool cursorHidden;
|
bool cursorHidden;
|
||||||
TISInputSourceRef inputSource;
|
TISInputSourceRef inputSource;
|
||||||
IOHIDManagerRef hidManager;
|
IOHIDManagerRef hidManager;
|
||||||
@@ -160,11 +165,12 @@ typedef struct _GLFWlibraryNS
|
|||||||
id helper;
|
id helper;
|
||||||
id keyUpMonitor;
|
id keyUpMonitor;
|
||||||
id keyDownMonitor;
|
id keyDownMonitor;
|
||||||
|
id nibObjects;
|
||||||
|
|
||||||
char keyName[64];
|
char keyName[64];
|
||||||
char text[256];
|
char text[256];
|
||||||
short int keycodes[256];
|
short int keycodes[256];
|
||||||
short int scancodes[GLFW_KEY_LAST + 1];
|
short int key_to_keycode[GLFW_KEY_LAST + 1];
|
||||||
char* clipboardString;
|
char* clipboardString;
|
||||||
CGPoint cascadePoint;
|
CGPoint cascadePoint;
|
||||||
// Where to place the cursor when re-enabled
|
// Where to place the cursor when re-enabled
|
||||||
@@ -215,8 +221,6 @@ typedef struct _GLFWtimerNS
|
|||||||
} _GLFWtimerNS;
|
} _GLFWtimerNS;
|
||||||
|
|
||||||
|
|
||||||
void _glfwInitTimerNS(void);
|
|
||||||
|
|
||||||
void _glfwPollMonitorsNS(void);
|
void _glfwPollMonitorsNS(void);
|
||||||
void _glfwSetVideoModeNS(_GLFWmonitor* monitor, const GLFWvidmode* desired);
|
void _glfwSetVideoModeNS(_GLFWmonitor* monitor, const GLFWvidmode* desired);
|
||||||
void _glfwRestoreVideoModeNS(_GLFWmonitor* monitor);
|
void _glfwRestoreVideoModeNS(_GLFWmonitor* monitor);
|
||||||
|
|||||||
62
glfw/cocoa_time.c
vendored
62
glfw/cocoa_time.c
vendored
@@ -1,62 +0,0 @@
|
|||||||
//========================================================================
|
|
||||||
// GLFW 3.3 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
//========================================================================
|
//========================================================================
|
||||||
// GLFW 3.3 macOS - www.glfw.org
|
// GLFW 3.4 macOS - www.glfw.org
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
// Copyright (c) 2009-2019 Camilla Löwy <elmindreda@glfw.org>
|
// Copyright (c) 2009-2019 Camilla Löwy <elmindreda@glfw.org>
|
||||||
//
|
//
|
||||||
@@ -27,26 +27,78 @@
|
|||||||
//========================================================================
|
//========================================================================
|
||||||
|
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
|
#include "../kitty/monotonic.h"
|
||||||
|
|
||||||
#include <float.h>
|
#include <float.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
// Needed for _NSGetProgname
|
|
||||||
#include <crt_externs.h>
|
#define PARAGRAPH_UTF_8 0xc2a7 // §
|
||||||
|
#define MASCULINE_UTF_8 0xc2ba // º
|
||||||
|
#define A_DIAERESIS_UPPER_CASE_UTF_8 0xc384 // Ä
|
||||||
|
#define O_DIAERESIS_UPPER_CASE_UTF_8 0xc396 // Ö
|
||||||
|
#define U_DIAERESIS_UPPER_CASE_UTF_8 0xc39c // Ü
|
||||||
|
#define S_SHARP_UTF_8 0xc39f // ß
|
||||||
|
#define A_GRAVE_LOWER_CASE_UTF_8 0xc3a0 // à
|
||||||
|
#define A_DIAERESIS_LOWER_CASE_UTF_8 0xc3a4 // ä
|
||||||
|
#define A_RING_LOWER_CASE_UTF_8 0xc3a5 // å
|
||||||
|
#define AE_LOWER_CASE_UTF_8 0xc3a6 // æ
|
||||||
|
#define C_CEDILLA_LOWER_CASE_UTF_8 0xc3a7 // ç
|
||||||
|
#define E_GRAVE_LOWER_CASE_UTF_8 0xc3a8 // è
|
||||||
|
#define E_ACUTE_LOWER_CASE_UTF_8 0xc3a9 // é
|
||||||
|
#define I_GRAVE_LOWER_CASE_UTF_8 0xc3ac // ì
|
||||||
|
#define N_TILDE_LOWER_CASE_UTF_8 0xc3b1 // ñ
|
||||||
|
#define O_GRAVE_LOWER_CASE_UTF_8 0xc3b2 // ò
|
||||||
|
#define O_DIAERESIS_LOWER_CASE_UTF_8 0xc3b6 // ö
|
||||||
|
#define O_SLASH_LOWER_CASE_UTF_8 0xc3b8 // ø
|
||||||
|
#define U_GRAVE_LOWER_CASE_UTF_8 0xc3b9 // ù
|
||||||
|
#define U_DIAERESIS_LOWER_CASE_UTF_8 0xc3bc // ü
|
||||||
|
#define CYRILLIC_A_LOWER_CASE_UTF_8 0xd0b0 // а
|
||||||
|
#define CYRILLIC_BE_LOWER_CASE_UTF_8 0xd0b1 // б
|
||||||
|
#define CYRILLIC_VE_LOWER_CASE_UTF_8 0xd0b2 // в
|
||||||
|
#define CYRILLIC_GHE_LOWER_CASE_UTF_8 0xd0b3 // г
|
||||||
|
#define CYRILLIC_DE_LOWER_CASE_UTF_8 0xd0b4 // д
|
||||||
|
#define CYRILLIC_IE_LOWER_CASE_UTF_8 0xd0b5 // е
|
||||||
|
#define CYRILLIC_ZHE_LOWER_CASE_UTF_8 0xd0b6 // ж
|
||||||
|
#define CYRILLIC_ZE_LOWER_CASE_UTF_8 0xd0b7 // з
|
||||||
|
#define CYRILLIC_I_LOWER_CASE_UTF_8 0xd0b8 // и
|
||||||
|
#define CYRILLIC_SHORT_I_LOWER_CASE_UTF_8 0xd0b9 // й
|
||||||
|
#define CYRILLIC_KA_LOWER_CASE_UTF_8 0xd0ba // к
|
||||||
|
#define CYRILLIC_EL_LOWER_CASE_UTF_8 0xd0bb // л
|
||||||
|
#define CYRILLIC_EM_LOWER_CASE_UTF_8 0xd0bc // м
|
||||||
|
#define CYRILLIC_EN_LOWER_CASE_UTF_8 0xd0bd // н
|
||||||
|
#define CYRILLIC_O_LOWER_CASE_UTF_8 0xd0be // о
|
||||||
|
#define CYRILLIC_PE_LOWER_CASE_UTF_8 0xd0bf // п
|
||||||
|
#define CYRILLIC_ER_LOWER_CASE_UTF_8 0xd180 // р
|
||||||
|
#define CYRILLIC_ES_LOWER_CASE_UTF_8 0xd181 // с
|
||||||
|
#define CYRILLIC_TE_LOWER_CASE_UTF_8 0xd182 // т
|
||||||
|
#define CYRILLIC_U_LOWER_CASE_UTF_8 0xd183 // у
|
||||||
|
#define CYRILLIC_EF_LOWER_CASE_UTF_8 0xd184 // ф
|
||||||
|
#define CYRILLIC_HA_LOWER_CASE_UTF_8 0xd185 // х
|
||||||
|
#define CYRILLIC_TSE_LOWER_CASE_UTF_8 0xd186 // ц
|
||||||
|
#define CYRILLIC_CHE_LOWER_CASE_UTF_8 0xd187 // ч
|
||||||
|
#define CYRILLIC_SHA_LOWER_CASE_UTF_8 0xd188 // ш
|
||||||
|
#define CYRILLIC_SHCHA_LOWER_CASE_UTF_8 0xd189 // щ
|
||||||
|
#define CYRILLIC_HARD_SIGN_LOWER_CASE_UTF_8 0xd18a // ъ
|
||||||
|
#define CYRILLIC_YERU_LOWER_CASE_UTF_8 0xd18b // ы
|
||||||
|
#define CYRILLIC_SOFT_SIGN_LOWER_CASE_UTF_8 0xd18c // ь
|
||||||
|
#define CYRILLIC_E_LOWER_CASE_UTF_8 0xd18d // э
|
||||||
|
#define CYRILLIC_YU_LOWER_CASE_UTF_8 0xd18e // ю
|
||||||
|
#define CYRILLIC_YA_LOWER_CASE_UTF_8 0xd18f // я
|
||||||
|
#define CYRILLIC_IO_LOWER_CASE_UTF_8 0xd191 // ё
|
||||||
|
|
||||||
// Returns the style mask corresponding to the window settings
|
// Returns the style mask corresponding to the window settings
|
||||||
//
|
//
|
||||||
static NSUInteger getStyleMask(_GLFWwindow* window)
|
static NSUInteger getStyleMask(_GLFWwindow* window)
|
||||||
{
|
{
|
||||||
NSUInteger styleMask = 0;
|
NSUInteger styleMask = NSWindowStyleMaskMiniaturizable;
|
||||||
|
|
||||||
if (window->monitor || !window->decorated)
|
if (window->monitor || !window->decorated)
|
||||||
styleMask |= NSWindowStyleMaskBorderless;
|
styleMask |= NSWindowStyleMaskBorderless;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
styleMask |= NSWindowStyleMaskTitled |
|
styleMask |= NSWindowStyleMaskTitled |
|
||||||
NSWindowStyleMaskClosable |
|
NSWindowStyleMaskClosable;
|
||||||
NSWindowStyleMaskMiniaturizable;
|
|
||||||
|
|
||||||
if (window->resizable)
|
if (window->resizable)
|
||||||
styleMask |= NSWindowStyleMaskResizable;
|
styleMask |= NSWindowStyleMaskResizable;
|
||||||
@@ -65,7 +117,7 @@ CGDirectDisplayID displayIDForWindow(_GLFWwindow *w) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static unsigned long long display_link_shutdown_timer = 0;
|
static unsigned long long display_link_shutdown_timer = 0;
|
||||||
#define DISPLAY_LINK_SHUTDOWN_CHECK_INTERVAL 30
|
#define DISPLAY_LINK_SHUTDOWN_CHECK_INTERVAL s_to_monotonic_t(30ll)
|
||||||
|
|
||||||
void
|
void
|
||||||
_glfwShutdownCVDisplayLink(unsigned long long timer_id UNUSED, void *user_data UNUSED) {
|
_glfwShutdownCVDisplayLink(unsigned long long timer_id UNUSED, void *user_data UNUSED) {
|
||||||
@@ -92,7 +144,7 @@ requestRenderFrame(_GLFWwindow *w, GLFWcocoarenderframefun callback) {
|
|||||||
} else {
|
} else {
|
||||||
display_link_shutdown_timer = _glfwPlatformAddTimer(DISPLAY_LINK_SHUTDOWN_CHECK_INTERVAL, false, _glfwShutdownCVDisplayLink, NULL, NULL);
|
display_link_shutdown_timer = _glfwPlatformAddTimer(DISPLAY_LINK_SHUTDOWN_CHECK_INTERVAL, false, _glfwShutdownCVDisplayLink, NULL, NULL);
|
||||||
}
|
}
|
||||||
double now = glfwGetTime();
|
monotonic_t now = glfwGetTime();
|
||||||
for (size_t i = 0; i < _glfw.ns.displayLinks.count; i++) {
|
for (size_t i = 0; i < _glfw.ns.displayLinks.count; i++) {
|
||||||
_GLFWDisplayLinkNS *dl = &_glfw.ns.displayLinks.entries[i];
|
_GLFWDisplayLinkNS *dl = &_glfw.ns.displayLinks.entries[i];
|
||||||
if (dl->displayID == displayID) {
|
if (dl->displayID == displayID) {
|
||||||
@@ -261,17 +313,21 @@ static inline const char*
|
|||||||
format_text(const char *src) {
|
format_text(const char *src) {
|
||||||
static char buf[256];
|
static char buf[256];
|
||||||
char *p = buf;
|
char *p = buf;
|
||||||
|
const char *last_char = buf + sizeof(buf) - 1;
|
||||||
if (!src[0]) return "<none>";
|
if (!src[0]) return "<none>";
|
||||||
while (*src) {
|
while (*src) {
|
||||||
p += snprintf(p, sizeof(buf) - (p - buf), "0x%x ", (unsigned char)*(src++));
|
int num = snprintf(p, sizeof(buf) - (p - buf), "0x%x ", (unsigned char)*(src++));
|
||||||
|
if (num < 0) return "<error>";
|
||||||
|
if (p + num >= last_char) break;
|
||||||
|
p += num;
|
||||||
}
|
}
|
||||||
if (p != buf) *(--p) = 0;
|
if (p != buf) *(--p) = 0;
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char*
|
static const char*
|
||||||
safe_name_for_scancode(unsigned int scancode) {
|
safe_name_for_keycode(unsigned int keycode) {
|
||||||
const char *ans = _glfwPlatformGetScancodeName(scancode);
|
const char *ans = _glfwPlatformGetNativeKeyName(keycode);
|
||||||
if (!ans) return "<noname>";
|
if (!ans) return "<noname>";
|
||||||
if ((1 <= ans[0] && ans[0] <= 31) || ans[0] == 127) ans = "<cc>";
|
if ((1 <= ans[0] && ans[0] <= 31) || ans[0] == 127) ans = "<cc>";
|
||||||
return ans;
|
return ans;
|
||||||
@@ -284,11 +340,47 @@ static int translateKey(unsigned int key, bool apply_keymap)
|
|||||||
{
|
{
|
||||||
if (apply_keymap) {
|
if (apply_keymap) {
|
||||||
// Look for the effective key name after applying any keyboard layouts/mappings
|
// Look for the effective key name after applying any keyboard layouts/mappings
|
||||||
const char *name = _glfwPlatformGetScancodeName(key);
|
const char *name_chars = _glfwPlatformGetNativeKeyName(key);
|
||||||
if (name && name[1] == 0) {
|
uint32_t name = 0;
|
||||||
// Single letter key name
|
if (name_chars) {
|
||||||
switch(name[0]) {
|
for (int i = 0; i < 4; i++) {
|
||||||
|
if (!name_chars[i]) break;
|
||||||
|
name <<= 8;
|
||||||
|
name |= (uint8_t)name_chars[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (name) {
|
||||||
|
// Key name
|
||||||
|
switch(name) {
|
||||||
#define K(ch, name) case ch: return GLFW_KEY_##name
|
#define K(ch, name) case ch: return GLFW_KEY_##name
|
||||||
|
K('!', EXCLAM);
|
||||||
|
K('"', DOUBLE_QUOTE);
|
||||||
|
K('#', NUMBER_SIGN);
|
||||||
|
K('$', DOLLAR);
|
||||||
|
K('&', AMPERSAND);
|
||||||
|
K('\'', APOSTROPHE);
|
||||||
|
K('(', PARENTHESIS_LEFT);
|
||||||
|
K(')', PARENTHESIS_RIGHT);
|
||||||
|
K('+', PLUS);
|
||||||
|
K(',', COMMA);
|
||||||
|
K('-', MINUS);
|
||||||
|
K('.', PERIOD);
|
||||||
|
K('/', SLASH);
|
||||||
|
K('0', 0);
|
||||||
|
K('1', 1);
|
||||||
|
K('2', 2);
|
||||||
|
K('3', 3);
|
||||||
|
K('5', 5);
|
||||||
|
K('6', 6);
|
||||||
|
K('7', 7);
|
||||||
|
K('8', 8);
|
||||||
|
K('9', 9);
|
||||||
|
K(':', COLON);
|
||||||
|
K(';', SEMICOLON);
|
||||||
|
K('<', LESS);
|
||||||
|
K('=', EQUAL);
|
||||||
|
K('>', GREATER);
|
||||||
|
K('@', AT);
|
||||||
K('A', A); K('a', A);
|
K('A', A); K('a', A);
|
||||||
K('B', B); K('b', B);
|
K('B', B); K('b', B);
|
||||||
K('C', C); K('c', C);
|
K('C', C); K('c', C);
|
||||||
@@ -315,28 +407,64 @@ static int translateKey(unsigned int key, bool apply_keymap)
|
|||||||
K('X', X); K('x', X);
|
K('X', X); K('x', X);
|
||||||
K('Y', Y); K('y', Y);
|
K('Y', Y); K('y', Y);
|
||||||
K('Z', Z); K('z', Z);
|
K('Z', Z); K('z', Z);
|
||||||
K('0', 0);
|
|
||||||
K('1', 1);
|
|
||||||
K('2', 2);
|
|
||||||
K('3', 3);
|
|
||||||
K('5', 5);
|
|
||||||
K('6', 6);
|
|
||||||
K('7', 7);
|
|
||||||
K('8', 8);
|
|
||||||
K('9', 9);
|
|
||||||
K('\'', APOSTROPHE);
|
|
||||||
K(',', COMMA);
|
|
||||||
K('.', PERIOD);
|
|
||||||
K('/', SLASH);
|
|
||||||
K('-', MINUS);
|
|
||||||
K('=', EQUAL);
|
|
||||||
K(';', SEMICOLON);
|
|
||||||
K('[', LEFT_BRACKET);
|
K('[', LEFT_BRACKET);
|
||||||
|
K('\\', BACKSLASH);
|
||||||
K(']', RIGHT_BRACKET);
|
K(']', RIGHT_BRACKET);
|
||||||
K('+', PLUS);
|
|
||||||
K('_', UNDERSCORE);
|
K('_', UNDERSCORE);
|
||||||
K('`', GRAVE_ACCENT);
|
K('`', GRAVE_ACCENT);
|
||||||
K('\\', BACKSLASH);
|
K(PARAGRAPH_UTF_8, PARAGRAPH);
|
||||||
|
K(MASCULINE_UTF_8, MASCULINE);
|
||||||
|
K(A_DIAERESIS_UPPER_CASE_UTF_8, A_DIAERESIS);
|
||||||
|
K(O_DIAERESIS_UPPER_CASE_UTF_8, O_DIAERESIS);
|
||||||
|
K(U_DIAERESIS_UPPER_CASE_UTF_8, U_DIAERESIS);
|
||||||
|
K(S_SHARP_UTF_8, S_SHARP);
|
||||||
|
K(A_GRAVE_LOWER_CASE_UTF_8, A_GRAVE);
|
||||||
|
K(A_DIAERESIS_LOWER_CASE_UTF_8, A_DIAERESIS);
|
||||||
|
K(A_RING_LOWER_CASE_UTF_8, A_RING);
|
||||||
|
K(AE_LOWER_CASE_UTF_8, AE);
|
||||||
|
K(C_CEDILLA_LOWER_CASE_UTF_8, C_CEDILLA);
|
||||||
|
K(E_GRAVE_LOWER_CASE_UTF_8, E_GRAVE);
|
||||||
|
K(E_ACUTE_LOWER_CASE_UTF_8, E_ACUTE);
|
||||||
|
K(I_GRAVE_LOWER_CASE_UTF_8, I_GRAVE);
|
||||||
|
K(N_TILDE_LOWER_CASE_UTF_8, N_TILDE);
|
||||||
|
K(O_GRAVE_LOWER_CASE_UTF_8, O_GRAVE);
|
||||||
|
K(O_DIAERESIS_LOWER_CASE_UTF_8, O_DIAERESIS);
|
||||||
|
K(O_SLASH_LOWER_CASE_UTF_8, O_SLASH);
|
||||||
|
K(U_GRAVE_LOWER_CASE_UTF_8, U_GRAVE);
|
||||||
|
K(U_DIAERESIS_LOWER_CASE_UTF_8, U_DIAERESIS);
|
||||||
|
K(CYRILLIC_A_LOWER_CASE_UTF_8, CYRILLIC_A);
|
||||||
|
K(CYRILLIC_BE_LOWER_CASE_UTF_8, CYRILLIC_BE);
|
||||||
|
K(CYRILLIC_VE_LOWER_CASE_UTF_8, CYRILLIC_VE);
|
||||||
|
K(CYRILLIC_GHE_LOWER_CASE_UTF_8, CYRILLIC_GHE);
|
||||||
|
K(CYRILLIC_DE_LOWER_CASE_UTF_8, CYRILLIC_DE);
|
||||||
|
K(CYRILLIC_IE_LOWER_CASE_UTF_8, CYRILLIC_IE);
|
||||||
|
K(CYRILLIC_ZHE_LOWER_CASE_UTF_8, CYRILLIC_ZHE);
|
||||||
|
K(CYRILLIC_ZE_LOWER_CASE_UTF_8, CYRILLIC_ZE);
|
||||||
|
K(CYRILLIC_I_LOWER_CASE_UTF_8, CYRILLIC_I);
|
||||||
|
K(CYRILLIC_SHORT_I_LOWER_CASE_UTF_8, CYRILLIC_SHORT_I);
|
||||||
|
K(CYRILLIC_KA_LOWER_CASE_UTF_8, CYRILLIC_KA);
|
||||||
|
K(CYRILLIC_EL_LOWER_CASE_UTF_8, CYRILLIC_EL);
|
||||||
|
K(CYRILLIC_EM_LOWER_CASE_UTF_8, CYRILLIC_EM);
|
||||||
|
K(CYRILLIC_EN_LOWER_CASE_UTF_8, CYRILLIC_EN);
|
||||||
|
K(CYRILLIC_O_LOWER_CASE_UTF_8, CYRILLIC_O);
|
||||||
|
K(CYRILLIC_PE_LOWER_CASE_UTF_8, CYRILLIC_PE);
|
||||||
|
K(CYRILLIC_ER_LOWER_CASE_UTF_8, CYRILLIC_ER);
|
||||||
|
K(CYRILLIC_ES_LOWER_CASE_UTF_8, CYRILLIC_ES);
|
||||||
|
K(CYRILLIC_TE_LOWER_CASE_UTF_8, CYRILLIC_TE);
|
||||||
|
K(CYRILLIC_U_LOWER_CASE_UTF_8, CYRILLIC_U);
|
||||||
|
K(CYRILLIC_EF_LOWER_CASE_UTF_8, CYRILLIC_EF);
|
||||||
|
K(CYRILLIC_HA_LOWER_CASE_UTF_8, CYRILLIC_HA);
|
||||||
|
K(CYRILLIC_TSE_LOWER_CASE_UTF_8, CYRILLIC_TSE);
|
||||||
|
K(CYRILLIC_CHE_LOWER_CASE_UTF_8, CYRILLIC_CHE);
|
||||||
|
K(CYRILLIC_SHA_LOWER_CASE_UTF_8, CYRILLIC_SHA);
|
||||||
|
K(CYRILLIC_SHCHA_LOWER_CASE_UTF_8, CYRILLIC_SHCHA);
|
||||||
|
K(CYRILLIC_HARD_SIGN_LOWER_CASE_UTF_8, CYRILLIC_HARD_SIGN);
|
||||||
|
K(CYRILLIC_YERU_LOWER_CASE_UTF_8, CYRILLIC_YERU);
|
||||||
|
K(CYRILLIC_SOFT_SIGN_LOWER_CASE_UTF_8, CYRILLIC_SOFT_SIGN);
|
||||||
|
K(CYRILLIC_E_LOWER_CASE_UTF_8, CYRILLIC_E);
|
||||||
|
K(CYRILLIC_YU_LOWER_CASE_UTF_8, CYRILLIC_YU);
|
||||||
|
K(CYRILLIC_YA_LOWER_CASE_UTF_8, CYRILLIC_YA);
|
||||||
|
K(CYRILLIC_IO_LOWER_CASE_UTF_8, CYRILLIC_IO);
|
||||||
#undef K
|
#undef K
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@@ -349,17 +477,6 @@ static int translateKey(unsigned int key, bool apply_keymap)
|
|||||||
return _glfw.ns.keycodes[key];
|
return _glfw.ns.keycodes[key];
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
display_reconfigured(CGDirectDisplayID display UNUSED, CGDisplayChangeSummaryFlags flags, void *userInfo UNUSED)
|
|
||||||
{
|
|
||||||
if (flags & kCGDisplayBeginConfigurationFlag) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (flags & kCGDisplaySetModeFlag) {
|
|
||||||
// GPU possibly changed
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Translate a GLFW keycode to a Cocoa modifier flag
|
// Translate a GLFW keycode to a Cocoa modifier flag
|
||||||
//
|
//
|
||||||
static NSUInteger translateKeyToModifierFlag(int key)
|
static NSUInteger translateKeyToModifierFlag(int key)
|
||||||
@@ -441,17 +558,17 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
|
|||||||
if (fbRect.size.width != window->ns.fbWidth ||
|
if (fbRect.size.width != window->ns.fbWidth ||
|
||||||
fbRect.size.height != window->ns.fbHeight)
|
fbRect.size.height != window->ns.fbHeight)
|
||||||
{
|
{
|
||||||
window->ns.fbWidth = fbRect.size.width;
|
window->ns.fbWidth = (int)fbRect.size.width;
|
||||||
window->ns.fbHeight = fbRect.size.height;
|
window->ns.fbHeight = (int)fbRect.size.height;
|
||||||
_glfwInputFramebufferSize(window, fbRect.size.width, fbRect.size.height);
|
_glfwInputFramebufferSize(window, (int)fbRect.size.width, (int)fbRect.size.height);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (contentRect.size.width != window->ns.width ||
|
if (contentRect.size.width != window->ns.width ||
|
||||||
contentRect.size.height != window->ns.height)
|
contentRect.size.height != window->ns.height)
|
||||||
{
|
{
|
||||||
window->ns.width = contentRect.size.width;
|
window->ns.width = (int)contentRect.size.width;
|
||||||
window->ns.height = contentRect.size.height;
|
window->ns.height = (int)contentRect.size.height;
|
||||||
_glfwInputWindowSize(window, contentRect.size.width, contentRect.size.height);
|
_glfwInputWindowSize(window, (int)contentRect.size.width, (int)contentRect.size.height);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -530,77 +647,8 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@end // }}}
|
@end // }}}
|
||||||
|
|
||||||
// Delegate for application related notifications {{{
|
|
||||||
|
|
||||||
@interface GLFWApplicationDelegate : NSObject
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation GLFWApplicationDelegate
|
|
||||||
|
|
||||||
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
|
|
||||||
{
|
|
||||||
(void)sender;
|
|
||||||
_GLFWwindow* window;
|
|
||||||
|
|
||||||
for (window = _glfw.windowListHead; window; window = window->next)
|
|
||||||
_glfwInputWindowCloseRequest(window);
|
|
||||||
|
|
||||||
return NSTerminateCancel;
|
|
||||||
}
|
|
||||||
|
|
||||||
static GLFWapplicationshouldhandlereopenfun handle_reopen_callback = NULL;
|
|
||||||
|
|
||||||
- (BOOL)applicationShouldHandleReopen:(NSApplication *)sender hasVisibleWindows:(BOOL)flag
|
|
||||||
{
|
|
||||||
(void)sender;
|
|
||||||
if (!handle_reopen_callback) return YES;
|
|
||||||
if (handle_reopen_callback(flag)) return YES;
|
|
||||||
return NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)applicationDidChangeScreenParameters:(NSNotification *) notification
|
|
||||||
{
|
|
||||||
(void)notification;
|
|
||||||
_GLFWwindow* window;
|
|
||||||
|
|
||||||
for (window = _glfw.windowListHead; window; window = window->next)
|
|
||||||
{
|
|
||||||
if (window->context.client != GLFW_NO_API)
|
|
||||||
[window->context.nsgl.object update];
|
|
||||||
}
|
|
||||||
|
|
||||||
_glfwPollMonitorsNS();
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)applicationDidFinishLaunching:(NSNotification *)notification
|
|
||||||
{
|
|
||||||
(void)notification;
|
|
||||||
[NSApp stop:nil];
|
|
||||||
|
|
||||||
CGDisplayRegisterReconfigurationCallback(display_reconfigured, NULL);
|
|
||||||
_glfwCocoaPostEmptyEvent();
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)applicationWillTerminate:(NSNotification *)aNotification
|
|
||||||
{
|
|
||||||
(void)aNotification;
|
|
||||||
CGDisplayRemoveReconfigurationCallback(display_reconfigured, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)applicationDidHide:(NSNotification *)notification
|
|
||||||
{
|
|
||||||
(void)notification;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < _glfw.monitorCount; i++)
|
|
||||||
_glfwRestoreVideoModeNS(_glfw.monitors[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
// }}}
|
|
||||||
|
|
||||||
// Content view class for the GLFW window {{{
|
// Content view class for the GLFW window {{{
|
||||||
|
|
||||||
@@ -630,7 +678,7 @@ static GLFWapplicationshouldhandlereopenfun handle_reopen_callback = NULL;
|
|||||||
markedRect = NSMakeRect(0.0, 0.0, 0.0, 0.0);
|
markedRect = NSMakeRect(0.0, 0.0, 0.0, 0.0);
|
||||||
|
|
||||||
[self updateTrackingAreas];
|
[self updateTrackingAreas];
|
||||||
[self registerForDraggedTypes:@[NSPasteboardTypeFileURL]];
|
[self registerForDraggedTypes:@[NSPasteboardTypeFileURL, NSPasteboardTypeString]];
|
||||||
}
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
@@ -692,8 +740,8 @@ static GLFWapplicationshouldhandlereopenfun handle_reopen_callback = NULL;
|
|||||||
[window->context.nsgl.object update];
|
[window->context.nsgl.object update];
|
||||||
} @catch (NSException *e) {
|
} @catch (NSException *e) {
|
||||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
"Failed to update NSGL Context object with error: %s (%s)",
|
"Failed to update NSGL Context object with error: %s (%s)",
|
||||||
[[e name] UTF8String], [[e reason] UTF8String]);
|
[[e name] UTF8String], [[e reason] UTF8String]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -829,9 +877,9 @@ static GLFWapplicationshouldhandlereopenfun handle_reopen_callback = NULL;
|
|||||||
if (fbRect.size.width != window->ns.fbWidth ||
|
if (fbRect.size.width != window->ns.fbWidth ||
|
||||||
fbRect.size.height != window->ns.fbHeight)
|
fbRect.size.height != window->ns.fbHeight)
|
||||||
{
|
{
|
||||||
window->ns.fbWidth = fbRect.size.width;
|
window->ns.fbWidth = (int)fbRect.size.width;
|
||||||
window->ns.fbHeight = fbRect.size.height;
|
window->ns.fbHeight = (int)fbRect.size.height;
|
||||||
_glfwInputFramebufferSize(window, fbRect.size.width, fbRect.size.height);
|
_glfwInputFramebufferSize(window, (int)fbRect.size.width, (int)fbRect.size.height);
|
||||||
}
|
}
|
||||||
|
|
||||||
const float xscale = fbRect.size.width / contentRect.size.width;
|
const float xscale = fbRect.size.width / contentRect.size.width;
|
||||||
@@ -916,14 +964,16 @@ is_ascii_control_char(char x) {
|
|||||||
|
|
||||||
- (void)keyDown:(NSEvent *)event
|
- (void)keyDown:(NSEvent *)event
|
||||||
{
|
{
|
||||||
const unsigned int scancode = [event keyCode];
|
const unsigned int keycode = [event keyCode];
|
||||||
const NSUInteger flags = [event modifierFlags];
|
const NSUInteger flags = [event modifierFlags];
|
||||||
const int mods = translateFlags(flags);
|
const int mods = translateFlags(flags);
|
||||||
const int key = translateKey(scancode, true);
|
const int key = translateKey(keycode, true);
|
||||||
const bool process_text = !window->ns.textInputFilterCallback || window->ns.textInputFilterCallback(key, mods, scancode, flags) != 1;
|
const bool process_text = !window->ns.textInputFilterCallback || window->ns.textInputFilterCallback(key, mods, keycode, flags) != 1;
|
||||||
const bool previous_has_marked_text = [self hasMarkedText];
|
const bool previous_has_marked_text = [self hasMarkedText];
|
||||||
[self unmarkText];
|
[self unmarkText];
|
||||||
_glfw.ns.text[0] = 0;
|
_glfw.ns.text[0] = 0;
|
||||||
|
GLFWkeyevent glfw_keyevent;
|
||||||
|
_glfwInitializeKeyEvent(&glfw_keyevent, key, keycode, GLFW_PRESS, mods);
|
||||||
if (!_glfw.ns.unicodeData) {
|
if (!_glfw.ns.unicodeData) {
|
||||||
// Using the cocoa API for key handling is disabled, as there is no
|
// Using the cocoa API for key handling is disabled, as there is no
|
||||||
// reliable way to handle dead keys using it. Only use it if the
|
// reliable way to handle dead keys using it. Only use it if the
|
||||||
@@ -938,7 +988,7 @@ is_ascii_control_char(char x) {
|
|||||||
const bool in_compose_sequence = window->ns.deadKeyState != 0;
|
const bool in_compose_sequence = window->ns.deadKeyState != 0;
|
||||||
if (UCKeyTranslate(
|
if (UCKeyTranslate(
|
||||||
[(NSData*) _glfw.ns.unicodeData bytes],
|
[(NSData*) _glfw.ns.unicodeData bytes],
|
||||||
scancode,
|
keycode,
|
||||||
kUCKeyActionDown,
|
kUCKeyActionDown,
|
||||||
convert_cocoa_to_carbon_modifiers(flags),
|
convert_cocoa_to_carbon_modifiers(flags),
|
||||||
LMGetKbdType(),
|
LMGetKbdType(),
|
||||||
@@ -948,49 +998,55 @@ is_ascii_control_char(char x) {
|
|||||||
&char_count,
|
&char_count,
|
||||||
text
|
text
|
||||||
) != noErr) {
|
) != noErr) {
|
||||||
debug_key(@"UCKeyTranslate failed for scancode: 0x%x (%s) %s\n",
|
debug_key(@"UCKeyTranslate failed for keycode: 0x%x (%@) %@\n",
|
||||||
scancode, safe_name_for_scancode(scancode), format_mods(mods));
|
keycode, @(safe_name_for_keycode(keycode)), @(format_mods(mods)));
|
||||||
window->ns.deadKeyState = 0;
|
window->ns.deadKeyState = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
debug_key(@"scancode: 0x%x (%s) %schar_count: %lu deadKeyState: %u repeat: %d",
|
debug_key(@"keycode: 0x%x (%@) %@char_count: %lu deadKeyState: %u repeat: %d",
|
||||||
scancode, safe_name_for_scancode(scancode), format_mods(mods), char_count, window->ns.deadKeyState, event.ARepeat);
|
keycode, @(safe_name_for_keycode(keycode)), @(format_mods(mods)), char_count, window->ns.deadKeyState, event.ARepeat);
|
||||||
if (process_text) {
|
if (process_text) {
|
||||||
// this will call insertText which will fill up _glfw.ns.text
|
// this will call insertText which will fill up _glfw.ns.text
|
||||||
[self interpretKeyEvents:[NSArray arrayWithObject:event]];
|
[self interpretKeyEvents:[NSArray arrayWithObject:event]];
|
||||||
} else {
|
} else {
|
||||||
window->ns.deadKeyState = 0;
|
window->ns.deadKeyState = 0;
|
||||||
}
|
}
|
||||||
if (window->ns.deadKeyState && (char_count == 0 || scancode == 0x75)) {
|
if (window->ns.deadKeyState && (char_count == 0 || keycode == 0x75)) {
|
||||||
// 0x75 is the delete key which needs to be ignored during a compose sequence
|
// 0x75 is the delete key which needs to be ignored during a compose sequence
|
||||||
debug_key(@"Sending pre-edit text for dead key (text: %s markedText: %@).\n", format_text(_glfw.ns.text), markedText);
|
debug_key(@"Sending pre-edit text for dead key (text: %@ markedText: %@).\n", @(format_text(_glfw.ns.text)), markedText);
|
||||||
_glfwInputKeyboard(window, key, scancode, GLFW_PRESS, mods,
|
glfw_keyevent.text = [[markedText string] UTF8String];
|
||||||
[[markedText string] UTF8String], 1); // update pre-edit text
|
glfw_keyevent.ime_state = 1;
|
||||||
|
_glfwInputKeyboard(window, &glfw_keyevent); // update pre-edit text
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (in_compose_sequence) {
|
if (in_compose_sequence) {
|
||||||
debug_key(@"Clearing pre-edit text at end of compose sequence\n");
|
debug_key(@"Clearing pre-edit text at end of compose sequence\n");
|
||||||
_glfwInputKeyboard(window, key, scancode, GLFW_PRESS, mods,
|
glfw_keyevent.text = NULL;
|
||||||
NULL, 1); // clear pre-edit text
|
glfw_keyevent.ime_state = 1;
|
||||||
|
_glfwInputKeyboard(window, &glfw_keyevent); // clear pre-edit text
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (is_ascii_control_char(_glfw.ns.text[0])) _glfw.ns.text[0] = 0; // don't send text for ascii control codes
|
if (is_ascii_control_char(_glfw.ns.text[0])) _glfw.ns.text[0] = 0; // don't send text for ascii control codes
|
||||||
debug_key(@"text: %s glfw_key: %s marked_text: %@\n",
|
debug_key(@"text: %@ glfw_key: %@ marked_text: %@\n",
|
||||||
format_text(_glfw.ns.text), _glfwGetKeyName(key), markedText);
|
@(format_text(_glfw.ns.text)), @(_glfwGetKeyName(key)), markedText);
|
||||||
if (!window->ns.deadKeyState) {
|
if (!window->ns.deadKeyState) {
|
||||||
if ([self hasMarkedText]) {
|
if ([self hasMarkedText]) {
|
||||||
_glfwInputKeyboard(window, key, scancode, GLFW_PRESS, mods,
|
glfw_keyevent.text = [[markedText string] UTF8String];
|
||||||
[[markedText string] UTF8String], 1); // update pre-edit text
|
glfw_keyevent.ime_state = 1;
|
||||||
|
_glfwInputKeyboard(window, &glfw_keyevent); // update pre-edit text
|
||||||
} else if (previous_has_marked_text) {
|
} else if (previous_has_marked_text) {
|
||||||
_glfwInputKeyboard(window, key, scancode, GLFW_PRESS, mods,
|
glfw_keyevent.text = NULL;
|
||||||
NULL, 1); // clear pre-edit text
|
glfw_keyevent.ime_state = 1;
|
||||||
|
_glfwInputKeyboard(window, &glfw_keyevent); // clear pre-edit text
|
||||||
}
|
}
|
||||||
if (([self hasMarkedText] || previous_has_marked_text) && !_glfw.ns.text[0]) {
|
if (([self hasMarkedText] || previous_has_marked_text) && !_glfw.ns.text[0]) {
|
||||||
// do not pass keys like BACKSPACE while there's pre-edit text, let IME handle it
|
// do not pass keys like BACKSPACE while there's pre-edit text, let IME handle it
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_glfwInputKeyboard(window, key, scancode, GLFW_PRESS, mods, _glfw.ns.text, 0);
|
glfw_keyevent.text = _glfw.ns.text;
|
||||||
|
glfw_keyevent.ime_state = 0;
|
||||||
|
_glfwInputKeyboard(window, &glfw_keyevent);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)flagsChanged:(NSEvent *)event
|
- (void)flagsChanged:(NSEvent *)event
|
||||||
@@ -1012,14 +1068,19 @@ is_ascii_control_char(char x) {
|
|||||||
else
|
else
|
||||||
action = GLFW_RELEASE;
|
action = GLFW_RELEASE;
|
||||||
|
|
||||||
_glfwInputKeyboard(window, key, [event keyCode], action, mods, "", 0);
|
GLFWkeyevent glfw_keyevent;
|
||||||
|
_glfwInitializeKeyEvent(&glfw_keyevent, key, [event keyCode], action, mods);
|
||||||
|
_glfwInputKeyboard(window, &glfw_keyevent);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)keyUp:(NSEvent *)event
|
- (void)keyUp:(NSEvent *)event
|
||||||
{
|
{
|
||||||
const int key = translateKey([event keyCode], true);
|
const int key = translateKey([event keyCode], true);
|
||||||
const int mods = translateFlags([event modifierFlags]);
|
const int mods = translateFlags([event modifierFlags]);
|
||||||
_glfwInputKeyboard(window, key, [event keyCode], GLFW_RELEASE, mods, "", 0);
|
|
||||||
|
GLFWkeyevent glfw_keyevent;
|
||||||
|
_glfwInitializeKeyEvent(&glfw_keyevent, key, [event keyCode], GLFW_RELEASE, mods);
|
||||||
|
_glfwInputKeyboard(window, &glfw_keyevent);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)scrollWheel:(NSEvent *)event
|
- (void)scrollWheel:(NSEvent *)event
|
||||||
@@ -1073,16 +1134,27 @@ is_ascii_control_char(char x) {
|
|||||||
|
|
||||||
NSPasteboard* pasteboard = [sender draggingPasteboard];
|
NSPasteboard* pasteboard = [sender draggingPasteboard];
|
||||||
NSDictionary* options = @{NSPasteboardURLReadingFileURLsOnlyKey:@YES};
|
NSDictionary* options = @{NSPasteboardURLReadingFileURLsOnlyKey:@YES};
|
||||||
NSArray* urls = [pasteboard readObjectsForClasses:@[[NSURL class]]
|
NSArray* objs = [pasteboard readObjectsForClasses:@[[NSURL class], [NSString class]]
|
||||||
options:options];
|
options:options];
|
||||||
if (!urls) return NO;
|
if (!objs) return NO;
|
||||||
const NSUInteger count = [urls count];
|
const NSUInteger count = [objs count];
|
||||||
if (count)
|
if (count)
|
||||||
{
|
{
|
||||||
char** paths = calloc(count, sizeof(char*));
|
char** paths = calloc(count, sizeof(char*));
|
||||||
|
|
||||||
for (NSUInteger i = 0; i < count; i++)
|
for (NSUInteger i = 0; i < count; i++)
|
||||||
paths[i] = _glfw_strdup([urls[i] fileSystemRepresentation]);
|
{
|
||||||
|
id obj = objs[i];
|
||||||
|
if ([obj isKindOfClass:[NSURL class]]) {
|
||||||
|
paths[i] = _glfw_strdup([obj fileSystemRepresentation]);
|
||||||
|
} else if ([obj isKindOfClass:[NSString class]]) {
|
||||||
|
paths[i] = _glfw_strdup([obj UTF8String]);
|
||||||
|
} else {
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"Cocoa: Object is neither a URL nor a string");
|
||||||
|
paths[i] = _glfw_strdup("");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_glfwInputDrop(window, (int) count, (const char**) paths);
|
_glfwInputDrop(window, (int) count, (const char**) paths);
|
||||||
|
|
||||||
@@ -1199,7 +1271,7 @@ void _glfwPlatformUpdateIMEState(_GLFWwindow *w, int which, int a, int b, int c,
|
|||||||
@end
|
@end
|
||||||
// }}}
|
// }}}
|
||||||
|
|
||||||
// GLFW Window class {{{
|
// GLFW window class {{{
|
||||||
|
|
||||||
@interface GLFWWindow : NSWindow {
|
@interface GLFWWindow : NSWindow {
|
||||||
_GLFWwindow* glfw_window;
|
_GLFWwindow* glfw_window;
|
||||||
@@ -1252,154 +1324,6 @@ void _glfwPlatformUpdateIMEState(_GLFWwindow *w, int which, int a, int b, int c,
|
|||||||
@end
|
@end
|
||||||
// }}}
|
// }}}
|
||||||
|
|
||||||
// Set up the menu bar (manually)
|
|
||||||
// This is nasty, nasty stuff -- calls to undocumented semi-private APIs that
|
|
||||||
// could go away at any moment, lots of stuff that really should be
|
|
||||||
// localize(d|able), etc. Add a nib to save us this horror.
|
|
||||||
//
|
|
||||||
static void createMenuBar(void)
|
|
||||||
{
|
|
||||||
size_t i;
|
|
||||||
NSString* appName = nil;
|
|
||||||
NSDictionary* bundleInfo = [[NSBundle mainBundle] infoDictionary];
|
|
||||||
NSString* nameKeys[] =
|
|
||||||
{
|
|
||||||
@"CFBundleDisplayName",
|
|
||||||
@"CFBundleName",
|
|
||||||
@"CFBundleExecutable",
|
|
||||||
};
|
|
||||||
|
|
||||||
// Try to figure out what the calling application is called
|
|
||||||
|
|
||||||
for (i = 0; i < sizeof(nameKeys) / sizeof(nameKeys[0]); i++)
|
|
||||||
{
|
|
||||||
id name = bundleInfo[nameKeys[i]];
|
|
||||||
if (name &&
|
|
||||||
[name isKindOfClass:[NSString class]] &&
|
|
||||||
![name isEqualToString:@""])
|
|
||||||
{
|
|
||||||
appName = name;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!appName)
|
|
||||||
{
|
|
||||||
char** progname = _NSGetProgname();
|
|
||||||
if (progname && *progname)
|
|
||||||
appName = @(*progname);
|
|
||||||
else
|
|
||||||
appName = @"GLFW Application";
|
|
||||||
}
|
|
||||||
|
|
||||||
NSMenu* bar = [[NSMenu alloc] init];
|
|
||||||
[NSApp setMainMenu:bar];
|
|
||||||
|
|
||||||
NSMenuItem* appMenuItem =
|
|
||||||
[bar addItemWithTitle:@"" action:NULL keyEquivalent:@""];
|
|
||||||
NSMenu* appMenu = [[NSMenu alloc] init];
|
|
||||||
[appMenuItem setSubmenu:appMenu];
|
|
||||||
|
|
||||||
[appMenu addItemWithTitle:[NSString stringWithFormat:@"About %@", appName]
|
|
||||||
action:@selector(orderFrontStandardAboutPanel:)
|
|
||||||
keyEquivalent:@""];
|
|
||||||
[appMenu addItem:[NSMenuItem separatorItem]];
|
|
||||||
NSMenu* servicesMenu = [[NSMenu alloc] init];
|
|
||||||
[NSApp setServicesMenu:servicesMenu];
|
|
||||||
[[appMenu addItemWithTitle:@"Services"
|
|
||||||
action:NULL
|
|
||||||
keyEquivalent:@""] setSubmenu:servicesMenu];
|
|
||||||
[servicesMenu release];
|
|
||||||
[appMenu addItem:[NSMenuItem separatorItem]];
|
|
||||||
[appMenu addItemWithTitle:[NSString stringWithFormat:@"Hide %@", appName]
|
|
||||||
action:@selector(hide:)
|
|
||||||
keyEquivalent:@"h"];
|
|
||||||
[[appMenu addItemWithTitle:@"Hide Others"
|
|
||||||
action:@selector(hideOtherApplications:)
|
|
||||||
keyEquivalent:@"h"]
|
|
||||||
setKeyEquivalentModifierMask:NSEventModifierFlagOption | NSEventModifierFlagCommand];
|
|
||||||
[appMenu addItemWithTitle:@"Show All"
|
|
||||||
action:@selector(unhideAllApplications:)
|
|
||||||
keyEquivalent:@""];
|
|
||||||
[appMenu addItem:[NSMenuItem separatorItem]];
|
|
||||||
[appMenu addItemWithTitle:[NSString stringWithFormat:@"Quit %@", appName]
|
|
||||||
action:@selector(terminate:)
|
|
||||||
keyEquivalent:@"q"];
|
|
||||||
|
|
||||||
NSMenuItem* windowMenuItem =
|
|
||||||
[bar addItemWithTitle:@"" action:NULL keyEquivalent:@""];
|
|
||||||
[bar release];
|
|
||||||
NSMenu* windowMenu = [[NSMenu alloc] initWithTitle:@"Window"];
|
|
||||||
[NSApp setWindowsMenu:windowMenu];
|
|
||||||
[windowMenuItem setSubmenu:windowMenu];
|
|
||||||
|
|
||||||
[windowMenu addItemWithTitle:@"Minimize"
|
|
||||||
action:@selector(performMiniaturize:)
|
|
||||||
keyEquivalent:@"m"];
|
|
||||||
[windowMenu addItemWithTitle:@"Zoom"
|
|
||||||
action:@selector(performZoom:)
|
|
||||||
keyEquivalent:@""];
|
|
||||||
[windowMenu addItem:[NSMenuItem separatorItem]];
|
|
||||||
[windowMenu addItemWithTitle:@"Bring All to Front"
|
|
||||||
action:@selector(arrangeInFront:)
|
|
||||||
keyEquivalent:@""];
|
|
||||||
|
|
||||||
// TODO: Make this appear at the bottom of the menu (for consistency)
|
|
||||||
[windowMenu addItem:[NSMenuItem separatorItem]];
|
|
||||||
[[windowMenu addItemWithTitle:@"Enter Full Screen"
|
|
||||||
action:@selector(toggleFullScreen:)
|
|
||||||
keyEquivalent:@"f"]
|
|
||||||
setKeyEquivalentModifierMask:NSEventModifierFlagControl | NSEventModifierFlagCommand];
|
|
||||||
|
|
||||||
// Prior to Snow Leopard, we need to use this oddly-named semi-private API
|
|
||||||
// to get the application menu working properly.
|
|
||||||
SEL setAppleMenuSelector = NSSelectorFromString(@"setAppleMenu:");
|
|
||||||
[NSApp performSelector:setAppleMenuSelector withObject:appMenu];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize the Cocoa Application Kit
|
|
||||||
//
|
|
||||||
static bool initializeAppKit(void)
|
|
||||||
{
|
|
||||||
if (_glfw.ns.delegate)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
// There can only be one application delegate, but we allocate it the
|
|
||||||
// first time a window is created to keep all window code in this file
|
|
||||||
_glfw.ns.delegate = [[GLFWApplicationDelegate alloc] init];
|
|
||||||
if (_glfw.ns.delegate == nil)
|
|
||||||
{
|
|
||||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
|
||||||
"Cocoa: Failed to create application delegate");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
[NSApp setDelegate:_glfw.ns.delegate];
|
|
||||||
|
|
||||||
if (_glfw.hints.init.ns.menubar)
|
|
||||||
{
|
|
||||||
// In case we are unbundled, make us a proper UI application
|
|
||||||
[NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
|
|
||||||
|
|
||||||
// Menu bar setup must go between sharedApplication above and
|
|
||||||
// finishLaunching below, in order to properly emulate the behavior
|
|
||||||
// of NSApplicationMain
|
|
||||||
|
|
||||||
// disabled by Kovid
|
|
||||||
/* if ([[NSBundle mainBundle] pathForResource:@"MainMenu" ofType:@"nib"]) */
|
|
||||||
/* [NSApp loadMainMenu]; */
|
|
||||||
/* else */
|
|
||||||
createMenuBar();
|
|
||||||
}
|
|
||||||
|
|
||||||
[NSApp run];
|
|
||||||
|
|
||||||
// Press and Hold prevents some keys from emitting repeated characters
|
|
||||||
NSDictionary* defaults = @{@"ApplePressAndHoldEnabled":@NO};
|
|
||||||
|
|
||||||
[[NSUserDefaults standardUserDefaults] registerDefaults:defaults];
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the Cocoa window
|
// Create the Cocoa window
|
||||||
//
|
//
|
||||||
@@ -1447,7 +1371,7 @@ static bool createNativeWindow(_GLFWwindow* window,
|
|||||||
[window->ns.object setLevel:NSMainMenuWindowLevel + 1];
|
[window->ns.object setLevel:NSMainMenuWindowLevel + 1];
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
[(NSWindow*)window->ns.object center];
|
[(NSWindow*) window->ns.object center];
|
||||||
_glfw.ns.cascadePoint =
|
_glfw.ns.cascadePoint =
|
||||||
NSPointToCGPoint([window->ns.object cascadeTopLeftFromPoint:
|
NSPointToCGPoint([window->ns.object cascadeTopLeftFromPoint:
|
||||||
NSPointFromCGPoint(_glfw.ns.cascadePoint)]);
|
NSPointFromCGPoint(_glfw.ns.cascadePoint)]);
|
||||||
@@ -1504,8 +1428,11 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window,
|
|||||||
const _GLFWfbconfig* fbconfig)
|
const _GLFWfbconfig* fbconfig)
|
||||||
{
|
{
|
||||||
window->ns.deadKeyState = 0;
|
window->ns.deadKeyState = 0;
|
||||||
if (!initializeAppKit())
|
if (!_glfw.ns.finishedLaunching)
|
||||||
return false;
|
{
|
||||||
|
[NSApp run];
|
||||||
|
_glfw.ns.finishedLaunching = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (!createNativeWindow(window, wndconfig, fbconfig))
|
if (!createNativeWindow(window, wndconfig, fbconfig))
|
||||||
return false;
|
return false;
|
||||||
@@ -1571,7 +1498,7 @@ void _glfwPlatformDestroyWindow(_GLFWwindow* window)
|
|||||||
window->ns.object = nil;
|
window->ns.object = nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformSetWindowTitle(_GLFWwindow* window UNUSED, const char *title)
|
void _glfwPlatformSetWindowTitle(_GLFWwindow* window UNUSED, const char* title)
|
||||||
{
|
{
|
||||||
NSString* string = @(title);
|
NSString* string = @(title);
|
||||||
[window->ns.object setTitle:string];
|
[window->ns.object setTitle:string];
|
||||||
@@ -1592,9 +1519,9 @@ void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos)
|
|||||||
[window->ns.object contentRectForFrameRect:[window->ns.object frame]];
|
[window->ns.object contentRectForFrameRect:[window->ns.object frame]];
|
||||||
|
|
||||||
if (xpos)
|
if (xpos)
|
||||||
*xpos = contentRect.origin.x;
|
*xpos = (int)contentRect.origin.x;
|
||||||
if (ypos)
|
if (ypos)
|
||||||
*ypos = _glfwTransformYNS(contentRect.origin.y + contentRect.size.height - 1);
|
*ypos = (int)_glfwTransformYNS(contentRect.origin.y + contentRect.size.height - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformSetWindowPos(_GLFWwindow* window, int x, int y)
|
void _glfwPlatformSetWindowPos(_GLFWwindow* window, int x, int y)
|
||||||
@@ -1610,9 +1537,9 @@ void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height)
|
|||||||
const NSRect contentRect = [window->ns.view frame];
|
const NSRect contentRect = [window->ns.view frame];
|
||||||
|
|
||||||
if (width)
|
if (width)
|
||||||
*width = contentRect.size.width;
|
*width = (int)contentRect.size.width;
|
||||||
if (height)
|
if (height)
|
||||||
*height = contentRect.size.height;
|
*height = (int)contentRect.size.height;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height)
|
void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height)
|
||||||
@@ -1623,7 +1550,14 @@ void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height)
|
|||||||
acquireMonitor(window);
|
acquireMonitor(window);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
[window->ns.object setContentSize:NSMakeSize(width, height)];
|
{
|
||||||
|
NSRect contentRect =
|
||||||
|
[window->ns.object contentRectForFrameRect:[window->ns.object frame]];
|
||||||
|
contentRect.origin.y += contentRect.size.height - height;
|
||||||
|
contentRect.size = NSMakeSize(width, height);
|
||||||
|
[window->ns.object setFrame:[window->ns.object frameRectForContentRect:contentRect]
|
||||||
|
display:YES];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window,
|
void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window,
|
||||||
@@ -1668,15 +1602,15 @@ void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window,
|
|||||||
const NSRect frameRect = [window->ns.object frameRectForContentRect:contentRect];
|
const NSRect frameRect = [window->ns.object frameRectForContentRect:contentRect];
|
||||||
|
|
||||||
if (left)
|
if (left)
|
||||||
*left = contentRect.origin.x - frameRect.origin.x;
|
*left = (int)(contentRect.origin.x - frameRect.origin.x);
|
||||||
if (top)
|
if (top)
|
||||||
*top = frameRect.origin.y + frameRect.size.height -
|
*top = (int)(frameRect.origin.y + frameRect.size.height -
|
||||||
contentRect.origin.y - contentRect.size.height;
|
contentRect.origin.y - contentRect.size.height);
|
||||||
if (right)
|
if (right)
|
||||||
*right = frameRect.origin.x + frameRect.size.width -
|
*right = (int)(frameRect.origin.x + frameRect.size.width -
|
||||||
contentRect.origin.x - contentRect.size.width;
|
contentRect.origin.x - contentRect.size.width);
|
||||||
if (bottom)
|
if (bottom)
|
||||||
*bottom = contentRect.origin.y - frameRect.origin.y;
|
*bottom = (int)(contentRect.origin.y - frameRect.origin.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformGetWindowContentScale(_GLFWwindow* window,
|
void _glfwPlatformGetWindowContentScale(_GLFWwindow* window,
|
||||||
@@ -1691,9 +1625,9 @@ void _glfwPlatformGetWindowContentScale(_GLFWwindow* window,
|
|||||||
*yscale = (float) (pixels.size.height / points.size.height);
|
*yscale = (float) (pixels.size.height / points.size.height);
|
||||||
}
|
}
|
||||||
|
|
||||||
double _glfwPlatformGetDoubleClickInterval(_GLFWwindow* window UNUSED)
|
monotonic_t _glfwPlatformGetDoubleClickInterval(_GLFWwindow* window UNUSED)
|
||||||
{
|
{
|
||||||
return [NSEvent doubleClickInterval];
|
return s_double_to_monotonic_t([NSEvent doubleClickInterval]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformIconifyWindow(_GLFWwindow* window)
|
void _glfwPlatformIconifyWindow(_GLFWwindow* window)
|
||||||
@@ -1961,14 +1895,14 @@ void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode UNUSED)
|
|||||||
updateCursorMode(window);
|
updateCursorMode(window);
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* _glfwPlatformGetScancodeName(int scancode)
|
const char* _glfwPlatformGetNativeKeyName(int keycode)
|
||||||
{
|
{
|
||||||
UInt32 deadKeyState = 0;
|
UInt32 deadKeyState = 0;
|
||||||
UniChar characters[8];
|
UniChar characters[8];
|
||||||
UniCharCount characterCount = 0;
|
UniCharCount characterCount = 0;
|
||||||
|
|
||||||
if (UCKeyTranslate([(NSData*) _glfw.ns.unicodeData bytes],
|
if (UCKeyTranslate([(NSData*) _glfw.ns.unicodeData bytes],
|
||||||
scancode,
|
keycode,
|
||||||
kUCKeyActionDisplay,
|
kUCKeyActionDisplay,
|
||||||
0,
|
0,
|
||||||
LMGetKbdType(),
|
LMGetKbdType(),
|
||||||
@@ -1988,9 +1922,9 @@ const char* _glfwPlatformGetScancodeName(int scancode)
|
|||||||
return _glfw.ns.keyName;
|
return _glfw.ns.keyName;
|
||||||
}
|
}
|
||||||
|
|
||||||
int _glfwPlatformGetKeyScancode(int key)
|
int _glfwPlatformGetNativeKeyForKey(int key)
|
||||||
{
|
{
|
||||||
return _glfw.ns.scancodes[key];
|
return _glfw.ns.key_to_keycode[key];
|
||||||
}
|
}
|
||||||
|
|
||||||
int _glfwPlatformCreateCursor(_GLFWcursor* cursor,
|
int _glfwPlatformCreateCursor(_GLFWcursor* cursor,
|
||||||
@@ -2240,12 +2174,6 @@ GLFWAPI GLFWcocoatogglefullscreenfun glfwSetCocoaToggleFullscreenIntercept(GLFWw
|
|||||||
return previous;
|
return previous;
|
||||||
}
|
}
|
||||||
|
|
||||||
GLFWAPI GLFWapplicationshouldhandlereopenfun glfwSetApplicationShouldHandleReopen(GLFWapplicationshouldhandlereopenfun callback) {
|
|
||||||
GLFWapplicationshouldhandlereopenfun previous = handle_reopen_callback;
|
|
||||||
handle_reopen_callback = callback;
|
|
||||||
return previous;
|
|
||||||
}
|
|
||||||
|
|
||||||
GLFWAPI void glfwCocoaRequestRenderFrame(GLFWwindow *w, GLFWcocoarenderframefun callback) {
|
GLFWAPI void glfwCocoaRequestRenderFrame(GLFWwindow *w, GLFWcocoarenderframefun callback) {
|
||||||
requestRenderFrame((_GLFWwindow*)w, callback);
|
requestRenderFrame((_GLFWwindow*)w, callback);
|
||||||
}
|
}
|
||||||
@@ -2268,6 +2196,39 @@ GLFWAPI void glfwGetCocoaKeyEquivalent(int glfw_key, int glfw_mods, unsigned sho
|
|||||||
START_ALLOW_CASE_RANGE
|
START_ALLOW_CASE_RANGE
|
||||||
switch(glfw_key) {
|
switch(glfw_key) {
|
||||||
#define K(ch, name) case GLFW_KEY_##name: *cocoa_key = ch; break;
|
#define K(ch, name) case GLFW_KEY_##name: *cocoa_key = ch; break;
|
||||||
|
K('!', EXCLAM);
|
||||||
|
K('"', DOUBLE_QUOTE);
|
||||||
|
K('#', NUMBER_SIGN);
|
||||||
|
K('$', DOLLAR);
|
||||||
|
K('&', AMPERSAND);
|
||||||
|
K('\'', APOSTROPHE);
|
||||||
|
K('(', PARENTHESIS_LEFT);
|
||||||
|
K(')', PARENTHESIS_RIGHT);
|
||||||
|
K('+', PLUS);
|
||||||
|
K(',', COMMA);
|
||||||
|
K('-', MINUS);
|
||||||
|
K('.', PERIOD);
|
||||||
|
K('/', SLASH);
|
||||||
|
K('0', 0);
|
||||||
|
K('1', 1);
|
||||||
|
K('2', 2);
|
||||||
|
K('3', 3);
|
||||||
|
K('5', 5);
|
||||||
|
K('6', 6);
|
||||||
|
K('7', 7);
|
||||||
|
K('8', 8);
|
||||||
|
K('9', 9);
|
||||||
|
K(':', COLON);
|
||||||
|
K(';', SEMICOLON);
|
||||||
|
K('<', LESS);
|
||||||
|
K('=', EQUAL);
|
||||||
|
K('>', GREATER);
|
||||||
|
K('@', AT);
|
||||||
|
K('[', LEFT_BRACKET);
|
||||||
|
K('\\', BACKSLASH);
|
||||||
|
K(']', RIGHT_BRACKET);
|
||||||
|
K('_', UNDERSCORE);
|
||||||
|
K('`', GRAVE_ACCENT);
|
||||||
K('a', A);
|
K('a', A);
|
||||||
K('b', B);
|
K('b', B);
|
||||||
K('c', C);
|
K('c', C);
|
||||||
@@ -2294,28 +2255,56 @@ START_ALLOW_CASE_RANGE
|
|||||||
K('x', X);
|
K('x', X);
|
||||||
K('y', Y);
|
K('y', Y);
|
||||||
K('z', Z);
|
K('z', Z);
|
||||||
K('0', 0);
|
K(PARAGRAPH_UTF_8, PARAGRAPH);
|
||||||
K('1', 1);
|
K(MASCULINE_UTF_8, MASCULINE);
|
||||||
K('2', 2);
|
K(S_SHARP_UTF_8, S_SHARP);
|
||||||
K('3', 3);
|
K(A_GRAVE_LOWER_CASE_UTF_8, A_GRAVE);
|
||||||
K('5', 5);
|
K(A_DIAERESIS_LOWER_CASE_UTF_8, A_DIAERESIS);
|
||||||
K('6', 6);
|
K(A_RING_LOWER_CASE_UTF_8, A_RING);
|
||||||
K('7', 7);
|
K(AE_LOWER_CASE_UTF_8, AE);
|
||||||
K('8', 8);
|
K(C_CEDILLA_LOWER_CASE_UTF_8, C_CEDILLA);
|
||||||
K('9', 9);
|
K(E_GRAVE_LOWER_CASE_UTF_8, E_GRAVE);
|
||||||
K('\'', APOSTROPHE);
|
K(E_ACUTE_LOWER_CASE_UTF_8, E_ACUTE);
|
||||||
K(',', COMMA);
|
K(I_GRAVE_LOWER_CASE_UTF_8, I_GRAVE);
|
||||||
K('.', PERIOD);
|
K(N_TILDE_LOWER_CASE_UTF_8, N_TILDE);
|
||||||
K('/', SLASH);
|
K(O_GRAVE_LOWER_CASE_UTF_8, O_GRAVE);
|
||||||
K('-', MINUS);
|
K(O_DIAERESIS_LOWER_CASE_UTF_8, O_DIAERESIS);
|
||||||
K('=', EQUAL);
|
K(O_SLASH_LOWER_CASE_UTF_8, O_SLASH);
|
||||||
K(';', SEMICOLON);
|
K(U_GRAVE_LOWER_CASE_UTF_8, U_GRAVE);
|
||||||
K('[', LEFT_BRACKET);
|
K(U_DIAERESIS_LOWER_CASE_UTF_8, U_DIAERESIS);
|
||||||
K(']', RIGHT_BRACKET);
|
K(CYRILLIC_A_LOWER_CASE_UTF_8, CYRILLIC_A);
|
||||||
K('+', PLUS);
|
K(CYRILLIC_BE_LOWER_CASE_UTF_8, CYRILLIC_BE);
|
||||||
K('_', UNDERSCORE);
|
K(CYRILLIC_VE_LOWER_CASE_UTF_8, CYRILLIC_VE);
|
||||||
K('`', GRAVE_ACCENT);
|
K(CYRILLIC_GHE_LOWER_CASE_UTF_8, CYRILLIC_GHE);
|
||||||
K('\\', BACKSLASH);
|
K(CYRILLIC_DE_LOWER_CASE_UTF_8, CYRILLIC_DE);
|
||||||
|
K(CYRILLIC_IE_LOWER_CASE_UTF_8, CYRILLIC_IE);
|
||||||
|
K(CYRILLIC_ZHE_LOWER_CASE_UTF_8, CYRILLIC_ZHE);
|
||||||
|
K(CYRILLIC_ZE_LOWER_CASE_UTF_8, CYRILLIC_ZE);
|
||||||
|
K(CYRILLIC_I_LOWER_CASE_UTF_8, CYRILLIC_I);
|
||||||
|
K(CYRILLIC_SHORT_I_LOWER_CASE_UTF_8, CYRILLIC_SHORT_I);
|
||||||
|
K(CYRILLIC_KA_LOWER_CASE_UTF_8, CYRILLIC_KA);
|
||||||
|
K(CYRILLIC_EL_LOWER_CASE_UTF_8, CYRILLIC_EL);
|
||||||
|
K(CYRILLIC_EM_LOWER_CASE_UTF_8, CYRILLIC_EM);
|
||||||
|
K(CYRILLIC_EN_LOWER_CASE_UTF_8, CYRILLIC_EN);
|
||||||
|
K(CYRILLIC_O_LOWER_CASE_UTF_8, CYRILLIC_O);
|
||||||
|
K(CYRILLIC_PE_LOWER_CASE_UTF_8, CYRILLIC_PE);
|
||||||
|
K(CYRILLIC_ER_LOWER_CASE_UTF_8, CYRILLIC_ER);
|
||||||
|
K(CYRILLIC_ES_LOWER_CASE_UTF_8, CYRILLIC_ES);
|
||||||
|
K(CYRILLIC_TE_LOWER_CASE_UTF_8, CYRILLIC_TE);
|
||||||
|
K(CYRILLIC_U_LOWER_CASE_UTF_8, CYRILLIC_U);
|
||||||
|
K(CYRILLIC_EF_LOWER_CASE_UTF_8, CYRILLIC_EF);
|
||||||
|
K(CYRILLIC_HA_LOWER_CASE_UTF_8, CYRILLIC_HA);
|
||||||
|
K(CYRILLIC_TSE_LOWER_CASE_UTF_8, CYRILLIC_TSE);
|
||||||
|
K(CYRILLIC_CHE_LOWER_CASE_UTF_8, CYRILLIC_CHE);
|
||||||
|
K(CYRILLIC_SHA_LOWER_CASE_UTF_8, CYRILLIC_SHA);
|
||||||
|
K(CYRILLIC_SHCHA_LOWER_CASE_UTF_8, CYRILLIC_SHCHA);
|
||||||
|
K(CYRILLIC_HARD_SIGN_LOWER_CASE_UTF_8, CYRILLIC_HARD_SIGN);
|
||||||
|
K(CYRILLIC_YERU_LOWER_CASE_UTF_8, CYRILLIC_YERU);
|
||||||
|
K(CYRILLIC_SOFT_SIGN_LOWER_CASE_UTF_8, CYRILLIC_SOFT_SIGN);
|
||||||
|
K(CYRILLIC_E_LOWER_CASE_UTF_8, CYRILLIC_E);
|
||||||
|
K(CYRILLIC_YU_LOWER_CASE_UTF_8, CYRILLIC_YU);
|
||||||
|
K(CYRILLIC_YA_LOWER_CASE_UTF_8, CYRILLIC_YA);
|
||||||
|
K(CYRILLIC_IO_LOWER_CASE_UTF_8, CYRILLIC_IO);
|
||||||
|
|
||||||
K(0x35, ESCAPE);
|
K(0x35, ESCAPE);
|
||||||
K('\r', ENTER);
|
K('\r', ENTER);
|
||||||
|
|||||||
2
glfw/context.c
vendored
2
glfw/context.c
vendored
@@ -1,5 +1,5 @@
|
|||||||
//========================================================================
|
//========================================================================
|
||||||
// GLFW 3.3 - www.glfw.org
|
// GLFW 3.4 - www.glfw.org
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||||
// Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
|
// Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
|
||||||
|
|||||||
5
glfw/dbus_glfw.c
vendored
5
glfw/dbus_glfw.c
vendored
@@ -1,5 +1,5 @@
|
|||||||
//========================================================================
|
//========================================================================
|
||||||
// GLFW 3.3 XKB - www.glfw.org
|
// GLFW 3.4 XKB - www.glfw.org
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
// Copyright (c) 2018 Kovid Goyal <kovid@kovidgoyal.net>
|
// Copyright (c) 2018 Kovid Goyal <kovid@kovidgoyal.net>
|
||||||
//
|
//
|
||||||
@@ -27,6 +27,7 @@
|
|||||||
|
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
#include "dbus_glfw.h"
|
#include "dbus_glfw.h"
|
||||||
|
#include "../kitty/monotonic.h"
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
@@ -107,7 +108,7 @@ on_dbus_timer_ready(id_type timer_id UNUSED, void *data) {
|
|||||||
static dbus_bool_t
|
static dbus_bool_t
|
||||||
add_dbus_timeout(DBusTimeout *timeout, void *data) {
|
add_dbus_timeout(DBusTimeout *timeout, void *data) {
|
||||||
int enabled = dbus_timeout_get_enabled(timeout) ? 1 : 0;
|
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;
|
if (interval < 0) return FALSE;
|
||||||
id_type timer_id = addTimer(dbus_data->eld, data, interval, enabled, true, on_dbus_timer_ready, timeout, NULL);
|
id_type timer_id = addTimer(dbus_data->eld, data, interval, enabled, true, on_dbus_timer_ready, timeout, NULL);
|
||||||
if (!timer_id) return FALSE;
|
if (!timer_id) return FALSE;
|
||||||
|
|||||||
2
glfw/dbus_glfw.h
vendored
2
glfw/dbus_glfw.h
vendored
@@ -1,5 +1,5 @@
|
|||||||
//========================================================================
|
//========================================================================
|
||||||
// GLFW 3.3 XKB - www.glfw.org
|
// GLFW 3.4 XKB - www.glfw.org
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
// Copyright (c) 2018 Kovid Goyal <kovid@kovidgoyal.net>
|
// Copyright (c) 2018 Kovid Goyal <kovid@kovidgoyal.net>
|
||||||
//
|
//
|
||||||
|
|||||||
33
glfw/egl_context.c
vendored
33
glfw/egl_context.c
vendored
@@ -1,5 +1,5 @@
|
|||||||
//========================================================================
|
//========================================================================
|
||||||
// GLFW 3.3 EGL - www.glfw.org
|
// GLFW 3.4 EGL - www.glfw.org
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||||
// Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
|
// Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
|
||||||
@@ -123,23 +123,24 @@ static bool chooseEGLConfig(const _GLFWctxconfig* ctxconfig,
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
#if defined(_GLFW_X11)
|
#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 vi = {0};
|
||||||
XVisualInfo* vis = XGetVisualInfo(_glfw.x11.display,
|
|
||||||
VisualIDMask, &vi,
|
// Only consider EGLConfigs with associated Visuals
|
||||||
&count);
|
vi.visualid = getEGLConfigAttrib(n, EGL_NATIVE_VISUAL_ID);
|
||||||
if (vis)
|
if (!vi.visualid)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (desired->transparent)
|
||||||
{
|
{
|
||||||
u->transparent = _glfwIsVisualTransparentX11(vis[0].visual);
|
int count;
|
||||||
XFree(vis);
|
XVisualInfo* vis =
|
||||||
|
XGetVisualInfo(_glfw.x11.display, VisualIDMask, &vi, &count);
|
||||||
|
if (vis)
|
||||||
|
{
|
||||||
|
u->transparent = _glfwIsVisualTransparentX11(vis[0].visual);
|
||||||
|
XFree(vis);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif // _GLFW_X11
|
#endif // _GLFW_X11
|
||||||
|
|||||||
2
glfw/egl_context.h
vendored
2
glfw/egl_context.h
vendored
@@ -1,5 +1,5 @@
|
|||||||
//========================================================================
|
//========================================================================
|
||||||
// GLFW 3.3 EGL - www.glfw.org
|
// GLFW 3.4 EGL - www.glfw.org
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||||
// Copyright (c) 2006-2017 Camilla Löwy <elmindreda@glfw.org>
|
// Copyright (c) 2006-2017 Camilla Löwy <elmindreda@glfw.org>
|
||||||
|
|||||||
44
glfw/glfw.py
44
glfw/glfw.py
@@ -8,11 +8,7 @@ import re
|
|||||||
import sys
|
import sys
|
||||||
|
|
||||||
_plat = sys.platform.lower()
|
_plat = sys.platform.lower()
|
||||||
is_macos = 'darwin' in _plat
|
is_linux = 'linux' in _plat
|
||||||
is_freebsd = 'freebsd' in _plat
|
|
||||||
is_netbsd = 'netbsd' in _plat
|
|
||||||
is_dragonflybsd = 'dragonfly' in _plat
|
|
||||||
is_bsd = is_freebsd or is_netbsd or is_dragonflybsd
|
|
||||||
base = os.path.dirname(os.path.abspath(__file__))
|
base = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
|
||||||
|
|
||||||
@@ -23,31 +19,24 @@ def wayland_protocol_file_name(base, ext='c'):
|
|||||||
|
|
||||||
def init_env(env, pkg_config, at_least_version, test_compile, module='x11'):
|
def init_env(env, pkg_config, at_least_version, test_compile, module='x11'):
|
||||||
ans = env.copy()
|
ans = env.copy()
|
||||||
if not is_macos:
|
|
||||||
ans.cflags.append('-pthread')
|
|
||||||
ans.ldpaths.append('-pthread')
|
|
||||||
ans.cflags.append('-fpic')
|
ans.cflags.append('-fpic')
|
||||||
ans.cppflags.append('-D_GLFW_' + module.upper())
|
ans.cppflags.append('-D_GLFW_' + module.upper())
|
||||||
ans.cppflags.append('-D_GLFW_BUILD_DLL')
|
ans.cppflags.append('-D_GLFW_BUILD_DLL')
|
||||||
|
|
||||||
if is_macos:
|
with open(os.path.join(base, 'source-info.json')) as f:
|
||||||
ans.cppflags.append('-DGL_SILENCE_DEPRECATION')
|
sinfo = json.load(f)
|
||||||
ans.ldpaths.extend(
|
|
||||||
"-framework Cocoa -framework IOKit -framework CoreFoundation -framework CoreVideo".
|
|
||||||
split()
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
ans.ldpaths.extend('-lrt -lm -ldl'.split())
|
|
||||||
sinfo = json.load(open(os.path.join(base, 'source-info.json')))
|
|
||||||
module_sources = list(sinfo[module]['sources'])
|
module_sources = list(sinfo[module]['sources'])
|
||||||
if module in ('x11', 'wayland'):
|
if module in ('x11', 'wayland'):
|
||||||
remove = 'linux_joystick.c' if is_bsd else 'null_joystick.c'
|
remove = 'null_joystick.c' if is_linux else 'linux_joystick.c'
|
||||||
module_sources.remove(remove)
|
module_sources.remove(remove)
|
||||||
|
|
||||||
ans.sources = sinfo['common']['sources'] + module_sources
|
ans.sources = sinfo['common']['sources'] + module_sources
|
||||||
ans.all_headers = [x for x in os.listdir(base) if x.endswith('.h')]
|
ans.all_headers = [x for x in os.listdir(base) if x.endswith('.h')]
|
||||||
|
|
||||||
if module in ('x11', 'wayland'):
|
if module in ('x11', 'wayland'):
|
||||||
|
ans.cflags.append('-pthread')
|
||||||
|
ans.ldpaths.append('-pthread')
|
||||||
|
ans.ldpaths.extend('-lrt -lm -ldl'.split())
|
||||||
at_least_version('xkbcommon', 0, 5)
|
at_least_version('xkbcommon', 0, 5)
|
||||||
|
|
||||||
if module == 'x11':
|
if module == 'x11':
|
||||||
@@ -56,6 +45,7 @@ def init_env(env, pkg_config, at_least_version, test_compile, module='x11'):
|
|||||||
ans.ldpaths.extend(pkg_config(dep, '--libs'))
|
ans.ldpaths.extend(pkg_config(dep, '--libs'))
|
||||||
|
|
||||||
elif module == 'cocoa':
|
elif module == 'cocoa':
|
||||||
|
ans.cppflags.append('-DGL_SILENCE_DEPRECATION')
|
||||||
for f in 'Cocoa IOKit CoreFoundation CoreVideo'.split():
|
for f in 'Cocoa IOKit CoreFoundation CoreVideo'.split():
|
||||||
ans.ldpaths.extend(('-framework', f))
|
ans.ldpaths.extend(('-framework', f))
|
||||||
|
|
||||||
@@ -157,7 +147,8 @@ class Function:
|
|||||||
|
|
||||||
|
|
||||||
def generate_wrappers(glfw_header):
|
def generate_wrappers(glfw_header):
|
||||||
src = open(glfw_header).read()
|
with open(glfw_header) as f:
|
||||||
|
src = f.read()
|
||||||
functions = []
|
functions = []
|
||||||
first = None
|
first = None
|
||||||
for m in re.finditer(r'^GLFWAPI\s+(.+[)]);\s*$', src, flags=re.MULTILINE):
|
for m in re.finditer(r'^GLFWAPI\s+(.+[)]);\s*$', src, flags=re.MULTILINE):
|
||||||
@@ -174,13 +165,14 @@ def generate_wrappers(glfw_header):
|
|||||||
GLFWcocoatextinputfilterfun glfwSetCocoaTextInputFilter(GLFWwindow* window, GLFWcocoatextinputfilterfun callback)
|
GLFWcocoatextinputfilterfun glfwSetCocoaTextInputFilter(GLFWwindow* window, GLFWcocoatextinputfilterfun callback)
|
||||||
GLFWcocoatogglefullscreenfun glfwSetCocoaToggleFullscreenIntercept(GLFWwindow *window, GLFWcocoatogglefullscreenfun callback)
|
GLFWcocoatogglefullscreenfun glfwSetCocoaToggleFullscreenIntercept(GLFWwindow *window, GLFWcocoatogglefullscreenfun callback)
|
||||||
GLFWapplicationshouldhandlereopenfun glfwSetApplicationShouldHandleReopen(GLFWapplicationshouldhandlereopenfun callback)
|
GLFWapplicationshouldhandlereopenfun glfwSetApplicationShouldHandleReopen(GLFWapplicationshouldhandlereopenfun callback)
|
||||||
|
GLFWapplicationwillfinishlaunchingfun glfwSetApplicationWillFinishLaunching(GLFWapplicationwillfinishlaunchingfun callback)
|
||||||
void glfwGetCocoaKeyEquivalent(int glfw_key, int glfw_mods, void* cocoa_key, void* cocoa_mods)
|
void glfwGetCocoaKeyEquivalent(int glfw_key, int glfw_mods, void* cocoa_key, void* cocoa_mods)
|
||||||
void glfwCocoaRequestRenderFrame(GLFWwindow *w, GLFWcocoarenderframefun callback)
|
void glfwCocoaRequestRenderFrame(GLFWwindow *w, GLFWcocoarenderframefun callback)
|
||||||
void* glfwGetX11Display(void)
|
void* glfwGetX11Display(void)
|
||||||
int32_t glfwGetX11Window(GLFWwindow* window)
|
int32_t glfwGetX11Window(GLFWwindow* window)
|
||||||
void glfwSetPrimarySelectionString(GLFWwindow* window, const char* string)
|
void glfwSetPrimarySelectionString(GLFWwindow* window, const char* string)
|
||||||
const char* glfwGetPrimarySelectionString(GLFWwindow* window, void)
|
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)
|
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, \
|
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)
|
const char *action_text, int32_t timeout, GLFWDBusnotificationcreatedfun callback, void *data)
|
||||||
@@ -194,15 +186,23 @@ const char *action_text, int32_t timeout, GLFWDBusnotificationcreatedfun callbac
|
|||||||
p = src.find('*/', p)
|
p = src.find('*/', p)
|
||||||
preamble = src[p + 2:first]
|
preamble = src[p + 2:first]
|
||||||
header = '''\
|
header = '''\
|
||||||
|
//
|
||||||
|
// THIS FILE IS GENERATED BY glfw.py
|
||||||
|
//
|
||||||
|
// SAVE YOURSELF SOME TIME, DO NOT MANUALLY EDIT
|
||||||
|
//
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include "monotonic.h"
|
||||||
|
|
||||||
{}
|
{}
|
||||||
|
|
||||||
typedef int (* GLFWcocoatextinputfilterfun)(int,int,unsigned int,unsigned long);
|
typedef int (* GLFWcocoatextinputfilterfun)(int,int,unsigned int,unsigned long);
|
||||||
typedef int (* GLFWapplicationshouldhandlereopenfun)(int);
|
typedef bool (* GLFWapplicationshouldhandlereopenfun)(int);
|
||||||
typedef int (* GLFWcocoatogglefullscreenfun)(GLFWwindow*);
|
typedef void (* GLFWapplicationwillfinishlaunchingfun)(void);
|
||||||
|
typedef bool (* GLFWcocoatogglefullscreenfun)(GLFWwindow*);
|
||||||
typedef void (* GLFWcocoarenderframefun)(GLFWwindow*);
|
typedef void (* GLFWcocoarenderframefun)(GLFWwindow*);
|
||||||
typedef void (*GLFWwaylandframecallbackfunc)(unsigned long long id);
|
typedef void (*GLFWwaylandframecallbackfunc)(unsigned long long id);
|
||||||
typedef void (*GLFWDBusnotificationcreatedfun)(unsigned long long, uint32_t, void*);
|
typedef void (*GLFWDBusnotificationcreatedfun)(unsigned long long, uint32_t, void*);
|
||||||
|
|||||||
851
glfw/glfw3.h
vendored
851
glfw/glfw3.h
vendored
File diff suppressed because it is too large
Load Diff
2
glfw/glx_context.c
vendored
2
glfw/glx_context.c
vendored
@@ -1,5 +1,5 @@
|
|||||||
//========================================================================
|
//========================================================================
|
||||||
// GLFW 3.3 GLX - www.glfw.org
|
// GLFW 3.4 GLX - www.glfw.org
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||||
// Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
|
// Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
|
||||||
|
|||||||
26
glfw/glx_context.h
vendored
26
glfw/glx_context.h
vendored
@@ -1,5 +1,5 @@
|
|||||||
//========================================================================
|
//========================================================================
|
||||||
// GLFW 3.3 GLX - www.glfw.org
|
// GLFW 3.4 GLX - www.glfw.org
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||||
// Copyright (c) 2006-2017 Camilla Löwy <elmindreda@glfw.org>
|
// Copyright (c) 2006-2017 Camilla Löwy <elmindreda@glfw.org>
|
||||||
@@ -153,18 +153,18 @@ typedef struct _GLFWlibraryGLX
|
|||||||
PFNGLXSWAPINTERVALEXTPROC SwapIntervalEXT;
|
PFNGLXSWAPINTERVALEXTPROC SwapIntervalEXT;
|
||||||
PFNGLXSWAPINTERVALMESAPROC SwapIntervalMESA;
|
PFNGLXSWAPINTERVALMESAPROC SwapIntervalMESA;
|
||||||
PFNGLXCREATECONTEXTATTRIBSARBPROC CreateContextAttribsARB;
|
PFNGLXCREATECONTEXTATTRIBSARBPROC CreateContextAttribsARB;
|
||||||
bool SGI_swap_control;
|
bool SGI_swap_control;
|
||||||
bool EXT_swap_control;
|
bool EXT_swap_control;
|
||||||
bool MESA_swap_control;
|
bool MESA_swap_control;
|
||||||
bool ARB_multisample;
|
bool ARB_multisample;
|
||||||
bool ARB_framebuffer_sRGB;
|
bool ARB_framebuffer_sRGB;
|
||||||
bool EXT_framebuffer_sRGB;
|
bool EXT_framebuffer_sRGB;
|
||||||
bool ARB_create_context;
|
bool ARB_create_context;
|
||||||
bool ARB_create_context_profile;
|
bool ARB_create_context_profile;
|
||||||
bool ARB_create_context_robustness;
|
bool ARB_create_context_robustness;
|
||||||
bool EXT_create_context_es2_profile;
|
bool EXT_create_context_es2_profile;
|
||||||
bool ARB_create_context_no_error;
|
bool ARB_create_context_no_error;
|
||||||
bool ARB_context_flush_control;
|
bool ARB_context_flush_control;
|
||||||
|
|
||||||
} _GLFWlibraryGLX;
|
} _GLFWlibraryGLX;
|
||||||
|
|
||||||
|
|||||||
31
glfw/ibus_glfw.c
vendored
31
glfw/ibus_glfw.c
vendored
@@ -1,5 +1,5 @@
|
|||||||
//========================================================================
|
//========================================================================
|
||||||
// GLFW 3.3 XKB - www.glfw.org
|
// GLFW 3.4 XKB - www.glfw.org
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
// Copyright (c) 2018 Kovid Goyal <kovid@kovidgoyal.net>
|
// Copyright (c) 2018 Kovid Goyal <kovid@kovidgoyal.net>
|
||||||
//
|
//
|
||||||
@@ -107,10 +107,14 @@ get_ibus_text_from_message(DBusMessage *msg) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
send_text(const char *text, int state) {
|
send_text(const char *text, int ime_state) {
|
||||||
_GLFWwindow *w = _glfwFocusedWindow();
|
_GLFWwindow *w = _glfwFocusedWindow();
|
||||||
if (w && w->callbacks.keyboard) {
|
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
|
void
|
||||||
key_event_processed(DBusMessage *msg, const char* errmsg, void *data) {
|
key_event_processed(DBusMessage *msg, const char* errmsg, void *data) {
|
||||||
uint32_t handled = 0;
|
uint32_t handled = 0;
|
||||||
KeyEvent *ev = (KeyEvent*)data;
|
_GLFWIBUSKeyEvent *ev = (_GLFWIBUSKeyEvent*)data;
|
||||||
bool is_release = ev->action == GLFW_RELEASE;
|
// 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;
|
bool failed = false;
|
||||||
if (errmsg) {
|
if (errmsg) {
|
||||||
_glfwInputError(GLFW_PLATFORM_ERROR, "IBUS: Failed to process key with error: %s", errmsg);
|
_glfwInputError(GLFW_PLATFORM_ERROR, "IBUS: Failed to process key with error: %s", errmsg);
|
||||||
failed = true;
|
failed = true;
|
||||||
} else {
|
} else {
|
||||||
glfw_dbus_get_args(msg, "Failed to get IBUS handled key from reply", DBUS_TYPE_BOOLEAN, &handled, DBUS_TYPE_INVALID);
|
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);
|
glfw_xkb_key_from_ime(ev, handled ? true : false, failed);
|
||||||
free(ev);
|
free(ev);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
ibus_process_key(const KeyEvent *ev_, _GLFWIBUSData *ibus) {
|
ibus_process_key(const _GLFWIBUSKeyEvent *ev_, _GLFWIBUSData *ibus) {
|
||||||
if (!check_connection(ibus)) return false;
|
if (!check_connection(ibus)) return false;
|
||||||
KeyEvent *ev = malloc(sizeof(KeyEvent));
|
_GLFWIBUSKeyEvent *ev = calloc(1, sizeof(_GLFWIBUSKeyEvent));
|
||||||
if (!ev) return false;
|
if (!ev) return false;
|
||||||
memcpy(ev, ev_, sizeof(KeyEvent));
|
memcpy(ev, ev_, sizeof(_GLFWIBUSKeyEvent));
|
||||||
uint32_t state = ibus_key_state(ev->glfw_modifiers, ev->action);
|
// 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(
|
if (!glfw_dbus_call_method_with_reply(
|
||||||
ibus->conn, IBUS_SERVICE, ibus->input_ctx_path, IBUS_INPUT_INTERFACE, "ProcessKeyEvent",
|
ibus->conn, IBUS_SERVICE, ibus->input_ctx_path, IBUS_INPUT_INTERFACE, "ProcessKeyEvent",
|
||||||
3000, key_event_processed, ev,
|
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)) {
|
&state, DBUS_TYPE_INVALID)) {
|
||||||
free(ev);
|
free(ev);
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
17
glfw/ibus_glfw.h
vendored
17
glfw/ibus_glfw.h
vendored
@@ -1,5 +1,5 @@
|
|||||||
//========================================================================
|
//========================================================================
|
||||||
// GLFW 3.3 XKB - www.glfw.org
|
// GLFW 3.4 XKB - www.glfw.org
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
// Copyright (c) 2018 Kovid Goyal <kovid@kovidgoyal.net>
|
// Copyright (c) 2018 Kovid Goyal <kovid@kovidgoyal.net>
|
||||||
//
|
//
|
||||||
@@ -27,6 +27,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "internal.h"
|
||||||
#include "dbus_glfw.h"
|
#include "dbus_glfw.h"
|
||||||
#include <xkbcommon/xkbcommon.h>
|
#include <xkbcommon/xkbcommon.h>
|
||||||
|
|
||||||
@@ -38,18 +39,16 @@ typedef struct {
|
|||||||
} _GLFWIBUSData;
|
} _GLFWIBUSData;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
xkb_keycode_t keycode, ibus_keycode;
|
xkb_keycode_t ibus_keycode;
|
||||||
xkb_keysym_t keysym, ibus_sym;
|
xkb_keysym_t ibus_keysym;
|
||||||
unsigned int glfw_modifiers;
|
|
||||||
int action;
|
|
||||||
GLFWid window_id;
|
GLFWid window_id;
|
||||||
int glfw_keycode;
|
GLFWkeyevent glfw_ev;
|
||||||
char text[64];
|
char __embedded_text[64];
|
||||||
} KeyEvent;
|
} _GLFWIBUSKeyEvent;
|
||||||
|
|
||||||
void glfw_connect_to_ibus(_GLFWIBUSData *ibus);
|
void glfw_connect_to_ibus(_GLFWIBUSData *ibus);
|
||||||
void glfw_ibus_terminate(_GLFWIBUSData *ibus);
|
void glfw_ibus_terminate(_GLFWIBUSData *ibus);
|
||||||
void glfw_ibus_set_focused(_GLFWIBUSData *ibus, bool focused);
|
void glfw_ibus_set_focused(_GLFWIBUSData *ibus, bool focused);
|
||||||
void glfw_ibus_dispatch(_GLFWIBUSData *ibus);
|
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);
|
void glfw_ibus_set_cursor_geometry(_GLFWIBUSData *ibus, int x, int y, int w, int h);
|
||||||
|
|||||||
12
glfw/init.c
vendored
12
glfw/init.c
vendored
@@ -1,5 +1,5 @@
|
|||||||
//========================================================================
|
//========================================================================
|
||||||
// GLFW 3.3 - www.glfw.org
|
// GLFW 3.4 - www.glfw.org
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||||
// Copyright (c) 2006-2018 Camilla Löwy <elmindreda@glfw.org>
|
// Copyright (c) 2006-2018 Camilla Löwy <elmindreda@glfw.org>
|
||||||
@@ -201,7 +201,7 @@ _glfwDebug(const char *format, ...) {
|
|||||||
{
|
{
|
||||||
va_list vl;
|
va_list vl;
|
||||||
|
|
||||||
fprintf(stderr, "[%.4f] ", glfwGetTime());
|
fprintf(stderr, "[%.4f] ", monotonic_t_to_s_double(glfwGetTime()));
|
||||||
va_start(vl, format);
|
va_start(vl, format);
|
||||||
vfprintf(stderr, format, vl);
|
vfprintf(stderr, format, vl);
|
||||||
va_end(vl);
|
va_end(vl);
|
||||||
@@ -214,10 +214,11 @@ _glfwDebug(const char *format, ...) {
|
|||||||
////// GLFW public API //////
|
////// GLFW public API //////
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
GLFWAPI int glfwInit(void)
|
GLFWAPI int glfwInit(monotonic_t start_time)
|
||||||
{
|
{
|
||||||
if (_glfw.initialized)
|
if (_glfw.initialized)
|
||||||
return true;
|
return true;
|
||||||
|
monotonic_start_time = start_time;
|
||||||
|
|
||||||
memset(&_glfw, 0, sizeof(_glfw));
|
memset(&_glfw, 0, sizeof(_glfw));
|
||||||
_glfw.hints.init = _glfwInitHints;
|
_glfw.hints.init = _glfwInitHints;
|
||||||
@@ -239,7 +240,6 @@ GLFWAPI int glfwInit(void)
|
|||||||
_glfwPlatformSetTls(&_glfw.errorSlot, &_glfwMainThreadError);
|
_glfwPlatformSetTls(&_glfw.errorSlot, &_glfwMainThreadError);
|
||||||
|
|
||||||
_glfw.initialized = true;
|
_glfw.initialized = true;
|
||||||
_glfw.timer.offset = _glfwPlatformGetTimerValue();
|
|
||||||
|
|
||||||
glfwDefaultWindowHints();
|
glfwDefaultWindowHints();
|
||||||
|
|
||||||
@@ -350,13 +350,13 @@ GLFWAPI void glfwStopMainLoop(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
GLFWAPI unsigned long long glfwAddTimer(
|
GLFWAPI unsigned long long glfwAddTimer(
|
||||||
double interval, bool repeats, GLFWuserdatafun callback,
|
monotonic_t interval, bool repeats, GLFWuserdatafun callback,
|
||||||
void *callback_data, GLFWuserdatafun free_callback)
|
void *callback_data, GLFWuserdatafun free_callback)
|
||||||
{
|
{
|
||||||
return _glfwPlatformAddTimer(interval, repeats, callback, callback_data, 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);
|
_glfwPlatformUpdateTimer(timer_id, interval, enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
384
glfw/input.c
vendored
384
glfw/input.c
vendored
@@ -1,5 +1,5 @@
|
|||||||
//========================================================================
|
//========================================================================
|
||||||
// GLFW 3.3 - www.glfw.org
|
// GLFW 3.4 - www.glfw.org
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||||
// Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
|
// Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
|
||||||
@@ -28,6 +28,7 @@
|
|||||||
//========================================================================
|
//========================================================================
|
||||||
|
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
|
#include "../kitty/monotonic.h"
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <float.h>
|
#include <float.h>
|
||||||
@@ -256,33 +257,44 @@ static bool parseMapping(_GLFWmapping* mapping, const char* string)
|
|||||||
////// GLFW event API //////
|
////// 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
|
// 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;
|
bool repeated = false;
|
||||||
|
|
||||||
if (action == GLFW_RELEASE && window->keys[key] == GLFW_RELEASE)
|
if (ev->action == GLFW_RELEASE && window->keys[ev->key] == GLFW_RELEASE)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (action == GLFW_PRESS && window->keys[key] == GLFW_PRESS)
|
if (ev->action == GLFW_PRESS && window->keys[ev->key] == GLFW_PRESS)
|
||||||
repeated = true;
|
repeated = true;
|
||||||
|
|
||||||
if (action == GLFW_RELEASE && window->stickyKeys)
|
if (ev->action == GLFW_RELEASE && window->stickyKeys)
|
||||||
window->keys[key] = _GLFW_STICK;
|
window->keys[ev->key] = _GLFW_STICK;
|
||||||
else
|
else
|
||||||
window->keys[key] = (char) action;
|
window->keys[ev->key] = (char) ev->action;
|
||||||
|
|
||||||
if (repeated)
|
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->callbacks.keyboard) {
|
||||||
if (!window->lockKeyMods) mods &= ~(GLFW_MOD_CAPS_LOCK | GLFW_MOD_NUM_LOCK);
|
if (!window->lockKeyMods) ev->mods &= ~(GLFW_MOD_CAPS_LOCK | GLFW_MOD_NUM_LOCK);
|
||||||
window->callbacks.keyboard((GLFWwindow*) window, key, scancode, action, mods, text, state);
|
window->callbacks.keyboard((GLFWwindow*) window, ev);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -439,132 +451,193 @@ const char* _glfwGetKeyName(int key)
|
|||||||
switch (key)
|
switch (key)
|
||||||
{
|
{
|
||||||
// Printable keys
|
// Printable keys
|
||||||
case GLFW_KEY_A: return "A";
|
case GLFW_KEY_SPACE: return "SPACE";
|
||||||
case GLFW_KEY_B: return "B";
|
case GLFW_KEY_EXCLAM: return "EXCLAM";
|
||||||
case GLFW_KEY_C: return "C";
|
case GLFW_KEY_DOUBLE_QUOTE: return "DOUBLE_QUOTE";
|
||||||
case GLFW_KEY_D: return "D";
|
case GLFW_KEY_NUMBER_SIGN: return "NUMBER_SIGN";
|
||||||
case GLFW_KEY_E: return "E";
|
case GLFW_KEY_DOLLAR: return "DOLLAR";
|
||||||
case GLFW_KEY_F: return "F";
|
case GLFW_KEY_AMPERSAND: return "AMPERSAND";
|
||||||
case GLFW_KEY_G: return "G";
|
case GLFW_KEY_APOSTROPHE: return "APOSTROPHE";
|
||||||
case GLFW_KEY_H: return "H";
|
case GLFW_KEY_PARENTHESIS_LEFT: return "PARENTHESIS_LEFT";
|
||||||
case GLFW_KEY_I: return "I";
|
case GLFW_KEY_PARENTHESIS_RIGHT: return "PARENTHESIS_RIGHT";
|
||||||
case GLFW_KEY_J: return "J";
|
case GLFW_KEY_PLUS: return "PLUS";
|
||||||
case GLFW_KEY_K: return "K";
|
case GLFW_KEY_COMMA: return "COMMA";
|
||||||
case GLFW_KEY_L: return "L";
|
case GLFW_KEY_MINUS: return "MINUS";
|
||||||
case GLFW_KEY_M: return "M";
|
case GLFW_KEY_PERIOD: return "PERIOD";
|
||||||
case GLFW_KEY_N: return "N";
|
case GLFW_KEY_SLASH: return "SLASH";
|
||||||
case GLFW_KEY_O: return "O";
|
case GLFW_KEY_0: return "0";
|
||||||
case GLFW_KEY_P: return "P";
|
case GLFW_KEY_1: return "1";
|
||||||
case GLFW_KEY_Q: return "Q";
|
case GLFW_KEY_2: return "2";
|
||||||
case GLFW_KEY_R: return "R";
|
case GLFW_KEY_3: return "3";
|
||||||
case GLFW_KEY_S: return "S";
|
case GLFW_KEY_4: return "4";
|
||||||
case GLFW_KEY_T: return "T";
|
case GLFW_KEY_5: return "5";
|
||||||
case GLFW_KEY_U: return "U";
|
case GLFW_KEY_6: return "6";
|
||||||
case GLFW_KEY_V: return "V";
|
case GLFW_KEY_7: return "7";
|
||||||
case GLFW_KEY_W: return "W";
|
case GLFW_KEY_8: return "8";
|
||||||
case GLFW_KEY_X: return "X";
|
case GLFW_KEY_9: return "9";
|
||||||
case GLFW_KEY_Y: return "Y";
|
case GLFW_KEY_COLON: return "COLON";
|
||||||
case GLFW_KEY_Z: return "Z";
|
case GLFW_KEY_SEMICOLON: return "SEMICOLON";
|
||||||
case GLFW_KEY_1: return "1";
|
case GLFW_KEY_LESS: return "LESS";
|
||||||
case GLFW_KEY_2: return "2";
|
case GLFW_KEY_EQUAL: return "EQUAL";
|
||||||
case GLFW_KEY_3: return "3";
|
case GLFW_KEY_GREATER: return "GREATER";
|
||||||
case GLFW_KEY_4: return "4";
|
case GLFW_KEY_AT: return "AT";
|
||||||
case GLFW_KEY_5: return "5";
|
case GLFW_KEY_A: return "A";
|
||||||
case GLFW_KEY_6: return "6";
|
case GLFW_KEY_B: return "B";
|
||||||
case GLFW_KEY_7: return "7";
|
case GLFW_KEY_C: return "C";
|
||||||
case GLFW_KEY_8: return "8";
|
case GLFW_KEY_D: return "D";
|
||||||
case GLFW_KEY_9: return "9";
|
case GLFW_KEY_E: return "E";
|
||||||
case GLFW_KEY_0: return "0";
|
case GLFW_KEY_F: return "F";
|
||||||
case GLFW_KEY_SPACE: return "SPACE";
|
case GLFW_KEY_G: return "G";
|
||||||
case GLFW_KEY_MINUS: return "MINUS";
|
case GLFW_KEY_H: return "H";
|
||||||
case GLFW_KEY_EQUAL: return "EQUAL";
|
case GLFW_KEY_I: return "I";
|
||||||
case GLFW_KEY_LEFT_BRACKET: return "LEFT BRACKET";
|
case GLFW_KEY_J: return "J";
|
||||||
case GLFW_KEY_RIGHT_BRACKET: return "RIGHT BRACKET";
|
case GLFW_KEY_K: return "K";
|
||||||
case GLFW_KEY_BACKSLASH: return "BACKSLASH";
|
case GLFW_KEY_L: return "L";
|
||||||
case GLFW_KEY_SEMICOLON: return "SEMICOLON";
|
case GLFW_KEY_M: return "M";
|
||||||
case GLFW_KEY_APOSTROPHE: return "APOSTROPHE";
|
case GLFW_KEY_N: return "N";
|
||||||
case GLFW_KEY_GRAVE_ACCENT: return "GRAVE ACCENT";
|
case GLFW_KEY_O: return "O";
|
||||||
case GLFW_KEY_COMMA: return "COMMA";
|
case GLFW_KEY_P: return "P";
|
||||||
case GLFW_KEY_PERIOD: return "PERIOD";
|
case GLFW_KEY_Q: return "Q";
|
||||||
case GLFW_KEY_SLASH: return "SLASH";
|
case GLFW_KEY_R: return "R";
|
||||||
case GLFW_KEY_WORLD_1: return "WORLD 1";
|
case GLFW_KEY_S: return "S";
|
||||||
case GLFW_KEY_WORLD_2: return "WORLD 2";
|
case GLFW_KEY_T: return "T";
|
||||||
case GLFW_KEY_PLUS: return "PLUS";
|
case GLFW_KEY_U: return "U";
|
||||||
case GLFW_KEY_UNDERSCORE: return "UNDERSCORE";
|
case GLFW_KEY_V: return "V";
|
||||||
|
case GLFW_KEY_W: return "W";
|
||||||
|
case GLFW_KEY_X: return "X";
|
||||||
|
case GLFW_KEY_Y: return "Y";
|
||||||
|
case GLFW_KEY_Z: return "Z";
|
||||||
|
case GLFW_KEY_LEFT_BRACKET: return "LEFT_BRACKET";
|
||||||
|
case GLFW_KEY_BACKSLASH: return "BACKSLASH";
|
||||||
|
case GLFW_KEY_RIGHT_BRACKET: return "RIGHT_BRACKET";
|
||||||
|
case GLFW_KEY_UNDERSCORE: return "UNDERSCORE";
|
||||||
|
case GLFW_KEY_GRAVE_ACCENT: return "GRAVE_ACCENT";
|
||||||
|
case GLFW_KEY_WORLD_1: return "WORLD_1";
|
||||||
|
case GLFW_KEY_WORLD_2: return "WORLD_2";
|
||||||
|
case GLFW_KEY_PARAGRAPH: return "PARAGRAPH";
|
||||||
|
case GLFW_KEY_MASCULINE: return "MASCULINE";
|
||||||
|
case GLFW_KEY_A_GRAVE: return "A_GRAVE";
|
||||||
|
case GLFW_KEY_A_DIAERESIS: return "A_DIAERESIS";
|
||||||
|
case GLFW_KEY_A_RING: return "A_RING";
|
||||||
|
case GLFW_KEY_AE: return "AE";
|
||||||
|
case GLFW_KEY_C_CEDILLA: return "C_CEDILLA";
|
||||||
|
case GLFW_KEY_E_GRAVE: return "E_GRAVE";
|
||||||
|
case GLFW_KEY_E_ACUTE: return "E_ACUTE";
|
||||||
|
case GLFW_KEY_I_GRAVE: return "I_GRAVE";
|
||||||
|
case GLFW_KEY_N_TILDE: return "N_TILDE";
|
||||||
|
case GLFW_KEY_O_GRAVE: return "O_GRAVE";
|
||||||
|
case GLFW_KEY_O_DIAERESIS: return "O_DIAERESIS";
|
||||||
|
case GLFW_KEY_O_SLASH: return "O_SLASH";
|
||||||
|
case GLFW_KEY_U_GRAVE: return "U_GRAVE";
|
||||||
|
case GLFW_KEY_U_DIAERESIS: return "U_DIAERESIS";
|
||||||
|
case GLFW_KEY_S_SHARP: return "S_SHARP";
|
||||||
|
case GLFW_KEY_CYRILLIC_A: return "CYRILLIC_A";
|
||||||
|
case GLFW_KEY_CYRILLIC_BE: return "CYRILLIC_BE";
|
||||||
|
case GLFW_KEY_CYRILLIC_VE: return "CYRILLIC_VE";
|
||||||
|
case GLFW_KEY_CYRILLIC_GHE: return "CYRILLIC_GHE";
|
||||||
|
case GLFW_KEY_CYRILLIC_DE: return "CYRILLIC_DE";
|
||||||
|
case GLFW_KEY_CYRILLIC_IE: return "CYRILLIC_IE";
|
||||||
|
case GLFW_KEY_CYRILLIC_ZHE: return "CYRILLIC_ZHE";
|
||||||
|
case GLFW_KEY_CYRILLIC_ZE: return "CYRILLIC_ZE";
|
||||||
|
case GLFW_KEY_CYRILLIC_I: return "CYRILLIC_I";
|
||||||
|
case GLFW_KEY_CYRILLIC_SHORT_I: return "CYRILLIC_SHORT_I";
|
||||||
|
case GLFW_KEY_CYRILLIC_KA: return "CYRILLIC_KA";
|
||||||
|
case GLFW_KEY_CYRILLIC_EL: return "CYRILLIC_EL";
|
||||||
|
case GLFW_KEY_CYRILLIC_EM: return "CYRILLIC_EM";
|
||||||
|
case GLFW_KEY_CYRILLIC_EN: return "CYRILLIC_EN";
|
||||||
|
case GLFW_KEY_CYRILLIC_O: return "CYRILLIC_O";
|
||||||
|
case GLFW_KEY_CYRILLIC_PE: return "CYRILLIC_PE";
|
||||||
|
case GLFW_KEY_CYRILLIC_ER: return "CYRILLIC_ER";
|
||||||
|
case GLFW_KEY_CYRILLIC_ES: return "CYRILLIC_ES";
|
||||||
|
case GLFW_KEY_CYRILLIC_TE: return "CYRILLIC_TE";
|
||||||
|
case GLFW_KEY_CYRILLIC_U: return "CYRILLIC_U";
|
||||||
|
case GLFW_KEY_CYRILLIC_EF: return "CYRILLIC_EF";
|
||||||
|
case GLFW_KEY_CYRILLIC_HA: return "CYRILLIC_HA";
|
||||||
|
case GLFW_KEY_CYRILLIC_TSE: return "CYRILLIC_TSE";
|
||||||
|
case GLFW_KEY_CYRILLIC_CHE: return "CYRILLIC_CHE";
|
||||||
|
case GLFW_KEY_CYRILLIC_SHA: return "CYRILLIC_SHA";
|
||||||
|
case GLFW_KEY_CYRILLIC_SHCHA: return "CYRILLIC_SHCHA";
|
||||||
|
case GLFW_KEY_CYRILLIC_HARD_SIGN: return "CYRILLIC_HARD_SIGN";
|
||||||
|
case GLFW_KEY_CYRILLIC_YERU: return "CYRILLIC_YERU";
|
||||||
|
case GLFW_KEY_CYRILLIC_SOFT_SIGN: return "CYRILLIC_SOFT_SIGN";
|
||||||
|
case GLFW_KEY_CYRILLIC_E: return "CYRILLIC_E";
|
||||||
|
case GLFW_KEY_CYRILLIC_YU: return "CYRILLIC_YU";
|
||||||
|
case GLFW_KEY_CYRILLIC_YA: return "CYRILLIC_YA";
|
||||||
|
case GLFW_KEY_CYRILLIC_IO: return "CYRILLIC_IO";
|
||||||
|
|
||||||
// Function keys
|
// Function keys
|
||||||
case GLFW_KEY_ESCAPE: return "ESCAPE";
|
case GLFW_KEY_ESCAPE: return "ESCAPE";
|
||||||
case GLFW_KEY_F1: return "F1";
|
case GLFW_KEY_F1: return "F1";
|
||||||
case GLFW_KEY_F2: return "F2";
|
case GLFW_KEY_F2: return "F2";
|
||||||
case GLFW_KEY_F3: return "F3";
|
case GLFW_KEY_F3: return "F3";
|
||||||
case GLFW_KEY_F4: return "F4";
|
case GLFW_KEY_F4: return "F4";
|
||||||
case GLFW_KEY_F5: return "F5";
|
case GLFW_KEY_F5: return "F5";
|
||||||
case GLFW_KEY_F6: return "F6";
|
case GLFW_KEY_F6: return "F6";
|
||||||
case GLFW_KEY_F7: return "F7";
|
case GLFW_KEY_F7: return "F7";
|
||||||
case GLFW_KEY_F8: return "F8";
|
case GLFW_KEY_F8: return "F8";
|
||||||
case GLFW_KEY_F9: return "F9";
|
case GLFW_KEY_F9: return "F9";
|
||||||
case GLFW_KEY_F10: return "F10";
|
case GLFW_KEY_F10: return "F10";
|
||||||
case GLFW_KEY_F11: return "F11";
|
case GLFW_KEY_F11: return "F11";
|
||||||
case GLFW_KEY_F12: return "F12";
|
case GLFW_KEY_F12: return "F12";
|
||||||
case GLFW_KEY_F13: return "F13";
|
case GLFW_KEY_F13: return "F13";
|
||||||
case GLFW_KEY_F14: return "F14";
|
case GLFW_KEY_F14: return "F14";
|
||||||
case GLFW_KEY_F15: return "F15";
|
case GLFW_KEY_F15: return "F15";
|
||||||
case GLFW_KEY_F16: return "F16";
|
case GLFW_KEY_F16: return "F16";
|
||||||
case GLFW_KEY_F17: return "F17";
|
case GLFW_KEY_F17: return "F17";
|
||||||
case GLFW_KEY_F18: return "F18";
|
case GLFW_KEY_F18: return "F18";
|
||||||
case GLFW_KEY_F19: return "F19";
|
case GLFW_KEY_F19: return "F19";
|
||||||
case GLFW_KEY_F20: return "F20";
|
case GLFW_KEY_F20: return "F20";
|
||||||
case GLFW_KEY_F21: return "F21";
|
case GLFW_KEY_F21: return "F21";
|
||||||
case GLFW_KEY_F22: return "F22";
|
case GLFW_KEY_F22: return "F22";
|
||||||
case GLFW_KEY_F23: return "F23";
|
case GLFW_KEY_F23: return "F23";
|
||||||
case GLFW_KEY_F24: return "F24";
|
case GLFW_KEY_F24: return "F24";
|
||||||
case GLFW_KEY_F25: return "F25";
|
case GLFW_KEY_F25: return "F25";
|
||||||
case GLFW_KEY_UP: return "UP";
|
case GLFW_KEY_UP: return "UP";
|
||||||
case GLFW_KEY_DOWN: return "DOWN";
|
case GLFW_KEY_DOWN: return "DOWN";
|
||||||
case GLFW_KEY_LEFT: return "LEFT";
|
case GLFW_KEY_LEFT: return "LEFT";
|
||||||
case GLFW_KEY_RIGHT: return "RIGHT";
|
case GLFW_KEY_RIGHT: return "RIGHT";
|
||||||
case GLFW_KEY_LEFT_SHIFT: return "LEFT SHIFT";
|
case GLFW_KEY_LEFT_SHIFT: return "LEFT SHIFT";
|
||||||
case GLFW_KEY_RIGHT_SHIFT: return "RIGHT SHIFT";
|
case GLFW_KEY_RIGHT_SHIFT: return "RIGHT SHIFT";
|
||||||
case GLFW_KEY_LEFT_CONTROL: return "LEFT CONTROL";
|
case GLFW_KEY_LEFT_CONTROL: return "LEFT CONTROL";
|
||||||
case GLFW_KEY_RIGHT_CONTROL: return "RIGHT CONTROL";
|
case GLFW_KEY_RIGHT_CONTROL: return "RIGHT CONTROL";
|
||||||
case GLFW_KEY_LEFT_ALT: return "LEFT ALT";
|
case GLFW_KEY_LEFT_ALT: return "LEFT ALT";
|
||||||
case GLFW_KEY_RIGHT_ALT: return "RIGHT ALT";
|
case GLFW_KEY_RIGHT_ALT: return "RIGHT ALT";
|
||||||
case GLFW_KEY_TAB: return "TAB";
|
case GLFW_KEY_TAB: return "TAB";
|
||||||
case GLFW_KEY_ENTER: return "ENTER";
|
case GLFW_KEY_ENTER: return "ENTER";
|
||||||
case GLFW_KEY_BACKSPACE: return "BACKSPACE";
|
case GLFW_KEY_BACKSPACE: return "BACKSPACE";
|
||||||
case GLFW_KEY_INSERT: return "INSERT";
|
case GLFW_KEY_INSERT: return "INSERT";
|
||||||
case GLFW_KEY_DELETE: return "DELETE";
|
case GLFW_KEY_DELETE: return "DELETE";
|
||||||
case GLFW_KEY_PAGE_UP: return "PAGE UP";
|
case GLFW_KEY_PAGE_UP: return "PAGE UP";
|
||||||
case GLFW_KEY_PAGE_DOWN: return "PAGE DOWN";
|
case GLFW_KEY_PAGE_DOWN: return "PAGE DOWN";
|
||||||
case GLFW_KEY_HOME: return "HOME";
|
case GLFW_KEY_HOME: return "HOME";
|
||||||
case GLFW_KEY_END: return "END";
|
case GLFW_KEY_END: return "END";
|
||||||
case GLFW_KEY_KP_0: return "KEYPAD 0";
|
case GLFW_KEY_KP_0: return "KEYPAD 0";
|
||||||
case GLFW_KEY_KP_1: return "KEYPAD 1";
|
case GLFW_KEY_KP_1: return "KEYPAD 1";
|
||||||
case GLFW_KEY_KP_2: return "KEYPAD 2";
|
case GLFW_KEY_KP_2: return "KEYPAD 2";
|
||||||
case GLFW_KEY_KP_3: return "KEYPAD 3";
|
case GLFW_KEY_KP_3: return "KEYPAD 3";
|
||||||
case GLFW_KEY_KP_4: return "KEYPAD 4";
|
case GLFW_KEY_KP_4: return "KEYPAD 4";
|
||||||
case GLFW_KEY_KP_5: return "KEYPAD 5";
|
case GLFW_KEY_KP_5: return "KEYPAD 5";
|
||||||
case GLFW_KEY_KP_6: return "KEYPAD 6";
|
case GLFW_KEY_KP_6: return "KEYPAD 6";
|
||||||
case GLFW_KEY_KP_7: return "KEYPAD 7";
|
case GLFW_KEY_KP_7: return "KEYPAD 7";
|
||||||
case GLFW_KEY_KP_8: return "KEYPAD 8";
|
case GLFW_KEY_KP_8: return "KEYPAD 8";
|
||||||
case GLFW_KEY_KP_9: return "KEYPAD 9";
|
case GLFW_KEY_KP_9: return "KEYPAD 9";
|
||||||
case GLFW_KEY_KP_DIVIDE: return "KEYPAD DIVIDE";
|
case GLFW_KEY_KP_DIVIDE: return "KEYPAD DIVIDE";
|
||||||
case GLFW_KEY_KP_MULTIPLY: return "KEYPAD MULTPLY";
|
case GLFW_KEY_KP_MULTIPLY: return "KEYPAD MULTIPLY";
|
||||||
case GLFW_KEY_KP_SUBTRACT: return "KEYPAD SUBTRACT";
|
case GLFW_KEY_KP_SUBTRACT: return "KEYPAD SUBTRACT";
|
||||||
case GLFW_KEY_KP_ADD: return "KEYPAD ADD";
|
case GLFW_KEY_KP_ADD: return "KEYPAD ADD";
|
||||||
case GLFW_KEY_KP_DECIMAL: return "KEYPAD DECIMAL";
|
case GLFW_KEY_KP_DECIMAL: return "KEYPAD DECIMAL";
|
||||||
case GLFW_KEY_KP_EQUAL: return "KEYPAD EQUAL";
|
case GLFW_KEY_KP_EQUAL: return "KEYPAD EQUAL";
|
||||||
case GLFW_KEY_KP_ENTER: return "KEYPAD ENTER";
|
case GLFW_KEY_KP_ENTER: return "KEYPAD ENTER";
|
||||||
case GLFW_KEY_PRINT_SCREEN: return "PRINT SCREEN";
|
case GLFW_KEY_PRINT_SCREEN: return "PRINT SCREEN";
|
||||||
case GLFW_KEY_NUM_LOCK: return "NUM LOCK";
|
case GLFW_KEY_NUM_LOCK: return "NUM LOCK";
|
||||||
case GLFW_KEY_CAPS_LOCK: return "CAPS LOCK";
|
case GLFW_KEY_CAPS_LOCK: return "CAPS LOCK";
|
||||||
case GLFW_KEY_SCROLL_LOCK: return "SCROLL LOCK";
|
case GLFW_KEY_SCROLL_LOCK: return "SCROLL LOCK";
|
||||||
case GLFW_KEY_PAUSE: return "PAUSE";
|
case GLFW_KEY_PAUSE: return "PAUSE";
|
||||||
case GLFW_KEY_LEFT_SUPER: return "LEFT SUPER";
|
case GLFW_KEY_LEFT_SUPER: return "LEFT SUPER";
|
||||||
case GLFW_KEY_RIGHT_SUPER: return "RIGHT SUPER";
|
case GLFW_KEY_RIGHT_SUPER: return "RIGHT SUPER";
|
||||||
case GLFW_KEY_MENU: return "MENU";
|
case GLFW_KEY_MENU: return "MENU";
|
||||||
|
|
||||||
default: return "UNKNOWN";
|
default: return "UNKNOWN";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -683,7 +756,7 @@ GLFWAPI void glfwSetInputMode(GLFWwindow* handle, int mode, int value)
|
|||||||
_glfwInputError(GLFW_INVALID_ENUM, "Invalid input mode 0x%08X", mode);
|
_glfwInputError(GLFW_INVALID_ENUM, "Invalid input mode 0x%08X", mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
GLFWAPI const char* glfwGetKeyName(int key, int scancode)
|
GLFWAPI const char* glfwGetKeyName(int key, int native_key)
|
||||||
{
|
{
|
||||||
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||||
|
|
||||||
@@ -691,18 +764,18 @@ GLFWAPI const char* glfwGetKeyName(int key, int scancode)
|
|||||||
{
|
{
|
||||||
if (key != GLFW_KEY_KP_EQUAL &&
|
if (key != GLFW_KEY_KP_EQUAL &&
|
||||||
(key < GLFW_KEY_KP_0 || key > GLFW_KEY_KP_ADD) &&
|
(key < GLFW_KEY_KP_0 || key > GLFW_KEY_KP_ADD) &&
|
||||||
(key < GLFW_KEY_APOSTROPHE || key > GLFW_KEY_WORLD_2))
|
(key < GLFW_KEY_APOSTROPHE || key > GLFW_KEY_LAST_PRINTABLE))
|
||||||
{
|
{
|
||||||
return NULL;
|
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);
|
_GLFW_REQUIRE_INIT_OR_RETURN(-1);
|
||||||
|
|
||||||
@@ -712,7 +785,7 @@ GLFWAPI int glfwGetKeyScancode(int key)
|
|||||||
return GLFW_RELEASE;
|
return GLFW_RELEASE;
|
||||||
}
|
}
|
||||||
|
|
||||||
return _glfwPlatformGetKeyScancode(key);
|
return _glfwPlatformGetNativeKeyForKey(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
GLFWAPI int glfwGetKey(GLFWwindow* handle, int key)
|
GLFWAPI int glfwGetKey(GLFWwindow* handle, int key)
|
||||||
@@ -1405,35 +1478,8 @@ GLFWAPI const char* glfwGetPrimarySelectionString(GLFWwindow* handle UNUSED)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
GLFWAPI double glfwGetTime(void)
|
GLFWAPI monotonic_t 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)
|
|
||||||
{
|
{
|
||||||
_GLFW_REQUIRE_INIT_OR_RETURN(0);
|
_GLFW_REQUIRE_INIT_OR_RETURN(0);
|
||||||
return _glfwPlatformGetTimerValue();
|
return monotonic();
|
||||||
}
|
|
||||||
|
|
||||||
GLFWAPI uint64_t glfwGetTimerFrequency(void)
|
|
||||||
{
|
|
||||||
_GLFW_REQUIRE_INIT_OR_RETURN(0);
|
|
||||||
return _glfwPlatformGetTimerFrequency();
|
|
||||||
}
|
}
|
||||||
|
|||||||
28
glfw/internal.h
vendored
28
glfw/internal.h
vendored
@@ -1,5 +1,5 @@
|
|||||||
//========================================================================
|
//========================================================================
|
||||||
// GLFW 3.3 - www.glfw.org
|
// GLFW 3.4 - www.glfw.org
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||||
// Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
|
// Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
|
||||||
@@ -27,6 +27,8 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "../kitty/monotonic.h"
|
||||||
|
|
||||||
#if defined(_GLFW_USE_CONFIG_H)
|
#if defined(_GLFW_USE_CONFIG_H)
|
||||||
#include "glfw_config.h"
|
#include "glfw_config.h"
|
||||||
#endif
|
#endif
|
||||||
@@ -572,12 +574,6 @@ struct _GLFWlibrary
|
|||||||
_GLFWtls contextSlot;
|
_GLFWtls contextSlot;
|
||||||
_GLFWmutex errorLock;
|
_GLFWmutex errorLock;
|
||||||
|
|
||||||
struct {
|
|
||||||
uint64_t offset;
|
|
||||||
// This is defined in the platform's time.h
|
|
||||||
_GLFW_PLATFORM_LIBRARY_TIMER_STATE;
|
|
||||||
} timer;
|
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
bool available;
|
bool available;
|
||||||
void* handle;
|
void* handle;
|
||||||
@@ -638,8 +634,8 @@ int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, GLFWCursorShape shape
|
|||||||
void _glfwPlatformDestroyCursor(_GLFWcursor* cursor);
|
void _glfwPlatformDestroyCursor(_GLFWcursor* cursor);
|
||||||
void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor);
|
void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor);
|
||||||
|
|
||||||
const char* _glfwPlatformGetScancodeName(int scancode);
|
const char* _glfwPlatformGetNativeKeyName(int native_key);
|
||||||
int _glfwPlatformGetKeyScancode(int key);
|
int _glfwPlatformGetNativeKeyForKey(int key);
|
||||||
|
|
||||||
void _glfwPlatformFreeMonitor(_GLFWmonitor* monitor);
|
void _glfwPlatformFreeMonitor(_GLFWmonitor* monitor);
|
||||||
void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos);
|
void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos);
|
||||||
@@ -661,9 +657,6 @@ const char* _glfwPlatformGetPrimarySelectionString(void);
|
|||||||
int _glfwPlatformPollJoystick(_GLFWjoystick* js, int mode);
|
int _glfwPlatformPollJoystick(_GLFWjoystick* js, int mode);
|
||||||
void _glfwPlatformUpdateGamepadGUID(char* guid);
|
void _glfwPlatformUpdateGamepadGUID(char* guid);
|
||||||
|
|
||||||
uint64_t _glfwPlatformGetTimerValue(void);
|
|
||||||
uint64_t _glfwPlatformGetTimerFrequency(void);
|
|
||||||
|
|
||||||
int _glfwPlatformCreateWindow(_GLFWwindow* window,
|
int _glfwPlatformCreateWindow(_GLFWwindow* window,
|
||||||
const _GLFWwndconfig* wndconfig,
|
const _GLFWwndconfig* wndconfig,
|
||||||
const _GLFWctxconfig* ctxconfig,
|
const _GLFWctxconfig* ctxconfig,
|
||||||
@@ -687,7 +680,7 @@ void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window,
|
|||||||
int* right, int* bottom);
|
int* right, int* bottom);
|
||||||
void _glfwPlatformGetWindowContentScale(_GLFWwindow* window,
|
void _glfwPlatformGetWindowContentScale(_GLFWwindow* window,
|
||||||
float* xscale, float* yscale);
|
float* xscale, float* yscale);
|
||||||
double _glfwPlatformGetDoubleClickInterval(_GLFWwindow* window);
|
monotonic_t _glfwPlatformGetDoubleClickInterval(_GLFWwindow* window);
|
||||||
void _glfwPlatformIconifyWindow(_GLFWwindow* window);
|
void _glfwPlatformIconifyWindow(_GLFWwindow* window);
|
||||||
void _glfwPlatformRestoreWindow(_GLFWwindow* window);
|
void _glfwPlatformRestoreWindow(_GLFWwindow* window);
|
||||||
void _glfwPlatformMaximizeWindow(_GLFWwindow* window);
|
void _glfwPlatformMaximizeWindow(_GLFWwindow* window);
|
||||||
@@ -716,7 +709,7 @@ void _glfwPlatformUpdateIMEState(_GLFWwindow *w, int which, int a, int b, int c,
|
|||||||
|
|
||||||
void _glfwPlatformPollEvents(void);
|
void _glfwPlatformPollEvents(void);
|
||||||
void _glfwPlatformWaitEvents(void);
|
void _glfwPlatformWaitEvents(void);
|
||||||
void _glfwPlatformWaitEventsTimeout(double timeout);
|
void _glfwPlatformWaitEventsTimeout(monotonic_t timeout);
|
||||||
void _glfwPlatformPostEmptyEvent(void);
|
void _glfwPlatformPostEmptyEvent(void);
|
||||||
|
|
||||||
void _glfwPlatformGetRequiredInstanceExtensions(char** extensions);
|
void _glfwPlatformGetRequiredInstanceExtensions(char** extensions);
|
||||||
@@ -756,7 +749,8 @@ void _glfwInputWindowDamage(_GLFWwindow* window);
|
|||||||
void _glfwInputWindowCloseRequest(_GLFWwindow* window);
|
void _glfwInputWindowCloseRequest(_GLFWwindow* window);
|
||||||
void _glfwInputWindowMonitor(_GLFWwindow* window, _GLFWmonitor* monitor);
|
void _glfwInputWindowMonitor(_GLFWwindow* window, _GLFWmonitor* monitor);
|
||||||
|
|
||||||
void _glfwInputKeyboard(_GLFWwindow* window, int key, int scancode, int action, int mods, const char* text, int state);
|
void _glfwInitializeKeyEvent(GLFWkeyevent *ev, int key, int native_key, int action, int mods);
|
||||||
|
void _glfwInputKeyboard(_GLFWwindow *window, GLFWkeyevent *ev);
|
||||||
void _glfwInputScroll(_GLFWwindow* window, double xoffset, double yoffset, int flags);
|
void _glfwInputScroll(_GLFWwindow* window, double xoffset, double yoffset, int flags);
|
||||||
void _glfwInputMouseClick(_GLFWwindow* window, int button, int action, int mods);
|
void _glfwInputMouseClick(_GLFWwindow* window, int button, int action, int mods);
|
||||||
void _glfwInputCursorPos(_GLFWwindow* window, double xpos, double ypos);
|
void _glfwInputCursorPos(_GLFWwindow* window, double xpos, double ypos);
|
||||||
@@ -823,8 +817,8 @@ _GLFWwindow* _glfwFocusedWindow(void);
|
|||||||
_GLFWwindow* _glfwWindowForId(GLFWid id);
|
_GLFWwindow* _glfwWindowForId(GLFWid id);
|
||||||
void _glfwPlatformRunMainLoop(GLFWtickcallback, void*);
|
void _glfwPlatformRunMainLoop(GLFWtickcallback, void*);
|
||||||
void _glfwPlatformStopMainLoop(void);
|
void _glfwPlatformStopMainLoop(void);
|
||||||
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);
|
||||||
void _glfwPlatformUpdateTimer(unsigned long long timer_id, double interval, bool enabled);
|
void _glfwPlatformUpdateTimer(unsigned long long timer_id, monotonic_t interval, bool enabled);
|
||||||
void _glfwPlatformRemoveTimer(unsigned long long timer_id);
|
void _glfwPlatformRemoveTimer(unsigned long long timer_id);
|
||||||
|
|
||||||
char* _glfw_strdup(const char* source);
|
char* _glfw_strdup(const char* source);
|
||||||
|
|||||||
15
glfw/linux_joystick.c
vendored
15
glfw/linux_joystick.c
vendored
@@ -1,5 +1,5 @@
|
|||||||
//========================================================================
|
//========================================================================
|
||||||
// GLFW 3.3 Linux - www.glfw.org
|
// GLFW 3.4 Linux - www.glfw.org
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||||
// Copyright (c) 2006-2017 Camilla Löwy <elmindreda@glfw.org>
|
// Copyright (c) 2006-2017 Camilla Löwy <elmindreda@glfw.org>
|
||||||
@@ -144,10 +144,10 @@ static bool openJoystickDevice(const char* path)
|
|||||||
char absBits[(ABS_CNT + 7) / 8] = {0};
|
char absBits[(ABS_CNT + 7) / 8] = {0};
|
||||||
struct input_id id;
|
struct input_id id;
|
||||||
|
|
||||||
if (ioctl(linjs.fd, EVIOCGBIT(0, sizeof(evBits)), evBits) < 0 ||
|
if (ioctl(linjs.fd, (int32_t)EVIOCGBIT(0, sizeof(evBits)), evBits) < 0 ||
|
||||||
ioctl(linjs.fd, EVIOCGBIT(EV_KEY, sizeof(keyBits)), keyBits) < 0 ||
|
ioctl(linjs.fd, (int32_t)EVIOCGBIT(EV_KEY, sizeof(keyBits)), keyBits) < 0 ||
|
||||||
ioctl(linjs.fd, EVIOCGBIT(EV_ABS, sizeof(absBits)), absBits) < 0 ||
|
ioctl(linjs.fd, (int32_t)EVIOCGBIT(EV_ABS, sizeof(absBits)), absBits) < 0 ||
|
||||||
ioctl(linjs.fd, EVIOCGID, &id) < 0)
|
ioctl(linjs.fd, (int32_t)EVIOCGID, &id) < 0)
|
||||||
{
|
{
|
||||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
"Linux: Failed to query input device: %s",
|
"Linux: Failed to query input device: %s",
|
||||||
@@ -165,7 +165,7 @@ static bool openJoystickDevice(const char* path)
|
|||||||
|
|
||||||
char name[256] = "";
|
char name[256] = "";
|
||||||
|
|
||||||
if (ioctl(linjs.fd, EVIOCGNAME(sizeof(name)), name) < 0)
|
if (ioctl(linjs.fd, (int32_t)EVIOCGNAME(sizeof(name)), name) < 0)
|
||||||
strncpy(name, "Unknown", sizeof(name));
|
strncpy(name, "Unknown", sizeof(name));
|
||||||
|
|
||||||
char guid[33] = "";
|
char guid[33] = "";
|
||||||
@@ -222,7 +222,8 @@ static bool openJoystickDevice(const char* path)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_GLFWjoystick* js = _glfwAllocJoystick(name, guid, axisCount, buttonCount, hatCount);
|
_GLFWjoystick* js =
|
||||||
|
_glfwAllocJoystick(name, guid, axisCount, buttonCount, hatCount);
|
||||||
if (!js)
|
if (!js)
|
||||||
{
|
{
|
||||||
close(linjs.fd);
|
close(linjs.fd);
|
||||||
|
|||||||
4
glfw/linux_joystick.h
vendored
4
glfw/linux_joystick.h
vendored
@@ -1,5 +1,5 @@
|
|||||||
//========================================================================
|
//========================================================================
|
||||||
// GLFW 3.3 Linux - www.glfw.org
|
// GLFW 3.4 Linux - www.glfw.org
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
// Copyright (c) 2014 Jonas Ådahl <jadahl@gmail.com>
|
// Copyright (c) 2014 Jonas Ådahl <jadahl@gmail.com>
|
||||||
//
|
//
|
||||||
@@ -52,7 +52,7 @@ typedef struct _GLFWlibraryLinux
|
|||||||
int inotify;
|
int inotify;
|
||||||
int watch;
|
int watch;
|
||||||
regex_t regex;
|
regex_t regex;
|
||||||
bool dropped;
|
bool dropped;
|
||||||
} _GLFWlibraryLinux;
|
} _GLFWlibraryLinux;
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
5
glfw/main_loop.h
vendored
5
glfw/main_loop.h
vendored
@@ -7,6 +7,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
|
#include "../kitty/monotonic.h"
|
||||||
|
|
||||||
#ifndef GLFW_LOOP_BACKEND
|
#ifndef GLFW_LOOP_BACKEND
|
||||||
#define GLFW_LOOP_BACKEND x11
|
#define GLFW_LOOP_BACKEND x11
|
||||||
@@ -36,7 +37,7 @@ void _glfwPlatformRunMainLoop(GLFWtickcallback tick_callback, void* data) {
|
|||||||
EVDBG("main loop exiting");
|
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);
|
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);
|
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);
|
changeTimerInterval(&_glfw.GLFW_LOOP_BACKEND.eventLoopData, timer_id, interval);
|
||||||
toggleTimer(&_glfw.GLFW_LOOP_BACKEND.eventLoopData, timer_id, enabled);
|
toggleTimer(&_glfw.GLFW_LOOP_BACKEND.eventLoopData, timer_id, enabled);
|
||||||
}
|
}
|
||||||
|
|||||||
2
glfw/mappings.h
vendored
2
glfw/mappings.h
vendored
@@ -1,5 +1,5 @@
|
|||||||
//========================================================================
|
//========================================================================
|
||||||
// GLFW 3.3 - www.glfw.org
|
// GLFW 3.4 - www.glfw.org
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
// Copyright (c) 2006-2018 Camilla Löwy <elmindreda@glfw.org>
|
// Copyright (c) 2006-2018 Camilla Löwy <elmindreda@glfw.org>
|
||||||
//
|
//
|
||||||
|
|||||||
6
glfw/monitor.c
vendored
6
glfw/monitor.c
vendored
@@ -1,5 +1,5 @@
|
|||||||
//========================================================================
|
//========================================================================
|
||||||
// GLFW 3.3 - www.glfw.org
|
// GLFW 3.4 - www.glfw.org
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||||
// Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
|
// Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
|
||||||
@@ -56,6 +56,10 @@ static int compareVideoModes(const void* fp, const void* sp)
|
|||||||
if (farea != sarea)
|
if (farea != sarea)
|
||||||
return farea - sarea;
|
return farea - sarea;
|
||||||
|
|
||||||
|
// Then sort on width
|
||||||
|
if (fm->width != sm->width)
|
||||||
|
return fm->width - sm->width;
|
||||||
|
|
||||||
// Lastly sort on refresh rate
|
// Lastly sort on refresh rate
|
||||||
return fm->refreshRate - sm->refreshRate;
|
return fm->refreshRate - sm->refreshRate;
|
||||||
}
|
}
|
||||||
|
|||||||
10
glfw/monotonic.c
vendored
Normal file
10
glfw/monotonic.c
vendored
Normal 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"
|
||||||
6
glfw/nsgl_context.h
vendored
6
glfw/nsgl_context.h
vendored
@@ -1,5 +1,5 @@
|
|||||||
//========================================================================
|
//========================================================================
|
||||||
// GLFW 3.3 macOS - www.glfw.org
|
// GLFW 3.4 macOS - www.glfw.org
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
// Copyright (c) 2009-2019 Camilla Löwy <elmindreda@glfw.org>
|
// Copyright (c) 2009-2019 Camilla Löwy <elmindreda@glfw.org>
|
||||||
//
|
//
|
||||||
@@ -32,8 +32,8 @@
|
|||||||
//
|
//
|
||||||
typedef struct _GLFWcontextNSGL
|
typedef struct _GLFWcontextNSGL
|
||||||
{
|
{
|
||||||
id pixelFormat;
|
id pixelFormat;
|
||||||
id object;
|
id object;
|
||||||
|
|
||||||
} _GLFWcontextNSGL;
|
} _GLFWcontextNSGL;
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
//========================================================================
|
//========================================================================
|
||||||
// GLFW 3.3 macOS - www.glfw.org
|
// GLFW 3.4 macOS - www.glfw.org
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
// Copyright (c) 2009-2019 Camilla Löwy <elmindreda@glfw.org>
|
// Copyright (c) 2009-2019 Camilla Löwy <elmindreda@glfw.org>
|
||||||
//
|
//
|
||||||
@@ -271,7 +271,7 @@ bool _glfwCreateContextNSGL(_GLFWwindow* window,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
NSOpenGLContext* share = NULL;
|
NSOpenGLContext* share = nil;
|
||||||
|
|
||||||
if (ctxconfig->share)
|
if (ctxconfig->share)
|
||||||
share = ctxconfig->share->context.nsgl.object;
|
share = ctxconfig->share->context.nsgl.object;
|
||||||
@@ -293,8 +293,7 @@ bool _glfwCreateContextNSGL(_GLFWwindow* window,
|
|||||||
forParameter:NSOpenGLContextParameterSurfaceOpacity];
|
forParameter:NSOpenGLContextParameterSurfaceOpacity];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (window->ns.retina)
|
[window->ns.view setWantsBestResolutionOpenGLSurface:window->ns.retina];
|
||||||
[window->ns.view setWantsBestResolutionOpenGLSurface:YES];
|
|
||||||
|
|
||||||
GLint interval = 0;
|
GLint interval = 0;
|
||||||
[window->context.nsgl.object setValues:&interval
|
[window->context.nsgl.object setValues:&interval
|
||||||
@@ -325,7 +324,7 @@ GLFWAPI id glfwGetNSGLContext(GLFWwindow* handle)
|
|||||||
if (window->context.client == GLFW_NO_API)
|
if (window->context.client == GLFW_NO_API)
|
||||||
{
|
{
|
||||||
_glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
|
_glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
|
||||||
return NULL;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
return window->context.nsgl.object;
|
return window->context.nsgl.object;
|
||||||
|
|||||||
4
glfw/null_init.c
vendored
4
glfw/null_init.c
vendored
@@ -1,5 +1,5 @@
|
|||||||
//========================================================================
|
//========================================================================
|
||||||
// GLFW 3.3 - www.glfw.org
|
// GLFW 3.4 - www.glfw.org
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
// Copyright (c) 2016 Google Inc.
|
// Copyright (c) 2016 Google Inc.
|
||||||
// Copyright (c) 2016-2017 Camilla Löwy <elmindreda@glfw.org>
|
// Copyright (c) 2016-2017 Camilla Löwy <elmindreda@glfw.org>
|
||||||
@@ -36,7 +36,6 @@
|
|||||||
|
|
||||||
int _glfwPlatformInit(void)
|
int _glfwPlatformInit(void)
|
||||||
{
|
{
|
||||||
_glfwInitTimerPOSIX();
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,4 +48,3 @@ const char* _glfwPlatformGetVersionString(void)
|
|||||||
{
|
{
|
||||||
return _GLFW_VERSION_NUMBER " null OSMesa";
|
return _GLFW_VERSION_NUMBER " null OSMesa";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
6
glfw/null_joystick.c
vendored
6
glfw/null_joystick.c
vendored
@@ -1,5 +1,5 @@
|
|||||||
//========================================================================
|
//========================================================================
|
||||||
// GLFW 3.3 - www.glfw.org
|
// GLFW 3.4 - www.glfw.org
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
// Copyright (c) 2016-2017 Camilla Löwy <elmindreda@glfw.org>
|
// Copyright (c) 2016-2017 Camilla Löwy <elmindreda@glfw.org>
|
||||||
//
|
//
|
||||||
@@ -33,12 +33,12 @@
|
|||||||
////// GLFW platform API //////
|
////// GLFW platform API //////
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
int _glfwPlatformPollJoystick(_GLFWjoystick* js, int mode)
|
int _glfwPlatformPollJoystick(_GLFWjoystick* js UNUSED, int mode UNUSED)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformUpdateGamepadGUID(char* guid)
|
void _glfwPlatformUpdateGamepadGUID(char* guid UNUSED)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
2
glfw/null_joystick.h
vendored
2
glfw/null_joystick.h
vendored
@@ -1,5 +1,5 @@
|
|||||||
//========================================================================
|
//========================================================================
|
||||||
// GLFW 3.3 - www.glfw.org
|
// GLFW 3.4 - www.glfw.org
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
// Copyright (c) 2006-2017 Camilla Löwy <elmindreda@glfw.org>
|
// Copyright (c) 2006-2017 Camilla Löwy <elmindreda@glfw.org>
|
||||||
//
|
//
|
||||||
|
|||||||
22
glfw/null_monitor.c
vendored
22
glfw/null_monitor.c
vendored
@@ -1,5 +1,5 @@
|
|||||||
//========================================================================
|
//========================================================================
|
||||||
// GLFW 3.3 - www.glfw.org
|
// GLFW 3.4 - www.glfw.org
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
// Copyright (c) 2016 Google Inc.
|
// Copyright (c) 2016 Google Inc.
|
||||||
// Copyright (c) 2016-2019 Camilla Löwy <elmindreda@glfw.org>
|
// Copyright (c) 2016-2019 Camilla Löwy <elmindreda@glfw.org>
|
||||||
@@ -34,15 +34,15 @@
|
|||||||
////// GLFW platform API //////
|
////// GLFW platform API //////
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void _glfwPlatformFreeMonitor(_GLFWmonitor* monitor)
|
void _glfwPlatformFreeMonitor(_GLFWmonitor* monitor UNUSED)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos)
|
void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor UNUSED, int* xpos UNUSED, int* ypos UNUSED)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor,
|
void _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor UNUSED,
|
||||||
float* xscale, float* yscale)
|
float* xscale, float* yscale)
|
||||||
{
|
{
|
||||||
if (xscale)
|
if (xscale)
|
||||||
@@ -51,27 +51,27 @@ void _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor,
|
|||||||
*yscale = 1.f;
|
*yscale = 1.f;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformGetMonitorWorkarea(_GLFWmonitor* monitor,
|
void _glfwPlatformGetMonitorWorkarea(_GLFWmonitor* monitor UNUSED,
|
||||||
int* xpos, int* ypos,
|
int* xpos UNUSED, int* ypos UNUSED,
|
||||||
int* width, int* height)
|
int* width UNUSED, int* height UNUSED)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* found)
|
GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor UNUSED, int* found UNUSED)
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode)
|
void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor UNUSED, GLFWvidmode* mode UNUSED)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
bool _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
|
bool _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor UNUSED, GLFWgammaramp* ramp UNUSED)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp)
|
void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor UNUSED, const GLFWgammaramp* ramp UNUSED)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
2
glfw/null_platform.h
vendored
2
glfw/null_platform.h
vendored
@@ -1,5 +1,5 @@
|
|||||||
//========================================================================
|
//========================================================================
|
||||||
// GLFW 3.3 - www.glfw.org
|
// GLFW 3.4 - www.glfw.org
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
// Copyright (c) 2016 Google Inc.
|
// Copyright (c) 2016 Google Inc.
|
||||||
// Copyright (c) 2016-2017 Camilla Löwy <elmindreda@glfw.org>
|
// Copyright (c) 2016-2017 Camilla Löwy <elmindreda@glfw.org>
|
||||||
|
|||||||
127
glfw/null_window.c
vendored
127
glfw/null_window.c
vendored
@@ -1,5 +1,5 @@
|
|||||||
//========================================================================
|
//========================================================================
|
||||||
// GLFW 3.3 - www.glfw.org
|
// GLFW 3.4 - www.glfw.org
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
// Copyright (c) 2016 Google Inc.
|
// Copyright (c) 2016 Google Inc.
|
||||||
// Copyright (c) 2016-2019 Camilla Löwy <elmindreda@glfw.org>
|
// Copyright (c) 2016-2019 Camilla Löwy <elmindreda@glfw.org>
|
||||||
@@ -28,6 +28,7 @@
|
|||||||
//========================================================================
|
//========================================================================
|
||||||
|
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
|
#include "../kitty/monotonic.h"
|
||||||
|
|
||||||
|
|
||||||
static int createNativeWindow(_GLFWwindow* window,
|
static int createNativeWindow(_GLFWwindow* window,
|
||||||
@@ -78,28 +79,28 @@ void _glfwPlatformDestroyWindow(_GLFWwindow* window)
|
|||||||
window->context.destroy(window);
|
window->context.destroy(window);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title)
|
void _glfwPlatformSetWindowTitle(_GLFWwindow* window UNUSED, const char* title UNUSED)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformSetWindowIcon(_GLFWwindow* window, int count,
|
void _glfwPlatformSetWindowIcon(_GLFWwindow* window UNUSED, int count UNUSED,
|
||||||
const GLFWimage* images)
|
const GLFWimage* images UNUSED)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformSetWindowMonitor(_GLFWwindow* window,
|
void _glfwPlatformSetWindowMonitor(_GLFWwindow* window UNUSED,
|
||||||
_GLFWmonitor* monitor,
|
_GLFWmonitor* monitor UNUSED,
|
||||||
int xpos, int ypos,
|
int xpos UNUSED, int ypos UNUSED,
|
||||||
int width, int height,
|
int width UNUSED, int height UNUSED,
|
||||||
int refreshRate)
|
int refreshRate UNUSED)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos)
|
void _glfwPlatformGetWindowPos(_GLFWwindow* window UNUSED, int* xpos UNUSED, int* ypos UNUSED)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformSetWindowPos(_GLFWwindow* window, int xpos, int ypos)
|
void _glfwPlatformSetWindowPos(_GLFWwindow* window UNUSED, int xpos UNUSED, int ypos UNUSED)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,13 +118,13 @@ void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height)
|
|||||||
window->null.height = height;
|
window->null.height = height;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window,
|
void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window UNUSED,
|
||||||
int minwidth, int minheight,
|
int minwidth UNUSED, int minheight UNUSED,
|
||||||
int maxwidth, int maxheight)
|
int maxwidth UNUSED, int maxheight UNUSED)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window, int n, int d)
|
void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window UNUSED, int n UNUSED, int d UNUSED)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,13 +136,13 @@ void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* heigh
|
|||||||
*height = window->null.height;
|
*height = window->null.height;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window,
|
void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window UNUSED,
|
||||||
int* left, int* top,
|
int* left UNUSED, int* top UNUSED,
|
||||||
int* right, int* bottom)
|
int* right UNUSED, int* bottom UNUSED)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformGetWindowContentScale(_GLFWwindow* window,
|
void _glfwPlatformGetWindowContentScale(_GLFWwindow* window UNUSED,
|
||||||
float* xscale, float* yscale)
|
float* xscale, float* yscale)
|
||||||
{
|
{
|
||||||
if (xscale)
|
if (xscale)
|
||||||
@@ -150,101 +151,101 @@ void _glfwPlatformGetWindowContentScale(_GLFWwindow* window,
|
|||||||
*yscale = 1.f;
|
*yscale = 1.f;
|
||||||
}
|
}
|
||||||
|
|
||||||
double _glfwPlatformGetDoubleClickInterval(_GLFWwindow* window)
|
monotonic_t _glfwPlatformGetDoubleClickInterval(_GLFWwindow* window UNUSED)
|
||||||
{
|
{
|
||||||
return 0.5;
|
return ms_to_monotonic_t(500ll);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformIconifyWindow(_GLFWwindow* window)
|
void _glfwPlatformIconifyWindow(_GLFWwindow* window UNUSED)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformRestoreWindow(_GLFWwindow* window)
|
void _glfwPlatformRestoreWindow(_GLFWwindow* window UNUSED)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformMaximizeWindow(_GLFWwindow* window)
|
void _glfwPlatformMaximizeWindow(_GLFWwindow* window UNUSED)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
int _glfwPlatformWindowMaximized(_GLFWwindow* window)
|
int _glfwPlatformWindowMaximized(_GLFWwindow* window UNUSED)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int _glfwPlatformWindowHovered(_GLFWwindow* window)
|
int _glfwPlatformWindowHovered(_GLFWwindow* window UNUSED)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int _glfwPlatformFramebufferTransparent(_GLFWwindow* window)
|
int _glfwPlatformFramebufferTransparent(_GLFWwindow* window UNUSED)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformSetWindowResizable(_GLFWwindow* window, bool enabled)
|
void _glfwPlatformSetWindowResizable(_GLFWwindow* window UNUSED, bool enabled UNUSED)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformSetWindowDecorated(_GLFWwindow* window, bool enabled)
|
void _glfwPlatformSetWindowDecorated(_GLFWwindow* window UNUSED, bool enabled UNUSED)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformSetWindowFloating(_GLFWwindow* window, bool enabled)
|
void _glfwPlatformSetWindowFloating(_GLFWwindow* window UNUSED, bool enabled UNUSED)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
float _glfwPlatformGetWindowOpacity(_GLFWwindow* window)
|
float _glfwPlatformGetWindowOpacity(_GLFWwindow* window UNUSED)
|
||||||
{
|
{
|
||||||
return 1.f;
|
return 1.f;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformSetWindowOpacity(_GLFWwindow* window, float opacity)
|
void _glfwPlatformSetWindowOpacity(_GLFWwindow* window UNUSED, float opacity UNUSED)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformShowWindow(_GLFWwindow* window)
|
void _glfwPlatformShowWindow(_GLFWwindow* window UNUSED)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void _glfwPlatformRequestWindowAttention(_GLFWwindow* window)
|
void _glfwPlatformRequestWindowAttention(_GLFWwindow* window UNUSED)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
int _glfwPlatformWindowBell(_GLFWwindow* window)
|
int _glfwPlatformWindowBell(_GLFWwindow* window UNUSED)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformUnhideWindow(_GLFWwindow* window)
|
void _glfwPlatformUnhideWindow(_GLFWwindow* window UNUSED)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformHideWindow(_GLFWwindow* window)
|
void _glfwPlatformHideWindow(_GLFWwindow* window UNUSED)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformFocusWindow(_GLFWwindow* window)
|
void _glfwPlatformFocusWindow(_GLFWwindow* window UNUSED)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
int _glfwPlatformWindowFocused(_GLFWwindow* window)
|
int _glfwPlatformWindowFocused(_GLFWwindow* window UNUSED)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int _glfwPlatformWindowOccluded(_GLFWwindow* window)
|
int _glfwPlatformWindowOccluded(_GLFWwindow* window UNUSED)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int _glfwPlatformWindowIconified(_GLFWwindow* window)
|
int _glfwPlatformWindowIconified(_GLFWwindow* window UNUSED)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int _glfwPlatformWindowVisible(_GLFWwindow* window)
|
int _glfwPlatformWindowVisible(_GLFWwindow* window UNUSED)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -257,7 +258,7 @@ void _glfwPlatformWaitEvents(void)
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformWaitEventsTimeout(double timeout)
|
void _glfwPlatformWaitEventsTimeout(monotonic_t timeout UNUSED)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -265,39 +266,39 @@ void _glfwPlatformPostEmptyEvent(void)
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos)
|
void _glfwPlatformGetCursorPos(_GLFWwindow* window UNUSED, double* xpos UNUSED, double* ypos UNUSED)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformSetCursorPos(_GLFWwindow* window, double x, double y)
|
void _glfwPlatformSetCursorPos(_GLFWwindow* window UNUSED, double x UNUSED, double y UNUSED)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode)
|
void _glfwPlatformSetCursorMode(_GLFWwindow* window UNUSED, int mode UNUSED)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
int _glfwPlatformCreateCursor(_GLFWcursor* cursor,
|
int _glfwPlatformCreateCursor(_GLFWcursor* cursor UNUSED,
|
||||||
const GLFWimage* image,
|
const GLFWimage* image UNUSED,
|
||||||
int xhot, int yhot, int count)
|
int xhot UNUSED, int yhot UNUSED, int count UNUSED)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape)
|
int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor UNUSED, int shape UNUSED)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformDestroyCursor(_GLFWcursor* cursor)
|
void _glfwPlatformDestroyCursor(_GLFWcursor* cursor UNUSED)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor)
|
void _glfwPlatformSetCursor(_GLFWwindow* window UNUSED, _GLFWcursor* cursor UNUSED)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformSetClipboardString(const char* string)
|
void _glfwPlatformSetClipboardString(const char* string UNUSED)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -306,31 +307,31 @@ const char* _glfwPlatformGetClipboardString(void)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* _glfwPlatformGetScancodeName(int scancode)
|
const char* _glfwPlatformGetNativeKeyName(int native_key UNUSED)
|
||||||
{
|
{
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
int _glfwPlatformGetKeyScancode(int key)
|
int _glfwPlatformGetNativeKeyForKey(int key UNUSED)
|
||||||
{
|
{
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformGetRequiredInstanceExtensions(char** extensions)
|
void _glfwPlatformGetRequiredInstanceExtensions(char** extensions UNUSED)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance,
|
int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance UNUSED,
|
||||||
VkPhysicalDevice device,
|
VkPhysicalDevice device UNUSED,
|
||||||
uint32_t queuefamily)
|
uint32_t queuefamily UNUSED)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
VkResult _glfwPlatformCreateWindowSurface(VkInstance instance,
|
VkResult _glfwPlatformCreateWindowSurface(VkInstance instance UNUSED,
|
||||||
_GLFWwindow* window,
|
_GLFWwindow* window UNUSED,
|
||||||
const VkAllocationCallbacks* allocator,
|
const VkAllocationCallbacks* allocator UNUSED,
|
||||||
VkSurfaceKHR* surface)
|
VkSurfaceKHR* surface UNUSED)
|
||||||
{
|
{
|
||||||
// This seems like the most appropriate error to return here
|
// This seems like the most appropriate error to return here
|
||||||
return VK_ERROR_INITIALIZATION_FAILED;
|
return VK_ERROR_INITIALIZATION_FAILED;
|
||||||
|
|||||||
2
glfw/osmesa_context.c
vendored
2
glfw/osmesa_context.c
vendored
@@ -1,5 +1,5 @@
|
|||||||
//========================================================================
|
//========================================================================
|
||||||
// GLFW 3.3 OSMesa - www.glfw.org
|
// GLFW 3.4 OSMesa - www.glfw.org
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
// Copyright (c) 2016 Google Inc.
|
// Copyright (c) 2016 Google Inc.
|
||||||
// Copyright (c) 2016-2017 Camilla Löwy <elmindreda@glfw.org>
|
// Copyright (c) 2016-2017 Camilla Löwy <elmindreda@glfw.org>
|
||||||
|
|||||||
2
glfw/osmesa_context.h
vendored
2
glfw/osmesa_context.h
vendored
@@ -1,5 +1,5 @@
|
|||||||
//========================================================================
|
//========================================================================
|
||||||
// GLFW 3.3 OSMesa - www.glfw.org
|
// GLFW 3.4 OSMesa - www.glfw.org
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
// Copyright (c) 2016 Google Inc.
|
// Copyright (c) 2016 Google Inc.
|
||||||
// Copyright (c) 2016-2017 Camilla Löwy <elmindreda@glfw.org>
|
// Copyright (c) 2016-2017 Camilla Löwy <elmindreda@glfw.org>
|
||||||
|
|||||||
2
glfw/posix_thread.c
vendored
2
glfw/posix_thread.c
vendored
@@ -1,5 +1,5 @@
|
|||||||
//========================================================================
|
//========================================================================
|
||||||
// GLFW 3.3 POSIX - www.glfw.org
|
// GLFW 3.4 POSIX - www.glfw.org
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||||
// Copyright (c) 2006-2017 Camilla Löwy <elmindreda@glfw.org>
|
// Copyright (c) 2006-2017 Camilla Löwy <elmindreda@glfw.org>
|
||||||
|
|||||||
6
glfw/posix_thread.h
vendored
6
glfw/posix_thread.h
vendored
@@ -1,5 +1,5 @@
|
|||||||
//========================================================================
|
//========================================================================
|
||||||
// GLFW 3.3 POSIX - www.glfw.org
|
// GLFW 3.4 POSIX - www.glfw.org
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||||
// Copyright (c) 2006-2017 Camilla Löwy <elmindreda@glfw.org>
|
// Copyright (c) 2006-2017 Camilla Löwy <elmindreda@glfw.org>
|
||||||
@@ -35,7 +35,7 @@
|
|||||||
//
|
//
|
||||||
typedef struct _GLFWtlsPOSIX
|
typedef struct _GLFWtlsPOSIX
|
||||||
{
|
{
|
||||||
bool allocated;
|
bool allocated;
|
||||||
pthread_key_t key;
|
pthread_key_t key;
|
||||||
|
|
||||||
} _GLFWtlsPOSIX;
|
} _GLFWtlsPOSIX;
|
||||||
@@ -44,7 +44,7 @@ typedef struct _GLFWtlsPOSIX
|
|||||||
//
|
//
|
||||||
typedef struct _GLFWmutexPOSIX
|
typedef struct _GLFWmutexPOSIX
|
||||||
{
|
{
|
||||||
bool allocated;
|
bool allocated;
|
||||||
pthread_mutex_t handle;
|
pthread_mutex_t handle;
|
||||||
|
|
||||||
} _GLFWmutexPOSIX;
|
} _GLFWmutexPOSIX;
|
||||||
|
|||||||
87
glfw/posix_time.c
vendored
87
glfw/posix_time.c
vendored
@@ -1,87 +0,0 @@
|
|||||||
//========================================================================
|
|
||||||
// GLFW 3.3 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
44
glfw/posix_time.h
vendored
@@ -1,44 +0,0 @@
|
|||||||
//========================================================================
|
|
||||||
// GLFW 3.3 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);
|
|
||||||
|
|
||||||
@@ -13,7 +13,6 @@
|
|||||||
"cocoa_joystick.m",
|
"cocoa_joystick.m",
|
||||||
"cocoa_monitor.m",
|
"cocoa_monitor.m",
|
||||||
"cocoa_window.m",
|
"cocoa_window.m",
|
||||||
"cocoa_time.c",
|
|
||||||
"posix_thread.c",
|
"posix_thread.c",
|
||||||
"nsgl_context.m",
|
"nsgl_context.m",
|
||||||
"egl_context.c",
|
"egl_context.c",
|
||||||
@@ -31,6 +30,7 @@
|
|||||||
"input.c",
|
"input.c",
|
||||||
"monitor.c",
|
"monitor.c",
|
||||||
"vulkan.c",
|
"vulkan.c",
|
||||||
|
"monotonic.c",
|
||||||
"window.c"
|
"window.c"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@@ -38,7 +38,6 @@
|
|||||||
"headers": [
|
"headers": [
|
||||||
"null_platform.h",
|
"null_platform.h",
|
||||||
"null_joystick.h",
|
"null_joystick.h",
|
||||||
"posix_time.h",
|
|
||||||
"posix_thread.h",
|
"posix_thread.h",
|
||||||
"osmesa_context.h"
|
"osmesa_context.h"
|
||||||
],
|
],
|
||||||
@@ -47,7 +46,6 @@
|
|||||||
"null_monitor.c",
|
"null_monitor.c",
|
||||||
"null_window.c",
|
"null_window.c",
|
||||||
"null_joystick.c",
|
"null_joystick.c",
|
||||||
"posix_time.c",
|
|
||||||
"posix_thread.c",
|
"posix_thread.c",
|
||||||
"osmesa_context.c"
|
"osmesa_context.c"
|
||||||
]
|
]
|
||||||
@@ -55,7 +53,6 @@
|
|||||||
"wayland": {
|
"wayland": {
|
||||||
"headers": [
|
"headers": [
|
||||||
"wl_platform.h",
|
"wl_platform.h",
|
||||||
"posix_time.h",
|
|
||||||
"posix_thread.h",
|
"posix_thread.h",
|
||||||
"xkb_glfw.h",
|
"xkb_glfw.h",
|
||||||
"dbus_glfw.h",
|
"dbus_glfw.h",
|
||||||
@@ -81,7 +78,6 @@
|
|||||||
"wl_init.c",
|
"wl_init.c",
|
||||||
"wl_monitor.c",
|
"wl_monitor.c",
|
||||||
"wl_window.c",
|
"wl_window.c",
|
||||||
"posix_time.c",
|
|
||||||
"posix_thread.c",
|
"posix_thread.c",
|
||||||
"xkb_glfw.c",
|
"xkb_glfw.c",
|
||||||
"dbus_glfw.c",
|
"dbus_glfw.c",
|
||||||
@@ -125,7 +121,6 @@
|
|||||||
"dbus_glfw.h",
|
"dbus_glfw.h",
|
||||||
"ibus_glfw.h",
|
"ibus_glfw.h",
|
||||||
"backend_utils.h",
|
"backend_utils.h",
|
||||||
"posix_time.h",
|
|
||||||
"posix_thread.h",
|
"posix_thread.h",
|
||||||
"glx_context.h",
|
"glx_context.h",
|
||||||
"egl_context.h",
|
"egl_context.h",
|
||||||
@@ -142,7 +137,6 @@
|
|||||||
"xkb_glfw.c",
|
"xkb_glfw.c",
|
||||||
"dbus_glfw.c",
|
"dbus_glfw.c",
|
||||||
"ibus_glfw.c",
|
"ibus_glfw.c",
|
||||||
"posix_time.c",
|
|
||||||
"posix_thread.c",
|
"posix_thread.c",
|
||||||
"glx_context.c",
|
"glx_context.c",
|
||||||
"egl_context.c",
|
"egl_context.c",
|
||||||
|
|||||||
2
glfw/vulkan.c
vendored
2
glfw/vulkan.c
vendored
@@ -1,5 +1,5 @@
|
|||||||
//========================================================================
|
//========================================================================
|
||||||
// GLFW 3.3 - www.glfw.org
|
// GLFW 3.4 - www.glfw.org
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||||
// Copyright (c) 2006-2018 Camilla Löwy <elmindreda@glfw.org>
|
// Copyright (c) 2006-2018 Camilla Löwy <elmindreda@glfw.org>
|
||||||
|
|||||||
13
glfw/window.c
vendored
13
glfw/window.c
vendored
@@ -1,5 +1,5 @@
|
|||||||
//========================================================================
|
//========================================================================
|
||||||
// GLFW 3.3 - www.glfw.org
|
// GLFW 3.4 - www.glfw.org
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||||
// Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
|
// Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
|
||||||
@@ -29,6 +29,7 @@
|
|||||||
//========================================================================
|
//========================================================================
|
||||||
|
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
|
#include "../kitty/monotonic.h"
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@@ -56,8 +57,10 @@ void _glfwInputWindowFocus(_GLFWwindow* window, bool focused)
|
|||||||
{
|
{
|
||||||
if (window->keys[key] == GLFW_PRESS)
|
if (window->keys[key] == GLFW_PRESS)
|
||||||
{
|
{
|
||||||
const int scancode = _glfwPlatformGetKeyScancode(key);
|
const int native_key = _glfwPlatformGetNativeKeyForKey(key);
|
||||||
_glfwInputKeyboard(window, key, scancode, GLFW_RELEASE, 0, "", 0);
|
GLFWkeyevent ev;
|
||||||
|
_glfwInitializeKeyEvent(&ev, key, native_key, GLFW_RELEASE, 0);
|
||||||
|
_glfwInputKeyboard(window, &ev);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -736,12 +739,12 @@ GLFWAPI void glfwGetWindowContentScale(GLFWwindow* handle,
|
|||||||
_glfwPlatformGetWindowContentScale(window, xscale, yscale);
|
_glfwPlatformGetWindowContentScale(window, xscale, yscale);
|
||||||
}
|
}
|
||||||
|
|
||||||
GLFWAPI double glfwGetDoubleClickInterval(GLFWwindow* handle)
|
GLFWAPI monotonic_t glfwGetDoubleClickInterval(GLFWwindow* handle)
|
||||||
{
|
{
|
||||||
_GLFWwindow* window = (_GLFWwindow*) handle;
|
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||||
assert(window != NULL);
|
assert(window != NULL);
|
||||||
|
|
||||||
_GLFW_REQUIRE_INIT_OR_RETURN(0.5f);
|
_GLFW_REQUIRE_INIT_OR_RETURN(ms_to_monotonic_t(500ll));
|
||||||
return _glfwPlatformGetDoubleClickInterval(window);
|
return _glfwPlatformGetDoubleClickInterval(window);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
60
glfw/wl_init.c
vendored
60
glfw/wl_init.c
vendored
@@ -1,5 +1,5 @@
|
|||||||
//========================================================================
|
//========================================================================
|
||||||
// GLFW 3.3 Wayland - www.glfw.org
|
// GLFW 3.4 Wayland - www.glfw.org
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
// Copyright (c) 2014 Jonas Ådahl <jadahl@gmail.com>
|
// Copyright (c) 2014 Jonas Ådahl <jadahl@gmail.com>
|
||||||
//
|
//
|
||||||
@@ -29,6 +29,7 @@
|
|||||||
#define _GNU_SOURCE
|
#define _GNU_SOURCE
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
#include "backend_utils.h"
|
#include "backend_utils.h"
|
||||||
|
#include "../kitty/monotonic.h"
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
@@ -136,6 +137,7 @@ static void pointerHandleLeave(void* data UNUSED,
|
|||||||
_glfw.wl.pointerSerial = serial;
|
_glfw.wl.pointerSerial = serial;
|
||||||
_glfw.wl.pointerFocus = NULL;
|
_glfw.wl.pointerFocus = NULL;
|
||||||
_glfwInputCursorEnter(window, false);
|
_glfwInputCursorEnter(window, false);
|
||||||
|
_glfw.wl.cursorPreviousShape = GLFW_INVALID_CURSOR;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void setCursor(GLFWCursorShape shape)
|
static void setCursor(GLFWCursorShape shape)
|
||||||
@@ -164,6 +166,7 @@ static void setCursor(GLFWCursorShape shape)
|
|||||||
wl_surface_damage(surface, 0, 0,
|
wl_surface_damage(surface, 0, 0,
|
||||||
image->width, image->height);
|
image->width, image->height);
|
||||||
wl_surface_commit(surface);
|
wl_surface_commit(surface);
|
||||||
|
_glfw.wl.cursorPreviousShape = shape;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pointerHandleMotion(void* data UNUSED,
|
static void pointerHandleMotion(void* data UNUSED,
|
||||||
@@ -174,43 +177,46 @@ static void pointerHandleMotion(void* data UNUSED,
|
|||||||
{
|
{
|
||||||
_GLFWwindow* window = _glfw.wl.pointerFocus;
|
_GLFWwindow* window = _glfw.wl.pointerFocus;
|
||||||
GLFWCursorShape cursorShape = GLFW_ARROW_CURSOR;
|
GLFWCursorShape cursorShape = GLFW_ARROW_CURSOR;
|
||||||
|
double x, y;
|
||||||
|
|
||||||
if (!window)
|
if (!window)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (window->cursorMode == GLFW_CURSOR_DISABLED)
|
if (window->cursorMode == GLFW_CURSOR_DISABLED)
|
||||||
return;
|
return;
|
||||||
window->wl.cursorPosX = wl_fixed_to_double(sx);
|
x = wl_fixed_to_double(sx);
|
||||||
window->wl.cursorPosY = wl_fixed_to_double(sy);
|
y = wl_fixed_to_double(sy);
|
||||||
|
|
||||||
switch (window->wl.decorations.focus)
|
switch (window->wl.decorations.focus)
|
||||||
{
|
{
|
||||||
case mainWindow:
|
case mainWindow:
|
||||||
_glfwInputCursorPos(window,
|
window->wl.cursorPosX = x;
|
||||||
window->wl.cursorPosX, window->wl.cursorPosY);
|
window->wl.cursorPosY = y;
|
||||||
|
_glfwInputCursorPos(window, x, y);
|
||||||
|
_glfw.wl.cursorPreviousShape = GLFW_INVALID_CURSOR;
|
||||||
return;
|
return;
|
||||||
case topDecoration:
|
case topDecoration:
|
||||||
if (window->wl.cursorPosY < _GLFW_DECORATION_WIDTH)
|
if (y < _GLFW_DECORATION_WIDTH)
|
||||||
cursorShape = GLFW_VRESIZE_CURSOR;
|
cursorShape = GLFW_VRESIZE_CURSOR;
|
||||||
else
|
else
|
||||||
cursorShape = GLFW_ARROW_CURSOR;
|
cursorShape = GLFW_ARROW_CURSOR;
|
||||||
break;
|
break;
|
||||||
case leftDecoration:
|
case leftDecoration:
|
||||||
if (window->wl.cursorPosY < _GLFW_DECORATION_WIDTH)
|
if (y < _GLFW_DECORATION_WIDTH)
|
||||||
cursorShape = GLFW_NW_RESIZE_CURSOR;
|
cursorShape = GLFW_NW_RESIZE_CURSOR;
|
||||||
else
|
else
|
||||||
cursorShape = GLFW_HRESIZE_CURSOR;
|
cursorShape = GLFW_HRESIZE_CURSOR;
|
||||||
break;
|
break;
|
||||||
case rightDecoration:
|
case rightDecoration:
|
||||||
if (window->wl.cursorPosY < _GLFW_DECORATION_WIDTH)
|
if (y < _GLFW_DECORATION_WIDTH)
|
||||||
cursorShape = GLFW_NE_RESIZE_CURSOR;
|
cursorShape = GLFW_NE_RESIZE_CURSOR;
|
||||||
else
|
else
|
||||||
cursorShape = GLFW_HRESIZE_CURSOR;
|
cursorShape = GLFW_HRESIZE_CURSOR;
|
||||||
break;
|
break;
|
||||||
case bottomDecoration:
|
case bottomDecoration:
|
||||||
if (window->wl.cursorPosX < _GLFW_DECORATION_WIDTH)
|
if (x < _GLFW_DECORATION_WIDTH)
|
||||||
cursorShape = GLFW_SW_RESIZE_CURSOR;
|
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;
|
cursorShape = GLFW_SE_RESIZE_CURSOR;
|
||||||
else
|
else
|
||||||
cursorShape = GLFW_VRESIZE_CURSOR;
|
cursorShape = GLFW_VRESIZE_CURSOR;
|
||||||
@@ -218,7 +224,8 @@ static void pointerHandleMotion(void* data UNUSED,
|
|||||||
default:
|
default:
|
||||||
assert(0);
|
assert(0);
|
||||||
}
|
}
|
||||||
setCursor(cursorShape);
|
if (_glfw.wl.cursorPreviousShape != cursorShape)
|
||||||
|
setCursor(cursorShape);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pointerHandleButton(void* data UNUSED,
|
static void pointerHandleButton(void* data UNUSED,
|
||||||
@@ -284,8 +291,8 @@ static void pointerHandleButton(void* data UNUSED,
|
|||||||
{
|
{
|
||||||
xdg_toplevel_show_window_menu(window->wl.xdg.toplevel,
|
xdg_toplevel_show_window_menu(window->wl.xdg.toplevel,
|
||||||
_glfw.wl.seat, serial,
|
_glfw.wl.seat, serial,
|
||||||
window->wl.cursorPosX,
|
(int32_t)window->wl.cursorPosX,
|
||||||
window->wl.cursorPosY);
|
(int32_t)window->wl.cursorPosY);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -367,7 +374,7 @@ static void keyboardHandleEnter(void* data UNUSED,
|
|||||||
struct wl_keyboard* keyboard UNUSED,
|
struct wl_keyboard* keyboard UNUSED,
|
||||||
uint32_t serial UNUSED,
|
uint32_t serial UNUSED,
|
||||||
struct wl_surface* surface,
|
struct wl_surface* surface,
|
||||||
struct wl_array* keys UNUSED)
|
struct wl_array* keys)
|
||||||
{
|
{
|
||||||
// Happens in the case we just destroyed the surface.
|
// Happens in the case we just destroyed the surface.
|
||||||
if (!surface)
|
if (!surface)
|
||||||
@@ -383,6 +390,15 @@ static void keyboardHandleEnter(void* data UNUSED,
|
|||||||
|
|
||||||
_glfw.wl.keyboardFocus = window;
|
_glfw.wl.keyboardFocus = window;
|
||||||
_glfwInputWindowFocus(window, true);
|
_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,
|
static void keyboardHandleLeave(void* data UNUSED,
|
||||||
@@ -397,13 +413,14 @@ static void keyboardHandleLeave(void* data UNUSED,
|
|||||||
|
|
||||||
_glfw.wl.keyboardFocus = NULL;
|
_glfw.wl.keyboardFocus = NULL;
|
||||||
_glfwInputWindowFocus(window, false);
|
_glfwInputWindowFocus(window, false);
|
||||||
|
toggleTimer(&_glfw.wl.eventLoopData, _glfw.wl.keyRepeatInfo.keyRepeatTimer, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
dispatchPendingKeyRepeats(id_type timer_id UNUSED, void *data UNUSED) {
|
dispatchPendingKeyRepeats(id_type timer_id UNUSED, void *data UNUSED) {
|
||||||
if (_glfw.wl.keyRepeatInfo.keyboardFocus != _glfw.wl.keyboardFocus || _glfw.wl.keyboardRepeatRate == 0) return;
|
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);
|
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);
|
toggleTimer(&_glfw.wl.eventLoopData, _glfw.wl.keyRepeatInfo.keyRepeatTimer, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -421,6 +438,7 @@ static void keyboardHandleKey(void* data UNUSED,
|
|||||||
int action = state == WL_KEYBOARD_KEY_STATE_PRESSED ? GLFW_PRESS : GLFW_RELEASE;
|
int action = state == WL_KEYBOARD_KEY_STATE_PRESSED ? GLFW_PRESS : GLFW_RELEASE;
|
||||||
glfw_xkb_handle_key_event(window, &_glfw.wl.xkb, key, action);
|
glfw_xkb_handle_key_event(window, &_glfw.wl.xkb, key, action);
|
||||||
bool repeatable = false;
|
bool repeatable = false;
|
||||||
|
_glfw.wl.keyRepeatInfo.key = 0;
|
||||||
|
|
||||||
if (action == GLFW_PRESS && _glfw.wl.keyboardRepeatRate > 0 && glfw_xkb_should_repeat(&_glfw.wl.xkb, key))
|
if (action == GLFW_PRESS && _glfw.wl.keyboardRepeatRate > 0 && glfw_xkb_should_repeat(&_glfw.wl.xkb, key))
|
||||||
{
|
{
|
||||||
@@ -429,7 +447,7 @@ static void keyboardHandleKey(void* data UNUSED,
|
|||||||
_glfw.wl.keyRepeatInfo.keyboardFocus = window;
|
_glfw.wl.keyRepeatInfo.keyboardFocus = window;
|
||||||
}
|
}
|
||||||
if (repeatable) {
|
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);
|
toggleTimer(&_glfw.wl.eventLoopData, _glfw.wl.keyRepeatInfo.keyRepeatTimer, repeatable ? 1 : 0);
|
||||||
}
|
}
|
||||||
@@ -454,7 +472,7 @@ static void keyboardHandleRepeatInfo(void* data UNUSED,
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
_glfw.wl.keyboardRepeatRate = rate;
|
_glfw.wl.keyboardRepeatRate = rate;
|
||||||
_glfw.wl.keyboardRepeatDelay = delay;
|
_glfw.wl.keyboardRepeatDelay = ms_to_monotonic_t(delay);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct wl_keyboard_listener keyboardListener = {
|
static const struct wl_keyboard_listener keyboardListener = {
|
||||||
@@ -607,8 +625,7 @@ static void registryHandleGlobal(void* data UNUSED,
|
|||||||
_glfwSetupWaylandDataDevice();
|
_glfwSetupWaylandDataDevice();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (strcmp(interface, "zwp_primary_selection_device_manager_v1") == 0 ||
|
else if (strcmp(interface, "zwp_primary_selection_device_manager_v1") == 0)
|
||||||
strcmp(interface, "gtk_primary_selection_device_manager") == 0)
|
|
||||||
{
|
{
|
||||||
_glfw.wl.primarySelectionDeviceManager =
|
_glfw.wl.primarySelectionDeviceManager =
|
||||||
wl_registry_bind(registry, name,
|
wl_registry_bind(registry, name,
|
||||||
@@ -728,8 +745,8 @@ int _glfwPlatformInit(void)
|
|||||||
"Wayland: Failed to initialize event loop data");
|
"Wayland: Failed to initialize event loop data");
|
||||||
}
|
}
|
||||||
glfw_dbus_init(&_glfw.wl.dbus, &_glfw.wl.eventLoopData);
|
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.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", 0.5, 0, true, animateCursorImage, 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);
|
_glfw.wl.registry = wl_display_get_registry(_glfw.wl.display);
|
||||||
wl_registry_add_listener(_glfw.wl.registry, ®istryListener, NULL);
|
wl_registry_add_listener(_glfw.wl.registry, ®istryListener, NULL);
|
||||||
@@ -749,7 +766,6 @@ int _glfwPlatformInit(void)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
_glfwInitTimerPOSIX();
|
|
||||||
if (!_glfw.wl.wmBase)
|
if (!_glfw.wl.wmBase)
|
||||||
{
|
{
|
||||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
|||||||
2
glfw/wl_monitor.c
vendored
2
glfw/wl_monitor.c
vendored
@@ -1,5 +1,5 @@
|
|||||||
//========================================================================
|
//========================================================================
|
||||||
// GLFW 3.3 Wayland - www.glfw.org
|
// GLFW 3.4 Wayland - www.glfw.org
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
// Copyright (c) 2014 Jonas Ådahl <jadahl@gmail.com>
|
// Copyright (c) 2014 Jonas Ådahl <jadahl@gmail.com>
|
||||||
//
|
//
|
||||||
|
|||||||
7
glfw/wl_platform.h
vendored
7
glfw/wl_platform.h
vendored
@@ -1,5 +1,5 @@
|
|||||||
//========================================================================
|
//========================================================================
|
||||||
// GLFW 3.3 Wayland - www.glfw.org
|
// GLFW 3.4 Wayland - www.glfw.org
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
// Copyright (c) 2014 Jonas Ådahl <jadahl@gmail.com>
|
// Copyright (c) 2014 Jonas Ådahl <jadahl@gmail.com>
|
||||||
//
|
//
|
||||||
@@ -43,7 +43,6 @@ typedef VkResult (APIENTRY *PFN_vkCreateWaylandSurfaceKHR)(VkInstance,const VkWa
|
|||||||
typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR)(VkPhysicalDevice,uint32_t,struct wl_display*);
|
typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR)(VkPhysicalDevice,uint32_t,struct wl_display*);
|
||||||
|
|
||||||
#include "posix_thread.h"
|
#include "posix_thread.h"
|
||||||
#include "posix_time.h"
|
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
#include "linux_joystick.h"
|
#include "linux_joystick.h"
|
||||||
#else
|
#else
|
||||||
@@ -156,6 +155,7 @@ typedef struct _GLFWwindowWayland
|
|||||||
// We need to track the monitors the window spans on to calculate the
|
// We need to track the monitors the window spans on to calculate the
|
||||||
// optimal scaling factor.
|
// optimal scaling factor.
|
||||||
int scale;
|
int scale;
|
||||||
|
bool initial_scale_notified;
|
||||||
_GLFWmonitor** monitors;
|
_GLFWmonitor** monitors;
|
||||||
int monitorsCount;
|
int monitorsCount;
|
||||||
int monitorsSize;
|
int monitorsSize;
|
||||||
@@ -247,10 +247,11 @@ typedef struct _GLFWlibraryWayland
|
|||||||
|
|
||||||
struct wl_cursor_theme* cursorTheme;
|
struct wl_cursor_theme* cursorTheme;
|
||||||
struct wl_surface* cursorSurface;
|
struct wl_surface* cursorSurface;
|
||||||
|
GLFWCursorShape cursorPreviousShape;
|
||||||
uint32_t pointerSerial;
|
uint32_t pointerSerial;
|
||||||
|
|
||||||
int32_t keyboardRepeatRate;
|
int32_t keyboardRepeatRate;
|
||||||
int32_t keyboardRepeatDelay;
|
monotonic_t keyboardRepeatDelay;
|
||||||
struct {
|
struct {
|
||||||
uint32_t key;
|
uint32_t key;
|
||||||
id_type keyRepeatTimer;
|
id_type keyRepeatTimer;
|
||||||
|
|||||||
58
glfw/wl_window.c
vendored
58
glfw/wl_window.c
vendored
@@ -1,5 +1,5 @@
|
|||||||
//========================================================================
|
//========================================================================
|
||||||
// GLFW 3.3 Wayland - www.glfw.org
|
// GLFW 3.4 Wayland - www.glfw.org
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
// Copyright (c) 2014 Jonas Ådahl <jadahl@gmail.com>
|
// Copyright (c) 2014 Jonas Ådahl <jadahl@gmail.com>
|
||||||
//
|
//
|
||||||
@@ -32,6 +32,7 @@
|
|||||||
#include "backend_utils.h"
|
#include "backend_utils.h"
|
||||||
#include "memfd.h"
|
#include "memfd.h"
|
||||||
#include "linux_notify.h"
|
#include "linux_notify.h"
|
||||||
|
#include "../kitty/monotonic.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@@ -54,13 +55,18 @@ static bool checkScaleChange(_GLFWwindow* window)
|
|||||||
if (_glfw.wl.compositorVersion < 3)
|
if (_glfw.wl.compositorVersion < 3)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Get the scale factor from the highest scale monitor.
|
// Get the scale factor from the highest scale monitor that this window is on
|
||||||
for (i = 0; i < window->wl.monitorsCount; ++i)
|
for (i = 0; i < window->wl.monitorsCount; ++i)
|
||||||
{
|
{
|
||||||
monitorScale = window->wl.monitors[i]->wl.scale;
|
monitorScale = window->wl.monitors[i]->wl.scale;
|
||||||
if (scale < monitorScale)
|
if (scale < monitorScale)
|
||||||
scale = monitorScale;
|
scale = monitorScale;
|
||||||
}
|
}
|
||||||
|
if (window->wl.monitorsCount < 1 && _glfw.monitorCount > 0) {
|
||||||
|
// The window has not yet been assigned to any monitors, use the primary monitor
|
||||||
|
_GLFWmonitor *m = _glfw.monitors[0];
|
||||||
|
if (m && m->wl.scale > scale) scale = m->wl.scale;
|
||||||
|
}
|
||||||
|
|
||||||
// Only change the framebuffer size if the scale changed.
|
// Only change the framebuffer size if the scale changed.
|
||||||
if (scale != window->wl.scale)
|
if (scale != window->wl.scale)
|
||||||
@@ -69,6 +75,10 @@ static bool checkScaleChange(_GLFWwindow* window)
|
|||||||
wl_surface_set_buffer_scale(window->wl.surface, scale);
|
wl_surface_set_buffer_scale(window->wl.surface, scale);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
if (window->wl.monitorsCount > 0 && !window->wl.initial_scale_notified) {
|
||||||
|
window->wl.initial_scale_notified = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -173,7 +183,7 @@ static void dispatchChangesAfterConfigure(_GLFWwindow *window, int32_t width, in
|
|||||||
* SCM_RIGHTS methods.
|
* SCM_RIGHTS methods.
|
||||||
*
|
*
|
||||||
* posix_fallocate() is used to guarantee that disk space is available
|
* posix_fallocate() is used to guarantee that disk space is available
|
||||||
* for the file at the given size. If disk space is insufficent, errno
|
* for the file at the given size. If disk space is insufficient, errno
|
||||||
* is set to ENOSPC. If posix_fallocate() is not supported, program may
|
* is set to ENOSPC. If posix_fallocate() is not supported, program may
|
||||||
* receive SIGBUS on accessing mmap()'ed file contents instead.
|
* receive SIGBUS on accessing mmap()'ed file contents instead.
|
||||||
*/
|
*/
|
||||||
@@ -241,8 +251,8 @@ static struct wl_buffer* createShmBuffer(const GLFWimage* image)
|
|||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
{
|
{
|
||||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
"Wayland: Creating a buffer file for %d B failed: %%m",
|
"Wayland: Creating a buffer file for %d B failed: %s",
|
||||||
length);
|
length, strerror(errno));
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -250,7 +260,7 @@ static struct wl_buffer* createShmBuffer(const GLFWimage* image)
|
|||||||
if (data == MAP_FAILED)
|
if (data == MAP_FAILED)
|
||||||
{
|
{
|
||||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
"Wayland: mmap failed: %%m");
|
"Wayland: mmap failed: %s", strerror(errno));
|
||||||
close(fd);
|
close(fd);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -545,9 +555,9 @@ static void xdgToplevelHandleConfigure(void* data,
|
|||||||
aspectRatio = (float)width / (float)height;
|
aspectRatio = (float)width / (float)height;
|
||||||
targetRatio = (float)window->numer / (float)window->denom;
|
targetRatio = (float)window->numer / (float)window->denom;
|
||||||
if (aspectRatio < targetRatio)
|
if (aspectRatio < targetRatio)
|
||||||
height = width / targetRatio;
|
height = (int32_t)((float)width / targetRatio);
|
||||||
else if (aspectRatio > targetRatio)
|
else if (aspectRatio > targetRatio)
|
||||||
width = height * targetRatio;
|
width = (int32_t)((float)height * targetRatio);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -684,7 +694,7 @@ setCursorImage(_GLFWcursorWayland* cursorWayland)
|
|||||||
image = cursorWayland->cursor->images[cursorWayland->currentImage];
|
image = cursorWayland->cursor->images[cursorWayland->currentImage];
|
||||||
buffer = wl_cursor_image_get_buffer(image);
|
buffer = wl_cursor_image_get_buffer(image);
|
||||||
if (image->delay) {
|
if (image->delay) {
|
||||||
changeTimerInterval(&_glfw.wl.eventLoopData, _glfw.wl.cursorAnimationTimer, ((double)image->delay) / 1000.0);
|
changeTimerInterval(&_glfw.wl.eventLoopData, _glfw.wl.cursorAnimationTimer, ms_to_monotonic_t(image->delay));
|
||||||
toggleTimer(&_glfw.wl.eventLoopData, _glfw.wl.cursorAnimationTimer, 1);
|
toggleTimer(&_glfw.wl.eventLoopData, _glfw.wl.cursorAnimationTimer, 1);
|
||||||
} else {
|
} else {
|
||||||
toggleTimer(&_glfw.wl.eventLoopData, _glfw.wl.cursorAnimationTimer, 0);
|
toggleTimer(&_glfw.wl.eventLoopData, _glfw.wl.cursorAnimationTimer, 0);
|
||||||
@@ -745,11 +755,11 @@ abortOnFatalError(int last_error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
handleEvents(double timeout)
|
handleEvents(monotonic_t timeout)
|
||||||
{
|
{
|
||||||
struct wl_display* display = _glfw.wl.display;
|
struct wl_display* display = _glfw.wl.display;
|
||||||
errno = 0;
|
errno = 0;
|
||||||
EVDBG("starting handleEvents(%.2f)", timeout);
|
EVDBG("starting handleEvents(%.2f)", monotonic_t_to_s_double(timeout));
|
||||||
|
|
||||||
while (wl_display_prepare_read(display) != 0) {
|
while (wl_display_prepare_read(display) != 0) {
|
||||||
while(1) {
|
while(1) {
|
||||||
@@ -1052,9 +1062,9 @@ void _glfwPlatformGetWindowContentScale(_GLFWwindow* window,
|
|||||||
*yscale = (float) window->wl.scale;
|
*yscale = (float) window->wl.scale;
|
||||||
}
|
}
|
||||||
|
|
||||||
double _glfwPlatformGetDoubleClickInterval(_GLFWwindow* window UNUSED)
|
monotonic_t _glfwPlatformGetDoubleClickInterval(_GLFWwindow* window UNUSED)
|
||||||
{
|
{
|
||||||
return 0.5;
|
return ms_to_monotonic_t(500ll);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformIconifyWindow(_GLFWwindow* window)
|
void _glfwPlatformIconifyWindow(_GLFWwindow* window)
|
||||||
@@ -1227,11 +1237,11 @@ void _glfwPlatformPollEvents(void)
|
|||||||
|
|
||||||
void _glfwPlatformWaitEvents(void)
|
void _glfwPlatformWaitEvents(void)
|
||||||
{
|
{
|
||||||
double timeout = wl_display_dispatch_pending(_glfw.wl.display) > 0 ? 0 : -1;
|
monotonic_t timeout = wl_display_dispatch_pending(_glfw.wl.display) > 0 ? 0 : -1;
|
||||||
handleEvents(timeout);
|
handleEvents(timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformWaitEventsTimeout(double timeout)
|
void _glfwPlatformWaitEventsTimeout(monotonic_t timeout)
|
||||||
{
|
{
|
||||||
if (wl_display_dispatch_pending(_glfw.wl.display) > 0) timeout = 0;
|
if (wl_display_dispatch_pending(_glfw.wl.display) > 0) timeout = 0;
|
||||||
handleEvents(timeout);
|
handleEvents(timeout);
|
||||||
@@ -1268,12 +1278,12 @@ void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode UNUSED)
|
|||||||
_glfwPlatformSetCursor(window, window->wl.currentCursor);
|
_glfwPlatformSetCursor(window, window->wl.currentCursor);
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* _glfwPlatformGetScancodeName(int scancode)
|
const char* _glfwPlatformGetNativeKeyName(int native_key)
|
||||||
{
|
{
|
||||||
return glfw_xkb_keysym_name(scancode);
|
return glfw_xkb_keysym_name(native_key);
|
||||||
}
|
}
|
||||||
|
|
||||||
int _glfwPlatformGetKeyScancode(int key)
|
int _glfwPlatformGetNativeKeyForKey(int key)
|
||||||
{
|
{
|
||||||
return glfw_xkb_sym_for_key(key);
|
return glfw_xkb_sym_for_key(key);
|
||||||
}
|
}
|
||||||
@@ -1462,8 +1472,8 @@ static void send_text(char *text, int fd)
|
|||||||
{
|
{
|
||||||
if (text) {
|
if (text) {
|
||||||
size_t len = strlen(text), pos = 0;
|
size_t len = strlen(text), pos = 0;
|
||||||
double start = glfwGetTime();
|
monotonic_t start = glfwGetTime();
|
||||||
while (pos < len && glfwGetTime() - start < 2.0) {
|
while (pos < len && glfwGetTime() - start < s_to_monotonic_t(2ll)) {
|
||||||
ssize_t ret = write(fd, text + pos, len - pos);
|
ssize_t ret = write(fd, text + pos, len - pos);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
if (errno == EAGAIN || errno == EINTR) continue;
|
if (errno == EAGAIN || errno == EINTR) continue;
|
||||||
@@ -1496,7 +1506,7 @@ static char* read_offer_string(int data_pipe) {
|
|||||||
struct pollfd fds;
|
struct pollfd fds;
|
||||||
fds.fd = data_pipe;
|
fds.fd = data_pipe;
|
||||||
fds.events = POLLIN;
|
fds.events = POLLIN;
|
||||||
double start = glfwGetTime();
|
monotonic_t start = glfwGetTime();
|
||||||
#define bail(...) { \
|
#define bail(...) { \
|
||||||
_glfwInputError(GLFW_PLATFORM_ERROR, __VA_ARGS__); \
|
_glfwInputError(GLFW_PLATFORM_ERROR, __VA_ARGS__); \
|
||||||
free(buf); buf = NULL; \
|
free(buf); buf = NULL; \
|
||||||
@@ -1504,7 +1514,7 @@ static char* read_offer_string(int data_pipe) {
|
|||||||
return NULL; \
|
return NULL; \
|
||||||
}
|
}
|
||||||
|
|
||||||
while (glfwGetTime() - start < 2) {
|
while (glfwGetTime() - start < s_to_monotonic_t(2ll)) {
|
||||||
int ret = poll(&fds, 1, 2000);
|
int ret = poll(&fds, 1, 2000);
|
||||||
if (ret == -1) {
|
if (ret == -1) {
|
||||||
if (errno == EINTR) continue;
|
if (errno == EINTR) continue;
|
||||||
@@ -1836,7 +1846,7 @@ static inline bool _glfwEnsureDataDevice(void) {
|
|||||||
if (!_glfw.wl.dataDevice)
|
if (!_glfw.wl.dataDevice)
|
||||||
{
|
{
|
||||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
"Wayland: Cannot use clipboard, failed to create data device");
|
"Wayland: Cannot use clipboard, failed to create data device");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2031,7 +2041,7 @@ GLFWAPI struct wl_surface* glfwGetWaylandWindow(GLFWwindow* handle)
|
|||||||
return window->wl.surface;
|
return window->wl.surface;
|
||||||
}
|
}
|
||||||
|
|
||||||
GLFWAPI int glfwGetXKBScancode(const char* keyName, bool caseSensitive) {
|
GLFWAPI int glfwGetNativeKeyForName(const char* keyName, bool caseSensitive) {
|
||||||
return glfw_xkb_keysym_from_name(keyName, caseSensitive);
|
return glfw_xkb_keysym_from_name(keyName, caseSensitive);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
16
glfw/x11_init.c
vendored
16
glfw/x11_init.c
vendored
@@ -1,5 +1,5 @@
|
|||||||
//========================================================================
|
//========================================================================
|
||||||
// GLFW 3.3 X11 - www.glfw.org
|
// GLFW 3.4 X11 - www.glfw.org
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||||
// Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
|
// Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
|
||||||
@@ -433,12 +433,10 @@ static bool initExtensions(void)
|
|||||||
//
|
//
|
||||||
void _glfwGetSystemContentScaleX11(float* xscale, float* yscale, bool bypass_cache)
|
void _glfwGetSystemContentScaleX11(float* xscale, float* yscale, bool bypass_cache)
|
||||||
{
|
{
|
||||||
// NOTE: Default to the display-wide DPI as we don't currently have a policy
|
// Start by assuming the default X11 DPI
|
||||||
// for which monitor a window is considered to be on
|
// NOTE: Some desktop environments (KDE) may remove the Xft.dpi field when it
|
||||||
float xdpi = DisplayWidth(_glfw.x11.display, _glfw.x11.screen) *
|
// would be set to 96, so assume that is the case if we cannot find it
|
||||||
25.4f / DisplayWidthMM(_glfw.x11.display, _glfw.x11.screen);
|
float xdpi = 96.f, ydpi = 96.f;
|
||||||
float ydpi = DisplayHeight(_glfw.x11.display, _glfw.x11.screen) *
|
|
||||||
25.4f / DisplayHeightMM(_glfw.x11.display, _glfw.x11.screen);
|
|
||||||
|
|
||||||
// NOTE: Basing the scale on Xft.dpi where available should provide the most
|
// NOTE: Basing the scale on Xft.dpi where available should provide the most
|
||||||
// consistent user experience (matches Qt, Gtk, etc), although not
|
// 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 (XrmGetResource(db, "Xft.dpi", "Xft.Dpi", &type, &value))
|
||||||
{
|
{
|
||||||
if (type && strcmp(type, "String") == 0)
|
if (type && strcmp(type, "String") == 0)
|
||||||
xdpi = ydpi = atof(value.addr);
|
xdpi = ydpi = (float)atof(value.addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
XrmDestroyDatabase(db);
|
XrmDestroyDatabase(db);
|
||||||
@@ -637,8 +635,6 @@ int _glfwPlatformInit(void)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
_glfwInitTimerPOSIX();
|
|
||||||
|
|
||||||
_glfwPollMonitorsX11();
|
_glfwPollMonitorsX11();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
12
glfw/x11_monitor.c
vendored
12
glfw/x11_monitor.c
vendored
@@ -1,5 +1,5 @@
|
|||||||
//========================================================================
|
//========================================================================
|
||||||
// GLFW 3.3 X11 - www.glfw.org
|
// GLFW 3.4 X11 - www.glfw.org
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||||
// Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
|
// Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
|
||||||
@@ -166,6 +166,16 @@ void _glfwPollMonitorsX11(void)
|
|||||||
heightMM = oi->mm_height;
|
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);
|
_GLFWmonitor* monitor = _glfwAllocMonitor(oi->name, widthMM, heightMM);
|
||||||
monitor->x11.output = sr->outputs[i];
|
monitor->x11.output = sr->outputs[i];
|
||||||
monitor->x11.crtc = oi->crtc;
|
monitor->x11.crtc = oi->crtc;
|
||||||
|
|||||||
3
glfw/x11_platform.h
vendored
3
glfw/x11_platform.h
vendored
@@ -1,5 +1,5 @@
|
|||||||
//========================================================================
|
//========================================================================
|
||||||
// GLFW 3.3 X11 - www.glfw.org
|
// GLFW 3.4 X11 - www.glfw.org
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||||
// Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
|
// Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
|
||||||
@@ -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);
|
typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR)(VkPhysicalDevice,uint32_t,xcb_connection_t*,xcb_visualid_t);
|
||||||
|
|
||||||
#include "posix_thread.h"
|
#include "posix_thread.h"
|
||||||
#include "posix_time.h"
|
|
||||||
#include "glx_context.h"
|
#include "glx_context.h"
|
||||||
#include "egl_context.h"
|
#include "egl_context.h"
|
||||||
#include "osmesa_context.h"
|
#include "osmesa_context.h"
|
||||||
|
|||||||
211
glfw/x11_window.c
vendored
211
glfw/x11_window.c
vendored
@@ -1,5 +1,5 @@
|
|||||||
//========================================================================
|
//========================================================================
|
||||||
// GLFW 3.3 X11 - www.glfw.org
|
// GLFW 3.4 X11 - www.glfw.org
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||||
// Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
|
// Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
|
||||||
@@ -31,6 +31,7 @@
|
|||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
#include "backend_utils.h"
|
#include "backend_utils.h"
|
||||||
#include "linux_notify.h"
|
#include "linux_notify.h"
|
||||||
|
#include "../kitty/monotonic.h"
|
||||||
|
|
||||||
#include <X11/cursorfont.h>
|
#include <X11/cursorfont.h>
|
||||||
#include <X11/Xmd.h>
|
#include <X11/Xmd.h>
|
||||||
@@ -51,6 +52,10 @@
|
|||||||
#define Button6 6
|
#define Button6 6
|
||||||
#define Button7 7
|
#define Button7 7
|
||||||
|
|
||||||
|
// Motif WM hints flags
|
||||||
|
#define MWM_HINTS_DECORATIONS 2
|
||||||
|
#define MWM_DECOR_ALL 1
|
||||||
|
|
||||||
#define _GLFW_XDND_VERSION 5
|
#define _GLFW_XDND_VERSION 5
|
||||||
|
|
||||||
|
|
||||||
@@ -61,8 +66,8 @@
|
|||||||
static unsigned _glfwDispatchX11Events(void);
|
static unsigned _glfwDispatchX11Events(void);
|
||||||
|
|
||||||
static void
|
static void
|
||||||
handleEvents(double timeout) {
|
handleEvents(monotonic_t timeout) {
|
||||||
EVDBG("starting handleEvents(%.2f)", timeout);
|
EVDBG("starting handleEvents(%.2f)", monotonic_t_to_s_double(timeout));
|
||||||
int display_read_ok = pollForEvents(&_glfw.x11.eventLoopData, timeout);
|
int display_read_ok = pollForEvents(&_glfw.x11.eventLoopData, timeout);
|
||||||
EVDBG("display_read_ok: %d", display_read_ok);
|
EVDBG("display_read_ok: %d", display_read_ok);
|
||||||
if (display_read_ok) {
|
if (display_read_ok) {
|
||||||
@@ -77,9 +82,9 @@ handleEvents(double timeout) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
waitForX11Event(double timeout) {
|
waitForX11Event(monotonic_t timeout) {
|
||||||
// returns true iff there is X11 data waiting to be read, does not run watches and timers
|
// 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) {
|
while(true) {
|
||||||
if (timeout >= 0) {
|
if (timeout >= 0) {
|
||||||
const int result = pollWithTimeout(_glfw.x11.eventLoopData.fds, 1, timeout);
|
const int result = pollWithTimeout(_glfw.x11.eventLoopData.fds, 1, timeout);
|
||||||
@@ -109,7 +114,7 @@ static bool waitForVisibilityNotify(_GLFWwindow* window)
|
|||||||
VisibilityNotify,
|
VisibilityNotify,
|
||||||
&dummy))
|
&dummy))
|
||||||
{
|
{
|
||||||
if (!waitForX11Event(0.1))
|
if (!waitForX11Event(ms_to_monotonic_t(100ll)))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -508,8 +513,8 @@ static bool createNativeWindow(_GLFWwindow* window,
|
|||||||
|
|
||||||
if (wndconfig->scaleToMonitor)
|
if (wndconfig->scaleToMonitor)
|
||||||
{
|
{
|
||||||
width *= _glfw.x11.contentScaleX;
|
width *= (int)_glfw.x11.contentScaleX;
|
||||||
height *= _glfw.x11.contentScaleY;
|
height *= (int)_glfw.x11.contentScaleY;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a colormap based on the visual used by the current context
|
// Create a colormap based on the visual used by the current context
|
||||||
@@ -589,7 +594,7 @@ static bool createNativeWindow(_GLFWwindow* window,
|
|||||||
{
|
{
|
||||||
XChangeProperty(_glfw.x11.display, window->x11.handle,
|
XChangeProperty(_glfw.x11.display, window->x11.handle,
|
||||||
_glfw.x11.NET_WM_STATE, XA_ATOM, 32,
|
_glfw.x11.NET_WM_STATE, XA_ATOM, 32,
|
||||||
PropModeReplace, (unsigned char*) &states, count);
|
PropModeReplace, (unsigned char*) states, count);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -880,7 +885,7 @@ static const char* getSelectionString(Atom selection)
|
|||||||
Atom actualType;
|
Atom actualType;
|
||||||
int actualFormat;
|
int actualFormat;
|
||||||
unsigned long itemCount, bytesAfter;
|
unsigned long itemCount, bytesAfter;
|
||||||
double start = glfwGetTime();
|
monotonic_t start = glfwGetTime();
|
||||||
XEvent notification, dummy;
|
XEvent notification, dummy;
|
||||||
|
|
||||||
XConvertSelection(_glfw.x11.display,
|
XConvertSelection(_glfw.x11.display,
|
||||||
@@ -895,10 +900,10 @@ static const char* getSelectionString(Atom selection)
|
|||||||
SelectionNotify,
|
SelectionNotify,
|
||||||
¬ification))
|
¬ification))
|
||||||
{
|
{
|
||||||
double time = glfwGetTime();
|
monotonic_t time = glfwGetTime();
|
||||||
if (time - start > 2)
|
if (time - start > s_to_monotonic_t(2ll))
|
||||||
return "";
|
return "";
|
||||||
waitForX11Event(2.0 - (time - start));
|
waitForX11Event(s_to_monotonic_t(2ll) - (time - start));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (notification.xselection.property == None)
|
if (notification.xselection.property == None)
|
||||||
@@ -935,10 +940,10 @@ static const char* getSelectionString(Atom selection)
|
|||||||
isSelPropNewValueNotify,
|
isSelPropNewValueNotify,
|
||||||
(XPointer) ¬ification))
|
(XPointer) ¬ification))
|
||||||
{
|
{
|
||||||
double time = glfwGetTime();
|
monotonic_t time = glfwGetTime();
|
||||||
if (time - start > 2)
|
if (time - start > s_to_monotonic_t(2ll))
|
||||||
return "";
|
return "";
|
||||||
waitForX11Event(2.0 - (time - start));
|
waitForX11Event(s_to_monotonic_t(2ll) - (time - start));
|
||||||
}
|
}
|
||||||
|
|
||||||
XFree(data);
|
XFree(data);
|
||||||
@@ -2066,7 +2071,7 @@ void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window,
|
|||||||
isFrameExtentsEvent,
|
isFrameExtentsEvent,
|
||||||
(XPointer) window))
|
(XPointer) window))
|
||||||
{
|
{
|
||||||
if (!waitForX11Event(0.5))
|
if (!waitForX11Event(ms_to_monotonic_t(500ll)))
|
||||||
{
|
{
|
||||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
"X11: The window manager has a broken _NET_REQUEST_FRAME_EXTENTS implementation; please report this issue");
|
"X11: The window manager has a broken _NET_REQUEST_FRAME_EXTENTS implementation; please report this issue");
|
||||||
@@ -2103,9 +2108,9 @@ void _glfwPlatformGetWindowContentScale(_GLFWwindow* window UNUSED,
|
|||||||
*yscale = _glfw.x11.contentScaleY;
|
*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)
|
void _glfwPlatformIconifyWindow(_GLFWwindow* window)
|
||||||
@@ -2141,18 +2146,67 @@ void _glfwPlatformRestoreWindow(_GLFWwindow* window)
|
|||||||
|
|
||||||
void _glfwPlatformMaximizeWindow(_GLFWwindow* window)
|
void _glfwPlatformMaximizeWindow(_GLFWwindow* window)
|
||||||
{
|
{
|
||||||
if (_glfw.x11.NET_WM_STATE &&
|
if (!_glfw.x11.NET_WM_STATE ||
|
||||||
_glfw.x11.NET_WM_STATE_MAXIMIZED_VERT &&
|
!_glfw.x11.NET_WM_STATE_MAXIMIZED_VERT ||
|
||||||
_glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ)
|
!_glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_glfwPlatformWindowVisible(window))
|
||||||
{
|
{
|
||||||
sendEventToWM(window,
|
sendEventToWM(window,
|
||||||
_glfw.x11.NET_WM_STATE,
|
_glfw.x11.NET_WM_STATE,
|
||||||
_NET_WM_STATE_ADD,
|
_NET_WM_STATE_ADD,
|
||||||
_glfw.x11.NET_WM_STATE_MAXIMIZED_VERT,
|
_glfw.x11.NET_WM_STATE_MAXIMIZED_VERT,
|
||||||
_glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ,
|
_glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ,
|
||||||
1, 0);
|
1, 0);
|
||||||
XFlush(_glfw.x11.display);
|
|
||||||
}
|
}
|
||||||
|
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)
|
void _glfwPlatformShowWindow(_GLFWwindow* window)
|
||||||
@@ -2172,6 +2226,9 @@ void _glfwPlatformHideWindow(_GLFWwindow* window)
|
|||||||
|
|
||||||
void _glfwPlatformRequestWindowAttention(_GLFWwindow* window)
|
void _glfwPlatformRequestWindowAttention(_GLFWwindow* window)
|
||||||
{
|
{
|
||||||
|
if (!_glfw.x11.NET_WM_STATE || !_glfw.x11.NET_WM_STATE_DEMANDS_ATTENTION)
|
||||||
|
return;
|
||||||
|
|
||||||
sendEventToWM(window,
|
sendEventToWM(window,
|
||||||
_glfw.x11.NET_WM_STATE,
|
_glfw.x11.NET_WM_STATE,
|
||||||
_NET_WM_STATE_ADD,
|
_NET_WM_STATE_ADD,
|
||||||
@@ -2350,33 +2407,24 @@ void _glfwPlatformSetWindowResizable(_GLFWwindow* window, bool enabled UNUSED)
|
|||||||
|
|
||||||
void _glfwPlatformSetWindowDecorated(_GLFWwindow* window, bool enabled)
|
void _glfwPlatformSetWindowDecorated(_GLFWwindow* window, bool enabled)
|
||||||
{
|
{
|
||||||
if (enabled)
|
struct
|
||||||
{
|
{
|
||||||
XDeleteProperty(_glfw.x11.display,
|
unsigned long flags;
|
||||||
window->x11.handle,
|
unsigned long functions;
|
||||||
_glfw.x11.MOTIF_WM_HINTS);
|
unsigned long decorations;
|
||||||
}
|
long input_mode;
|
||||||
else
|
unsigned long status;
|
||||||
{
|
} hints = {0};
|
||||||
struct
|
|
||||||
{
|
|
||||||
unsigned long flags;
|
|
||||||
unsigned long functions;
|
|
||||||
unsigned long decorations;
|
|
||||||
long input_mode;
|
|
||||||
unsigned long status;
|
|
||||||
} hints;
|
|
||||||
|
|
||||||
hints.flags = 2; // Set decorations
|
hints.flags = MWM_HINTS_DECORATIONS;
|
||||||
hints.decorations = 0; // No decorations
|
hints.decorations = enabled ? MWM_DECOR_ALL : 0;
|
||||||
|
|
||||||
XChangeProperty(_glfw.x11.display, window->x11.handle,
|
XChangeProperty(_glfw.x11.display, window->x11.handle,
|
||||||
_glfw.x11.MOTIF_WM_HINTS,
|
_glfw.x11.MOTIF_WM_HINTS,
|
||||||
_glfw.x11.MOTIF_WM_HINTS, 32,
|
_glfw.x11.MOTIF_WM_HINTS, 32,
|
||||||
PropModeReplace,
|
PropModeReplace,
|
||||||
(unsigned char*) &hints,
|
(unsigned char*) &hints,
|
||||||
sizeof(hints) / sizeof(long));
|
sizeof(hints) / sizeof(long));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformSetWindowFloating(_GLFWwindow* window, bool enabled)
|
void _glfwPlatformSetWindowFloating(_GLFWwindow* window, bool enabled)
|
||||||
@@ -2386,7 +2434,7 @@ void _glfwPlatformSetWindowFloating(_GLFWwindow* window, bool enabled)
|
|||||||
|
|
||||||
if (_glfwPlatformWindowVisible(window))
|
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,
|
sendEventToWM(window,
|
||||||
_glfw.x11.NET_WM_STATE,
|
_glfw.x11.NET_WM_STATE,
|
||||||
action,
|
action,
|
||||||
@@ -2395,15 +2443,16 @@ void _glfwPlatformSetWindowFloating(_GLFWwindow* window, bool enabled)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Atom* states;
|
Atom* states = NULL;
|
||||||
unsigned long i, count;
|
unsigned long i, count;
|
||||||
|
|
||||||
count = _glfwGetWindowPropertyX11(window->x11.handle,
|
count = _glfwGetWindowPropertyX11(window->x11.handle,
|
||||||
_glfw.x11.NET_WM_STATE,
|
_glfw.x11.NET_WM_STATE,
|
||||||
XA_ATOM,
|
XA_ATOM,
|
||||||
(unsigned char**) &states);
|
(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)
|
if (enabled)
|
||||||
{
|
{
|
||||||
@@ -2413,32 +2462,36 @@ void _glfwPlatformSetWindowFloating(_GLFWwindow* window, bool enabled)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i == count)
|
if (i < count)
|
||||||
{
|
return;
|
||||||
XChangeProperty(_glfw.x11.display, window->x11.handle,
|
|
||||||
_glfw.x11.NET_WM_STATE, XA_ATOM, 32,
|
XChangeProperty(_glfw.x11.display, window->x11.handle,
|
||||||
PropModeAppend,
|
_glfw.x11.NET_WM_STATE, XA_ATOM, 32,
|
||||||
(unsigned char*) &_glfw.x11.NET_WM_STATE_ABOVE,
|
PropModeAppend,
|
||||||
1);
|
(unsigned char*) &_glfw.x11.NET_WM_STATE_ABOVE,
|
||||||
}
|
1);
|
||||||
}
|
}
|
||||||
else
|
else if (states)
|
||||||
{
|
{
|
||||||
for (i = 0; i < count; i++)
|
for (i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
if (states[i] == _glfw.x11.NET_WM_STATE_ABOVE)
|
if (states[i] == _glfw.x11.NET_WM_STATE_ABOVE)
|
||||||
{
|
break;
|
||||||
states[i] = states[count - 1];
|
|
||||||
count--;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (i == count)
|
||||||
|
return;
|
||||||
|
|
||||||
|
states[i] = states[count - 1];
|
||||||
|
count--;
|
||||||
|
|
||||||
XChangeProperty(_glfw.x11.display, window->x11.handle,
|
XChangeProperty(_glfw.x11.display, window->x11.handle,
|
||||||
_glfw.x11.NET_WM_STATE, XA_ATOM, 32,
|
_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);
|
XFlush(_glfw.x11.display);
|
||||||
@@ -2512,7 +2565,7 @@ _glfwDispatchX11Events(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
XFlush(_glfw.x11.display);
|
XFlush(_glfw.x11.display);
|
||||||
// XFlush can cause events to be queued, we dont use QueuedAfterFlush here
|
// XFlush can cause events to be queued, we don't use QueuedAfterFlush here
|
||||||
// as something might have inserted events into the queue, but we want to guarantee
|
// as something might have inserted events into the queue, but we want to guarantee
|
||||||
// a flush.
|
// a flush.
|
||||||
dispatched += dispatch_x11_queued_events(XEventsQueued(_glfw.x11.display, QueuedAlready));
|
dispatched += dispatch_x11_queued_events(XEventsQueued(_glfw.x11.display, QueuedAlready));
|
||||||
@@ -2527,11 +2580,11 @@ void _glfwPlatformPollEvents(void)
|
|||||||
|
|
||||||
void _glfwPlatformWaitEvents(void)
|
void _glfwPlatformWaitEvents(void)
|
||||||
{
|
{
|
||||||
double timeout = _glfwDispatchX11Events() ? 0 : -1;
|
monotonic_t timeout = _glfwDispatchX11Events() ? 0 : -1;
|
||||||
handleEvents(timeout);
|
handleEvents(timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformWaitEventsTimeout(double timeout)
|
void _glfwPlatformWaitEventsTimeout(monotonic_t timeout)
|
||||||
{
|
{
|
||||||
if (_glfwDispatchX11Events()) timeout = 0;
|
if (_glfwDispatchX11Events()) timeout = 0;
|
||||||
handleEvents(timeout);
|
handleEvents(timeout);
|
||||||
@@ -2585,13 +2638,13 @@ void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode)
|
|||||||
XFlush(_glfw.x11.display);
|
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);
|
return glfw_xkb_sym_for_key(key);
|
||||||
}
|
}
|
||||||
@@ -2870,7 +2923,7 @@ GLFWAPI Window glfwGetX11Window(GLFWwindow* handle)
|
|||||||
return window->x11.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);
|
return glfw_xkb_keysym_from_name(keyName, caseSensitive);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
239
glfw/xkb_glfw.c
vendored
239
glfw/xkb_glfw.c
vendored
@@ -1,5 +1,5 @@
|
|||||||
//========================================================================
|
//========================================================================
|
||||||
// GLFW 3.3 XKB - www.glfw.org
|
// GLFW 3.4 XKB - www.glfw.org
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
// Copyright (c) 2018 Kovid Goyal <kovid@kovidgoyal.net>
|
// Copyright (c) 2018 Kovid Goyal <kovid@kovidgoyal.net>
|
||||||
//
|
//
|
||||||
@@ -37,19 +37,130 @@ START_ALLOW_CASE_RANGE
|
|||||||
#define map_key(key) \
|
#define map_key(key) \
|
||||||
switch(key) { \
|
switch(key) { \
|
||||||
S(space, SPACE); \
|
S(space, SPACE); \
|
||||||
|
S(exclam, EXCLAM); \
|
||||||
|
S(quotedbl, DOUBLE_QUOTE); \
|
||||||
|
S(numbersign, NUMBER_SIGN); \
|
||||||
|
S(dollar, DOLLAR); \
|
||||||
|
S(ampersand, AMPERSAND); \
|
||||||
S(apostrophe, APOSTROPHE); \
|
S(apostrophe, APOSTROPHE); \
|
||||||
|
S(parenleft, PARENTHESIS_LEFT); \
|
||||||
|
S(parenright, PARENTHESIS_RIGHT); \
|
||||||
|
S(plus, PLUS); \
|
||||||
S(comma, COMMA); \
|
S(comma, COMMA); \
|
||||||
S(minus, MINUS); \
|
S(minus, MINUS); \
|
||||||
S(period, PERIOD); \
|
S(period, PERIOD); \
|
||||||
S(slash, SLASH); \
|
S(slash, SLASH); \
|
||||||
|
R(0, 9, 0, 9); \
|
||||||
|
S(colon, COLON); \
|
||||||
S(semicolon, SEMICOLON); \
|
S(semicolon, SEMICOLON); \
|
||||||
|
S(less, LESS); \
|
||||||
S(equal, EQUAL); \
|
S(equal, EQUAL); \
|
||||||
|
S(greater, GREATER); \
|
||||||
|
S(at, AT); \
|
||||||
|
D(A, Z, A, Z); \
|
||||||
S(bracketleft, LEFT_BRACKET); \
|
S(bracketleft, LEFT_BRACKET); \
|
||||||
S(backslash, BACKSLASH); \
|
S(backslash, BACKSLASH); \
|
||||||
S(bracketright, RIGHT_BRACKET); \
|
S(bracketright, RIGHT_BRACKET); \
|
||||||
S(plus, PLUS); \
|
|
||||||
S(underscore, UNDERSCORE); \
|
S(underscore, UNDERSCORE); \
|
||||||
S(grave, GRAVE_ACCENT); \
|
S(grave, GRAVE_ACCENT); \
|
||||||
|
R(a, z, A, Z); \
|
||||||
|
S(paragraph, PARAGRAPH); \
|
||||||
|
S(masculine, MASCULINE); \
|
||||||
|
S(agrave, A_GRAVE); \
|
||||||
|
F(Agrave, A_GRAVE); \
|
||||||
|
S(adiaeresis, A_DIAERESIS); \
|
||||||
|
F(Adiaeresis, A_DIAERESIS); \
|
||||||
|
S(aring, A_RING); \
|
||||||
|
F(Aring, A_RING); \
|
||||||
|
S(ae, AE); \
|
||||||
|
F(AE, AE); \
|
||||||
|
S(ccedilla, C_CEDILLA); \
|
||||||
|
F(Ccedilla, C_CEDILLA); \
|
||||||
|
S(egrave, E_GRAVE); \
|
||||||
|
F(Egrave, E_GRAVE); \
|
||||||
|
S(aacute, E_ACUTE); \
|
||||||
|
F(Eacute, E_ACUTE); \
|
||||||
|
S(igrave, I_GRAVE); \
|
||||||
|
F(Igrave, I_GRAVE); \
|
||||||
|
S(ntilde, N_TILDE); \
|
||||||
|
F(Ntilde, N_TILDE); \
|
||||||
|
S(ograve, O_GRAVE); \
|
||||||
|
F(Ograve, O_GRAVE); \
|
||||||
|
S(odiaeresis, O_DIAERESIS); \
|
||||||
|
F(Odiaeresis, O_DIAERESIS); \
|
||||||
|
S(oslash, O_SLASH); \
|
||||||
|
F(Oslash, O_SLASH); \
|
||||||
|
S(ugrave, U_GRAVE); \
|
||||||
|
F(Ugrave, U_GRAVE); \
|
||||||
|
S(udiaeresis, U_DIAERESIS); \
|
||||||
|
F(Udiaeresis, U_DIAERESIS); \
|
||||||
|
S(ssharp, S_SHARP); \
|
||||||
|
S(Cyrillic_a, CYRILLIC_A); \
|
||||||
|
F(Cyrillic_A, CYRILLIC_A); \
|
||||||
|
S(Cyrillic_be, CYRILLIC_BE); \
|
||||||
|
F(Cyrillic_BE, CYRILLIC_BE); \
|
||||||
|
S(Cyrillic_ve, CYRILLIC_VE); \
|
||||||
|
F(Cyrillic_VE, CYRILLIC_VE); \
|
||||||
|
S(Cyrillic_ghe, CYRILLIC_GHE); \
|
||||||
|
F(Cyrillic_GHE, CYRILLIC_GHE); \
|
||||||
|
S(Cyrillic_de, CYRILLIC_DE); \
|
||||||
|
F(Cyrillic_DE, CYRILLIC_DE); \
|
||||||
|
S(Cyrillic_ie, CYRILLIC_IE); \
|
||||||
|
F(Cyrillic_IE, CYRILLIC_IE); \
|
||||||
|
S(Cyrillic_zhe, CYRILLIC_ZHE); \
|
||||||
|
F(Cyrillic_ZHE, CYRILLIC_ZHE); \
|
||||||
|
S(Cyrillic_ze, CYRILLIC_ZE); \
|
||||||
|
F(Cyrillic_ZE, CYRILLIC_ZE); \
|
||||||
|
S(Cyrillic_i, CYRILLIC_I); \
|
||||||
|
F(Cyrillic_I, CYRILLIC_I); \
|
||||||
|
S(Cyrillic_shorti, CYRILLIC_SHORT_I); \
|
||||||
|
F(Cyrillic_SHORTI, CYRILLIC_SHORT_I); \
|
||||||
|
S(Cyrillic_ka, CYRILLIC_KA); \
|
||||||
|
F(Cyrillic_KA, CYRILLIC_KA); \
|
||||||
|
S(Cyrillic_el, CYRILLIC_EL); \
|
||||||
|
F(Cyrillic_EL, CYRILLIC_EL); \
|
||||||
|
S(Cyrillic_em, CYRILLIC_EM); \
|
||||||
|
F(Cyrillic_EM, CYRILLIC_EM); \
|
||||||
|
S(Cyrillic_en, CYRILLIC_EN); \
|
||||||
|
F(Cyrillic_EN, CYRILLIC_EN); \
|
||||||
|
S(Cyrillic_o, CYRILLIC_O); \
|
||||||
|
F(Cyrillic_O, CYRILLIC_O); \
|
||||||
|
S(Cyrillic_pe, CYRILLIC_PE); \
|
||||||
|
F(Cyrillic_PE, CYRILLIC_PE); \
|
||||||
|
S(Cyrillic_er, CYRILLIC_ER); \
|
||||||
|
F(Cyrillic_ER, CYRILLIC_ER); \
|
||||||
|
S(Cyrillic_es, CYRILLIC_ES); \
|
||||||
|
F(Cyrillic_ES, CYRILLIC_ES); \
|
||||||
|
S(Cyrillic_te, CYRILLIC_TE); \
|
||||||
|
F(Cyrillic_TE, CYRILLIC_TE); \
|
||||||
|
S(Cyrillic_u, CYRILLIC_U); \
|
||||||
|
F(Cyrillic_U, CYRILLIC_U); \
|
||||||
|
S(Cyrillic_ef, CYRILLIC_EF); \
|
||||||
|
F(Cyrillic_EF, CYRILLIC_EF); \
|
||||||
|
S(Cyrillic_ha, CYRILLIC_HA); \
|
||||||
|
F(Cyrillic_HA, CYRILLIC_HA); \
|
||||||
|
S(Cyrillic_tse, CYRILLIC_TSE); \
|
||||||
|
F(Cyrillic_TSE, CYRILLIC_TSE); \
|
||||||
|
S(Cyrillic_che, CYRILLIC_CHE); \
|
||||||
|
F(Cyrillic_CHE, CYRILLIC_CHE); \
|
||||||
|
S(Cyrillic_sha, CYRILLIC_SHA); \
|
||||||
|
F(Cyrillic_SHA, CYRILLIC_SHA); \
|
||||||
|
S(Cyrillic_shcha, CYRILLIC_SHCHA); \
|
||||||
|
F(Cyrillic_SHCHA, CYRILLIC_SHCHA); \
|
||||||
|
S(Cyrillic_hardsign, CYRILLIC_HARD_SIGN); \
|
||||||
|
F(Cyrillic_HARDSIGN, CYRILLIC_HARD_SIGN); \
|
||||||
|
S(Cyrillic_yeru, CYRILLIC_YERU); \
|
||||||
|
F(Cyrillic_YERU, CYRILLIC_YERU); \
|
||||||
|
S(Cyrillic_softsign, CYRILLIC_SOFT_SIGN); \
|
||||||
|
F(Cyrillic_SOFTSIGN, CYRILLIC_SOFT_SIGN); \
|
||||||
|
S(Cyrillic_e, CYRILLIC_E); \
|
||||||
|
F(Cyrillic_E, CYRILLIC_E); \
|
||||||
|
S(Cyrillic_yu, CYRILLIC_YU); \
|
||||||
|
F(Cyrillic_YU, CYRILLIC_YU); \
|
||||||
|
S(Cyrillic_ya, CYRILLIC_YA); \
|
||||||
|
F(Cyrillic_YA, CYRILLIC_YA); \
|
||||||
|
S(Cyrillic_io, CYRILLIC_IO); \
|
||||||
|
F(Cyrillic_IO, CYRILLIC_IO); \
|
||||||
S(Escape, ESCAPE); \
|
S(Escape, ESCAPE); \
|
||||||
S(Return, ENTER); \
|
S(Return, ENTER); \
|
||||||
S(Tab, TAB); \
|
S(Tab, TAB); \
|
||||||
@@ -91,9 +202,6 @@ START_ALLOW_CASE_RANGE
|
|||||||
S(Alt_R, RIGHT_ALT); \
|
S(Alt_R, RIGHT_ALT); \
|
||||||
S(Super_R, RIGHT_SUPER); \
|
S(Super_R, RIGHT_SUPER); \
|
||||||
S(Menu, MENU); \
|
S(Menu, MENU); \
|
||||||
R(0, 9, 0, 9); \
|
|
||||||
R(a, z, A, Z); \
|
|
||||||
D(A, Z, A, Z); \
|
|
||||||
R(F1, F25, F1, F25); \
|
R(F1, F25, F1, F25); \
|
||||||
R(KP_0, KP_9, KP_0, KP_9); \
|
R(KP_0, KP_9, KP_0, KP_9); \
|
||||||
|
|
||||||
@@ -329,24 +437,22 @@ glfw_xkb_update_modifiers(_GLFWXKBData *xkb, xkb_mod_mask_t depressed, xkb_mod_m
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
glfw_xkb_should_repeat(_GLFWXKBData *xkb, xkb_keycode_t scancode) {
|
glfw_xkb_should_repeat(_GLFWXKBData *xkb, xkb_keycode_t keycode) {
|
||||||
#ifdef _GLFW_WAYLAND
|
#ifdef _GLFW_WAYLAND
|
||||||
scancode += 8;
|
keycode += 8;
|
||||||
#endif
|
#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
|
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;
|
*compose_completed = 0;
|
||||||
if (sym == XKB_KEY_NoSymbol || !composeState) return sym;
|
if (sym == XKB_KEY_NoSymbol || !composeState) return sym;
|
||||||
if (xkb_compose_state_feed(composeState, sym) != XKB_COMPOSE_FEED_ACCEPTED) return sym;
|
if (xkb_compose_state_feed(composeState, sym) != XKB_COMPOSE_FEED_ACCEPTED) return sym;
|
||||||
switch (xkb_compose_state_get_status(composeState)) {
|
switch (xkb_compose_state_get_status(composeState)) {
|
||||||
case XKB_COMPOSE_COMPOSED:
|
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;
|
*compose_completed = 1;
|
||||||
return xkb_compose_state_get_one_sym(composeState);
|
return xkb_compose_state_get_one_sym(composeState);
|
||||||
case XKB_COMPOSE_COMPOSING:
|
case XKB_COMPOSE_COMPOSING:
|
||||||
@@ -426,66 +532,74 @@ glfw_xkb_update_ime_state(_GLFWwindow *w, _GLFWXKBData *xkb, int which, int a, i
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
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);
|
_GLFWwindow *window = _glfwWindowForId(ev->window_id);
|
||||||
if (failed && window && window->callbacks.keyboard) {
|
if (failed && window && window->callbacks.keyboard) {
|
||||||
// notify application to remove any existing pre-edit text
|
// 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;
|
static xkb_keycode_t last_handled_press_keycode = 0;
|
||||||
// We filter out release events that correspond to the last press event
|
// We filter out release events that correspond to the last press event
|
||||||
// handled by the IME system. This wont fix the case of multiple key
|
// handled by the IME system. This won't fix the case of multiple key
|
||||||
// presses before a release, but is better than nothing. For that case
|
// presses before a release, but is better than nothing. For that case
|
||||||
// you'd need to implement a ring buffer to store pending key presses.
|
// you'd need to implement a ring buffer to store pending key presses.
|
||||||
xkb_keycode_t prev_handled_press = last_handled_press_keycode;
|
xkb_keycode_t prev_handled_press = last_handled_press_keycode;
|
||||||
last_handled_press_keycode = 0;
|
last_handled_press_keycode = 0;
|
||||||
bool is_release = ev->action == GLFW_RELEASE;
|
bool is_release = ev->glfw_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);
|
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->keycode == prev_handled_press)) {
|
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",
|
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->glfw_ev.native_key, _glfwGetKeyName(ev->glfw_ev.native_key), ev->glfw_ev.key, glfw_xkb_keysym_name(ev->glfw_ev.key),
|
||||||
(ev->action == GLFW_RELEASE ? "RELEASE" : (ev->action == GLFW_PRESS ? "PRESS" : "REPEAT")),
|
(ev->glfw_ev.action == GLFW_RELEASE ? "RELEASE" : (ev->glfw_ev.action == GLFW_PRESS ? "PRESS" : "REPEAT")),
|
||||||
format_mods(ev->glfw_modifiers), ev->text
|
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");
|
} 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
|
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;
|
const xkb_keysym_t *syms, *clean_syms, *default_syms;
|
||||||
xkb_keysym_t glfw_sym;
|
xkb_keysym_t xkb_sym;
|
||||||
xkb_keycode_t code_for_sym = scancode;
|
xkb_keycode_t code_for_sym = xkb_keycode, ibus_keycode = xkb_keycode;
|
||||||
key_event.ibus_keycode = scancode;
|
GLFWkeyevent glfw_ev;
|
||||||
|
_glfwInitializeKeyEvent(&glfw_ev, GLFW_KEY_UNKNOWN, 0, GLFW_PRESS, 0); // init with default values
|
||||||
#ifdef _GLFW_WAYLAND
|
#ifdef _GLFW_WAYLAND
|
||||||
code_for_sym += 8;
|
code_for_sym += 8;
|
||||||
#else
|
#else
|
||||||
key_event.ibus_keycode -= 8;
|
ibus_keycode -= 8;
|
||||||
#endif
|
#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;
|
XKBStateGroup *sg = &xkb->states;
|
||||||
int num_syms = xkb_state_key_get_syms(sg->state, code_for_sym, &syms);
|
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);
|
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
|
// According to the documentation of xkb_compose_state_feed it does not
|
||||||
// support multi-sym events, so we ignore them
|
// support multi-sym events, so we ignore them
|
||||||
if (num_syms != 1 || num_clean_syms != 1) {
|
if (num_syms != 1 || num_clean_syms != 1) {
|
||||||
debug("num_syms: %d num_clean_syms: %d ignoring event\n", num_syms, num_clean_syms);
|
debug("num_syms: %d num_clean_syms: %d ignoring event\n", num_syms, num_clean_syms);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
glfw_sym = clean_syms[0];
|
xkb_sym = clean_syms[0];
|
||||||
debug("clean_sym: %s ", glfw_xkb_keysym_name(clean_syms[0]));
|
debug("clean_sym: %s ", glfw_xkb_keysym_name(clean_syms[0]));
|
||||||
if (action == GLFW_PRESS || action == GLFW_REPEAT) {
|
if (action == GLFW_PRESS || action == GLFW_REPEAT) {
|
||||||
const char *text_type = "composed_text";
|
const char *text_type = "composed_text";
|
||||||
int compose_completed;
|
int compose_completed;
|
||||||
glfw_sym = compose_symbol(sg->composeState, syms[0], &compose_completed);
|
xkb_sym = compose_symbol(sg->composeState, syms[0], &compose_completed, key_text, sizeof(key_text));
|
||||||
if (glfw_sym == XKB_KEY_NoSymbol && !compose_completed) {
|
if (xkb_sym == XKB_KEY_NoSymbol && !compose_completed) {
|
||||||
debug("compose not complete, ignoring.\n");
|
debug("compose not complete, ignoring.\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
debug("composed_sym: %s ", glfw_xkb_keysym_name(glfw_sym));
|
debug("composed_sym: %s ", glfw_xkb_keysym_name(xkb_sym));
|
||||||
if (glfw_sym == syms[0]) { // composed sym is the same as non-composed 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
|
// 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
|
// are active (for example if ISO_Shift_Level_* mods are active
|
||||||
// they are not reported by GLFW so the key should be the shifted
|
// they are not reported by GLFW so the key should be the shifted
|
||||||
@@ -493,37 +607,58 @@ glfw_xkb_handle_key_event(_GLFWwindow *window, _GLFWXKBData *xkb, xkb_keycode_t
|
|||||||
xkb_mod_mask_t consumed_unknown_mods = xkb_state_key_get_consumed_mods(sg->state, code_for_sym) & sg->activeUnknownModifiers;
|
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 (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)); }
|
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
|
// 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";
|
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 ((1 <= key_text[0] && key_text[0] <= 31) || key_text[0] == 127) {
|
||||||
if (key_event.text[0]) { debug("%s: %s ", text_type, key_event.text); }
|
key_text[0] = 0; // don't send text for ascii control codes
|
||||||
|
}
|
||||||
|
if (key_text[0]) { debug("%s: %s ", text_type, key_text); }
|
||||||
}
|
}
|
||||||
int glfw_keycode = glfw_key_for_sym(glfw_sym);
|
int glfw_sym = glfw_key_for_sym(xkb_sym);
|
||||||
bool is_fallback = false;
|
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);
|
int num_default_syms = xkb_state_key_get_syms(sg->default_state, code_for_sym, &default_syms);
|
||||||
if (num_default_syms > 0) {
|
if (num_default_syms > 0) {
|
||||||
glfw_sym = default_syms[0];
|
xkb_sym = default_syms[0];
|
||||||
glfw_keycode = glfw_key_for_sym(glfw_sym);
|
glfw_sym = glfw_key_for_sym(xkb_sym);
|
||||||
is_fallback = true;
|
is_fallback = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
debug(
|
debug(
|
||||||
"%s%s: %d (%s) xkb_key: %d (%s)\n",
|
"%s%s: %d (%s) xkb_key: %d (%s)\n",
|
||||||
format_mods(sg->modifiers),
|
format_mods(sg->modifiers),
|
||||||
is_fallback ? "glfw_fallback_key" : "glfw_key", glfw_keycode, _glfwGetKeyName(glfw_keycode),
|
is_fallback ? "glfw_fallback_key" : "glfw_key", glfw_sym, _glfwGetKeyName(glfw_sym),
|
||||||
glfw_sym, glfw_xkb_keysym_name(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;
|
// NOTE: On linux, the reported native key identifier is the XKB keysym value.
|
||||||
key_event.window_id = window->id; key_event.glfw_keycode = glfw_keycode;
|
// Do not confuse `native_key` with `xkb_keycode` (the native keycode reported for the
|
||||||
key_event.ibus_sym = syms[0];
|
// glfw event VS the X internal code for a key).
|
||||||
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));
|
// 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 {
|
} else {
|
||||||
_glfwInputKeyboard(window, glfw_keycode, glfw_sym, action, sg->modifiers, key_event.text, 0);
|
_glfwInputKeyboard(window, &glfw_ev);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
12
glfw/xkb_glfw.h
vendored
12
glfw/xkb_glfw.h
vendored
@@ -1,5 +1,5 @@
|
|||||||
//========================================================================
|
//========================================================================
|
||||||
// GLFW 3.3 XKB - www.glfw.org
|
// GLFW 3.4 XKB - www.glfw.org
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
// Copyright (c) 2018 Kovid Goyal <kovid@kovidgoyal.net>
|
// Copyright (c) 2018 Kovid Goyal <kovid@kovidgoyal.net>
|
||||||
//
|
//
|
||||||
@@ -67,8 +67,8 @@ typedef struct {
|
|||||||
|
|
||||||
#ifdef _GLFW_X11
|
#ifdef _GLFW_X11
|
||||||
int32_t keyboard_device_id;
|
int32_t keyboard_device_id;
|
||||||
bool available;
|
bool available;
|
||||||
bool detectable;
|
bool detectable;
|
||||||
int majorOpcode;
|
int majorOpcode;
|
||||||
int eventBase;
|
int eventBase;
|
||||||
int errorBase;
|
int errorBase;
|
||||||
@@ -87,10 +87,10 @@ void glfw_xkb_release(_GLFWXKBData *xkb);
|
|||||||
bool glfw_xkb_create_context(_GLFWXKBData *xkb);
|
bool glfw_xkb_create_context(_GLFWXKBData *xkb);
|
||||||
bool glfw_xkb_compile_keymap(_GLFWXKBData *xkb, const char *map_str);
|
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);
|
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);
|
const char* glfw_xkb_keysym_name(xkb_keysym_t sym);
|
||||||
xkb_keysym_t glfw_xkb_sym_for_key(int key);
|
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);
|
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_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);
|
||||||
|
|||||||
@@ -2,14 +2,17 @@
|
|||||||
# vim:fileencoding=utf-8
|
# vim:fileencoding=utf-8
|
||||||
# License: GPL v3 Copyright: 2018, Kovid Goyal <kovid at kovidgoyal.net>
|
# License: GPL v3 Copyright: 2018, Kovid Goyal <kovid at kovidgoyal.net>
|
||||||
|
|
||||||
|
import atexit
|
||||||
import os
|
import os
|
||||||
import signal
|
import signal
|
||||||
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
|
import tempfile
|
||||||
import warnings
|
import warnings
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
|
from contextlib import suppress
|
||||||
from functools import partial
|
from functools import partial
|
||||||
from gettext import gettext as _
|
from gettext import gettext as _
|
||||||
from contextlib import suppress
|
|
||||||
|
|
||||||
from kitty.cli import CONFIG_HELP, parse_args
|
from kitty.cli import CONFIG_HELP, parse_args
|
||||||
from kitty.constants import appname
|
from kitty.constants import appname
|
||||||
@@ -506,7 +509,7 @@ def showwarning(message, category, filename, lineno, file=None, line=None):
|
|||||||
|
|
||||||
|
|
||||||
showwarning.warnings = []
|
showwarning.warnings = []
|
||||||
help_text = 'Show a side-by-side diff of the specified files/directories'
|
help_text = 'Show a side-by-side diff of the specified files/directories. You can also use ssh:hostname:remote-file-path to diff remote files.'
|
||||||
usage = 'file_or_directory_left file_or_directory_right'
|
usage = 'file_or_directory_left file_or_directory_right'
|
||||||
|
|
||||||
|
|
||||||
@@ -516,6 +519,20 @@ def terminate_processes(processes):
|
|||||||
os.kill(pid, signal.SIGKILL)
|
os.kill(pid, signal.SIGKILL)
|
||||||
|
|
||||||
|
|
||||||
|
def get_remote_file(path):
|
||||||
|
if path.startswith('ssh:'):
|
||||||
|
parts = path.split(':', 2)
|
||||||
|
if len(parts) == 3:
|
||||||
|
hostname, rpath = parts[1:]
|
||||||
|
with tempfile.NamedTemporaryFile(suffix='-' + os.path.basename(rpath), prefix='remote:', delete=False) as tf:
|
||||||
|
atexit.register(os.remove, tf.name)
|
||||||
|
p = subprocess.Popen(['ssh', hostname, 'cat', rpath], stdout=tf)
|
||||||
|
if p.wait() != 0:
|
||||||
|
raise SystemExit(p.returncode)
|
||||||
|
return tf.name
|
||||||
|
return path
|
||||||
|
|
||||||
|
|
||||||
def main(args):
|
def main(args):
|
||||||
warnings.showwarning = showwarning
|
warnings.showwarning = showwarning
|
||||||
args, items = parse_args(args[1:], OPTIONS, usage, help_text, 'kitty +kitten diff')
|
args, items = parse_args(args[1:], OPTIONS, usage, help_text, 'kitty +kitten diff')
|
||||||
@@ -528,6 +545,7 @@ def main(args):
|
|||||||
opts = init_config(args)
|
opts = init_config(args)
|
||||||
set_diff_command(opts.diff_cmd)
|
set_diff_command(opts.diff_cmd)
|
||||||
lines_for_path.replace_tab_by = opts.replace_tab_by
|
lines_for_path.replace_tab_by = opts.replace_tab_by
|
||||||
|
left, right = map(get_remote_file, (left, right))
|
||||||
for f in left, right:
|
for f in left, right:
|
||||||
if not os.path.exists(f):
|
if not os.path.exists(f):
|
||||||
raise SystemExit('{} does not exist'.format(f))
|
raise SystemExit('{} does not exist'.format(f))
|
||||||
|
|||||||
@@ -20,35 +20,41 @@ from ..tui.loop import Loop
|
|||||||
from ..tui.operations import faint, styled
|
from ..tui.operations import faint, styled
|
||||||
|
|
||||||
URL_PREFIXES = 'http https file ftp'.split()
|
URL_PREFIXES = 'http https file ftp'.split()
|
||||||
HINT_ALPHABET = string.digits + string.ascii_lowercase
|
DEFAULT_HINT_ALPHABET = string.digits + string.ascii_lowercase
|
||||||
screen_size = screen_size_function()
|
screen_size = screen_size_function()
|
||||||
|
|
||||||
|
|
||||||
class Mark:
|
class Mark:
|
||||||
|
|
||||||
__slots__ = ('index', 'start', 'end', 'text')
|
__slots__ = ('index', 'start', 'end', 'text', 'groupdict')
|
||||||
|
|
||||||
def __init__(self, index, start, end, text):
|
def __init__(self, index, start, end, text, groupdict):
|
||||||
self.index, self.start, self.end = index, start, end
|
self.index, self.start, self.end = index, start, end
|
||||||
self.text = text
|
self.text = text
|
||||||
|
self.groupdict = groupdict
|
||||||
|
|
||||||
|
|
||||||
@lru_cache(maxsize=2048)
|
@lru_cache(maxsize=2048)
|
||||||
def encode_hint(num):
|
def encode_hint(num, alphabet):
|
||||||
res = ''
|
res = ''
|
||||||
d = len(HINT_ALPHABET)
|
d = len(alphabet)
|
||||||
while not res or num > 0:
|
while not res or num > 0:
|
||||||
num, i = divmod(num, d)
|
num, i = divmod(num, d)
|
||||||
res = HINT_ALPHABET[i] + res
|
res = alphabet[i] + res
|
||||||
return res
|
return res
|
||||||
|
|
||||||
|
|
||||||
def decode_hint(x):
|
def decode_hint(x, alphabet=DEFAULT_HINT_ALPHABET):
|
||||||
return int(x, 36)
|
base = len(alphabet)
|
||||||
|
index_map = {c: i for i, c in enumerate(alphabet)}
|
||||||
|
i = 0
|
||||||
|
for char in x:
|
||||||
|
i = i * base + index_map[char]
|
||||||
|
return i
|
||||||
|
|
||||||
|
|
||||||
def highlight_mark(m, text, current_input):
|
def highlight_mark(m, text, current_input, alphabet):
|
||||||
hint = encode_hint(m.index)
|
hint = encode_hint(m.index, alphabet)
|
||||||
if current_input and not hint.startswith(current_input):
|
if current_input and not hint.startswith(current_input):
|
||||||
return faint(text)
|
return faint(text)
|
||||||
hint = hint[len(current_input):] or ' '
|
hint = hint[len(current_input):] or ' '
|
||||||
@@ -63,11 +69,11 @@ def highlight_mark(m, text, current_input):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def render(text, current_input, all_marks, ignore_mark_indices):
|
def render(text, current_input, all_marks, ignore_mark_indices, alphabet):
|
||||||
for mark in reversed(all_marks):
|
for mark in reversed(all_marks):
|
||||||
if mark.index in ignore_mark_indices:
|
if mark.index in ignore_mark_indices:
|
||||||
continue
|
continue
|
||||||
mtext = highlight_mark(mark, text[mark.start:mark.end], current_input)
|
mtext = highlight_mark(mark, text[mark.start:mark.end], current_input, alphabet)
|
||||||
text = text[:mark.start] + mtext + text[mark.end:]
|
text = text[:mark.start] + mtext + text[mark.end:]
|
||||||
|
|
||||||
text = text.replace('\0', '')
|
text = text.replace('\0', '')
|
||||||
@@ -79,6 +85,7 @@ class Hints(Handler):
|
|||||||
|
|
||||||
def __init__(self, text, all_marks, index_map, args):
|
def __init__(self, text, all_marks, index_map, args):
|
||||||
self.text, self.index_map = text, index_map
|
self.text, self.index_map = text, index_map
|
||||||
|
self.alphabet = args.alphabet or DEFAULT_HINT_ALPHABET
|
||||||
self.all_marks = all_marks
|
self.all_marks = all_marks
|
||||||
self.ignore_mark_indices = set()
|
self.ignore_mark_indices = set()
|
||||||
self.args = args
|
self.args = args
|
||||||
@@ -88,6 +95,14 @@ class Hints(Handler):
|
|||||||
self.chosen = []
|
self.chosen = []
|
||||||
self.reset()
|
self.reset()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def text_matches(self):
|
||||||
|
return [m.text + self.match_suffix for m in self.chosen]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def groupdicts(self):
|
||||||
|
return [m.groupdict for m in self.chosen]
|
||||||
|
|
||||||
def get_match_suffix(self, args):
|
def get_match_suffix(self, args):
|
||||||
if args.add_trailing_space == 'always':
|
if args.add_trailing_space == 'always':
|
||||||
return ' '
|
return ' '
|
||||||
@@ -111,16 +126,16 @@ class Hints(Handler):
|
|||||||
def on_text(self, text, in_bracketed_paste):
|
def on_text(self, text, in_bracketed_paste):
|
||||||
changed = False
|
changed = False
|
||||||
for c in text:
|
for c in text:
|
||||||
if c in HINT_ALPHABET:
|
if c in self.alphabet:
|
||||||
self.current_input += c
|
self.current_input += c
|
||||||
changed = True
|
changed = True
|
||||||
if changed:
|
if changed:
|
||||||
matches = [
|
matches = [
|
||||||
m for idx, m in self.index_map.items()
|
m for idx, m in self.index_map.items()
|
||||||
if encode_hint(idx).startswith(self.current_input)
|
if encode_hint(idx, self.alphabet).startswith(self.current_input)
|
||||||
]
|
]
|
||||||
if len(matches) == 1:
|
if len(matches) == 1:
|
||||||
self.chosen.append(matches[0].text + self.match_suffix)
|
self.chosen.append(matches[0])
|
||||||
if self.multiple:
|
if self.multiple:
|
||||||
self.ignore_mark_indices.add(matches[0].index)
|
self.ignore_mark_indices.add(matches[0].index)
|
||||||
self.reset()
|
self.reset()
|
||||||
@@ -137,8 +152,8 @@ class Hints(Handler):
|
|||||||
self.draw_screen()
|
self.draw_screen()
|
||||||
elif key_event is enter_key and self.current_input:
|
elif key_event is enter_key and self.current_input:
|
||||||
try:
|
try:
|
||||||
idx = decode_hint(self.current_input)
|
idx = decode_hint(self.current_input, self.alphabet)
|
||||||
self.chosen.append(self.index_map[idx].text + self.match_suffix)
|
self.chosen.append(self.index_map[idx])
|
||||||
self.ignore_mark_indices.add(idx)
|
self.ignore_mark_indices.add(idx)
|
||||||
except Exception:
|
except Exception:
|
||||||
self.current_input = ''
|
self.current_input = ''
|
||||||
@@ -164,18 +179,19 @@ class Hints(Handler):
|
|||||||
|
|
||||||
def draw_screen(self):
|
def draw_screen(self):
|
||||||
if self.current_text is None:
|
if self.current_text is None:
|
||||||
self.current_text = render(self.text, self.current_input, self.all_marks, self.ignore_mark_indices)
|
self.current_text = render(self.text, self.current_input, self.all_marks, self.ignore_mark_indices, self.alphabet)
|
||||||
self.cmd.clear_screen()
|
self.cmd.clear_screen()
|
||||||
self.write(self.current_text)
|
self.write(self.current_text)
|
||||||
|
|
||||||
|
|
||||||
def regex_finditer(pat, minimum_match_length, text):
|
def regex_finditer(pat, minimum_match_length, text):
|
||||||
|
has_named_groups = bool(pat.groupindex)
|
||||||
for m in pat.finditer(text):
|
for m in pat.finditer(text):
|
||||||
s, e = m.span(pat.groups)
|
s, e = m.span(0 if has_named_groups else pat.groups)
|
||||||
while e > s + 1 and text[e-1] == '\0':
|
while e > s + 1 and text[e-1] == '\0':
|
||||||
e -= 1
|
e -= 1
|
||||||
if e - s >= minimum_match_length:
|
if e - s >= minimum_match_length:
|
||||||
yield s, e
|
yield s, e, m.groupdict()
|
||||||
|
|
||||||
|
|
||||||
closing_bracket_map = {'(': ')', '[': ']', '{': '}', '<': '>', '*': '*', '"': '"', "'": "'"}
|
closing_bracket_map = {'(': ')', '[': ']', '{': '}', '<': '>', '*': '*', '"': '"', "'": "'"}
|
||||||
@@ -234,21 +250,23 @@ def quotes(text, s, e):
|
|||||||
|
|
||||||
def mark(pattern, post_processors, text, args):
|
def mark(pattern, post_processors, text, args):
|
||||||
pat = re.compile(pattern)
|
pat = re.compile(pattern)
|
||||||
for idx, (s, e) in enumerate(regex_finditer(pat, args.minimum_match_length, text)):
|
for idx, (s, e, groupdict) in enumerate(regex_finditer(pat, args.minimum_match_length, text)):
|
||||||
for func in post_processors:
|
for func in post_processors:
|
||||||
s, e = func(text, s, e)
|
s, e = func(text, s, e)
|
||||||
mark_text = text[s:e].replace('\n', '').replace('\0', '')
|
mark_text = text[s:e].replace('\n', '').replace('\0', '')
|
||||||
yield Mark(idx, s, e, mark_text)
|
yield Mark(idx, s, e, mark_text, groupdict)
|
||||||
|
|
||||||
|
|
||||||
def run_loop(args, text, all_marks, index_map):
|
def run_loop(args, text, all_marks, index_map, extra_cli_args=()):
|
||||||
loop = Loop()
|
loop = Loop()
|
||||||
handler = Hints(text, all_marks, index_map, args)
|
handler = Hints(text, all_marks, index_map, args)
|
||||||
loop.loop(handler)
|
loop.loop(handler)
|
||||||
if handler.chosen and loop.return_code == 0:
|
if handler.chosen and loop.return_code == 0:
|
||||||
return {'match': handler.chosen, 'program': args.program,
|
return {
|
||||||
'multiple_joiner': args.multiple_joiner,
|
'match': handler.text_matches, 'programs': args.program,
|
||||||
'type': args.type}
|
'multiple_joiner': args.multiple_joiner, 'customize_processing': args.customize_processing,
|
||||||
|
'type': args.type, 'groupdicts': handler.groupdicts, 'extra_cli_args': extra_cli_args
|
||||||
|
}
|
||||||
raise SystemExit(loop.return_code)
|
raise SystemExit(loop.return_code)
|
||||||
|
|
||||||
|
|
||||||
@@ -305,11 +323,33 @@ def parse_input(text):
|
|||||||
return convert_text(text, cols)
|
return convert_text(text, cols)
|
||||||
|
|
||||||
|
|
||||||
def run(args, text):
|
def load_custom_processor(customize_processing):
|
||||||
|
if customize_processing.startswith('::import::'):
|
||||||
|
import importlib
|
||||||
|
m = importlib.import_module(customize_processing[len('::import::'):])
|
||||||
|
return {k: getattr(m, k) for k in dir(m)}
|
||||||
|
from kitty.constants import config_dir
|
||||||
|
customize_processing = os.path.expandvars(os.path.expanduser(customize_processing))
|
||||||
|
if os.path.isabs(customize_processing):
|
||||||
|
custom_path = customize_processing
|
||||||
|
else:
|
||||||
|
custom_path = os.path.join(config_dir, customize_processing)
|
||||||
|
import runpy
|
||||||
|
return runpy.run_path(custom_path, run_name='__main__')
|
||||||
|
|
||||||
|
|
||||||
|
def run(args, text, extra_cli_args=()):
|
||||||
try:
|
try:
|
||||||
pattern, post_processors = functions_for(args)
|
|
||||||
text = parse_input(text)
|
text = parse_input(text)
|
||||||
all_marks = tuple(mark(pattern, post_processors, text, args))
|
pattern, post_processors = functions_for(args)
|
||||||
|
if args.customize_processing:
|
||||||
|
m = load_custom_processor(args.customize_processing)
|
||||||
|
if 'mark' in m:
|
||||||
|
all_marks = tuple(m['mark'](text, args, Mark, extra_cli_args))
|
||||||
|
else:
|
||||||
|
all_marks = tuple(mark(pattern, post_processors, text, args))
|
||||||
|
else:
|
||||||
|
all_marks = tuple(mark(pattern, post_processors, text, args))
|
||||||
if not all_marks:
|
if not all_marks:
|
||||||
input(_('No {} found, press Enter to quit.').format(
|
input(_('No {} found, press Enter to quit.').format(
|
||||||
'URLs' if args.type == 'url' else 'matches'
|
'URLs' if args.type == 'url' else 'matches'
|
||||||
@@ -319,7 +359,10 @@ def run(args, text):
|
|||||||
largest_index = all_marks[-1].index
|
largest_index = all_marks[-1].index
|
||||||
offset = max(0, args.hints_offset)
|
offset = max(0, args.hints_offset)
|
||||||
for m in all_marks:
|
for m in all_marks:
|
||||||
m.index = largest_index - m.index + offset
|
if args.ascending:
|
||||||
|
m.index += offset
|
||||||
|
else:
|
||||||
|
m.index = largest_index - m.index + offset
|
||||||
index_map = {m.index: m for m in all_marks}
|
index_map = {m.index: m for m in all_marks}
|
||||||
except Exception:
|
except Exception:
|
||||||
import traceback
|
import traceback
|
||||||
@@ -327,16 +370,18 @@ def run(args, text):
|
|||||||
input('Press Enter to quit.')
|
input('Press Enter to quit.')
|
||||||
raise SystemExit(1)
|
raise SystemExit(1)
|
||||||
|
|
||||||
return run_loop(args, text, all_marks, index_map)
|
return run_loop(args, text, all_marks, index_map, extra_cli_args)
|
||||||
|
|
||||||
|
|
||||||
# CLI {{{
|
# CLI {{{
|
||||||
OPTIONS = r'''
|
OPTIONS = r'''
|
||||||
--program
|
--program
|
||||||
default=default
|
type=list
|
||||||
What program to use to open matched text. Defaults to the default open program
|
What program to use to open matched text. Defaults to the default open program
|
||||||
for the operating system. Use a value of :file:`-` to paste the match into the
|
for the operating system. Use a value of :file:`-` to paste the match into the
|
||||||
terminal window instead. A value of :file:`@` will copy the match to the clipboard.
|
terminal window instead. A value of :file:`@` will copy the match to the clipboard.
|
||||||
|
A value of :file:`default` will run the default open program. Can be specified
|
||||||
|
multiple times to run multiple programs.
|
||||||
|
|
||||||
|
|
||||||
--type
|
--type
|
||||||
@@ -348,11 +393,14 @@ The type of text to search for.
|
|||||||
--regex
|
--regex
|
||||||
default=(?m)^\s*(.+)\s*$
|
default=(?m)^\s*(.+)\s*$
|
||||||
The regular expression to use when :option:`kitty +kitten hints --type`=regex.
|
The regular expression to use when :option:`kitty +kitten hints --type`=regex.
|
||||||
If you specify a group in the regular expression only the group
|
The regular expression is in python syntax. If you specify a numbered group in
|
||||||
will be matched. This allow you to match text ignoring a prefix/suffix, as
|
the regular expression only the group will be matched. This allow you to match
|
||||||
needed. The default expression matches lines. To match text over
|
text ignoring a prefix/suffix, as needed. The default expression matches lines.
|
||||||
multiple lines you should prefix the regular expression with :code:`(?ms)`,
|
To match text over multiple lines you should prefix the regular expression with
|
||||||
which turns on MULTILINE and DOTALL modes for the regex engine.
|
:code:`(?ms)`, which turns on MULTILINE and DOTALL modes for the regex engine.
|
||||||
|
If you specify named groups and a :option:`kitty +kitten hints --program` then
|
||||||
|
the program will be passed arguments corresponding to each named group of
|
||||||
|
the form key=value.
|
||||||
|
|
||||||
|
|
||||||
--url-prefixes
|
--url-prefixes
|
||||||
@@ -362,7 +410,7 @@ Comma separated list of recognized URL prefixes.
|
|||||||
|
|
||||||
--word-characters
|
--word-characters
|
||||||
Characters to consider as part of a word. In addition, all characters marked as
|
Characters to consider as part of a word. In addition, all characters marked as
|
||||||
alpha-numeric in the unicode database will be considered as word characters.
|
alphanumeric in the unicode database will be considered as word characters.
|
||||||
Defaults to the select_by_word_characters setting from kitty.conf.
|
Defaults to the select_by_word_characters setting from kitty.conf.
|
||||||
|
|
||||||
|
|
||||||
@@ -401,6 +449,27 @@ default=1
|
|||||||
type=int
|
type=int
|
||||||
The offset (from zero) at which to start hint numbering. Note that only numbers
|
The offset (from zero) at which to start hint numbering. Note that only numbers
|
||||||
greater than or equal to zero are respected.
|
greater than or equal to zero are respected.
|
||||||
|
|
||||||
|
|
||||||
|
--alphabet
|
||||||
|
The list of characters to use for hints. The default is to use numbers and lowercase
|
||||||
|
English alphabets. Specify your preference as a string of characters. Note that
|
||||||
|
unless you specify the hints offset as zero the first match will be highlighted with
|
||||||
|
the second character you specify.
|
||||||
|
|
||||||
|
|
||||||
|
--ascending
|
||||||
|
type=bool-set
|
||||||
|
Have the hints increase from top to bottom instead of decreasing from top to bottom.
|
||||||
|
|
||||||
|
|
||||||
|
--customize-processing
|
||||||
|
Name of a python file in the kitty config directory which will be imported to provide
|
||||||
|
custom implementations for pattern finding and performing actions
|
||||||
|
on selected matches. See https://sw.kovidgoyal.net/kitty/kittens/hints.html
|
||||||
|
for details. You can also specify absolute paths to load the script from elsewhere.
|
||||||
|
|
||||||
|
|
||||||
'''.format(','.join(sorted(URL_PREFIXES))).format
|
'''.format(','.join(sorted(URL_PREFIXES))).format
|
||||||
help_text = 'Select text from the screen using the keyboard. Defaults to searching for URLs.'
|
help_text = 'Select text from the screen using the keyboard. Defaults to searching for URLs.'
|
||||||
usage = ''
|
usage = ''
|
||||||
@@ -427,16 +496,23 @@ def main(args):
|
|||||||
print(e.args[0], file=sys.stderr)
|
print(e.args[0], file=sys.stderr)
|
||||||
input(_('Press Enter to quit'))
|
input(_('Press Enter to quit'))
|
||||||
return
|
return
|
||||||
if items:
|
if items and not args.customize_processing:
|
||||||
print('Extra command line arguments present: {}'.format(' '.join(items)), file=sys.stderr)
|
print('Extra command line arguments present: {}'.format(' '.join(items)), file=sys.stderr)
|
||||||
input(_('Press Enter to quit'))
|
input(_('Press Enter to quit'))
|
||||||
return
|
return run(args, text, items)
|
||||||
return run(args, text)
|
|
||||||
|
|
||||||
|
|
||||||
def handle_result(args, data, target_window_id, boss):
|
def handle_result(args, data, target_window_id, boss):
|
||||||
program = data['program']
|
if data['customize_processing']:
|
||||||
matches = tuple(filter(None, data['match']))
|
m = load_custom_processor(data['customize_processing'])
|
||||||
|
if 'handle_result' in m:
|
||||||
|
return m['handle_result'](args, data, target_window_id, boss, data['extra_cli_args'])
|
||||||
|
|
||||||
|
programs = data['programs'] or ('default',)
|
||||||
|
matches, groupdicts = [], []
|
||||||
|
for m, g in zip(data['match'], data['groupdicts']):
|
||||||
|
if m:
|
||||||
|
matches.append(m), groupdicts.append(g)
|
||||||
joiner = data['multiple_joiner']
|
joiner = data['multiple_joiner']
|
||||||
try:
|
try:
|
||||||
is_int = int(joiner)
|
is_int = int(joiner)
|
||||||
@@ -444,6 +520,7 @@ def handle_result(args, data, target_window_id, boss):
|
|||||||
is_int = None
|
is_int = None
|
||||||
text_type = data['type']
|
text_type = data['type']
|
||||||
|
|
||||||
|
@lru_cache()
|
||||||
def joined_text():
|
def joined_text():
|
||||||
if is_int is not None:
|
if is_int is not None:
|
||||||
try:
|
try:
|
||||||
@@ -459,20 +536,25 @@ def handle_result(args, data, target_window_id, boss):
|
|||||||
q = {'newline': '\n\r', 'space': ' '}.get(joiner, '')
|
q = {'newline': '\n\r', 'space': ' '}.get(joiner, '')
|
||||||
return q.join(matches)
|
return q.join(matches)
|
||||||
|
|
||||||
if program == '-':
|
for program in programs:
|
||||||
w = boss.window_id_map.get(target_window_id)
|
if program == '-':
|
||||||
if w is not None:
|
w = boss.window_id_map.get(target_window_id)
|
||||||
w.paste(joined_text())
|
if w is not None:
|
||||||
elif program == '@':
|
w.paste(joined_text())
|
||||||
set_clipboard_string(joined_text())
|
elif program == '@':
|
||||||
else:
|
set_clipboard_string(joined_text())
|
||||||
cwd = None
|
else:
|
||||||
w = boss.window_id_map.get(target_window_id)
|
cwd = None
|
||||||
if w is not None:
|
w = boss.window_id_map.get(target_window_id)
|
||||||
cwd = w.cwd_of_child
|
if w is not None:
|
||||||
program = None if program == 'default' else program
|
cwd = w.cwd_of_child
|
||||||
for m in matches:
|
program = None if program == 'default' else program
|
||||||
boss.open_url(m, program, cwd=cwd)
|
for m, groupdict in zip(matches, groupdicts):
|
||||||
|
if groupdict:
|
||||||
|
m = []
|
||||||
|
for k, v in groupdict.items():
|
||||||
|
m.append('{}={}'.format(k, v or ''))
|
||||||
|
boss.open_url(m, program, cwd=cwd)
|
||||||
|
|
||||||
|
|
||||||
handle_result.type_of_input = 'screen'
|
handle_result.type_of_input = 'screen'
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ from ..tui.images import (
|
|||||||
)
|
)
|
||||||
from ..tui.operations import clear_images_on_screen, serialize_gr_command
|
from ..tui.operations import clear_images_on_screen, serialize_gr_command
|
||||||
|
|
||||||
screen_size = None
|
|
||||||
OPTIONS = '''\
|
OPTIONS = '''\
|
||||||
--align
|
--align
|
||||||
type=choices
|
type=choices
|
||||||
@@ -97,6 +96,21 @@ Do not print out anything to stdout during operation.
|
|||||||
'''
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
screen_size = None
|
||||||
|
|
||||||
|
|
||||||
|
def get_screen_size_function():
|
||||||
|
global screen_size
|
||||||
|
if screen_size is None:
|
||||||
|
screen_size = screen_size_function()
|
||||||
|
return screen_size
|
||||||
|
|
||||||
|
|
||||||
|
def get_screen_size():
|
||||||
|
screen_size = get_screen_size_function()
|
||||||
|
return screen_size()
|
||||||
|
|
||||||
|
|
||||||
def options_spec():
|
def options_spec():
|
||||||
if not hasattr(options_spec, 'ans'):
|
if not hasattr(options_spec, 'ans'):
|
||||||
options_spec.ans = OPTIONS.format(
|
options_spec.ans = OPTIONS.format(
|
||||||
@@ -122,7 +136,7 @@ def calculate_in_cell_x_offset(width, cell_width, align):
|
|||||||
|
|
||||||
|
|
||||||
def set_cursor(cmd, width, height, align):
|
def set_cursor(cmd, width, height, align):
|
||||||
ss = screen_size()
|
ss = get_screen_size()
|
||||||
cw = int(ss.width / ss.cols)
|
cw = int(ss.width / ss.cols)
|
||||||
num_of_cells_needed = int(ceil(width / cw))
|
num_of_cells_needed = int(ceil(width / cw))
|
||||||
if num_of_cells_needed > ss.cols:
|
if num_of_cells_needed > ss.cols:
|
||||||
@@ -143,7 +157,7 @@ def set_cursor(cmd, width, height, align):
|
|||||||
|
|
||||||
def set_cursor_for_place(place, cmd, width, height, align):
|
def set_cursor_for_place(place, cmd, width, height, align):
|
||||||
x = place.left + 1
|
x = place.left + 1
|
||||||
ss = screen_size()
|
ss = get_screen_size()
|
||||||
cw = int(ss.width / ss.cols)
|
cw = int(ss.width / ss.cols)
|
||||||
num_of_cells_needed = int(ceil(width / cw))
|
num_of_cells_needed = int(ceil(width / cw))
|
||||||
cmd['X'] = calculate_in_cell_x_offset(width, cw, align)
|
cmd['X'] = calculate_in_cell_x_offset(width, cw, align)
|
||||||
@@ -189,16 +203,18 @@ def show(outfile, width, height, fmt, transmit_mode='t', align='center', place=N
|
|||||||
|
|
||||||
def process(path, args, is_tempfile):
|
def process(path, args, is_tempfile):
|
||||||
m = identify(path)
|
m = identify(path)
|
||||||
ss = screen_size()
|
ss = get_screen_size()
|
||||||
available_width = args.place.width * (ss.width / ss.cols) if args.place else ss.width
|
available_width = args.place.width * (ss.width / ss.cols) if args.place else ss.width
|
||||||
available_height = args.place.height * (ss.height / ss.rows) if args.place else 10 * m.height
|
available_height = args.place.height * (ss.height / ss.rows) if args.place else 10 * m.height
|
||||||
needs_scaling = m.width > available_width or m.height > available_height
|
needs_scaling = m.width > available_width or m.height > available_height
|
||||||
needs_scaling = needs_scaling or args.scale_up
|
needs_scaling = needs_scaling or args.scale_up
|
||||||
|
file_removed = False
|
||||||
if m.fmt == 'png' and not needs_scaling:
|
if m.fmt == 'png' and not needs_scaling:
|
||||||
outfile = path
|
outfile = path
|
||||||
transmit_mode = 't' if is_tempfile else 'f'
|
transmit_mode = 't' if is_tempfile else 'f'
|
||||||
fmt = 100
|
fmt = 100
|
||||||
width, height = m.width, m.height
|
width, height = m.width, m.height
|
||||||
|
file_removed = transmit_mode == 't'
|
||||||
else:
|
else:
|
||||||
fmt = 24 if m.mode == 'rgb' else 32
|
fmt = 24 if m.mode == 'rgb' else 32
|
||||||
transmit_mode = 't'
|
transmit_mode = 't'
|
||||||
@@ -206,6 +222,7 @@ def process(path, args, is_tempfile):
|
|||||||
show(outfile, width, height, fmt, transmit_mode, align=args.align, place=args.place)
|
show(outfile, width, height, fmt, transmit_mode, align=args.align, place=args.place)
|
||||||
if not args.place:
|
if not args.place:
|
||||||
print() # ensure cursor is on a new line
|
print() # ensure cursor is on a new line
|
||||||
|
return file_removed
|
||||||
|
|
||||||
|
|
||||||
def scan(d):
|
def scan(d):
|
||||||
@@ -272,6 +289,7 @@ usage = 'image-file-or-url-or-directory ...'
|
|||||||
|
|
||||||
def process_single_item(item, args, url_pat=None, maybe_dir=True):
|
def process_single_item(item, args, url_pat=None, maybe_dir=True):
|
||||||
is_tempfile = False
|
is_tempfile = False
|
||||||
|
file_removed = False
|
||||||
try:
|
try:
|
||||||
if isinstance(item, bytes):
|
if isinstance(item, bytes):
|
||||||
tf = NamedTemporaryFile(prefix='stdin-image-data-', delete=False)
|
tf = NamedTemporaryFile(prefix='stdin-image-data-', delete=False)
|
||||||
@@ -287,7 +305,7 @@ def process_single_item(item, args, url_pat=None, maybe_dir=True):
|
|||||||
raise SystemExit('Failed to download image at URL: {} with error: {}'.format(item, e))
|
raise SystemExit('Failed to download image at URL: {} with error: {}'.format(item, e))
|
||||||
item = tf.name
|
item = tf.name
|
||||||
is_tempfile = True
|
is_tempfile = True
|
||||||
process(item, args, is_tempfile)
|
file_removed = process(item, args, is_tempfile)
|
||||||
elif item.lower().startswith('file://'):
|
elif item.lower().startswith('file://'):
|
||||||
from urllib.parse import urlparse
|
from urllib.parse import urlparse
|
||||||
from urllib.request import url2pathname
|
from urllib.request import url2pathname
|
||||||
@@ -297,20 +315,19 @@ def process_single_item(item, args, url_pat=None, maybe_dir=True):
|
|||||||
else:
|
else:
|
||||||
item = item.path
|
item = item.path
|
||||||
item = url2pathname(item)
|
item = url2pathname(item)
|
||||||
process(item, args, is_tempfile)
|
file_removed = process(item, args, is_tempfile)
|
||||||
else:
|
else:
|
||||||
if maybe_dir and os.path.isdir(item):
|
if maybe_dir and os.path.isdir(item):
|
||||||
for (x, mt) in scan(item):
|
for (x, mt) in scan(item):
|
||||||
process_single_item(x, args, url_pat=None, maybe_dir=False)
|
process_single_item(x, args, url_pat=None, maybe_dir=False)
|
||||||
else:
|
else:
|
||||||
process(item, args, is_tempfile)
|
file_removed = process(item, args, is_tempfile)
|
||||||
finally:
|
finally:
|
||||||
if is_tempfile:
|
if is_tempfile and not file_removed:
|
||||||
os.remove(item)
|
os.remove(item)
|
||||||
|
|
||||||
|
|
||||||
def main(args=sys.argv):
|
def main(args=sys.argv):
|
||||||
global screen_size
|
|
||||||
args, items = parse_args(args[1:], options_spec, usage, help_text, '{} +kitten icat'.format(appname))
|
args, items = parse_args(args[1:], options_spec, usage, help_text, '{} +kitten icat'.format(appname))
|
||||||
|
|
||||||
if args.print_window_size:
|
if args.print_window_size:
|
||||||
@@ -330,7 +347,7 @@ def main(args=sys.argv):
|
|||||||
sys.stdin.close()
|
sys.stdin.close()
|
||||||
sys.stdin = open(os.ctermid(), 'r')
|
sys.stdin = open(os.ctermid(), 'r')
|
||||||
|
|
||||||
screen_size = screen_size_function()
|
screen_size = get_screen_size_function()
|
||||||
signal.signal(signal.SIGWINCH, lambda signum, frame: setattr(screen_size, 'changed', True))
|
signal.signal(signal.SIGWINCH, lambda signum, frame: setattr(screen_size, 'changed', True))
|
||||||
if screen_size().width == 0:
|
if screen_size().width == 0:
|
||||||
if args.detect_support:
|
if args.detect_support:
|
||||||
|
|||||||
@@ -130,8 +130,8 @@ def main(sys_args):
|
|||||||
if not items:
|
if not items:
|
||||||
raise SystemExit('You must specify the program to run')
|
raise SystemExit('You must specify the program to run')
|
||||||
sys.argv = ['kitty']
|
sys.argv = ['kitty']
|
||||||
if args.config:
|
for config in args.config:
|
||||||
sys.argv.append('--config={}'.format(args.config))
|
sys.argv.append('--config={}'.format(config))
|
||||||
for override in args.override:
|
for override in args.override:
|
||||||
sys.argv.append('--override={}'.format(override))
|
sys.argv.append('--override={}'.format(override))
|
||||||
sys.argv.extend(items)
|
sys.argv.extend(items)
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
from contextlib import suppress
|
||||||
|
|
||||||
from kitty.cli import parse_args
|
from kitty.cli import parse_args
|
||||||
|
|
||||||
@@ -30,9 +31,8 @@ def real_main(args):
|
|||||||
|
|
||||||
def main(args):
|
def main(args):
|
||||||
try:
|
try:
|
||||||
real_main(args)
|
with suppress(KeyboardInterrupt):
|
||||||
except KeyboardInterrupt:
|
real_main(args)
|
||||||
pass
|
|
||||||
except Exception:
|
except Exception:
|
||||||
import traceback
|
import traceback
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
|
|||||||
@@ -76,6 +76,9 @@ def parse_ssh_args(args):
|
|||||||
if arg in boolean_ssh_args:
|
if arg in boolean_ssh_args:
|
||||||
ssh_args.append(arg)
|
ssh_args.append(arg)
|
||||||
continue
|
continue
|
||||||
|
if arg.startswith('-p') and arg[2:].isdigit():
|
||||||
|
ssh_args.append(arg)
|
||||||
|
continue
|
||||||
if arg in other_ssh_args:
|
if arg in other_ssh_args:
|
||||||
if i != len(all_args) - 1:
|
if i != len(all_args) - 1:
|
||||||
raise SystemExit('Option {} cannot occur in the middle'.format(arg))
|
raise SystemExit('Option {} cannot occur in the middle'.format(arg))
|
||||||
@@ -95,7 +98,7 @@ def parse_ssh_args(args):
|
|||||||
|
|
||||||
|
|
||||||
def quote(x):
|
def quote(x):
|
||||||
# we have to escape unbalanced quotes and other unparseable
|
# we have to escape unbalanced quotes and other unparsable
|
||||||
# args as they will break the shell script
|
# args as they will break the shell script
|
||||||
# But we do not want to quote things like * or 'echo hello'
|
# But we do not want to quote things like * or 'echo hello'
|
||||||
# See https://github.com/kovidgoyal/kitty/issues/1787
|
# See https://github.com/kovidgoyal/kitty/issues/1787
|
||||||
|
|||||||
@@ -249,7 +249,8 @@ class ImageManager:
|
|||||||
cmd, standard_b64encode(rgba_path.encode(fsenc)))
|
cmd, standard_b64encode(rgba_path.encode(fsenc)))
|
||||||
else:
|
else:
|
||||||
import zlib
|
import zlib
|
||||||
data = open(rgba_path, 'rb').read()
|
with open(rgba_path, 'rb') as f:
|
||||||
|
data = f.read()
|
||||||
cmd['S'] = len(data)
|
cmd['S'] = len(data)
|
||||||
data = zlib.compress(data)
|
data = zlib.compress(data)
|
||||||
cmd['o'] = 'z'
|
cmd['o'] = 'z'
|
||||||
|
|||||||
@@ -5,25 +5,27 @@
|
|||||||
import os
|
import os
|
||||||
import string
|
import string
|
||||||
import subprocess
|
import subprocess
|
||||||
|
import sys
|
||||||
|
from contextlib import suppress
|
||||||
from functools import lru_cache
|
from functools import lru_cache
|
||||||
from gettext import gettext as _
|
from gettext import gettext as _
|
||||||
from contextlib import suppress
|
|
||||||
|
|
||||||
|
from kitty.cli import parse_args
|
||||||
from kitty.config import cached_values_for
|
from kitty.config import cached_values_for
|
||||||
from kitty.constants import config_dir
|
from kitty.constants import config_dir
|
||||||
from kitty.utils import get_editor
|
from kitty.fast_data_types import wcswidth, is_emoji_presentation_base
|
||||||
from kitty.fast_data_types import wcswidth
|
|
||||||
from kitty.key_encoding import (
|
from kitty.key_encoding import (
|
||||||
DOWN, ESCAPE, F1, F2, F3, F4, F12, LEFT, RELEASE, RIGHT, SHIFT, TAB, UP,
|
DOWN, ESCAPE, F1, F2, F3, F4, F12, LEFT, RELEASE, RIGHT, SHIFT, TAB, UP,
|
||||||
enter_key
|
enter_key
|
||||||
)
|
)
|
||||||
|
from kitty.utils import get_editor
|
||||||
|
|
||||||
from ..tui.line_edit import LineEdit
|
|
||||||
from ..tui.handler import Handler
|
from ..tui.handler import Handler
|
||||||
|
from ..tui.line_edit import LineEdit
|
||||||
from ..tui.loop import Loop
|
from ..tui.loop import Loop
|
||||||
from ..tui.operations import (
|
from ..tui.operations import (
|
||||||
clear_screen, colored, cursor, faint, set_line_wrapping,
|
clear_screen, colored, cursor, faint, set_line_wrapping, set_window_title,
|
||||||
set_window_title, sgr, styled
|
sgr, styled
|
||||||
)
|
)
|
||||||
|
|
||||||
HEX, NAME, EMOTICONS, FAVORITES = 'HEX', 'NAME', 'EMOTICONS', 'FAVORITES'
|
HEX, NAME, EMOTICONS, FAVORITES = 'HEX', 'NAME', 'EMOTICONS', 'FAVORITES'
|
||||||
@@ -131,7 +133,8 @@ def decode_hint(x):
|
|||||||
|
|
||||||
class Table:
|
class Table:
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self, emoji_variation):
|
||||||
|
self.emoji_variation = emoji_variation
|
||||||
self.layout_dirty = True
|
self.layout_dirty = True
|
||||||
self.last_rows = self.last_cols = -1
|
self.last_rows = self.last_cols = -1
|
||||||
self.codepoints = []
|
self.codepoints = []
|
||||||
@@ -161,7 +164,10 @@ class Table:
|
|||||||
self.layout_dirty = False
|
self.layout_dirty = False
|
||||||
|
|
||||||
def safe_chr(codepoint):
|
def safe_chr(codepoint):
|
||||||
return chr(codepoint).encode('utf-8', 'replace').decode('utf-8')
|
ans = chr(codepoint).encode('utf-8', 'replace').decode('utf-8')
|
||||||
|
if self.emoji_variation and is_emoji_presentation_base(codepoint):
|
||||||
|
ans += self.emoji_variation
|
||||||
|
return ans
|
||||||
|
|
||||||
if self.mode is NAME:
|
if self.mode is NAME:
|
||||||
def as_parts(i, codepoint):
|
def as_parts(i, codepoint):
|
||||||
@@ -248,8 +254,13 @@ def is_index(w):
|
|||||||
|
|
||||||
class UnicodeInput(Handler):
|
class UnicodeInput(Handler):
|
||||||
|
|
||||||
def __init__(self, cached_values):
|
def __init__(self, cached_values, emoji_variation='none'):
|
||||||
self.cached_values = cached_values
|
self.cached_values = cached_values
|
||||||
|
self.emoji_variation = ''
|
||||||
|
if emoji_variation == 'text':
|
||||||
|
self.emoji_variation = '\ufe0e'
|
||||||
|
elif emoji_variation == 'graphic':
|
||||||
|
self.emoji_variation = '\ufe0f'
|
||||||
self.line_edit = LineEdit()
|
self.line_edit = LineEdit()
|
||||||
self.recent = list(self.cached_values.get('recent', DEFAULT_SET))
|
self.recent = list(self.cached_values.get('recent', DEFAULT_SET))
|
||||||
self.current_char = None
|
self.current_char = None
|
||||||
@@ -257,9 +268,17 @@ class UnicodeInput(Handler):
|
|||||||
self.last_updated_code_point_at = None
|
self.last_updated_code_point_at = None
|
||||||
self.choice_line = ''
|
self.choice_line = ''
|
||||||
self.mode = globals().get(cached_values.get('mode', 'HEX'), 'HEX')
|
self.mode = globals().get(cached_values.get('mode', 'HEX'), 'HEX')
|
||||||
self.table = Table()
|
self.table = Table(self.emoji_variation)
|
||||||
self.update_prompt()
|
self.update_prompt()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def resolved_current_char(self):
|
||||||
|
ans = self.current_char
|
||||||
|
if ans:
|
||||||
|
if self.emoji_variation and is_emoji_presentation_base(ord(ans[0])):
|
||||||
|
ans += self.emoji_variation
|
||||||
|
return ans
|
||||||
|
|
||||||
def update_codepoints(self):
|
def update_codepoints(self):
|
||||||
codepoints = None
|
codepoints = None
|
||||||
if self.mode is HEX:
|
if self.mode is HEX:
|
||||||
@@ -320,8 +339,10 @@ class UnicodeInput(Handler):
|
|||||||
self.choice_line = ''
|
self.choice_line = ''
|
||||||
else:
|
else:
|
||||||
c, color = self.current_char, 'green'
|
c, color = self.current_char, 'green'
|
||||||
|
if self.emoji_variation and is_emoji_presentation_base(ord(c[0])):
|
||||||
|
c += self.emoji_variation
|
||||||
self.choice_line = _('Chosen:') + ' {} U+{} {}'.format(
|
self.choice_line = _('Chosen:') + ' {} U+{} {}'.format(
|
||||||
colored(c, 'green'), hex(ord(c))[2:], faint(styled(name(c) or '', italic=True)))
|
colored(c, 'green'), hex(ord(c[0]))[2:], faint(styled(name(c) or '', italic=True)))
|
||||||
self.prompt = self.prompt_template.format(colored(c, color))
|
self.prompt = self.prompt_template.format(colored(c, color))
|
||||||
|
|
||||||
def init_terminal_state(self):
|
def init_terminal_state(self):
|
||||||
@@ -475,17 +496,43 @@ class UnicodeInput(Handler):
|
|||||||
self.refresh()
|
self.refresh()
|
||||||
|
|
||||||
|
|
||||||
|
help_text = 'Input a unicode character'
|
||||||
|
usage = ''
|
||||||
|
OPTIONS = '''
|
||||||
|
--emoji-variation
|
||||||
|
type=choices
|
||||||
|
default=none
|
||||||
|
choices=none,graphic,text
|
||||||
|
Whether to use the textual or the graphical form for emoji. By default the
|
||||||
|
default form specified in the unicode standard for the symbol is used.
|
||||||
|
|
||||||
|
|
||||||
|
'''.format
|
||||||
|
|
||||||
|
|
||||||
|
def parse_unicode_input_args(args):
|
||||||
|
return parse_args(args, OPTIONS, usage, help_text, 'kitty +kitten unicode_input')
|
||||||
|
|
||||||
|
|
||||||
def main(args):
|
def main(args):
|
||||||
|
try:
|
||||||
|
args, items = parse_unicode_input_args(args[1:])
|
||||||
|
except SystemExit as e:
|
||||||
|
if e.code != 0:
|
||||||
|
print(e.args[0], file=sys.stderr)
|
||||||
|
input(_('Press Enter to quit'))
|
||||||
|
return
|
||||||
|
|
||||||
loop = Loop()
|
loop = Loop()
|
||||||
with cached_values_for('unicode-input') as cached_values:
|
with cached_values_for('unicode-input') as cached_values:
|
||||||
handler = UnicodeInput(cached_values)
|
handler = UnicodeInput(cached_values, args.emoji_variation)
|
||||||
loop.loop(handler)
|
loop.loop(handler)
|
||||||
if handler.current_char and loop.return_code == 0:
|
if handler.current_char and loop.return_code == 0:
|
||||||
with suppress(Exception):
|
with suppress(Exception):
|
||||||
handler.recent.remove(ord(handler.current_char))
|
handler.recent.remove(ord(handler.current_char))
|
||||||
recent = [ord(handler.current_char)] + handler.recent
|
recent = [ord(handler.current_char)] + handler.recent
|
||||||
cached_values['recent'] = recent[:len(DEFAULT_SET)]
|
cached_values['recent'] = recent[:len(DEFAULT_SET)]
|
||||||
return handler.current_char
|
return handler.resolved_current_char
|
||||||
if loop.return_code != 0:
|
if loop.return_code != 0:
|
||||||
raise SystemExit(loop.return_code)
|
raise SystemExit(loop.return_code)
|
||||||
|
|
||||||
@@ -497,10 +544,10 @@ def handle_result(args, current_char, target_window_id, boss):
|
|||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
import sys
|
|
||||||
if '-h' in sys.argv or '--help' in sys.argv:
|
|
||||||
print('Choose a unicode character to input into the terminal')
|
|
||||||
raise SystemExit(0)
|
|
||||||
ans = main(sys.argv)
|
ans = main(sys.argv)
|
||||||
if ans:
|
if ans:
|
||||||
print(ans)
|
print(ans)
|
||||||
|
elif __name__ == '__doc__':
|
||||||
|
sys.cli_docs['usage'] = usage
|
||||||
|
sys.cli_docs['options'] = OPTIONS
|
||||||
|
sys.cli_docs['help_text'] = help_text
|
||||||
|
|||||||
41478
kittens/unicode_input/names.h
generated
41478
kittens/unicode_input/names.h
generated
File diff suppressed because one or more lines are too long
293
kitty/boss.py
293
kitty/boss.py
@@ -23,10 +23,10 @@ from .constants import (
|
|||||||
from .fast_data_types import (
|
from .fast_data_types import (
|
||||||
ChildMonitor, background_opacity_of, change_background_opacity,
|
ChildMonitor, background_opacity_of, change_background_opacity,
|
||||||
change_os_window_state, create_os_window, current_os_window,
|
change_os_window_state, create_os_window, current_os_window,
|
||||||
destroy_global_data, get_clipboard_string, global_font_size,
|
destroy_global_data, focus_os_window, get_clipboard_string,
|
||||||
mark_os_window_for_close, os_window_font_size, patch_global_colors,
|
global_font_size, mark_os_window_for_close, os_window_font_size,
|
||||||
safe_pipe, set_clipboard_string, set_in_sequence_mode, thread_write,
|
patch_global_colors, safe_pipe, set_clipboard_string, set_in_sequence_mode,
|
||||||
toggle_fullscreen, toggle_maximized
|
thread_write, toggle_fullscreen, toggle_maximized
|
||||||
)
|
)
|
||||||
from .keys import get_shortcut, shortcut_matches
|
from .keys import get_shortcut, shortcut_matches
|
||||||
from .layout import set_layout_options
|
from .layout import set_layout_options
|
||||||
@@ -58,9 +58,9 @@ def data_for_at(w, arg, add_wrap_markers=False):
|
|||||||
|
|
||||||
if arg == '@selection':
|
if arg == '@selection':
|
||||||
return w.text_for_selection()
|
return w.text_for_selection()
|
||||||
if arg == '@ansi':
|
if arg in ('@ansi', '@ansi_screen_scrollback'):
|
||||||
return as_text(as_ansi=True, add_history=True)
|
return as_text(as_ansi=True, add_history=True)
|
||||||
if arg == '@text':
|
if arg in ('@text', '@screen_scrollback'):
|
||||||
return as_text(add_history=True)
|
return as_text(add_history=True)
|
||||||
if arg == '@screen':
|
if arg == '@screen':
|
||||||
return as_text()
|
return as_text()
|
||||||
@@ -121,7 +121,7 @@ class Boss:
|
|||||||
talk_fd = getattr(single_instance, 'socket', None)
|
talk_fd = getattr(single_instance, 'socket', None)
|
||||||
talk_fd = -1 if talk_fd is None else talk_fd.fileno()
|
talk_fd = -1 if talk_fd is None else talk_fd.fileno()
|
||||||
listen_fd = -1
|
listen_fd = -1
|
||||||
if opts.allow_remote_control and args.listen_on:
|
if args.listen_on and (opts.allow_remote_control in ('y', 'socket-only')):
|
||||||
listen_fd = listen_on(args.listen_on)
|
listen_fd = listen_on(args.listen_on)
|
||||||
self.child_monitor = ChildMonitor(
|
self.child_monitor = ChildMonitor(
|
||||||
self.on_child_death,
|
self.on_child_death,
|
||||||
@@ -146,9 +146,9 @@ class Boss:
|
|||||||
from .fast_data_types import cocoa_set_notification_activated_callback
|
from .fast_data_types import cocoa_set_notification_activated_callback
|
||||||
cocoa_set_notification_activated_callback(self.notification_activated)
|
cocoa_set_notification_activated_callback(self.notification_activated)
|
||||||
|
|
||||||
def add_os_window(self, startup_session, os_window_id=None, wclass=None, wname=None, opts_for_size=None, startup_id=None):
|
def add_os_window(self, startup_session=None, os_window_id=None, wclass=None, wname=None, opts_for_size=None, startup_id=None):
|
||||||
if os_window_id is None:
|
if os_window_id is None:
|
||||||
opts_for_size = opts_for_size or startup_session.os_window_size or self.opts
|
opts_for_size = opts_for_size or getattr(startup_session, 'os_window_size', None) or self.opts
|
||||||
cls = wclass or self.args.cls or appname
|
cls = wclass or self.args.cls or appname
|
||||||
with startup_notification_handler(do_notify=startup_id is not None, startup_id=startup_id) as pre_show_callback:
|
with startup_notification_handler(do_notify=startup_id is not None, startup_id=startup_id) as pre_show_callback:
|
||||||
os_window_id = create_os_window(
|
os_window_id = create_os_window(
|
||||||
@@ -235,7 +235,7 @@ class Boss:
|
|||||||
if tab:
|
if tab:
|
||||||
yield tab
|
yield tab
|
||||||
|
|
||||||
def set_active_window(self, window):
|
def set_active_window(self, window, switch_os_window_if_needed=False):
|
||||||
for os_window_id, tm in self.os_window_map.items():
|
for os_window_id, tm in self.os_window_map.items():
|
||||||
for tab in tm:
|
for tab in tm:
|
||||||
for w in tab:
|
for w in tab:
|
||||||
@@ -243,6 +243,8 @@ class Boss:
|
|||||||
if tab is not self.active_tab:
|
if tab is not self.active_tab:
|
||||||
tm.set_active_tab(tab)
|
tm.set_active_tab(tab)
|
||||||
tab.set_active_window(w)
|
tab.set_active_window(w)
|
||||||
|
if switch_os_window_if_needed and current_os_window() != os_window_id:
|
||||||
|
focus_os_window(os_window_id, True)
|
||||||
return os_window_id
|
return os_window_id
|
||||||
|
|
||||||
def _new_os_window(self, args, cwd_from=None):
|
def _new_os_window(self, args, cwd_from=None):
|
||||||
@@ -276,9 +278,9 @@ class Boss:
|
|||||||
self.child_monitor.add_child(window.id, window.child.pid, window.child.child_fd, window.screen)
|
self.child_monitor.add_child(window.id, window.child.pid, window.child.child_fd, window.screen)
|
||||||
self.window_id_map[window.id] = window
|
self.window_id_map[window.id] = window
|
||||||
|
|
||||||
def _handle_remote_command(self, cmd, window=None):
|
def _handle_remote_command(self, cmd, window=None, from_peer=False):
|
||||||
response = None
|
response = None
|
||||||
if self.opts.allow_remote_control or getattr(window, 'allow_remote_control', False):
|
if self.opts.allow_remote_control == 'y' or from_peer or getattr(window, 'allow_remote_control', False):
|
||||||
try:
|
try:
|
||||||
response = handle_cmd(self, window, cmd)
|
response = handle_cmd(self, window, cmd)
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
@@ -287,7 +289,7 @@ class Boss:
|
|||||||
if not getattr(err, 'hide_traceback', False):
|
if not getattr(err, 'hide_traceback', False):
|
||||||
response['tb'] = traceback.format_exc()
|
response['tb'] = traceback.format_exc()
|
||||||
else:
|
else:
|
||||||
response = {'ok': False, 'error': 'Remote control is disabled. Add allow_remote_control yes to your kitty.conf'}
|
response = {'ok': False, 'error': 'Remote control is disabled. Add allow_remote_control to your kitty.conf'}
|
||||||
return response
|
return response
|
||||||
|
|
||||||
def peer_message_received(self, msg):
|
def peer_message_received(self, msg):
|
||||||
@@ -295,7 +297,7 @@ class Boss:
|
|||||||
cmd_prefix = '\x1bP@kitty-cmd'
|
cmd_prefix = '\x1bP@kitty-cmd'
|
||||||
if msg.startswith(cmd_prefix):
|
if msg.startswith(cmd_prefix):
|
||||||
cmd = msg[len(cmd_prefix):-2]
|
cmd = msg[len(cmd_prefix):-2]
|
||||||
response = self._handle_remote_command(cmd)
|
response = self._handle_remote_command(cmd, from_peer=True)
|
||||||
if response is not None:
|
if response is not None:
|
||||||
response = (cmd_prefix + json.dumps(response) + '\x1b\\').encode('utf-8')
|
response = (cmd_prefix + json.dumps(response) + '\x1b\\').encode('utf-8')
|
||||||
return response
|
return response
|
||||||
@@ -321,6 +323,16 @@ class Boss:
|
|||||||
if window is not None:
|
if window is not None:
|
||||||
window.send_cmd_response(response)
|
window.send_cmd_response(response)
|
||||||
|
|
||||||
|
def _cleanup_tab_after_window_removal(self, src_tab):
|
||||||
|
if len(src_tab) < 1:
|
||||||
|
tm = src_tab.tab_manager_ref()
|
||||||
|
if tm is not None:
|
||||||
|
tm.remove(src_tab)
|
||||||
|
src_tab.destroy()
|
||||||
|
if len(tm) == 0:
|
||||||
|
if not self.shutting_down:
|
||||||
|
mark_os_window_for_close(src_tab.os_window_id)
|
||||||
|
|
||||||
def on_child_death(self, window_id):
|
def on_child_death(self, window_id):
|
||||||
window = self.window_id_map.pop(window_id, None)
|
window = self.window_id_map.pop(window_id, None)
|
||||||
if window is None:
|
if window is None:
|
||||||
@@ -334,20 +346,22 @@ class Boss:
|
|||||||
os_window_id = window.os_window_id
|
os_window_id = window.os_window_id
|
||||||
window.destroy()
|
window.destroy()
|
||||||
tm = self.os_window_map.get(os_window_id)
|
tm = self.os_window_map.get(os_window_id)
|
||||||
if tm is None:
|
tab = None
|
||||||
return
|
if tm is not None:
|
||||||
for tab in tm:
|
for q in tm:
|
||||||
if window in tab:
|
if window in q:
|
||||||
break
|
tab = q
|
||||||
else:
|
break
|
||||||
return
|
if tab is not None:
|
||||||
tab.remove_window(window)
|
tab.remove_window(window)
|
||||||
if len(tab) == 0:
|
self._cleanup_tab_after_window_removal(tab)
|
||||||
tm.remove(tab)
|
if window.action_on_removal:
|
||||||
tab.destroy()
|
try:
|
||||||
if len(tm) == 0:
|
window.action_on_removal(window)
|
||||||
if not self.shutting_down:
|
except Exception:
|
||||||
mark_os_window_for_close(os_window_id)
|
import traceback
|
||||||
|
traceback.print_exc()
|
||||||
|
window.action_on_close = window.action_on_removal = None
|
||||||
|
|
||||||
def close_window(self, window=None):
|
def close_window(self, window=None):
|
||||||
if window is None:
|
if window is None:
|
||||||
@@ -512,27 +526,27 @@ class Boss:
|
|||||||
if t is not None:
|
if t is not None:
|
||||||
return t.active_window
|
return t.active_window
|
||||||
|
|
||||||
def dispatch_special_key(self, key, scancode, action, mods):
|
def dispatch_special_key(self, key, native_key, action, mods):
|
||||||
# Handles shortcuts, return True if the key was consumed
|
# Handles shortcuts, return True if the key was consumed
|
||||||
key_action = get_shortcut(self.keymap, mods, key, scancode)
|
key_action = get_shortcut(self.keymap, mods, key, native_key)
|
||||||
if key_action is None:
|
if key_action is None:
|
||||||
sequences = get_shortcut(self.opts.sequence_map, mods, key, scancode)
|
sequences = get_shortcut(self.opts.sequence_map, mods, key, native_key)
|
||||||
if sequences:
|
if sequences:
|
||||||
self.pending_sequences = sequences
|
self.pending_sequences = sequences
|
||||||
set_in_sequence_mode(True)
|
set_in_sequence_mode(True)
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
self.current_key_press_info = key, scancode, action, mods
|
self.current_key_press_info = key, native_key, action, mods
|
||||||
return self.dispatch_action(key_action)
|
return self.dispatch_action(key_action)
|
||||||
|
|
||||||
def process_sequence(self, key, scancode, action, mods):
|
def process_sequence(self, key, native_key, action, mods):
|
||||||
if not self.pending_sequences:
|
if not self.pending_sequences:
|
||||||
set_in_sequence_mode(False)
|
set_in_sequence_mode(False)
|
||||||
|
|
||||||
remaining = {}
|
remaining = {}
|
||||||
matched_action = None
|
matched_action = None
|
||||||
for seq, key_action in self.pending_sequences.items():
|
for seq, key_action in self.pending_sequences.items():
|
||||||
if shortcut_matches(seq[0], mods, key, scancode):
|
if shortcut_matches(seq[0], mods, key, native_key):
|
||||||
seq = seq[1:]
|
seq = seq[1:]
|
||||||
if seq:
|
if seq:
|
||||||
remaining[seq] = key_action
|
remaining[seq] = key_action
|
||||||
@@ -619,12 +633,12 @@ class Boss:
|
|||||||
if tm is not None:
|
if tm is not None:
|
||||||
tm.update_tab_bar_data()
|
tm.update_tab_bar_data()
|
||||||
|
|
||||||
def on_drop(self, os_window_id, paths):
|
def on_drop(self, os_window_id, strings):
|
||||||
tm = self.os_window_map.get(os_window_id)
|
tm = self.os_window_map.get(os_window_id)
|
||||||
if tm is not None:
|
if tm is not None:
|
||||||
w = tm.active_window
|
w = tm.active_window
|
||||||
if w is not None:
|
if w is not None:
|
||||||
w.paste('\n'.join(paths))
|
w.paste('\n'.join(strings))
|
||||||
|
|
||||||
def on_os_window_closed(self, os_window_id, viewport_width, viewport_height):
|
def on_os_window_closed(self, os_window_id, viewport_width, viewport_height):
|
||||||
self.cached_values['window-size'] = viewport_width, viewport_height
|
self.cached_values['window-size'] = viewport_width, viewport_height
|
||||||
@@ -670,7 +684,7 @@ class Boss:
|
|||||||
output += str(s.linebuf.line(i))
|
output += str(s.linebuf.line(i))
|
||||||
return output
|
return output
|
||||||
|
|
||||||
def _run_kitten(self, kitten, args=(), input_data=None, window=None):
|
def _run_kitten(self, kitten, args=(), input_data=None, window=None, custom_callback=None, action_on_removal=None):
|
||||||
orig_args, args = list(args), list(args)
|
orig_args, args = list(args), list(args)
|
||||||
from kittens.runner import create_kitten_handler
|
from kittens.runner import create_kitten_handler
|
||||||
end_kitten = create_kitten_handler(kitten, orig_args)
|
end_kitten = create_kitten_handler(kitten, orig_args)
|
||||||
@@ -716,8 +730,13 @@ class Boss:
|
|||||||
},
|
},
|
||||||
cwd=w.cwd_of_child,
|
cwd=w.cwd_of_child,
|
||||||
overlay_for=w.id
|
overlay_for=w.id
|
||||||
))
|
),
|
||||||
overlay_window.action_on_close = partial(self.on_kitten_finish, w.id, end_kitten)
|
copy_colors_from=w
|
||||||
|
)
|
||||||
|
wid = w.id
|
||||||
|
overlay_window.action_on_close = partial(self.on_kitten_finish, wid, custom_callback or end_kitten)
|
||||||
|
if action_on_removal is not None:
|
||||||
|
overlay_window.action_on_removal = lambda *a: action_on_removal(wid, self)
|
||||||
return overlay_window
|
return overlay_window
|
||||||
|
|
||||||
def kitten(self, kitten, *args):
|
def kitten(self, kitten, *args):
|
||||||
@@ -879,6 +898,9 @@ class Boss:
|
|||||||
stdin = stdin.encode('utf-8')
|
stdin = stdin.encode('utf-8')
|
||||||
return env, stdin
|
return env, stdin
|
||||||
|
|
||||||
|
def data_for_at(self, which, window=None, add_wrap_markers=False):
|
||||||
|
return data_for_at(window or self.active_window, which, add_wrap_markers=add_wrap_markers)
|
||||||
|
|
||||||
def special_window_for_cmd(self, cmd, window=None, stdin=None, cwd_from=None, as_overlay=False):
|
def special_window_for_cmd(self, cmd, window=None, stdin=None, cwd_from=None, as_overlay=False):
|
||||||
w = window or self.active_window
|
w = window or self.active_window
|
||||||
env, stdin = self.process_stdin_source(w, stdin)
|
env, stdin = self.process_stdin_source(w, stdin)
|
||||||
@@ -892,6 +914,25 @@ class Boss:
|
|||||||
overlay_for = w.id if as_overlay and w.overlay_for is None else None
|
overlay_for = w.id if as_overlay and w.overlay_for is None else None
|
||||||
return SpecialWindow(cmd, stdin, cwd_from=cwd_from, overlay_for=overlay_for, env=env)
|
return SpecialWindow(cmd, stdin, cwd_from=cwd_from, overlay_for=overlay_for, env=env)
|
||||||
|
|
||||||
|
def run_background_process(self, cmd, cwd=None, env=None, stdin=None, cwd_from=None):
|
||||||
|
import subprocess
|
||||||
|
if cwd_from:
|
||||||
|
with suppress(Exception):
|
||||||
|
cwd = cwd_of_process(cwd_from)
|
||||||
|
|
||||||
|
if stdin:
|
||||||
|
r, w = safe_pipe(False)
|
||||||
|
try:
|
||||||
|
subprocess.Popen(cmd, env=env, stdin=r, cwd=cwd)
|
||||||
|
except Exception:
|
||||||
|
os.close(w)
|
||||||
|
else:
|
||||||
|
thread_write(w, stdin)
|
||||||
|
finally:
|
||||||
|
os.close(r)
|
||||||
|
else:
|
||||||
|
subprocess.Popen(cmd, env=env, cwd=cwd)
|
||||||
|
|
||||||
def pipe(self, source, dest, exe, *args):
|
def pipe(self, source, dest, exe, *args):
|
||||||
cmd = [exe] + list(args)
|
cmd = [exe] + list(args)
|
||||||
window = self.active_window
|
window = self.active_window
|
||||||
@@ -917,24 +958,8 @@ class Boss:
|
|||||||
func = set_clipboard_string if dest == 'clipboard' else set_primary_selection
|
func = set_clipboard_string if dest == 'clipboard' else set_primary_selection
|
||||||
func(stdin)
|
func(stdin)
|
||||||
else:
|
else:
|
||||||
import subprocess
|
|
||||||
env, stdin = self.process_stdin_source(stdin=source, window=window)
|
env, stdin = self.process_stdin_source(stdin=source, window=window)
|
||||||
cwd = None
|
self.run_background_process(cmd, cwd_from=cwd_from, stdin=stdin, env=env)
|
||||||
if cwd_from:
|
|
||||||
with suppress(Exception):
|
|
||||||
cwd = cwd_of_process(cwd_from)
|
|
||||||
if stdin:
|
|
||||||
r, w = safe_pipe(False)
|
|
||||||
try:
|
|
||||||
subprocess.Popen(cmd, env=env, stdin=r, cwd=cwd)
|
|
||||||
except Exception:
|
|
||||||
os.close(w)
|
|
||||||
else:
|
|
||||||
thread_write(w, stdin)
|
|
||||||
finally:
|
|
||||||
os.close(r)
|
|
||||||
else:
|
|
||||||
subprocess.Popen(cmd, env=env, cwd=cwd)
|
|
||||||
|
|
||||||
def args_to_special_window(self, args, cwd_from=None):
|
def args_to_special_window(self, args, cwd_from=None):
|
||||||
args = list(args)
|
args = list(args)
|
||||||
@@ -989,14 +1014,20 @@ class Boss:
|
|||||||
def _new_window(self, args, cwd_from=None):
|
def _new_window(self, args, cwd_from=None):
|
||||||
tab = self.active_tab
|
tab = self.active_tab
|
||||||
if tab is not None:
|
if tab is not None:
|
||||||
|
allow_remote_control = False
|
||||||
location = None
|
location = None
|
||||||
if args and args[0].startswith('!'):
|
if args and args[0].startswith('!'):
|
||||||
location = args[0][1:].lower()
|
location = args[0][1:].lower()
|
||||||
args = args[1:]
|
args = args[1:]
|
||||||
|
if args and args[0] == '@':
|
||||||
|
args = args[1:]
|
||||||
|
allow_remote_control = True
|
||||||
if args:
|
if args:
|
||||||
return tab.new_special_window(self.args_to_special_window(args, cwd_from=cwd_from), location=location)
|
return tab.new_special_window(
|
||||||
|
self.args_to_special_window(args, cwd_from=cwd_from),
|
||||||
|
location=location, allow_remote_control=allow_remote_control)
|
||||||
else:
|
else:
|
||||||
return tab.new_window(cwd_from=cwd_from, location=location)
|
return tab.new_window(cwd_from=cwd_from, location=location, allow_remote_control=allow_remote_control)
|
||||||
|
|
||||||
def new_window(self, *args):
|
def new_window(self, *args):
|
||||||
self._new_window(args)
|
self._new_window(args)
|
||||||
@@ -1008,6 +1039,11 @@ class Boss:
|
|||||||
cwd_from = w.child.pid_for_cwd if w is not None else None
|
cwd_from = w.child.pid_for_cwd if w is not None else None
|
||||||
self._new_window(args, cwd_from=cwd_from)
|
self._new_window(args, cwd_from=cwd_from)
|
||||||
|
|
||||||
|
def launch(self, *args):
|
||||||
|
from kitty.launch import parse_launch_args, launch
|
||||||
|
opts, args = parse_launch_args(args)
|
||||||
|
launch(self, opts, args)
|
||||||
|
|
||||||
def move_tab_forward(self):
|
def move_tab_forward(self):
|
||||||
tm = self.active_tab_manager
|
tm = self.active_tab_manager
|
||||||
if tm is not None:
|
if tm is not None:
|
||||||
@@ -1094,3 +1130,144 @@ class Boss:
|
|||||||
|
|
||||||
msg = '\n'.join(map(format_bad_line, bad_lines)).rstrip()
|
msg = '\n'.join(map(format_bad_line, bad_lines)).rstrip()
|
||||||
self.show_error(_('Errors in kitty.conf'), msg)
|
self.show_error(_('Errors in kitty.conf'), msg)
|
||||||
|
|
||||||
|
def set_colors(self, *args):
|
||||||
|
from .cmds import parse_subcommand_cli, cmd_set_colors, set_colors
|
||||||
|
opts, items = parse_subcommand_cli(cmd_set_colors, ['set-colors'] + list(args))
|
||||||
|
payload = cmd_set_colors(None, opts, items)
|
||||||
|
set_colors(self, self.active_window, payload)
|
||||||
|
|
||||||
|
def _move_window_to(self, window=None, target_tab_id=None, target_os_window_id=None):
|
||||||
|
window = window or self.active_window
|
||||||
|
if not window:
|
||||||
|
return
|
||||||
|
src_tab = self.tab_for_window(window)
|
||||||
|
if src_tab is None:
|
||||||
|
return
|
||||||
|
if target_os_window_id == 'new':
|
||||||
|
target_os_window_id = self.add_os_window()
|
||||||
|
tm = self.os_window_map[target_os_window_id]
|
||||||
|
target_tab = tm.new_tab(empty_tab=True)
|
||||||
|
else:
|
||||||
|
target_os_window_id = target_os_window_id or current_os_window()
|
||||||
|
if target_tab_id == 'new':
|
||||||
|
tm = self.os_window_map[target_os_window_id]
|
||||||
|
target_tab = tm.new_tab(empty_tab=True)
|
||||||
|
else:
|
||||||
|
for tab in self.all_tabs:
|
||||||
|
if tab.id == target_tab_id:
|
||||||
|
target_tab = tab
|
||||||
|
target_os_window_id = tab.os_window_id
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
return
|
||||||
|
|
||||||
|
underlaid_window, overlaid_window = src_tab.detach_window(window)
|
||||||
|
if underlaid_window:
|
||||||
|
target_tab.attach_window(underlaid_window)
|
||||||
|
if overlaid_window:
|
||||||
|
target_tab.attach_window(overlaid_window)
|
||||||
|
self._cleanup_tab_after_window_removal(src_tab)
|
||||||
|
target_tab.make_active()
|
||||||
|
|
||||||
|
def _move_tab_to(self, tab=None, target_os_window_id=None):
|
||||||
|
tab = tab or self.active_tab
|
||||||
|
if tab is None:
|
||||||
|
return
|
||||||
|
if target_os_window_id is None:
|
||||||
|
target_os_window_id = self.add_os_window()
|
||||||
|
tm = self.os_window_map[target_os_window_id]
|
||||||
|
target_tab = tm.new_tab(empty_tab=True)
|
||||||
|
target_tab.take_over_from(tab)
|
||||||
|
self._cleanup_tab_after_window_removal(tab)
|
||||||
|
target_tab.make_active()
|
||||||
|
|
||||||
|
def detach_window(self, *args):
|
||||||
|
if not args or args[0] == 'new':
|
||||||
|
return self._move_window_to(target_os_window_id='new')
|
||||||
|
if args[0] == 'new-tab':
|
||||||
|
return self._move_window_to(target_tab_id='new')
|
||||||
|
lines = [
|
||||||
|
'Choose a tab to move the window to',
|
||||||
|
''
|
||||||
|
]
|
||||||
|
fmt = ': {1}'
|
||||||
|
tab_id_map = {}
|
||||||
|
current_tab = self.active_tab
|
||||||
|
for i, tab in enumerate(self.all_tabs):
|
||||||
|
if tab is not current_tab:
|
||||||
|
tab_id_map[len(tab_id_map)] = tab.id
|
||||||
|
lines.append(fmt.format(i + 1, tab.title))
|
||||||
|
new_idx = len(tab_id_map) + 1
|
||||||
|
tab_id_map[new_idx - 1] = 'new'
|
||||||
|
lines.append(fmt.format(new_idx, 'New tab'))
|
||||||
|
new_idx = len(tab_id_map) + 1
|
||||||
|
tab_id_map[new_idx - 1] = None
|
||||||
|
lines.append(fmt.format(new_idx, 'New OS Window'))
|
||||||
|
|
||||||
|
def done(data, target_window_id, self):
|
||||||
|
done.tab_id = tab_id_map[int(data['groupdicts'][0]['index'])]
|
||||||
|
|
||||||
|
def done2(target_window_id, self):
|
||||||
|
if not hasattr(done, 'tab_id'):
|
||||||
|
return
|
||||||
|
tab_id = done.tab_id
|
||||||
|
target_window = None
|
||||||
|
for w in self.all_windows:
|
||||||
|
if w.id == target_window_id:
|
||||||
|
target_window = w
|
||||||
|
break
|
||||||
|
if tab_id is None:
|
||||||
|
self._move_window_to(window=target_window, target_os_window_id='new')
|
||||||
|
else:
|
||||||
|
self._move_window_to(window=target_window, target_tab_id=tab_id)
|
||||||
|
|
||||||
|
self._run_kitten(
|
||||||
|
'hints', args=(
|
||||||
|
'--ascending', '--customize-processing=::import::kitty.choose_entry',
|
||||||
|
r'--regex=(?m)^:\s+.+$',
|
||||||
|
), input_data='\r\n'.join(lines).encode('utf-8'), custom_callback=done, action_on_removal=done2
|
||||||
|
)
|
||||||
|
|
||||||
|
def detach_tab(self, *args):
|
||||||
|
if not args or args[0] == 'new':
|
||||||
|
return self._move_tab_to()
|
||||||
|
|
||||||
|
lines = [
|
||||||
|
'Choose an OS window to move the tab to',
|
||||||
|
''
|
||||||
|
]
|
||||||
|
fmt = ': {1}'
|
||||||
|
os_window_id_map = {}
|
||||||
|
current_os_window = getattr(self.active_tab, 'os_window_id', 0)
|
||||||
|
for i, osw in enumerate(self.os_window_map):
|
||||||
|
tm = self.os_window_map[osw]
|
||||||
|
if current_os_window != osw and tm.active_tab and tm.active_tab:
|
||||||
|
os_window_id_map[len(os_window_id_map)] = osw
|
||||||
|
lines.append(fmt.format(i + 1, tm.active_tab.title))
|
||||||
|
new_idx = len(os_window_id_map) + 1
|
||||||
|
os_window_id_map[new_idx - 1] = None
|
||||||
|
lines.append(fmt.format(new_idx, 'New OS Window'))
|
||||||
|
|
||||||
|
def done(data, target_window_id, self):
|
||||||
|
done.os_window_id = os_window_id_map[int(data['groupdicts'][0]['index'])]
|
||||||
|
|
||||||
|
def done2(target_window_id, self):
|
||||||
|
if not hasattr(done, 'os_window_id'):
|
||||||
|
return
|
||||||
|
os_window_id = done.os_window_id
|
||||||
|
target_tab = self.active_tab
|
||||||
|
for w in self.all_windows:
|
||||||
|
if w.id == target_window_id:
|
||||||
|
target_tab = w.tabref()
|
||||||
|
break
|
||||||
|
if target_tab and target_tab.os_window_id == os_window_id:
|
||||||
|
return
|
||||||
|
self._move_tab_to(tab=target_tab, target_os_window_id=os_window_id)
|
||||||
|
|
||||||
|
self._run_kitten(
|
||||||
|
'hints', args=(
|
||||||
|
'--ascending', '--customize-processing=::import::kitty.choose_entry',
|
||||||
|
r'--regex=(?m)^:\s+.+$',
|
||||||
|
), input_data='\r\n'.join(lines).encode('utf-8'), custom_callback=done, action_on_removal=done2
|
||||||
|
)
|
||||||
|
|||||||
@@ -114,7 +114,7 @@ vec3 choose_color(float q, vec3 a, vec3 b) {
|
|||||||
return mix(b, a, q);
|
return mix(b, a, q);
|
||||||
}
|
}
|
||||||
|
|
||||||
float are_integers_equal(float a, float b) { // return 1 iff equal otherwise 0
|
float are_integers_equal(float a, float b) { // return 1 if equal otherwise 0
|
||||||
float delta = abs(a - b); // delta can be 0, 1 or larger
|
float delta = abs(a - b); // delta can be 0, 1 or larger
|
||||||
return step(delta, 0.5); // 0 if 0.5 < delta else 1
|
return step(delta, 0.5); // 0 if 0.5 < delta else 1
|
||||||
}
|
}
|
||||||
@@ -151,7 +151,8 @@ void main() {
|
|||||||
// set cell color indices {{{
|
// set cell color indices {{{
|
||||||
uvec2 default_colors = uvec2(default_fg, default_bg);
|
uvec2 default_colors = uvec2(default_fg, default_bg);
|
||||||
uint text_attrs = sprite_coords[3];
|
uint text_attrs = sprite_coords[3];
|
||||||
uint is_inverted = ((text_attrs >> REVERSE_SHIFT) & ONE) + inverted;
|
uint is_reversed = ((text_attrs >> REVERSE_SHIFT) & ONE);
|
||||||
|
uint is_inverted = is_reversed + inverted;
|
||||||
int fg_index = fg_index_map[is_inverted];
|
int fg_index = fg_index_map[is_inverted];
|
||||||
int bg_index = 1 - fg_index;
|
int bg_index = 1 - fg_index;
|
||||||
float cell_has_cursor = is_cursor(c, r);
|
float cell_has_cursor = is_cursor(c, r);
|
||||||
@@ -172,13 +173,15 @@ void main() {
|
|||||||
foreground = color_to_vec(resolved_fg);
|
foreground = color_to_vec(resolved_fg);
|
||||||
float has_dim = float((text_attrs >> DIM_SHIFT) & ONE);
|
float has_dim = float((text_attrs >> DIM_SHIFT) & ONE);
|
||||||
effective_text_alpha = inactive_text_alpha * mix(1.0, dim_opacity, has_dim);
|
effective_text_alpha = inactive_text_alpha * mix(1.0, dim_opacity, has_dim);
|
||||||
#ifdef USE_SELECTION_FG
|
|
||||||
// Selection
|
|
||||||
foreground = choose_color(float(is_selected & ONE), color_to_vec(highlight_fg), foreground);
|
|
||||||
#endif
|
|
||||||
// Underline and strike through (rendered via sprites)
|
|
||||||
float in_url = float((is_selected & TWO) >> 1);
|
float in_url = float((is_selected & TWO) >> 1);
|
||||||
decoration_fg = choose_color(in_url, color_to_vec(url_color), to_color(colors[2], resolved_fg));
|
decoration_fg = choose_color(in_url, color_to_vec(url_color), to_color(colors[2], resolved_fg));
|
||||||
|
#ifdef USE_SELECTION_FG
|
||||||
|
// Selection
|
||||||
|
vec3 selection_color = color_to_vec(highlight_fg);
|
||||||
|
foreground = choose_color(float(is_selected & ONE), selection_color, foreground);
|
||||||
|
decoration_fg = choose_color(float(is_selected & ONE), selection_color, decoration_fg);
|
||||||
|
#endif
|
||||||
|
// Underline and strike through (rendered via sprites)
|
||||||
underline_pos = choose_color(in_url, to_sprite_pos(pos, url_style, ZERO, ZERO), to_sprite_pos(pos, (text_attrs >> DECORATION_SHIFT) & THREE, ZERO, ZERO));
|
underline_pos = choose_color(in_url, to_sprite_pos(pos, url_style, ZERO, ZERO), to_sprite_pos(pos, (text_attrs >> DECORATION_SHIFT) & THREE, ZERO, ZERO));
|
||||||
strike_pos = to_sprite_pos(pos, ((text_attrs >> STRIKE_SHIFT) & ONE) * FOUR, ZERO, ZERO);
|
strike_pos = to_sprite_pos(pos, ((text_attrs >> STRIKE_SHIFT) & ONE) * FOUR, ZERO, ZERO);
|
||||||
|
|
||||||
@@ -198,21 +201,28 @@ void main() {
|
|||||||
background = bg;
|
background = bg;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(TRANSPARENT) && !defined(SPECIAL)
|
#if defined(TRANSPARENT)
|
||||||
// If the background color is default, set its opacity to background_opacity, otherwise it should be opaque
|
// Set bg_alpha to background_opacity on cells that have the default background color
|
||||||
bg_alpha = step(0.5, float(colors[bg_index] & BYTE_MASK));
|
// Which means they must not have a block cursor or a selection or reverse video
|
||||||
// Cursor must not be affected by background_opacity
|
// On other cells it should be 1. For the SPECIAL program it should be 1 on cells with
|
||||||
bg_alpha = mix(bg_alpha, 1.0, cell_has_block_cursor);
|
// selections/block cursor and 0 everywhere else.
|
||||||
|
float is_special_cell = cell_has_block_cursor + float(is_selected & ONE);
|
||||||
|
#ifndef SPECIAL
|
||||||
|
is_special_cell += float(colors[bg_index] & BYTE_MASK) + float(is_reversed);
|
||||||
|
#endif
|
||||||
|
bg_alpha = step(0.5, is_special_cell);
|
||||||
|
#ifndef SPECIAL
|
||||||
bg_alpha = bg_alpha + (1.0f - bg_alpha) * background_opacity;
|
bg_alpha = bg_alpha + (1.0f - bg_alpha) * background_opacity;
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(SPECIAL) || defined(SIMPLE)
|
#if defined(SPECIAL) || defined(SIMPLE)
|
||||||
// Selection and cursor
|
// Selection and cursor
|
||||||
bg = choose_color(float(is_selected & ONE), color_to_vec(highlight_bg), bg);
|
bg = choose_color(float(is_selected & ONE), color_to_vec(highlight_bg), bg);
|
||||||
background = choose_color(cell_has_block_cursor, color_to_vec(cursor_color), bg);
|
background = choose_color(cell_has_block_cursor, color_to_vec(cursor_color), bg);
|
||||||
#ifdef SPECIAL
|
#if !defined(TRANSPARENT) && defined(SPECIAL)
|
||||||
// bg_alpha should be 1 if cursor/selection otherwise 0
|
float is_special_cell = cell_has_block_cursor + float(is_selected & ONE);
|
||||||
bg_alpha = mix(0.0, 1.0, step(0.5, float(is_selected & ONE) + cell_has_block_cursor));
|
bg_alpha = step(0.5, is_special_cell);
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
#include "screen.h"
|
#include "screen.h"
|
||||||
#include "fonts.h"
|
#include "fonts.h"
|
||||||
#include "charsets.h"
|
#include "charsets.h"
|
||||||
|
#include "monotonic.h"
|
||||||
#include <termios.h>
|
#include <termios.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <float.h>
|
#include <float.h>
|
||||||
@@ -34,7 +35,7 @@ extern PyTypeObject Screen_Type;
|
|||||||
#endif
|
#endif
|
||||||
#define USE_RENDER_FRAMES (global_state.has_render_frames && OPT(sync_to_monitor))
|
#define USE_RENDER_FRAMES (global_state.has_render_frames && OPT(sync_to_monitor))
|
||||||
|
|
||||||
static void (*parse_func)(Screen*, PyObject*, double);
|
static void (*parse_func)(Screen*, PyObject*, monotonic_t);
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char *data;
|
char *data;
|
||||||
@@ -108,12 +109,12 @@ static size_t reaped_pids_count = 0;
|
|||||||
#define INCREF_CHILD(x) XREF_CHILD(x, Py_INCREF)
|
#define INCREF_CHILD(x) XREF_CHILD(x, Py_INCREF)
|
||||||
#define DECREF_CHILD(x) XREF_CHILD(x, Py_DECREF)
|
#define DECREF_CHILD(x) XREF_CHILD(x, Py_DECREF)
|
||||||
|
|
||||||
// The max time (in secs) to wait for events from the window system
|
// The max time to wait for events from the window system
|
||||||
// before ticking over the main loop. Negative values mean wait forever.
|
// before ticking over the main loop. Negative values mean wait forever.
|
||||||
static double maximum_wait = -1.0;
|
static monotonic_t maximum_wait = -1;
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
set_maximum_wait(double val) {
|
set_maximum_wait(monotonic_t val) {
|
||||||
if (val >= 0 && (val < maximum_wait || maximum_wait < 0)) maximum_wait = val;
|
if (val >= 0 && (val < maximum_wait || maximum_wait < 0)) maximum_wait = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -168,7 +169,7 @@ dealloc(ChildMonitor* self) {
|
|||||||
|
|
||||||
static void
|
static void
|
||||||
wakeup_io_loop(ChildMonitor *self, bool in_signal_handler) {
|
wakeup_io_loop(ChildMonitor *self, bool in_signal_handler) {
|
||||||
wakeup_loop(&self->io_loop_data, in_signal_handler);
|
wakeup_loop(&self->io_loop_data, in_signal_handler, "io_loop");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void* io_loop(void *data);
|
static void* io_loop(void *data);
|
||||||
@@ -296,11 +297,11 @@ shutdown_monitor(ChildMonitor *self, PyObject *a UNUSED) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline bool
|
static inline bool
|
||||||
do_parse(ChildMonitor *self, Screen *screen, double now) {
|
do_parse(ChildMonitor *self, Screen *screen, monotonic_t now) {
|
||||||
bool input_read = false;
|
bool input_read = false;
|
||||||
screen_mutex(lock, read);
|
screen_mutex(lock, read);
|
||||||
if (screen->read_buf_sz || screen->pending_mode.used) {
|
if (screen->read_buf_sz || screen->pending_mode.used) {
|
||||||
double time_since_new_input = now - screen->new_input_at;
|
monotonic_t time_since_new_input = now - screen->new_input_at;
|
||||||
if (time_since_new_input >= OPT(input_delay)) {
|
if (time_since_new_input >= OPT(input_delay)) {
|
||||||
bool read_buf_full = screen->read_buf_sz >= READ_BUF_SZ;
|
bool read_buf_full = screen->read_buf_sz >= READ_BUF_SZ;
|
||||||
input_read = true;
|
input_read = true;
|
||||||
@@ -308,7 +309,7 @@ do_parse(ChildMonitor *self, Screen *screen, double now) {
|
|||||||
if (read_buf_full) wakeup_io_loop(self, false); // Ensure the read fd has POLLIN set
|
if (read_buf_full) wakeup_io_loop(self, false); // Ensure the read fd has POLLIN set
|
||||||
screen->new_input_at = 0;
|
screen->new_input_at = 0;
|
||||||
if (screen->pending_mode.activated_at) {
|
if (screen->pending_mode.activated_at) {
|
||||||
double time_since_pending = MAX(0, now - screen->pending_mode.activated_at);
|
monotonic_t time_since_pending = MAX(0, now - screen->pending_mode.activated_at);
|
||||||
set_maximum_wait(screen->pending_mode.wait_time - time_since_pending);
|
set_maximum_wait(screen->pending_mode.wait_time - time_since_pending);
|
||||||
}
|
}
|
||||||
} else set_maximum_wait(OPT(input_delay) - time_since_new_input);
|
} else set_maximum_wait(OPT(input_delay) - time_since_new_input);
|
||||||
@@ -322,7 +323,7 @@ parse_input(ChildMonitor *self) {
|
|||||||
// Parse all available input that was read in the I/O thread.
|
// Parse all available input that was read in the I/O thread.
|
||||||
size_t count = 0, remove_count = 0;
|
size_t count = 0, remove_count = 0;
|
||||||
bool input_read = false;
|
bool input_read = false;
|
||||||
double now = monotonic();
|
monotonic_t now = monotonic();
|
||||||
PyObject *msg = NULL;
|
PyObject *msg = NULL;
|
||||||
children_mutex(lock);
|
children_mutex(lock);
|
||||||
while (remove_queue_count) {
|
while (remove_queue_count) {
|
||||||
@@ -485,22 +486,22 @@ pyset_iutf8(ChildMonitor *self, PyObject *args) {
|
|||||||
extern void cocoa_update_menu_bar_title(PyObject*);
|
extern void cocoa_update_menu_bar_title(PyObject*);
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
collect_cursor_info(CursorRenderInfo *ans, Window *w, double now, OSWindow *os_window) {
|
collect_cursor_info(CursorRenderInfo *ans, Window *w, monotonic_t now, OSWindow *os_window) {
|
||||||
ScreenRenderData *rd = &w->render_data;
|
ScreenRenderData *rd = &w->render_data;
|
||||||
Cursor *cursor = rd->screen->cursor;
|
Cursor *cursor = rd->screen->cursor;
|
||||||
ans->x = cursor->x; ans->y = cursor->y;
|
ans->x = cursor->x; ans->y = cursor->y;
|
||||||
ans->is_visible = false;
|
ans->is_visible = false;
|
||||||
if (rd->screen->scrolled_by || !screen_is_cursor_visible(rd->screen)) return;
|
if (rd->screen->scrolled_by || !screen_is_cursor_visible(rd->screen)) return;
|
||||||
double time_since_start_blink = now - os_window->cursor_blink_zero_time;
|
monotonic_t time_since_start_blink = now - os_window->cursor_blink_zero_time;
|
||||||
bool cursor_blinking = OPT(cursor_blink_interval) > 0 && os_window->is_focused && (OPT(cursor_stop_blinking_after) == 0 || time_since_start_blink <= OPT(cursor_stop_blinking_after));
|
bool cursor_blinking = OPT(cursor_blink_interval) > 0 && os_window->is_focused && (OPT(cursor_stop_blinking_after) == 0 || time_since_start_blink <= OPT(cursor_stop_blinking_after));
|
||||||
bool do_draw_cursor = true;
|
bool do_draw_cursor = true;
|
||||||
if (cursor_blinking) {
|
if (cursor_blinking) {
|
||||||
int t = (int)(time_since_start_blink * 1000);
|
int t = monotonic_t_to_ms(time_since_start_blink);
|
||||||
int d = (int)(OPT(cursor_blink_interval) * 1000);
|
int d = monotonic_t_to_ms(OPT(cursor_blink_interval));
|
||||||
int n = t / d;
|
int n = t / d;
|
||||||
do_draw_cursor = n % 2 == 0 ? true : false;
|
do_draw_cursor = n % 2 == 0 ? true : false;
|
||||||
double bucket = (n + 1) * d;
|
monotonic_t bucket = ms_to_monotonic_t((n + 1) * d);
|
||||||
double delay = (bucket / 1000.0) - time_since_start_blink;
|
monotonic_t delay = bucket - time_since_start_blink;
|
||||||
set_maximum_wait(delay);
|
set_maximum_wait(delay);
|
||||||
}
|
}
|
||||||
if (!do_draw_cursor) { ans->is_visible = false; return; }
|
if (!do_draw_cursor) { ans->is_visible = false; return; }
|
||||||
@@ -518,7 +519,7 @@ update_window_title(Window *w, OSWindow *os_window) {
|
|||||||
Py_INCREF(os_window->window_title);
|
Py_INCREF(os_window->window_title);
|
||||||
set_os_window_title(os_window, PyUnicode_AsUTF8(w->title));
|
set_os_window_title(os_window, PyUnicode_AsUTF8(w->title));
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
if (os_window->is_focused && OPT(macos_show_window_title_in_menubar)) cocoa_update_menu_bar_title(w->title);
|
if (os_window->is_focused && (OPT(macos_show_window_title_in) & MENUBAR)) cocoa_update_menu_bar_title(w->title);
|
||||||
#endif
|
#endif
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -526,7 +527,7 @@ update_window_title(Window *w, OSWindow *os_window) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline bool
|
static inline bool
|
||||||
prepare_to_render_os_window(OSWindow *os_window, double now, unsigned int *active_window_id, color_type *active_window_bg, unsigned int *num_visible_windows) {
|
prepare_to_render_os_window(OSWindow *os_window, monotonic_t now, unsigned int *active_window_id, color_type *active_window_bg, unsigned int *num_visible_windows, bool *all_windows_have_same_bg) {
|
||||||
#define TD os_window->tab_bar_render_data
|
#define TD os_window->tab_bar_render_data
|
||||||
bool needs_render = os_window->needs_render;
|
bool needs_render = os_window->needs_render;
|
||||||
os_window->needs_render = false;
|
os_window->needs_render = false;
|
||||||
@@ -543,16 +544,22 @@ prepare_to_render_os_window(OSWindow *os_window, double now, unsigned int *activ
|
|||||||
}
|
}
|
||||||
Tab *tab = os_window->tabs + os_window->active_tab;
|
Tab *tab = os_window->tabs + os_window->active_tab;
|
||||||
*active_window_bg = OPT(background);
|
*active_window_bg = OPT(background);
|
||||||
|
*all_windows_have_same_bg = true;
|
||||||
|
*num_visible_windows = 0;
|
||||||
|
color_type first_window_bg = 0;
|
||||||
for (unsigned int i = 0; i < tab->num_windows; i++) {
|
for (unsigned int i = 0; i < tab->num_windows; i++) {
|
||||||
Window *w = tab->windows + i;
|
Window *w = tab->windows + i;
|
||||||
#define WD w->render_data
|
#define WD w->render_data
|
||||||
if (w->visible && WD.screen) {
|
if (w->visible && WD.screen) {
|
||||||
*num_visible_windows += 1;
|
*num_visible_windows += 1;
|
||||||
|
color_type window_bg = colorprofile_to_color(WD.screen->color_profile, WD.screen->color_profile->overridden.default_bg, WD.screen->color_profile->configured.default_bg);
|
||||||
|
if (*num_visible_windows == 1) first_window_bg = window_bg;
|
||||||
|
if (first_window_bg != window_bg) all_windows_have_same_bg = false;
|
||||||
if (w->last_drag_scroll_at > 0) {
|
if (w->last_drag_scroll_at > 0) {
|
||||||
if (now - w->last_drag_scroll_at >= 0.02) {
|
if (now - w->last_drag_scroll_at >= ms_to_monotonic_t(20ll)) {
|
||||||
if (drag_scroll(w, os_window)) {
|
if (drag_scroll(w, os_window)) {
|
||||||
w->last_drag_scroll_at = now;
|
w->last_drag_scroll_at = now;
|
||||||
set_maximum_wait(0.02);
|
set_maximum_wait(ms_to_monotonic_t(20ll));
|
||||||
needs_render = true;
|
needs_render = true;
|
||||||
} else w->last_drag_scroll_at = 0;
|
} else w->last_drag_scroll_at = 0;
|
||||||
} else set_maximum_wait(now - w->last_drag_scroll_at);
|
} else set_maximum_wait(now - w->last_drag_scroll_at);
|
||||||
@@ -563,7 +570,7 @@ prepare_to_render_os_window(OSWindow *os_window, double now, unsigned int *activ
|
|||||||
collect_cursor_info(&WD.screen->cursor_render_info, w, now, os_window);
|
collect_cursor_info(&WD.screen->cursor_render_info, w, now, os_window);
|
||||||
if (w->cursor_visible_at_last_render != WD.screen->cursor_render_info.is_visible || w->last_cursor_x != WD.screen->cursor_render_info.x || w->last_cursor_y != WD.screen->cursor_render_info.y || w->last_cursor_shape != WD.screen->cursor_render_info.shape) needs_render = true;
|
if (w->cursor_visible_at_last_render != WD.screen->cursor_render_info.is_visible || w->last_cursor_x != WD.screen->cursor_render_info.x || w->last_cursor_y != WD.screen->cursor_render_info.y || w->last_cursor_shape != WD.screen->cursor_render_info.shape) needs_render = true;
|
||||||
update_window_title(w, os_window);
|
update_window_title(w, os_window);
|
||||||
*active_window_bg = colorprofile_to_color(WD.screen->color_profile, WD.screen->color_profile->overridden.default_bg, WD.screen->color_profile->configured.default_bg);
|
*active_window_bg = window_bg;
|
||||||
} else WD.screen->cursor_render_info.is_visible = false;
|
} else WD.screen->cursor_render_info.is_visible = false;
|
||||||
if (send_cell_data_to_gpu(WD.vao_idx, WD.gvao_idx, WD.xstart, WD.ystart, WD.dx, WD.dy, WD.screen, os_window)) needs_render = true;
|
if (send_cell_data_to_gpu(WD.vao_idx, WD.gvao_idx, WD.xstart, WD.ystart, WD.dx, WD.dy, WD.screen, os_window)) needs_render = true;
|
||||||
if (WD.screen->start_visual_bell_at != 0) needs_render = true;
|
if (WD.screen->start_visual_bell_at != 0) needs_render = true;
|
||||||
@@ -573,7 +580,7 @@ prepare_to_render_os_window(OSWindow *os_window, double now, unsigned int *activ
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
render_os_window(OSWindow *os_window, double now, unsigned int active_window_id, color_type active_window_bg, unsigned int num_visible_windows) {
|
render_os_window(OSWindow *os_window, monotonic_t now, unsigned int active_window_id, color_type active_window_bg, unsigned int num_visible_windows, bool all_windows_have_same_bg) {
|
||||||
// ensure all pixels are cleared to background color at least once in every buffer
|
// ensure all pixels are cleared to background color at least once in every buffer
|
||||||
if (os_window->clear_count++ < 3) blank_os_window(os_window);
|
if (os_window->clear_count++ < 3) blank_os_window(os_window);
|
||||||
Tab *tab = os_window->tabs + os_window->active_tab;
|
Tab *tab = os_window->tabs + os_window->active_tab;
|
||||||
@@ -581,11 +588,11 @@ render_os_window(OSWindow *os_window, double now, unsigned int active_window_id,
|
|||||||
bool static_live_resize_in_progress = os_window->live_resize.in_progress && OPT(resize_draw_strategy) == RESIZE_DRAW_STATIC;
|
bool static_live_resize_in_progress = os_window->live_resize.in_progress && OPT(resize_draw_strategy) == RESIZE_DRAW_STATIC;
|
||||||
float x_ratio = 1, y_ratio = 1;
|
float x_ratio = 1, y_ratio = 1;
|
||||||
if (static_live_resize_in_progress) {
|
if (static_live_resize_in_progress) {
|
||||||
x_ratio = os_window->viewport_width / (double) os_window->live_resize.width;
|
x_ratio = (float) os_window->viewport_width / (float) os_window->live_resize.width;
|
||||||
y_ratio = os_window->viewport_height / (double) os_window->live_resize.height;
|
y_ratio = (float) os_window->viewport_height / (float) os_window->live_resize.height;
|
||||||
}
|
}
|
||||||
if (!static_live_resize_in_progress) {
|
if (!static_live_resize_in_progress) {
|
||||||
draw_borders(br->vao_idx, br->num_border_rects, br->rect_buf, br->is_dirty, os_window->viewport_width, os_window->viewport_height, active_window_bg, num_visible_windows, os_window);
|
draw_borders(br->vao_idx, br->num_border_rects, br->rect_buf, br->is_dirty, os_window->viewport_width, os_window->viewport_height, active_window_bg, num_visible_windows, all_windows_have_same_bg, os_window);
|
||||||
br->is_dirty = false;
|
br->is_dirty = false;
|
||||||
}
|
}
|
||||||
if (TD.screen && os_window->num_tabs >= OPT(tab_bar_min_tabs)) draw_cells(TD.vao_idx, 0, TD.xstart, TD.ystart, TD.dx * x_ratio, TD.dy * y_ratio, TD.screen, os_window, true, false);
|
if (TD.screen && os_window->num_tabs >= OPT(tab_bar_min_tabs)) draw_cells(TD.vao_idx, 0, TD.xstart, TD.ystart, TD.dx * x_ratio, TD.dy * y_ratio, TD.screen, os_window, true, false);
|
||||||
@@ -595,7 +602,7 @@ render_os_window(OSWindow *os_window, double now, unsigned int active_window_id,
|
|||||||
bool is_active_window = i == tab->active_window;
|
bool is_active_window = i == tab->active_window;
|
||||||
draw_cells(WD.vao_idx, WD.gvao_idx, WD.xstart, WD.ystart, WD.dx * x_ratio, WD.dy * y_ratio, WD.screen, os_window, is_active_window, true);
|
draw_cells(WD.vao_idx, WD.gvao_idx, WD.xstart, WD.ystart, WD.dx * x_ratio, WD.dy * y_ratio, WD.screen, os_window, is_active_window, true);
|
||||||
if (WD.screen->start_visual_bell_at != 0) {
|
if (WD.screen->start_visual_bell_at != 0) {
|
||||||
double bell_left = global_state.opts.visual_bell_duration - (now - WD.screen->start_visual_bell_at);
|
monotonic_t bell_left = OPT(visual_bell_duration) - (now - WD.screen->start_visual_bell_at);
|
||||||
set_maximum_wait(bell_left);
|
set_maximum_wait(bell_left);
|
||||||
}
|
}
|
||||||
w->cursor_visible_at_last_render = WD.screen->cursor_render_info.is_visible; w->last_cursor_x = WD.screen->cursor_render_info.x; w->last_cursor_y = WD.screen->cursor_render_info.y; w->last_cursor_shape = WD.screen->cursor_render_info.shape;
|
w->cursor_visible_at_last_render = WD.screen->cursor_render_info.is_visible; w->last_cursor_x = WD.screen->cursor_render_info.x; w->last_cursor_y = WD.screen->cursor_render_info.y; w->last_cursor_shape = WD.screen->cursor_render_info.shape;
|
||||||
@@ -632,17 +639,17 @@ draw_resizing_text(OSWindow *w) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline bool
|
static inline bool
|
||||||
no_render_frame_received_recently(OSWindow *w, double now, double max_wait) {
|
no_render_frame_received_recently(OSWindow *w, monotonic_t now, monotonic_t max_wait) {
|
||||||
bool ans = now - w->last_render_frame_received_at > max_wait;
|
bool ans = now - w->last_render_frame_received_at > max_wait;
|
||||||
if (ans) log_error("No render frame received in %f seconds, re-requesting at: %f", max_wait, now);
|
if (ans) log_error("No render frame received in %f seconds, re-requesting at: %f", monotonic_t_to_s_double(max_wait), monotonic_t_to_s_double(now));
|
||||||
return ans;
|
return ans;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
render(double now, bool input_read) {
|
render(monotonic_t now, bool input_read) {
|
||||||
EVDBG("input_read: %d", input_read);
|
EVDBG("input_read: %d", input_read);
|
||||||
static double last_render_at = -DBL_MAX;
|
static monotonic_t last_render_at = MONOTONIC_T_MIN;
|
||||||
double time_since_last_render = now - last_render_at;
|
monotonic_t time_since_last_render = last_render_at == MONOTONIC_T_MIN ? OPT(repaint_delay) : now - last_render_at;
|
||||||
if (!input_read && time_since_last_render < OPT(repaint_delay)) {
|
if (!input_read && time_since_last_render < OPT(repaint_delay)) {
|
||||||
set_maximum_wait(OPT(repaint_delay) - time_since_last_render);
|
set_maximum_wait(OPT(repaint_delay) - time_since_last_render);
|
||||||
return;
|
return;
|
||||||
@@ -656,7 +663,7 @@ render(double now, bool input_read) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (USE_RENDER_FRAMES && w->render_state != RENDER_FRAME_READY) {
|
if (USE_RENDER_FRAMES && w->render_state != RENDER_FRAME_READY) {
|
||||||
if (w->render_state == RENDER_FRAME_NOT_REQUESTED || no_render_frame_received_recently(w, now, 0.25)) request_frame_render(w);
|
if (w->render_state == RENDER_FRAME_NOT_REQUESTED || no_render_frame_received_recently(w, now, ms_to_monotonic_t(250ll))) request_frame_render(w);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
make_os_window_context_current(w);
|
make_os_window_context_current(w);
|
||||||
@@ -676,11 +683,12 @@ render(double now, bool input_read) {
|
|||||||
needs_render = true;
|
needs_render = true;
|
||||||
}
|
}
|
||||||
unsigned int active_window_id = 0, num_visible_windows = 0;
|
unsigned int active_window_id = 0, num_visible_windows = 0;
|
||||||
|
bool all_windows_have_same_bg;
|
||||||
color_type active_window_bg = 0;
|
color_type active_window_bg = 0;
|
||||||
if (!w->fonts_data) { log_error("No fonts data found for window id: %llu", w->id); continue; }
|
if (!w->fonts_data) { log_error("No fonts data found for window id: %llu", w->id); continue; }
|
||||||
if (prepare_to_render_os_window(w, now, &active_window_id, &active_window_bg, &num_visible_windows)) needs_render = true;
|
if (prepare_to_render_os_window(w, now, &active_window_id, &active_window_bg, &num_visible_windows, &all_windows_have_same_bg)) needs_render = true;
|
||||||
if (w->last_active_window_id != active_window_id || w->last_active_tab != w->active_tab || w->focused_at_last_render != w->is_focused) needs_render = true;
|
if (w->last_active_window_id != active_window_id || w->last_active_tab != w->active_tab || w->focused_at_last_render != w->is_focused) needs_render = true;
|
||||||
if (needs_render) render_os_window(w, now, active_window_id, active_window_bg, num_visible_windows);
|
if (needs_render) render_os_window(w, now, active_window_id, active_window_bg, num_visible_windows, all_windows_have_same_bg);
|
||||||
}
|
}
|
||||||
last_render_at = now;
|
last_render_at = now;
|
||||||
#undef TD
|
#undef TD
|
||||||
@@ -799,7 +807,7 @@ add_python_timer(PyObject *self UNUSED, PyObject *args) {
|
|||||||
double interval;
|
double interval;
|
||||||
int repeats = 1;
|
int repeats = 1;
|
||||||
if (!PyArg_ParseTuple(args, "Od|p", &callback, &interval, &repeats)) return NULL;
|
if (!PyArg_ParseTuple(args, "Od|p", &callback, &interval, &repeats)) return NULL;
|
||||||
unsigned long long timer_id = add_main_loop_timer(interval, repeats ? true: false, python_timer_callback, callback, python_timer_cleanup);
|
unsigned long long timer_id = add_main_loop_timer(s_double_to_monotonic_t(interval), repeats ? true: false, python_timer_callback, callback, python_timer_cleanup);
|
||||||
Py_INCREF(callback);
|
Py_INCREF(callback);
|
||||||
return Py_BuildValue("K", timer_id);
|
return Py_BuildValue("K", timer_id);
|
||||||
}
|
}
|
||||||
@@ -814,7 +822,7 @@ remove_python_timer(PyObject *self UNUSED, PyObject *args) {
|
|||||||
|
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
process_pending_resizes(double now) {
|
process_pending_resizes(monotonic_t now) {
|
||||||
global_state.has_pending_resizes = false;
|
global_state.has_pending_resizes = false;
|
||||||
for (size_t i = 0; i < global_state.num_os_windows; i++) {
|
for (size_t i = 0; i < global_state.num_os_windows; i++) {
|
||||||
OSWindow *w = global_state.os_windows + i;
|
OSWindow *w = global_state.os_windows + i;
|
||||||
@@ -823,11 +831,11 @@ process_pending_resizes(double now) {
|
|||||||
if (w->live_resize.from_os_notification) {
|
if (w->live_resize.from_os_notification) {
|
||||||
if (w->live_resize.os_says_resize_complete || (now - w->live_resize.last_resize_event_at) > 1) update_viewport = true;
|
if (w->live_resize.os_says_resize_complete || (now - w->live_resize.last_resize_event_at) > 1) update_viewport = true;
|
||||||
} else {
|
} else {
|
||||||
double debounce_time = OPT(resize_debounce_time);
|
monotonic_t debounce_time = OPT(resize_debounce_time);
|
||||||
// if more than one resize event has occurred, wait at least 0.2 secs
|
// if more than one resize event has occurred, wait at least 0.2 secs
|
||||||
// before repainting, to avoid rapid transitions between the cells banner
|
// before repainting, to avoid rapid transitions between the cells banner
|
||||||
// and the normal screen
|
// and the normal screen
|
||||||
if (w->live_resize.num_of_resize_events > 1 && OPT(resize_draw_strategy) == RESIZE_DRAW_SIZE) debounce_time = MAX(0.2, debounce_time);
|
if (w->live_resize.num_of_resize_events > 1 && OPT(resize_draw_strategy) == RESIZE_DRAW_SIZE) debounce_time = MAX(ms_to_monotonic_t(200ll), debounce_time);
|
||||||
if (now - w->live_resize.last_resize_event_at >= debounce_time) update_viewport = true;
|
if (now - w->live_resize.last_resize_event_at >= debounce_time) update_viewport = true;
|
||||||
else {
|
else {
|
||||||
global_state.has_pending_resizes = true;
|
global_state.has_pending_resizes = true;
|
||||||
@@ -908,10 +916,14 @@ process_global_state(void *data) {
|
|||||||
ChildMonitor *self = data;
|
ChildMonitor *self = data;
|
||||||
maximum_wait = -1;
|
maximum_wait = -1;
|
||||||
bool state_check_timer_enabled = false;
|
bool state_check_timer_enabled = false;
|
||||||
|
bool input_read = false;
|
||||||
|
|
||||||
double now = monotonic();
|
monotonic_t now = monotonic();
|
||||||
if (global_state.has_pending_resizes) process_pending_resizes(now);
|
if (global_state.has_pending_resizes) {
|
||||||
bool input_read = parse_input(self);
|
process_pending_resizes(now);
|
||||||
|
input_read = true;
|
||||||
|
}
|
||||||
|
if (parse_input(self)) input_read = true;
|
||||||
render(now, input_read);
|
render(now, input_read);
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
if (cocoa_pending_actions) {
|
if (cocoa_pending_actions) {
|
||||||
@@ -1160,7 +1172,7 @@ io_loop(void *data) {
|
|||||||
size_t i;
|
size_t i;
|
||||||
int ret;
|
int ret;
|
||||||
bool has_more, data_received, has_pending_wakeups = false;
|
bool has_more, data_received, has_pending_wakeups = false;
|
||||||
double last_main_loop_wakeup_at = -1, now = -1;
|
monotonic_t last_main_loop_wakeup_at = -1, now = -1;
|
||||||
Screen *screen;
|
Screen *screen;
|
||||||
ChildMonitor *self = (ChildMonitor*)data;
|
ChildMonitor *self = (ChildMonitor*)data;
|
||||||
set_thread_name("KittyChildMon");
|
set_thread_name("KittyChildMon");
|
||||||
@@ -1181,8 +1193,8 @@ io_loop(void *data) {
|
|||||||
}
|
}
|
||||||
if (has_pending_wakeups) {
|
if (has_pending_wakeups) {
|
||||||
now = monotonic();
|
now = monotonic();
|
||||||
double time_delta = OPT(input_delay) - (now - last_main_loop_wakeup_at);
|
monotonic_t time_delta = OPT(input_delay) - (now - last_main_loop_wakeup_at);
|
||||||
if (time_delta >= 0) ret = poll(fds, self->count + EXTRA_FDS, (int)ceil(1000 * time_delta));
|
if (time_delta >= 0) ret = poll(fds, self->count + EXTRA_FDS, monotonic_t_to_ms(time_delta));
|
||||||
else ret = 0;
|
else ret = 0;
|
||||||
} else {
|
} else {
|
||||||
ret = poll(fds, self->count + EXTRA_FDS, -1);
|
ret = poll(fds, self->count + EXTRA_FDS, -1);
|
||||||
@@ -1414,7 +1426,7 @@ prune_finished_writes(void) {
|
|||||||
|
|
||||||
static void
|
static void
|
||||||
wakeup_talk_loop(bool in_signal_handler) {
|
wakeup_talk_loop(bool in_signal_handler) {
|
||||||
wakeup_loop(&talk_data.loop_data, in_signal_handler);
|
if (talk_thread_started) wakeup_loop(&talk_data.loop_data, in_signal_handler, "talk_loop");
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
|
|||||||
@@ -4,9 +4,9 @@
|
|||||||
|
|
||||||
import fcntl
|
import fcntl
|
||||||
import os
|
import os
|
||||||
|
import sys
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from contextlib import contextmanager
|
from contextlib import contextmanager, suppress
|
||||||
from contextlib import suppress
|
|
||||||
|
|
||||||
import kitty.fast_data_types as fast_data_types
|
import kitty.fast_data_types as fast_data_types
|
||||||
|
|
||||||
@@ -30,14 +30,16 @@ if is_macos:
|
|||||||
else:
|
else:
|
||||||
|
|
||||||
def cmdline_of_process(pid):
|
def cmdline_of_process(pid):
|
||||||
return list(filter(None, open('/proc/{}/cmdline'.format(pid), 'rb').read().decode('utf-8').split('\0')))
|
with open('/proc/{}/cmdline'.format(pid), 'rb') as f:
|
||||||
|
return list(filter(None, f.read().decode('utf-8').split('\0')))
|
||||||
|
|
||||||
def cwd_of_process(pid):
|
def cwd_of_process(pid):
|
||||||
ans = '/proc/{}/cwd'.format(pid)
|
ans = '/proc/{}/cwd'.format(pid)
|
||||||
return os.path.realpath(ans)
|
return os.path.realpath(ans)
|
||||||
|
|
||||||
def _environ_of_process(pid):
|
def _environ_of_process(pid):
|
||||||
return open('/proc/{}/environ'.format(pid), 'rb').read().decode('utf-8')
|
with open('/proc/{}/environ'.format(pid), 'rb') as f:
|
||||||
|
return f.read().decode('utf-8')
|
||||||
|
|
||||||
def process_group_map():
|
def process_group_map():
|
||||||
ans = defaultdict(list)
|
ans = defaultdict(list)
|
||||||
@@ -47,7 +49,8 @@ else:
|
|||||||
except Exception:
|
except Exception:
|
||||||
continue
|
continue
|
||||||
try:
|
try:
|
||||||
raw = open('/proc/' + x + '/stat', 'rb').read().decode('utf-8')
|
with open('/proc/' + x + '/stat', 'rb') as f:
|
||||||
|
raw = f.read().decode('utf-8')
|
||||||
except EnvironmentError:
|
except EnvironmentError:
|
||||||
continue
|
continue
|
||||||
try:
|
try:
|
||||||
@@ -118,31 +121,47 @@ def remove_cloexec(fd):
|
|||||||
fcntl.fcntl(fd, fcntl.F_SETFD, fcntl.fcntl(fd, fcntl.F_GETFD) & ~fcntl.FD_CLOEXEC)
|
fcntl.fcntl(fd, fcntl.F_SETFD, fcntl.fcntl(fd, fcntl.F_GETFD) & ~fcntl.FD_CLOEXEC)
|
||||||
|
|
||||||
|
|
||||||
|
def remove_blocking(fd):
|
||||||
|
os.set_blocking(fd, False)
|
||||||
|
|
||||||
|
|
||||||
|
def process_env():
|
||||||
|
ans = os.environ
|
||||||
|
ssl_env_var = getattr(sys, 'kitty_ssl_env_var', None)
|
||||||
|
if ssl_env_var is not None:
|
||||||
|
ans = ans.copy()
|
||||||
|
ans.pop(ssl_env_var, None)
|
||||||
|
return ans
|
||||||
|
|
||||||
|
|
||||||
def default_env():
|
def default_env():
|
||||||
try:
|
try:
|
||||||
return default_env.env
|
return default_env.env
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
return os.environ
|
return process_env()
|
||||||
|
|
||||||
|
|
||||||
def set_default_env(val=None):
|
def set_default_env(val=None):
|
||||||
env = os.environ.copy()
|
env = process_env().copy()
|
||||||
if val:
|
if val:
|
||||||
env.update(val)
|
env.update(val)
|
||||||
default_env.env = env
|
default_env.env = env
|
||||||
|
|
||||||
|
|
||||||
|
def openpty():
|
||||||
|
master, slave = os.openpty() # Note that master and slave are in blocking mode
|
||||||
|
remove_cloexec(slave)
|
||||||
|
fast_data_types.set_iutf8_fd(master, True)
|
||||||
|
return master, slave
|
||||||
|
|
||||||
|
|
||||||
class Child:
|
class Child:
|
||||||
|
|
||||||
child_fd = pid = None
|
child_fd = pid = None
|
||||||
forked = False
|
forked = False
|
||||||
|
|
||||||
def __init__(self, argv, cwd, opts, stdin=None, env=None, cwd_from=None):
|
def __init__(self, argv, cwd, opts, stdin=None, env=None, cwd_from=None, allow_remote_control=False):
|
||||||
self.allow_remote_control = False
|
self.allow_remote_control = allow_remote_control
|
||||||
if argv and argv[0] == '@':
|
|
||||||
self.allow_remote_control = True
|
|
||||||
if len(argv) > 1:
|
|
||||||
argv = argv[1:]
|
|
||||||
self.argv = argv
|
self.argv = argv
|
||||||
if cwd_from is not None:
|
if cwd_from is not None:
|
||||||
try:
|
try:
|
||||||
@@ -166,7 +185,7 @@ class Child:
|
|||||||
env['TERM'] = self.opts.term
|
env['TERM'] = self.opts.term
|
||||||
env['COLORTERM'] = 'truecolor'
|
env['COLORTERM'] = 'truecolor'
|
||||||
if self.cwd:
|
if self.cwd:
|
||||||
# needed incase cwd is a symlink, in which case shells
|
# needed in case cwd is a symlink, in which case shells
|
||||||
# can use it to display the current directory name rather
|
# can use it to display the current directory name rather
|
||||||
# than the resolved path
|
# than the resolved path
|
||||||
env['PWD'] = self.cwd
|
env['PWD'] = self.cwd
|
||||||
@@ -178,9 +197,7 @@ class Child:
|
|||||||
if self.forked:
|
if self.forked:
|
||||||
return
|
return
|
||||||
self.forked = True
|
self.forked = True
|
||||||
master, slave = os.openpty() # Note that master and slave are in blocking mode
|
master, slave = openpty()
|
||||||
remove_cloexec(slave)
|
|
||||||
fast_data_types.set_iutf8_fd(master, True)
|
|
||||||
stdin, self.stdin = self.stdin, None
|
stdin, self.stdin = self.stdin, None
|
||||||
ready_read_fd, ready_write_fd = os.pipe()
|
ready_read_fd, ready_write_fd = os.pipe()
|
||||||
remove_cloexec(ready_read_fd)
|
remove_cloexec(ready_read_fd)
|
||||||
@@ -194,8 +211,20 @@ class Child:
|
|||||||
argv = list(self.argv)
|
argv = list(self.argv)
|
||||||
exe = argv[0]
|
exe = argv[0]
|
||||||
if is_macos and exe == shell_path:
|
if is_macos and exe == shell_path:
|
||||||
# Some macOS machines need the shell to have argv[0] prefixed by
|
# bash will only source ~/.bash_profile if it detects it is a login
|
||||||
# hyphen, see https://github.com/kovidgoyal/kitty/issues/247
|
# shell (see the invocation section of the bash man page), which it
|
||||||
|
# does if argv[0] is prefixed by a hyphen see
|
||||||
|
# https://github.com/kovidgoyal/kitty/issues/247
|
||||||
|
# it is apparently common to use ~/.bash_profile instead of the
|
||||||
|
# more correct ~/.bashrc on macOS to setup env vars, so if
|
||||||
|
# the default shell is used prefix argv[0] by '-'
|
||||||
|
#
|
||||||
|
# it is arguable whether graphical terminals should start shells
|
||||||
|
# in login mode in general, there are at least a few Linux users
|
||||||
|
# that also make this incorrect assumption, see for example
|
||||||
|
# https://github.com/kovidgoyal/kitty/issues/1870
|
||||||
|
# xterm, urxvt, konsole and gnome-terminal do not do it in my
|
||||||
|
# testing.
|
||||||
argv[0] = ('-' + exe.split('/')[-1])
|
argv[0] = ('-' + exe.split('/')[-1])
|
||||||
pid = fast_data_types.spawn(exe, self.cwd, tuple(argv), env, master, slave, stdin_read_fd, stdin_write_fd, ready_read_fd, ready_write_fd)
|
pid = fast_data_types.spawn(exe, self.cwd, tuple(argv), env, master, slave, stdin_read_fd, stdin_write_fd, ready_read_fd, ready_write_fd)
|
||||||
os.close(slave)
|
os.close(slave)
|
||||||
@@ -206,7 +235,7 @@ class Child:
|
|||||||
fast_data_types.thread_write(stdin_write_fd, stdin)
|
fast_data_types.thread_write(stdin_write_fd, stdin)
|
||||||
os.close(ready_read_fd)
|
os.close(ready_read_fd)
|
||||||
self.terminal_ready_fd = ready_write_fd
|
self.terminal_ready_fd = ready_write_fd
|
||||||
fcntl.fcntl(self.child_fd, fcntl.F_SETFL, fcntl.fcntl(self.child_fd, fcntl.F_GETFL) | os.O_NONBLOCK)
|
remove_blocking(self.child_fd)
|
||||||
return pid
|
return pid
|
||||||
|
|
||||||
def mark_terminal_ready(self):
|
def mark_terminal_ready(self):
|
||||||
@@ -238,6 +267,13 @@ class Child:
|
|||||||
except Exception:
|
except Exception:
|
||||||
return list(self.argv)
|
return list(self.argv)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def foreground_cmdline(self):
|
||||||
|
try:
|
||||||
|
return cmdline_of_process(self.pid_for_cwd) or self.cmdline
|
||||||
|
except Exception:
|
||||||
|
return self.cmdline
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def environ(self):
|
def environ(self):
|
||||||
try:
|
try:
|
||||||
@@ -263,3 +299,14 @@ class Child:
|
|||||||
def foreground_cwd(self):
|
def foreground_cwd(self):
|
||||||
with suppress(Exception):
|
with suppress(Exception):
|
||||||
return cwd_of_process(self.pid_for_cwd) or None
|
return cwd_of_process(self.pid_for_cwd) or None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def foreground_environ(self):
|
||||||
|
try:
|
||||||
|
return environ_of_process(self.pid_for_cwd)
|
||||||
|
except Exception:
|
||||||
|
try:
|
||||||
|
return environ_of_process(self.pid)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
return {}
|
||||||
|
|||||||
12
kitty/choose_entry.py
Normal file
12
kitty/choose_entry.py
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# vim:fileencoding=utf-8
|
||||||
|
# License: GPLv3 Copyright: 2019, Kovid Goyal <kovid at kovidgoyal.net>
|
||||||
|
|
||||||
|
import re
|
||||||
|
|
||||||
|
|
||||||
|
def mark(text, args, Mark, extra_cli_args, *a):
|
||||||
|
for idx, m in enumerate(re.finditer(args.regex, text)):
|
||||||
|
start, end = m.span()
|
||||||
|
mark_text = text[start:end].replace('\n', '').replace('\0', '')
|
||||||
|
yield Mark(idx, start, end, mark_text, {'index': idx})
|
||||||
14
kitty/cli.py
14
kitty/cli.py
@@ -225,7 +225,7 @@ Run the :italic:`{appname}` terminal emulator. You can also specify the :italic:
|
|||||||
to run inside :italic:`{appname}` as normal arguments following the :italic:`options`.
|
to run inside :italic:`{appname}` as normal arguments following the :italic:`options`.
|
||||||
For example: {appname} /bin/sh
|
For example: {appname} /bin/sh
|
||||||
|
|
||||||
For comprehensive documentation for kitty, please see: https://sw.kovidgoyal.net/kitty''').format(appname=appname)
|
For comprehensive documentation for kitty, please see: https://sw.kovidgoyal.net/kitty/''').format(appname=appname)
|
||||||
|
|
||||||
|
|
||||||
def print_help_for_seq(seq, usage, message, appname):
|
def print_help_for_seq(seq, usage, message, appname):
|
||||||
@@ -423,8 +423,8 @@ class Options:
|
|||||||
class Namespace:
|
class Namespace:
|
||||||
|
|
||||||
def __init__(self, kwargs):
|
def __init__(self, kwargs):
|
||||||
for name in kwargs:
|
for name, val in kwargs.items():
|
||||||
setattr(self, name, kwargs[name])
|
setattr(self, name, val)
|
||||||
|
|
||||||
|
|
||||||
def parse_cmdline(oc, disabled, args=None):
|
def parse_cmdline(oc, disabled, args=None):
|
||||||
@@ -514,7 +514,7 @@ Detach from the controlling terminal, if any
|
|||||||
|
|
||||||
--session
|
--session
|
||||||
Path to a file containing the startup :italic:`session` (tabs, windows, layout, programs).
|
Path to a file containing the startup :italic:`session` (tabs, windows, layout, programs).
|
||||||
See the README file for details and an example.
|
Use - to read from STDIN. See the README file for details and an example.
|
||||||
|
|
||||||
|
|
||||||
--hold
|
--hold
|
||||||
@@ -728,9 +728,11 @@ def create_opts(args, debug_config=False, accumulate_bad_lines=None):
|
|||||||
import subprocess
|
import subprocess
|
||||||
print(' '.join(subprocess.check_output(['sw_vers']).decode('utf-8').splitlines()).strip())
|
print(' '.join(subprocess.check_output(['sw_vers']).decode('utf-8').splitlines()).strip())
|
||||||
if os.path.exists('/etc/issue'):
|
if os.path.exists('/etc/issue'):
|
||||||
print(open('/etc/issue', encoding='utf-8', errors='replace').read().strip())
|
with open('/etc/issue', encoding='utf-8', errors='replace') as f:
|
||||||
|
print(f.read().strip())
|
||||||
if os.path.exists('/etc/lsb-release'):
|
if os.path.exists('/etc/lsb-release'):
|
||||||
print(open('/etc/lsb-release', encoding='utf-8', errors='replace').read().strip())
|
with open('/etc/lsb-release', encoding='utf-8', errors='replace') as f:
|
||||||
|
print(f.read().strip())
|
||||||
config = tuple(x for x in config if os.path.exists(x))
|
config = tuple(x for x in config if os.path.exists(x))
|
||||||
if config:
|
if config:
|
||||||
print(green('Loaded config files:'), ', '.join(config))
|
print(green('Loaded config files:'), ', '.join(config))
|
||||||
|
|||||||
@@ -157,7 +157,8 @@ def replay(raw):
|
|||||||
|
|
||||||
|
|
||||||
def main(path):
|
def main(path):
|
||||||
raw = open(path).read()
|
with open(path) as f:
|
||||||
|
raw = f.read()
|
||||||
replay(raw)
|
replay(raw)
|
||||||
with suppress(EOFError, KeyboardInterrupt):
|
with suppress(EOFError, KeyboardInterrupt):
|
||||||
input()
|
input()
|
||||||
|
|||||||
176
kitty/cmds.py
176
kitty/cmds.py
@@ -7,10 +7,16 @@ import os
|
|||||||
import sys
|
import sys
|
||||||
from contextlib import suppress
|
from contextlib import suppress
|
||||||
|
|
||||||
from .cli import parse_args, parse_option_spec, get_defaults_from_seq
|
from .cli import (
|
||||||
|
Namespace, get_defaults_from_seq, parse_args, parse_option_spec
|
||||||
|
)
|
||||||
from .config import parse_config, parse_send_text_bytes
|
from .config import parse_config, parse_send_text_bytes
|
||||||
from .constants import appname
|
from .constants import appname
|
||||||
from .fast_data_types import focus_os_window
|
from .fast_data_types import focus_os_window
|
||||||
|
from .launch import (
|
||||||
|
launch as do_launch, options_spec as launch_options_spec,
|
||||||
|
parse_launch_args
|
||||||
|
)
|
||||||
from .tabs import SpecialWindow
|
from .tabs import SpecialWindow
|
||||||
from .utils import natsort_ints
|
from .utils import natsort_ints
|
||||||
|
|
||||||
@@ -375,6 +381,100 @@ def set_tab_title(boss, window, payload):
|
|||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
|
|
||||||
|
# detach_window {{{
|
||||||
|
@cmd(
|
||||||
|
'Detach a window and place it in a different/new tab',
|
||||||
|
'Detach the specified window and either move it into a new tab, a new OS window'
|
||||||
|
' or add it to the specified tab. Use the special value :code:`new` for --target-tab'
|
||||||
|
' to move to a new tab. If no target tab is specified the window is moved to a new OS window.',
|
||||||
|
options_spec=MATCH_WINDOW_OPTION + '\n\n' + MATCH_TAB_OPTION.replace('--match -m', '--target-tab -t') + '''\n
|
||||||
|
--self
|
||||||
|
type=bool-set
|
||||||
|
If specified detach the window this command is run in, rather than the active window.
|
||||||
|
''',
|
||||||
|
argspec=''
|
||||||
|
)
|
||||||
|
def cmd_detach_window(global_opts, opts, args):
|
||||||
|
'''
|
||||||
|
match: Which window to detach
|
||||||
|
target: Which tab to move the detached window to
|
||||||
|
self: Boolean indicating whether to detach the window the command is run in
|
||||||
|
'''
|
||||||
|
return {'match': opts.match, 'target': opts.target_tab, 'self': opts.self}
|
||||||
|
|
||||||
|
|
||||||
|
def detach_window(boss, window, payload):
|
||||||
|
pg = cmd_detach_window.payload_get
|
||||||
|
match = pg(payload, 'match')
|
||||||
|
if match:
|
||||||
|
windows = tuple(boss.match_windows(match))
|
||||||
|
if not windows:
|
||||||
|
raise MatchError(match)
|
||||||
|
else:
|
||||||
|
windows = [window if window and pg(payload, 'self') else boss.active_window]
|
||||||
|
match = pg(payload, 'target_tab')
|
||||||
|
kwargs = {}
|
||||||
|
if match:
|
||||||
|
if match == 'new':
|
||||||
|
kwargs['target_tab_id'] = 'new'
|
||||||
|
else:
|
||||||
|
tabs = tuple(boss.match_tabs(match))
|
||||||
|
if not tabs:
|
||||||
|
raise MatchError(match, 'tabs')
|
||||||
|
kwargs['target_tab_id'] = tabs[0].id
|
||||||
|
if not kwargs:
|
||||||
|
kwargs['target_os_window_id'] = 'new'
|
||||||
|
|
||||||
|
for window in windows:
|
||||||
|
boss._move_window_to(window=window, **kwargs)
|
||||||
|
|
||||||
|
# }}}
|
||||||
|
|
||||||
|
|
||||||
|
# detach_tab {{{
|
||||||
|
@cmd(
|
||||||
|
'Detach a tab and place it in a different/new OS Window',
|
||||||
|
'Detach the specified tab and either move it into a new OS window'
|
||||||
|
' or add it to the OS Window containing the tab specified by --target-tab',
|
||||||
|
options_spec=MATCH_TAB_OPTION + '\n\n' + MATCH_TAB_OPTION.replace('--match -m', '--target-tab -t') + '''\n
|
||||||
|
--self
|
||||||
|
type=bool-set
|
||||||
|
If specified detach the tab this command is run in, rather than the active tab.
|
||||||
|
''',
|
||||||
|
argspec=''
|
||||||
|
)
|
||||||
|
def cmd_detach_tab(global_opts, opts, args):
|
||||||
|
'''
|
||||||
|
match: Which tab to detach
|
||||||
|
target: Which OS Window to move the detached tab to
|
||||||
|
self: Boolean indicating whether to detach the tab the command is run in
|
||||||
|
'''
|
||||||
|
return {'match': opts.match, 'target': opts.target_tab, 'self': opts.self}
|
||||||
|
|
||||||
|
|
||||||
|
def detach_tab(boss, window, payload):
|
||||||
|
pg = cmd_detach_tab.payload_get
|
||||||
|
match = pg(payload, 'match')
|
||||||
|
if match:
|
||||||
|
tabs = tuple(boss.match_tabs(match))
|
||||||
|
if not tabs:
|
||||||
|
raise MatchError(match)
|
||||||
|
else:
|
||||||
|
tabs = [window.tabref() if pg(payload, 'self') and window and window.tabref() else boss.active_tab]
|
||||||
|
match = pg(payload, 'target_tab')
|
||||||
|
kwargs = {}
|
||||||
|
if match:
|
||||||
|
targets = tuple(boss.match_tabs(match))
|
||||||
|
if not targets:
|
||||||
|
raise MatchError(match, 'tabs')
|
||||||
|
kwargs['target_os_window_id'] = targets[0].os_window_id
|
||||||
|
|
||||||
|
for tab in tabs:
|
||||||
|
boss._move_tab_to(tab=tab, **kwargs)
|
||||||
|
|
||||||
|
# }}}
|
||||||
|
|
||||||
|
|
||||||
# goto_layout {{{
|
# goto_layout {{{
|
||||||
@cmd(
|
@cmd(
|
||||||
'Set the window layout',
|
'Set the window layout',
|
||||||
@@ -675,6 +775,76 @@ def new_window(boss, window, payload):
|
|||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
|
|
||||||
|
# launch {{{
|
||||||
|
@cmd(
|
||||||
|
'Run an arbitrary process in a new window/tab',
|
||||||
|
' Prints out the id of the newly opened window. Any command line arguments'
|
||||||
|
' are assumed to be the command line used to run in the new window, if none'
|
||||||
|
' are provided, the default shell is run. For example:'
|
||||||
|
' :italic:`kitty @ launch --title Email mutt`.',
|
||||||
|
options_spec=MATCH_TAB_OPTION + '\n\n' + '''\
|
||||||
|
--no-response
|
||||||
|
type=bool-set
|
||||||
|
Do not print out the id of the newly created window.
|
||||||
|
|
||||||
|
|
||||||
|
--self
|
||||||
|
type=bool-set
|
||||||
|
If specified the tab containing the window this command is run in is used
|
||||||
|
instead of the active tab
|
||||||
|
''' + '\n\n' + launch_options_spec().replace(':option:`launch', ':option:`kitty @ launch'),
|
||||||
|
argspec='[CMD ...]'
|
||||||
|
)
|
||||||
|
def cmd_launch(global_opts, opts, args):
|
||||||
|
'''
|
||||||
|
args+: The command line to run in the new window, as a list, use an empty list to run the default shell
|
||||||
|
match: The tab to open the new window in
|
||||||
|
window_title: Title for the new window
|
||||||
|
cwd: Working directory for the new window
|
||||||
|
env: List of environment varibles of the form NAME=VALUE
|
||||||
|
tab_title: Title for the new tab
|
||||||
|
type: The type of window to open
|
||||||
|
keep_focus: Boolean indicating whether the current window should retain focus or not
|
||||||
|
copy_colors: Boolean indicating whether to copy the colors from the current window
|
||||||
|
copy_cmdline: Boolean indicating whether to copy the cmdline from the current window
|
||||||
|
copy_env: Boolean indicating whether to copy the environ from the current window
|
||||||
|
location: Where in the tab to open the new window
|
||||||
|
allow_remote_control: Boolean indicating whether to allow remote control from the new window
|
||||||
|
stdin_source: Where to get stdin for thew process from
|
||||||
|
stdin_add_formatting: Boolean indicating whether to add formatting codes to stdin
|
||||||
|
stdin_add_line_wrap_markers: Boolean indicating whether to add line wrap markers to stdin
|
||||||
|
no_response: Boolean indicating whether to send back the window id
|
||||||
|
'''
|
||||||
|
if opts.no_response:
|
||||||
|
global_opts.no_command_response = True
|
||||||
|
ans = {'args': args or []}
|
||||||
|
for attr, val in opts.__dict__.items():
|
||||||
|
ans[attr] = val
|
||||||
|
return ans
|
||||||
|
|
||||||
|
|
||||||
|
def launch(boss, window, payload):
|
||||||
|
pg = cmd_launch.payload_get
|
||||||
|
default_opts = parse_launch_args()[0]
|
||||||
|
opts = {}
|
||||||
|
for key, default_value in default_opts.__dict__.items():
|
||||||
|
opts[key] = payload.get(key, default_value)
|
||||||
|
opts = Namespace(opts)
|
||||||
|
match = pg(payload, 'match')
|
||||||
|
if match:
|
||||||
|
tabs = tuple(boss.match_tabs(match))
|
||||||
|
if not tabs:
|
||||||
|
raise MatchError(match, 'tabs')
|
||||||
|
else:
|
||||||
|
tabs = [boss.active_tab]
|
||||||
|
if pg(payload, 'self') and window and window.tabref():
|
||||||
|
tabs = [window.tabref()]
|
||||||
|
tab = tabs[0]
|
||||||
|
w = do_launch(boss, opts, pg(payload, 'args') or None, target_tab=tab)
|
||||||
|
return None if pg(payload, 'no_response') else str(getattr(w, 'id', 0))
|
||||||
|
# }}}
|
||||||
|
|
||||||
|
|
||||||
# focus_window {{{
|
# focus_window {{{
|
||||||
@cmd(
|
@cmd(
|
||||||
'Focus the specified window',
|
'Focus the specified window',
|
||||||
@@ -882,7 +1052,7 @@ this option, any color arguments are ignored and --configured and --all are impl
|
|||||||
def cmd_set_colors(global_opts, opts, args):
|
def cmd_set_colors(global_opts, opts, args):
|
||||||
'''
|
'''
|
||||||
colors+: An object mapping names to colors as 24-bit RGB integers
|
colors+: An object mapping names to colors as 24-bit RGB integers
|
||||||
cursor_text_color: A 24-bit clor for text under the cursor
|
cursor_text_color: A 24-bit color for text under the cursor
|
||||||
match_window: Window to change colors in
|
match_window: Window to change colors in
|
||||||
match_tab: Tab to change colors in
|
match_tab: Tab to change colors in
|
||||||
all: Boolean indicating change colors everywhere or not
|
all: Boolean indicating change colors everywhere or not
|
||||||
@@ -999,7 +1169,7 @@ def cmd_set_background_opacity(global_opts, opts, args):
|
|||||||
def set_background_opacity(boss, window, payload):
|
def set_background_opacity(boss, window, payload):
|
||||||
if not boss.opts.dynamic_background_opacity:
|
if not boss.opts.dynamic_background_opacity:
|
||||||
raise OpacityError('You must turn on the dynamic_background_opacity option in kitty.conf to be able to set background opacity')
|
raise OpacityError('You must turn on the dynamic_background_opacity option in kitty.conf to be able to set background opacity')
|
||||||
windows = windows_for_payload(payload)
|
windows = windows_for_payload(boss, window, payload)
|
||||||
for os_window_id in {w.os_window_id for w in windows}:
|
for os_window_id in {w.os_window_id for w in windows}:
|
||||||
boss._set_os_window_background_opacity(os_window_id, payload['opacity'])
|
boss._set_os_window_background_opacity(os_window_id, payload['opacity'])
|
||||||
# }}}
|
# }}}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
|
|
||||||
#include "state.h"
|
#include "state.h"
|
||||||
|
#include "monotonic.h"
|
||||||
#include <Cocoa/Cocoa.h>
|
#include <Cocoa/Cocoa.h>
|
||||||
|
|
||||||
#include <AvailabilityMacros.h>
|
#include <AvailabilityMacros.h>
|
||||||
@@ -72,12 +73,12 @@ find_app_name(void) {
|
|||||||
|
|
||||||
@implementation GlobalMenuTarget
|
@implementation GlobalMenuTarget
|
||||||
|
|
||||||
- (void) show_preferences : (id)sender {
|
- (void)show_preferences:(id)sender {
|
||||||
(void)sender;
|
(void)sender;
|
||||||
set_cocoa_pending_action(PREFERENCES_WINDOW, NULL);
|
set_cocoa_pending_action(PREFERENCES_WINDOW, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) new_os_window : (id)sender {
|
- (void)new_os_window:(id)sender {
|
||||||
(void)sender;
|
(void)sender;
|
||||||
set_cocoa_pending_action(NEW_OS_WINDOW, NULL);
|
set_cocoa_pending_action(NEW_OS_WINDOW, NULL);
|
||||||
}
|
}
|
||||||
@@ -117,9 +118,10 @@ get_dock_menu(id self UNUSED, SEL _cmd UNUSED, NSApplication *sender UNUSED) {
|
|||||||
if (!dockMenu) {
|
if (!dockMenu) {
|
||||||
GlobalMenuTarget *global_menu_target = [GlobalMenuTarget shared_instance];
|
GlobalMenuTarget *global_menu_target = [GlobalMenuTarget shared_instance];
|
||||||
dockMenu = [[NSMenu alloc] init];
|
dockMenu = [[NSMenu alloc] init];
|
||||||
NSMenuItem *newWindowItem = [dockMenu addItemWithTitle:@"New OS window"
|
NSMenuItem *newWindowItem =
|
||||||
action:@selector(new_os_window:)
|
[dockMenu addItemWithTitle:@"New OS window"
|
||||||
keyEquivalent:@""];
|
action:@selector(new_os_window:)
|
||||||
|
keyEquivalent:@""];
|
||||||
[newWindowItem setTarget:global_menu_target];
|
[newWindowItem setTarget:global_menu_target];
|
||||||
}
|
}
|
||||||
return dockMenu;
|
return dockMenu;
|
||||||
@@ -231,21 +233,21 @@ cocoa_send_notification(PyObject *self UNUSED, PyObject *args) {
|
|||||||
// global menu {{{
|
// global menu {{{
|
||||||
void
|
void
|
||||||
cocoa_create_global_menu(void) {
|
cocoa_create_global_menu(void) {
|
||||||
@autoreleasepool {
|
|
||||||
|
|
||||||
NSString* app_name = find_app_name();
|
NSString* app_name = find_app_name();
|
||||||
NSMenu* bar = [[NSMenu alloc] init];
|
NSMenu* bar = [[NSMenu alloc] init];
|
||||||
GlobalMenuTarget *global_menu_target = [GlobalMenuTarget shared_instance];
|
GlobalMenuTarget *global_menu_target = [GlobalMenuTarget shared_instance];
|
||||||
[NSApp setMainMenu:bar];
|
[NSApp setMainMenu:bar];
|
||||||
|
|
||||||
NSMenuItem* appMenuItem =
|
NSMenuItem* appMenuItem =
|
||||||
[bar addItemWithTitle:@"" action:NULL keyEquivalent:@""];
|
[bar addItemWithTitle:@""
|
||||||
|
action:NULL
|
||||||
|
keyEquivalent:@""];
|
||||||
NSMenu* appMenu = [[NSMenu alloc] init];
|
NSMenu* appMenu = [[NSMenu alloc] init];
|
||||||
[appMenuItem setSubmenu:appMenu];
|
[appMenuItem setSubmenu:appMenu];
|
||||||
|
|
||||||
[appMenu addItemWithTitle:[NSString stringWithFormat:@"About %@", app_name]
|
[appMenu addItemWithTitle:[NSString stringWithFormat:@"About %@", app_name]
|
||||||
action:@selector(orderFrontStandardAboutPanel:)
|
action:@selector(orderFrontStandardAboutPanel:)
|
||||||
keyEquivalent:@""];
|
keyEquivalent:@""];
|
||||||
[appMenu addItem:[NSMenuItem separatorItem]];
|
[appMenu addItem:[NSMenuItem separatorItem]];
|
||||||
NSMenuItem* preferences_menu_item = [[NSMenuItem alloc] initWithTitle:@"Preferences..." action:@selector(show_preferences:) keyEquivalent:@","], *new_os_window_menu_item = NULL;
|
NSMenuItem* preferences_menu_item = [[NSMenuItem alloc] initWithTitle:@"Preferences..." action:@selector(show_preferences:) keyEquivalent:@","], *new_os_window_menu_item = NULL;
|
||||||
[preferences_menu_item setTarget:global_menu_target];
|
[preferences_menu_item setTarget:global_menu_target];
|
||||||
@@ -264,8 +266,8 @@ cocoa_create_global_menu(void) {
|
|||||||
action:@selector(hide:)
|
action:@selector(hide:)
|
||||||
keyEquivalent:@"h"];
|
keyEquivalent:@"h"];
|
||||||
[[appMenu addItemWithTitle:@"Hide Others"
|
[[appMenu addItemWithTitle:@"Hide Others"
|
||||||
action:@selector(hideOtherApplications:)
|
action:@selector(hideOtherApplications:)
|
||||||
keyEquivalent:@"h"]
|
keyEquivalent:@"h"]
|
||||||
setKeyEquivalentModifierMask:NSEventModifierFlagOption | NSEventModifierFlagCommand];
|
setKeyEquivalentModifierMask:NSEventModifierFlagOption | NSEventModifierFlagCommand];
|
||||||
[appMenu addItemWithTitle:@"Show All"
|
[appMenu addItemWithTitle:@"Show All"
|
||||||
action:@selector(unhideAllApplications:)
|
action:@selector(unhideAllApplications:)
|
||||||
@@ -275,19 +277,21 @@ cocoa_create_global_menu(void) {
|
|||||||
NSMenu* servicesMenu = [[NSMenu alloc] init];
|
NSMenu* servicesMenu = [[NSMenu alloc] init];
|
||||||
[NSApp setServicesMenu:servicesMenu];
|
[NSApp setServicesMenu:servicesMenu];
|
||||||
[[appMenu addItemWithTitle:@"Services"
|
[[appMenu addItemWithTitle:@"Services"
|
||||||
action:NULL
|
action:NULL
|
||||||
keyEquivalent:@""] setSubmenu:servicesMenu];
|
keyEquivalent:@""] setSubmenu:servicesMenu];
|
||||||
[servicesMenu release];
|
[servicesMenu release];
|
||||||
|
|
||||||
[appMenu addItem:[NSMenuItem separatorItem]];
|
[appMenu addItem:[NSMenuItem separatorItem]];
|
||||||
|
|
||||||
[appMenu addItemWithTitle:[NSString stringWithFormat:@"Quit %@", app_name]
|
[appMenu addItemWithTitle:[NSString stringWithFormat:@"Quit %@", app_name]
|
||||||
action:@selector(terminate:)
|
action:@selector(terminate:)
|
||||||
keyEquivalent:@"q"];
|
keyEquivalent:@"q"];
|
||||||
[appMenu release];
|
[appMenu release];
|
||||||
|
|
||||||
NSMenuItem* windowMenuItem =
|
NSMenuItem* windowMenuItem =
|
||||||
[bar addItemWithTitle:@"" action:NULL keyEquivalent:@""];
|
[bar addItemWithTitle:@""
|
||||||
|
action:NULL
|
||||||
|
keyEquivalent:@""];
|
||||||
NSMenu* windowMenu = [[NSMenu alloc] initWithTitle:@"Window"];
|
NSMenu* windowMenu = [[NSMenu alloc] initWithTitle:@"Window"];
|
||||||
[windowMenuItem setSubmenu:windowMenu];
|
[windowMenuItem setSubmenu:windowMenu];
|
||||||
|
|
||||||
@@ -317,20 +321,18 @@ cocoa_create_global_menu(void) {
|
|||||||
[bar release];
|
[bar release];
|
||||||
|
|
||||||
class_addMethod(
|
class_addMethod(
|
||||||
object_getClass([NSApp delegate]),
|
object_getClass([NSApp delegate]),
|
||||||
@selector(applicationDockMenu:),
|
@selector(applicationDockMenu:),
|
||||||
(IMP)get_dock_menu,
|
(IMP)get_dock_menu,
|
||||||
"@@:@");
|
"@@:@");
|
||||||
|
|
||||||
|
|
||||||
[NSApp setServicesProvider:[[[ServiceProvider alloc] init] autorelease]];
|
[NSApp setServicesProvider:[[[ServiceProvider alloc] init] autorelease]];
|
||||||
|
|
||||||
} // autoreleasepool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
cocoa_update_menu_bar_title(PyObject *pytitle) {
|
cocoa_update_menu_bar_title(PyObject *pytitle) {
|
||||||
NSString *title = [[NSString alloc] initWithUTF8String:PyUnicode_AsUTF8(pytitle)];
|
NSString *title = @(PyUnicode_AsUTF8(pytitle));
|
||||||
NSMenu *bar = [NSApp mainMenu];
|
NSMenu *bar = [NSApp mainMenu];
|
||||||
if (title_menu != NULL) {
|
if (title_menu != NULL) {
|
||||||
[bar removeItem:title_menu];
|
[bar removeItem:title_menu];
|
||||||
@@ -339,7 +341,6 @@ cocoa_update_menu_bar_title(PyObject *pytitle) {
|
|||||||
NSMenu *m = [[NSMenu alloc] initWithTitle:[NSString stringWithFormat:@" :: %@", title]];
|
NSMenu *m = [[NSMenu alloc] initWithTitle:[NSString stringWithFormat:@" :: %@", title]];
|
||||||
[title_menu setSubmenu:m];
|
[title_menu setSubmenu:m];
|
||||||
[m release];
|
[m release];
|
||||||
[title release];
|
|
||||||
} // }}}
|
} // }}}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
@@ -367,7 +368,7 @@ cocoa_make_window_resizable(void *w, bool resizable) {
|
|||||||
bool
|
bool
|
||||||
cocoa_alt_option_key_pressed(NSUInteger flags) {
|
cocoa_alt_option_key_pressed(NSUInteger flags) {
|
||||||
NSUInteger q = (OPT(macos_option_as_alt) == 1) ? NSRightAlternateKeyMask : NSLeftAlternateKeyMask;
|
NSUInteger q = (OPT(macos_option_as_alt) == 1) ? NSRightAlternateKeyMask : NSLeftAlternateKeyMask;
|
||||||
return ((q & flags) == q) ? true : false;
|
return (q & flags) == q;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -411,7 +412,7 @@ cocoa_get_lang(PyObject UNUSED *self) {
|
|||||||
} // autoreleasepool
|
} // autoreleasepool
|
||||||
}
|
}
|
||||||
|
|
||||||
double
|
monotonic_t
|
||||||
cocoa_cursor_blink_interval(void) {
|
cocoa_cursor_blink_interval(void) {
|
||||||
@autoreleasepool {
|
@autoreleasepool {
|
||||||
|
|
||||||
@@ -420,12 +421,12 @@ cocoa_cursor_blink_interval(void) {
|
|||||||
double off_period_ms = [defaults doubleForKey:@"NSTextInsertionPointBlinkPeriodOff"];
|
double off_period_ms = [defaults doubleForKey:@"NSTextInsertionPointBlinkPeriodOff"];
|
||||||
double period_ms = [defaults doubleForKey:@"NSTextInsertionPointBlinkPeriod"];
|
double period_ms = [defaults doubleForKey:@"NSTextInsertionPointBlinkPeriod"];
|
||||||
double max_value = 60 * 1000.0, ans = -1.0;
|
double max_value = 60 * 1000.0, ans = -1.0;
|
||||||
if (on_period_ms || off_period_ms) {
|
if (on_period_ms != 0. || off_period_ms != 0.) {
|
||||||
ans = on_period_ms + off_period_ms;
|
ans = on_period_ms + off_period_ms;
|
||||||
} else if (period_ms) {
|
} else if (period_ms != 0.) {
|
||||||
ans = period_ms;
|
ans = period_ms;
|
||||||
}
|
}
|
||||||
return ans > max_value ? 0.0 : ans;
|
return ans > max_value ? 0ll : ms_double_to_monotonic_t(ans);
|
||||||
|
|
||||||
} // autoreleasepool
|
} // autoreleasepool
|
||||||
}
|
}
|
||||||
@@ -477,6 +478,17 @@ cleanup() {
|
|||||||
} // autoreleasepool
|
} // autoreleasepool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
cocoa_hide_window_title(void *w)
|
||||||
|
{
|
||||||
|
@autoreleasepool {
|
||||||
|
|
||||||
|
NSWindow *window = (NSWindow*)w;
|
||||||
|
[window setTitleVisibility:NSWindowTitleHidden];
|
||||||
|
|
||||||
|
} // autoreleasepool
|
||||||
|
}
|
||||||
|
|
||||||
static PyMethodDef module_methods[] = {
|
static PyMethodDef module_methods[] = {
|
||||||
{"cocoa_get_lang", (PyCFunction)cocoa_get_lang, METH_NOARGS, ""},
|
{"cocoa_get_lang", (PyCFunction)cocoa_get_lang, METH_NOARGS, ""},
|
||||||
{"cocoa_set_new_window_trigger", (PyCFunction)cocoa_set_new_window_trigger, METH_VARARGS, ""},
|
{"cocoa_set_new_window_trigger", (PyCFunction)cocoa_set_new_window_trigger, METH_VARARGS, ""},
|
||||||
|
|||||||
@@ -36,12 +36,12 @@ init_FG_BG_table(void) {
|
|||||||
// colors 16..232: the 6x6x6 color cube
|
// colors 16..232: the 6x6x6 color cube
|
||||||
const uint8_t valuerange[6] = {0x00, 0x5f, 0x87, 0xaf, 0xd7, 0xff};
|
const uint8_t valuerange[6] = {0x00, 0x5f, 0x87, 0xaf, 0xd7, 0xff};
|
||||||
uint8_t i, j=16;
|
uint8_t i, j=16;
|
||||||
for(i = 0; i < 217; i++, j++) {
|
for(i = 0; i < 216; i++, j++) {
|
||||||
uint8_t r = valuerange[(i / 36) % 6], g = valuerange[(i / 6) % 6], b = valuerange[i % 6];
|
uint8_t r = valuerange[(i / 36) % 6], g = valuerange[(i / 6) % 6], b = valuerange[i % 6];
|
||||||
FG_BG_256[j] = (r << 16) | (g << 8) | b;
|
FG_BG_256[j] = (r << 16) | (g << 8) | b;
|
||||||
}
|
}
|
||||||
// colors 233..255: grayscale
|
// colors 232..255: grayscale
|
||||||
for(i = 1; i < 24; i++, j++) {
|
for(i = 0; i < 24; i++, j++) {
|
||||||
uint8_t v = 8 + i * 10;
|
uint8_t v = 8 + i * 10;
|
||||||
FG_BG_256[j] = (v << 16) | (v << 8) | v;
|
FG_BG_256[j] = (v << 16) | (v << 8) | v;
|
||||||
}
|
}
|
||||||
@@ -98,6 +98,15 @@ update_ansi_color_table(ColorProfile *self, PyObject *val) {
|
|||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
copy_color_profile(ColorProfile *dest, ColorProfile *src) {
|
||||||
|
memcpy(dest->color_table, src->color_table, sizeof(dest->color_table));
|
||||||
|
memcpy(dest->orig_color_table, src->orig_color_table, sizeof(dest->color_table));
|
||||||
|
memcpy(&dest->configured, &src->configured, sizeof(dest->configured));
|
||||||
|
memcpy(&dest->overridden, &src->overridden, sizeof(dest->overridden));
|
||||||
|
dest->dirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
patch_color_profiles(PyObject *module UNUSED, PyObject *args) {
|
patch_color_profiles(PyObject *module UNUSED, PyObject *args) {
|
||||||
PyObject *spec, *profiles, *v; ColorProfile *self; int change_configured; PyObject *cursor_text_color;
|
PyObject *spec, *profiles, *v; ColorProfile *self; int change_configured; PyObject *cursor_text_color;
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ from .shell import options_for_cmd
|
|||||||
To add completion for a new shell, you need to:
|
To add completion for a new shell, you need to:
|
||||||
|
|
||||||
1) Add an entry to completion scripts for your shell, this is
|
1) Add an entry to completion scripts for your shell, this is
|
||||||
a simple function that call's kitty's completion code and passes the
|
a simple function that calls kitty's completion code and passes the
|
||||||
results to the shell's completion system. This can be output by
|
results to the shell's completion system. This can be output by
|
||||||
`kitty +complete setup shell_name` and its output goes into
|
`kitty +complete setup shell_name` and its output goes into
|
||||||
your shell's rc file.
|
your shell's rc file.
|
||||||
@@ -185,11 +185,37 @@ def kitty_cli_opts(ans, prefix=None):
|
|||||||
|
|
||||||
def complete_kitty_cli_arg(ans, opt, prefix):
|
def complete_kitty_cli_arg(ans, opt, prefix):
|
||||||
prefix = prefix or ''
|
prefix = prefix or ''
|
||||||
if opt and opt['dest'] == 'override':
|
if not opt:
|
||||||
|
return
|
||||||
|
dest = opt['dest']
|
||||||
|
if dest == 'override':
|
||||||
from kitty.config import option_names_for_completion
|
from kitty.config import option_names_for_completion
|
||||||
k = 'Config directives'
|
k = 'Config directives'
|
||||||
ans.match_groups[k] = {k+'=': None for k in option_names_for_completion() if k.startswith(prefix)}
|
ans.match_groups[k] = {k+'=': None for k in option_names_for_completion() if k.startswith(prefix)}
|
||||||
ans.no_space_groups.add(k)
|
ans.no_space_groups.add(k)
|
||||||
|
elif dest == 'config':
|
||||||
|
|
||||||
|
def is_conf_file(x):
|
||||||
|
if os.path.isdir(x):
|
||||||
|
return True
|
||||||
|
return x.lower().endswith('.conf')
|
||||||
|
|
||||||
|
complete_files_and_dirs(ans, prefix, files_group_name='Config files', predicate=is_conf_file)
|
||||||
|
elif dest == 'session':
|
||||||
|
complete_files_and_dirs(ans, prefix, files_group_name='Session files')
|
||||||
|
elif dest == 'directory':
|
||||||
|
complete_files_and_dirs(ans, prefix, files_group_name='Directories', predicate=os.path.isdir)
|
||||||
|
elif dest == 'start_as':
|
||||||
|
k = 'Start as'
|
||||||
|
ans.match_groups[k] = {x: x for x in 'normal,fullscreen,maximized,minimized'.split(',') if x.startswith(prefix)}
|
||||||
|
ans.no_space_groups.add(k)
|
||||||
|
elif dest == 'listen_on':
|
||||||
|
if ':' not in prefix:
|
||||||
|
k = 'Address type'
|
||||||
|
ans.match_groups[k] = {x: x for x in ('unix:', 'tcp:') if x.startswith(prefix)}
|
||||||
|
ans.no_space_groups.add(k)
|
||||||
|
elif prefix.startswith('unix:') and not prefix.startswith('@'):
|
||||||
|
complete_files_and_dirs(ans, prefix[len('unix:'):], files_group_name='UNIX sockets', add_prefix='unix:')
|
||||||
|
|
||||||
|
|
||||||
def complete_alias_map(ans, words, new_word, option_map, complete_args=None):
|
def complete_alias_map(ans, words, new_word, option_map, complete_args=None):
|
||||||
@@ -273,9 +299,12 @@ def path_completion(prefix=''):
|
|||||||
return dirs, files
|
return dirs, files
|
||||||
|
|
||||||
|
|
||||||
def complete_files_and_dirs(ans, prefix, files_group_name='Files', predicate=None):
|
def complete_files_and_dirs(ans, prefix, files_group_name='Files', predicate=None, add_prefix=None):
|
||||||
dirs, files = path_completion(prefix or '')
|
dirs, files = path_completion(prefix or '')
|
||||||
files = filter(predicate, files)
|
files = filter(predicate, files)
|
||||||
|
if add_prefix:
|
||||||
|
dirs = (add_prefix + x for x in dirs)
|
||||||
|
files = (add_prefix + x for x in files)
|
||||||
|
|
||||||
if dirs:
|
if dirs:
|
||||||
ans.match_groups['Directories'] = dict.fromkeys(dirs)
|
ans.match_groups['Directories'] = dict.fromkeys(dirs)
|
||||||
|
|||||||
@@ -177,12 +177,11 @@ def load_config(Options, defaults, parse_config, merge_configs, *paths, override
|
|||||||
if not path:
|
if not path:
|
||||||
continue
|
continue
|
||||||
try:
|
try:
|
||||||
f = open(path, encoding='utf-8', errors='replace')
|
with open(path, encoding='utf-8', errors='replace') as f:
|
||||||
|
vals = parse_config(f)
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
continue
|
continue
|
||||||
with f:
|
ans = merge_configs(ans, vals)
|
||||||
vals = parse_config(f)
|
|
||||||
ans = merge_configs(ans, vals)
|
|
||||||
if overrides is not None:
|
if overrides is not None:
|
||||||
vals = parse_config(overrides)
|
vals = parse_config(overrides)
|
||||||
ans = merge_configs(ans, vals)
|
ans = merge_configs(ans, vals)
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user