Compare commits
1059 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e06ef732d8 | ||
|
|
792a3e7db8 | ||
|
|
9b32842f66 | ||
|
|
9816979169 | ||
|
|
a74679dd95 | ||
|
|
a40059729e | ||
|
|
6bab967586 | ||
|
|
bb88b33469 | ||
|
|
c440470276 | ||
|
|
ef6164eecb | ||
|
|
7ad360d872 | ||
|
|
0870a33956 | ||
|
|
3ccc2f538d | ||
|
|
17375f0be2 | ||
|
|
5a987a162e | ||
|
|
5058fb9919 | ||
|
|
3335f8602b | ||
|
|
87ab1bbe54 | ||
|
|
f8d52b33f4 | ||
|
|
bc2dcdf9db | ||
|
|
93d1aacfb6 | ||
|
|
3ddaa4aff9 | ||
|
|
75488d568a | ||
|
|
3df80545bd | ||
|
|
c605fd9783 | ||
|
|
60719e7bff | ||
|
|
e9faa3277a | ||
|
|
35f7388725 | ||
|
|
ef1486a779 | ||
|
|
95c44165e9 | ||
|
|
7b816bb96f | ||
|
|
d2ac51aa4a | ||
|
|
26974b1f3a | ||
|
|
3960c6678d | ||
|
|
30b8991a73 | ||
|
|
75a94bcd96 | ||
|
|
e160cbf32b | ||
|
|
2da2e63245 | ||
|
|
f160ea6012 | ||
|
|
8057bc639d | ||
|
|
6f5ec5aa03 | ||
|
|
e343c9445c | ||
|
|
c73e374f1a | ||
|
|
d9b292f808 | ||
|
|
46ef2f313b | ||
|
|
92a705c79e | ||
|
|
12ebdd2574 | ||
|
|
ed2e951032 | ||
|
|
01a34a8846 | ||
|
|
b13174cb9c | ||
|
|
03ac6cab99 | ||
|
|
532eebaefb | ||
|
|
f825345b14 | ||
|
|
1409477ed7 | ||
|
|
d8e4294432 | ||
|
|
5d13908776 | ||
|
|
2832a73285 | ||
|
|
4152ed5809 | ||
|
|
8a90ed70ee | ||
|
|
e2646c08a5 | ||
|
|
7122ba820f | ||
|
|
efca2658ea | ||
|
|
91a714947c | ||
|
|
5d3ac649ba | ||
|
|
6443e726a6 | ||
|
|
6a755bda45 | ||
|
|
dab555ea3b | ||
|
|
a3bbad0060 | ||
|
|
73db717a0c | ||
|
|
f1552c8354 | ||
|
|
fb87fc32f0 | ||
|
|
b04b0c670d | ||
|
|
b33845df8a | ||
|
|
12c9d8d8f8 | ||
|
|
fe97bbcbbf | ||
|
|
10533c3eba | ||
|
|
b4415c90f9 | ||
|
|
2970bbdf6f | ||
|
|
95a420534d | ||
|
|
be56a21574 | ||
|
|
3741a235fe | ||
|
|
523b6c4c2d | ||
|
|
c3b2300310 | ||
|
|
1c4a20d86f | ||
|
|
f5af475012 | ||
|
|
f149b74332 | ||
|
|
8cd51386cb | ||
|
|
fb2cca88df | ||
|
|
031d4dc85a | ||
|
|
bf66d1c0f5 | ||
|
|
0edfa88755 | ||
|
|
dba1f3bcbc | ||
|
|
e204cc8f12 | ||
|
|
9e3c60f43f | ||
|
|
b03dd5b6b2 | ||
|
|
2aa9886ebb | ||
|
|
225e52b8b9 | ||
|
|
0ae1f9906f | ||
|
|
a5918b50f8 | ||
|
|
fa0374ee61 | ||
|
|
5b1e1aee3d | ||
|
|
3ba11d08fb | ||
|
|
35d0f42d07 | ||
|
|
f08f222337 | ||
|
|
7c4ad278d5 | ||
|
|
d3d2930bd2 | ||
|
|
b571c20acc | ||
|
|
f6cc0302c4 | ||
|
|
d9abcf0c83 | ||
|
|
5346849439 | ||
|
|
9742b0c5b1 | ||
|
|
41cfe26898 | ||
|
|
05a254eee9 | ||
|
|
8ef53aa363 | ||
|
|
470abc25e4 | ||
|
|
7fe6c7e78b | ||
|
|
6c8a4f8d9f | ||
|
|
2a8c8c0cbb | ||
|
|
12bbe5459d | ||
|
|
e0d9e05fd4 | ||
|
|
8bea61cb99 | ||
|
|
d09666aba9 | ||
|
|
48e0ba1d3d | ||
|
|
fb72be41f4 | ||
|
|
ef1db6d089 | ||
|
|
9d4246a285 | ||
|
|
e0f5c39297 | ||
|
|
e4d353b105 | ||
|
|
0d665495b8 | ||
|
|
fdaf857885 | ||
|
|
987b41d2cb | ||
|
|
444080f320 | ||
|
|
b5007ba276 | ||
|
|
bf19d2b156 | ||
|
|
a78515e5bf | ||
|
|
581126c748 | ||
|
|
7b3e345a2a | ||
|
|
cc7cefd3ed | ||
|
|
de6528b7d8 | ||
|
|
9efdfe0de4 | ||
|
|
f936918278 | ||
|
|
00125577a9 | ||
|
|
083c47b0f0 | ||
|
|
8021686154 | ||
|
|
f55ca296da | ||
|
|
0d6bca3e5d | ||
|
|
be1ff61e4a | ||
|
|
e36d41b46f | ||
|
|
b4693dc1b3 | ||
|
|
ca6010789e | ||
|
|
f8a80ccf5f | ||
|
|
6461dccbdc | ||
|
|
b06f4f2574 | ||
|
|
7695e3a9c8 | ||
|
|
ae475b408f | ||
|
|
6d9d048287 | ||
|
|
09e4d101c5 | ||
|
|
36340caf4c | ||
|
|
9a80ab0700 | ||
|
|
339d972d8d | ||
|
|
6d1e1030bd | ||
|
|
8a3665ce55 | ||
|
|
8351f0beab | ||
|
|
c26808c59e | ||
|
|
50b1dfc746 | ||
|
|
2ec8ec2327 | ||
|
|
168480b0ee | ||
|
|
58f78afc2e | ||
|
|
d60020f5ac | ||
|
|
437efe5473 | ||
|
|
5737904cec | ||
|
|
431a8af08b | ||
|
|
be29c4a243 | ||
|
|
0a027fad9a | ||
|
|
e21a8e3cc2 | ||
|
|
4279d6514d | ||
|
|
457db5994b | ||
|
|
71c942d290 | ||
|
|
ee5bc8523b | ||
|
|
70f4112643 | ||
|
|
174f6b7ea8 | ||
|
|
b14fb6f3c4 | ||
|
|
d6e27e776b | ||
|
|
e6839b45e3 | ||
|
|
229134cf31 | ||
|
|
b552173185 | ||
|
|
399a1f8fee | ||
|
|
9293d9b0ed | ||
|
|
4a75952fc7 | ||
|
|
c19906eb87 | ||
|
|
00ea189074 | ||
|
|
c8e2061e2a | ||
|
|
78dc93721d | ||
|
|
33beecddda | ||
|
|
e99d93ca30 | ||
|
|
0cc54484a4 | ||
|
|
4df7d59de0 | ||
|
|
9a54da84dc | ||
|
|
83315f7999 | ||
|
|
eb5ebfd304 | ||
|
|
77c9124a3d | ||
|
|
317da76ced | ||
|
|
e8d8ced006 | ||
|
|
0321f9bddf | ||
|
|
5937892ebc | ||
|
|
e429bea2f4 | ||
|
|
d33ad5c616 | ||
|
|
3e0614a293 | ||
|
|
80e39212b8 | ||
|
|
d7a6ceb3a6 | ||
|
|
9d3a9e9d1e | ||
|
|
e95c789d4b | ||
|
|
a508161265 | ||
|
|
a935c80adc | ||
|
|
1d607bf13e | ||
|
|
ad57467c93 | ||
|
|
430eaefc3e | ||
|
|
3d60724651 | ||
|
|
31d9f663fc | ||
|
|
f324697c7c | ||
|
|
befae7e677 | ||
|
|
7a2c2587ba | ||
|
|
cf3f9d68b3 | ||
|
|
c99f7c554f | ||
|
|
f01c0945da | ||
|
|
1bcd0c4471 | ||
|
|
07f28e6ec7 | ||
|
|
7074f9f776 | ||
|
|
5029a9ad5a | ||
|
|
0bff30e954 | ||
|
|
601d37aa3d | ||
|
|
e2b1ca10c9 | ||
|
|
11942ed6dc | ||
|
|
f65914599b | ||
|
|
392c31f5fe | ||
|
|
f4ddaacb3c | ||
|
|
db64aef666 | ||
|
|
95c8bbd7fb | ||
|
|
67b4f37d53 | ||
|
|
427288c16b | ||
|
|
4202eee084 | ||
|
|
eca53bfab0 | ||
|
|
cd76d109f5 | ||
|
|
2787f9f19b | ||
|
|
4e3c6e52aa | ||
|
|
ae5ceedfe9 | ||
|
|
022e2eb1db | ||
|
|
2fe1ef4774 | ||
|
|
70afb2dd4d | ||
|
|
efa02e3f94 | ||
|
|
5eefd41059 | ||
|
|
6ca1b7c240 | ||
|
|
31191fd48c | ||
|
|
a6ed54ed48 | ||
|
|
95132b4fe1 | ||
|
|
df0c5d99e6 | ||
|
|
4b0724530e | ||
|
|
e5681a93f9 | ||
|
|
fb838a694e | ||
|
|
8c6f188767 | ||
|
|
55e15dc79e | ||
|
|
514073cb75 | ||
|
|
f6ece6522e | ||
|
|
817f0997cf | ||
|
|
1d651270d3 | ||
|
|
6ea58fac1a | ||
|
|
c7eb63d4ff | ||
|
|
4062365b19 | ||
|
|
7f48a927de | ||
|
|
4a740cc556 | ||
|
|
628b92f20b | ||
|
|
8f9616c230 | ||
|
|
df475dfde5 | ||
|
|
a835b56a51 | ||
|
|
5555a66638 | ||
|
|
dad355b932 | ||
|
|
90a097d45c | ||
|
|
dba01bc014 | ||
|
|
1d0a3ce998 | ||
|
|
076ad850bb | ||
|
|
868546abe4 | ||
|
|
6b421fabd1 | ||
|
|
ab3c9658bd | ||
|
|
8c7886d429 | ||
|
|
110a3e7e0f | ||
|
|
ee0b70f51b | ||
|
|
df48061a8f | ||
|
|
b1387d50f0 | ||
|
|
73dd218a95 | ||
|
|
ee4cedcc81 | ||
|
|
d1b2f9c6a9 | ||
|
|
40dee44978 | ||
|
|
db04c70d4a | ||
|
|
7401c6ac97 | ||
|
|
f7a1222cc3 | ||
|
|
069f09c43c | ||
|
|
35f821f6a1 | ||
|
|
67f60847ee | ||
|
|
65f6b142a5 | ||
|
|
81bda736d8 | ||
|
|
ec3998a9b8 | ||
|
|
01be77e0bc | ||
|
|
6f40b8d0a1 | ||
|
|
a083aa04b2 | ||
|
|
1f33348cf6 | ||
|
|
a45651933c | ||
|
|
ab57fbff73 | ||
|
|
6b3f774f05 | ||
|
|
1ef2880c6c | ||
|
|
ace152d8a3 | ||
|
|
8d08036a9d | ||
|
|
b0876fae64 | ||
|
|
01633776d3 | ||
|
|
e4202228eb | ||
|
|
79d5049273 | ||
|
|
9120e3b790 | ||
|
|
974e6140b3 | ||
|
|
1fd338cc6c | ||
|
|
bc61a81d7a | ||
|
|
06b30d1cc3 | ||
|
|
785973bb5e | ||
|
|
78efefcea1 | ||
|
|
1bb6242020 | ||
|
|
1af426bf84 | ||
|
|
dc4762a69a | ||
|
|
a785b77da9 | ||
|
|
1342767805 | ||
|
|
a3fc3233cd | ||
|
|
8093d70643 | ||
|
|
9d9ec84b54 | ||
|
|
6b26088c27 | ||
|
|
43af715caa | ||
|
|
c6eea488b1 | ||
|
|
b1c3999a81 | ||
|
|
4f19403518 | ||
|
|
4d1b537f78 | ||
|
|
dd54db47a9 | ||
|
|
44775e4644 | ||
|
|
805921d6a3 | ||
|
|
d7cd6edaa5 | ||
|
|
6a472bd6da | ||
|
|
d0c6ce9fd7 | ||
|
|
df48e2f9e2 | ||
|
|
2b4b3bbf18 | ||
|
|
6ea5027bf6 | ||
|
|
384ccb4fc7 | ||
|
|
ff763b099e | ||
|
|
741ae4c04b | ||
|
|
d84ec941c0 | ||
|
|
f0b5dd9799 | ||
|
|
cec4371b51 | ||
|
|
c0ff39c59d | ||
|
|
022634f2d9 | ||
|
|
392f576d07 | ||
|
|
6d59e2125e | ||
|
|
6476a1d2e0 | ||
|
|
ca998fb4b0 | ||
|
|
48631c4ea6 | ||
|
|
294be2a772 | ||
|
|
533688a67a | ||
|
|
4309e2371d | ||
|
|
ea30c84240 | ||
|
|
d4c2b13dda | ||
|
|
1decae2938 | ||
|
|
145ec86d3b | ||
|
|
e17c96b20f | ||
|
|
2cfcefd9eb | ||
|
|
356e950122 | ||
|
|
64dee63b73 | ||
|
|
431d013d32 | ||
|
|
40eb8455d0 | ||
|
|
c46b36509b | ||
|
|
f7ff63132d | ||
|
|
e17036a7a5 | ||
|
|
e678c41f56 | ||
|
|
ee3462592a | ||
|
|
521f921424 | ||
|
|
ee47a10b37 | ||
|
|
b81700144d | ||
|
|
9f28dd61d3 | ||
|
|
dad7d366b3 | ||
|
|
209b78a3ec | ||
|
|
17f34d1f95 | ||
|
|
26699cd9ef | ||
|
|
907db09a58 | ||
|
|
d506fa0565 | ||
|
|
de1a0d48a6 | ||
|
|
a20e5fefd3 | ||
|
|
44558560f9 | ||
|
|
677f154f03 | ||
|
|
0adaf064e7 | ||
|
|
3c828feef2 | ||
|
|
4d3c5e61fd | ||
|
|
67baefb52a | ||
|
|
d509a4fa8c | ||
|
|
cad1c12b7b | ||
|
|
9f751d8715 | ||
|
|
cf8a1dff33 | ||
|
|
973d98457f | ||
|
|
ce262f810d | ||
|
|
bd31c2b484 | ||
|
|
ef0e610802 | ||
|
|
3040d4c83f | ||
|
|
c9252e8639 | ||
|
|
e2e701460b | ||
|
|
f0c3641ebd | ||
|
|
025f6d7701 | ||
|
|
c68516ca8d | ||
|
|
a9e739e08d | ||
|
|
cc15ff73b7 | ||
|
|
fd3a4536e7 | ||
|
|
75caafb5ac | ||
|
|
cf2f8165eb | ||
|
|
a2f80740d7 | ||
|
|
c7703791d1 | ||
|
|
c39e9e9c61 | ||
|
|
713059319c | ||
|
|
d7a7509da6 | ||
|
|
57e6e7b2c5 | ||
|
|
d675977f10 | ||
|
|
7ef911e17d | ||
|
|
9a384c5045 | ||
|
|
2b3753d99c | ||
|
|
d173ab9f45 | ||
|
|
fbd0e8e26a | ||
|
|
50414b333a | ||
|
|
ee2fdb3d25 | ||
|
|
2b884377d4 | ||
|
|
36a20f7b00 | ||
|
|
35cbf49b08 | ||
|
|
21836cedda | ||
|
|
0a892b72e6 | ||
|
|
2c6e5a6e73 | ||
|
|
2cb25cf5a8 | ||
|
|
e07916425e | ||
|
|
f62e2374e4 | ||
|
|
eb4ee2f0af | ||
|
|
be3c76da20 | ||
|
|
b15e58621c | ||
|
|
601a6c9e3d | ||
|
|
3ff184348e | ||
|
|
c8efcd2be1 | ||
|
|
9c116a2975 | ||
|
|
8818b5d8df | ||
|
|
e96dfadae7 | ||
|
|
deb564e5a6 | ||
|
|
ffc71c348c | ||
|
|
19df7b94ea | ||
|
|
a3ecc79f0d | ||
|
|
b140b15119 | ||
|
|
b7b2b6075a | ||
|
|
7525e152b8 | ||
|
|
bc9dfec615 | ||
|
|
7824739034 | ||
|
|
e7b60a3628 | ||
|
|
97c3061b8f | ||
|
|
1a042c873c | ||
|
|
064aa3a150 | ||
|
|
8a178ebe55 | ||
|
|
9a97f0bced | ||
|
|
5c7471910d | ||
|
|
27b6517594 | ||
|
|
cd4dacb406 | ||
|
|
5f6faa1bf0 | ||
|
|
cfc5a952f8 | ||
|
|
10b186957b | ||
|
|
f597481736 | ||
|
|
9fa97e6187 | ||
|
|
3844321f20 | ||
|
|
8efe08c45b | ||
|
|
c78563b452 | ||
|
|
122e172092 | ||
|
|
8f85c0d167 | ||
|
|
ac6d1ce174 | ||
|
|
03e0bf4c0e | ||
|
|
1cb183f5e1 | ||
|
|
d78a553910 | ||
|
|
1326532850 | ||
|
|
408508247d | ||
|
|
e2be09e028 | ||
|
|
c7c14f184c | ||
|
|
24ca919f33 | ||
|
|
85fe783652 | ||
|
|
04b6bf3b74 | ||
|
|
8b2fb105d0 | ||
|
|
558caa232d | ||
|
|
d8886edbeb | ||
|
|
f72ecf1791 | ||
|
|
45d1b978d8 | ||
|
|
0b780cc065 | ||
|
|
5263f6598c | ||
|
|
f9e60e7ef6 | ||
|
|
45c00d0b1f | ||
|
|
c70e2f7d3e | ||
|
|
1ec0bed1ce | ||
|
|
46b5e4513a | ||
|
|
ffb5196f3b | ||
|
|
107f1af3c4 | ||
|
|
03b1484c96 | ||
|
|
aaf64ad63e | ||
|
|
f548e795d5 | ||
|
|
767da68239 | ||
|
|
f44e0ff4bd | ||
|
|
7f226f2ea1 | ||
|
|
1c82a39a6e | ||
|
|
b70cf276b4 | ||
|
|
80b2df2ef4 | ||
|
|
ad27452275 | ||
|
|
196a0b6b7e | ||
|
|
f356f63994 | ||
|
|
4947fb6b57 | ||
|
|
622f12b84e | ||
|
|
c1f84ce603 | ||
|
|
14912461ad | ||
|
|
a9f265e8b7 | ||
|
|
199ee20adb | ||
|
|
7c3c87abf6 | ||
|
|
b0ad44bcf2 | ||
|
|
9ba808ec3c | ||
|
|
eacf849e3a | ||
|
|
42c2791182 | ||
|
|
390e883ecf | ||
|
|
9fe631ee3f | ||
|
|
82d8c4b230 | ||
|
|
9775bb0a9d | ||
|
|
139c9a2d6d | ||
|
|
542880f87b | ||
|
|
3846286bee | ||
|
|
72be402a2d | ||
|
|
c6b9cb759a | ||
|
|
13ccf269a6 | ||
|
|
fcc7a0255a | ||
|
|
e7447f38cf | ||
|
|
7ae35631a6 | ||
|
|
55ad228166 | ||
|
|
48fb051253 | ||
|
|
f97e8b7eeb | ||
|
|
84f914742b | ||
|
|
0d704f3715 | ||
|
|
d8896eb210 | ||
|
|
b9d74e2012 | ||
|
|
803fba9cfd | ||
|
|
581548ed67 | ||
|
|
9a8c0f8e7e | ||
|
|
328f569c16 | ||
|
|
7931654a7c | ||
|
|
6eb0c10339 | ||
|
|
269f294d19 | ||
|
|
d19e2f1350 | ||
|
|
3b745b82db | ||
|
|
02f30c2a03 | ||
|
|
54002b386a | ||
|
|
0e2ff077af | ||
|
|
012cf70321 | ||
|
|
9da0ba52db | ||
|
|
7bfb07e59e | ||
|
|
9cb2c4b1ff | ||
|
|
8c088fad0f | ||
|
|
392722aed0 | ||
|
|
fabfb30fc4 | ||
|
|
c7cb021e92 | ||
|
|
be05d9c3e9 | ||
|
|
e38690e8d9 | ||
|
|
7172115559 | ||
|
|
7314019832 | ||
|
|
b9684941c4 | ||
|
|
a27289352c | ||
|
|
dc77009e55 | ||
|
|
d12e10830d | ||
|
|
936f6c22f0 | ||
|
|
9712be903d | ||
|
|
7441cefdbb | ||
|
|
7bf83603c8 | ||
|
|
6768bc1705 | ||
|
|
707cb37212 | ||
|
|
1cf0a8b78e | ||
|
|
3d2cb37af0 | ||
|
|
09fbd6f5e0 | ||
|
|
474bef65cb | ||
|
|
e97454c4a5 | ||
|
|
936dc74a27 | ||
|
|
362e4266bb | ||
|
|
d08f2e10f1 | ||
|
|
f1e5ee74a6 | ||
|
|
7832d33348 | ||
|
|
de25f94fae | ||
|
|
98625e9c36 | ||
|
|
5768cc98b6 | ||
|
|
da1cc6c1c5 | ||
|
|
50384fac97 | ||
|
|
424bd8a6cd | ||
|
|
421fae2b57 | ||
|
|
8bb8615a5a | ||
|
|
80f8692e92 | ||
|
|
25623c758d | ||
|
|
e1a0a195a9 | ||
|
|
f8cf49a90c | ||
|
|
ac9f8595c9 | ||
|
|
97f22bbff6 | ||
|
|
d6ddfa9d18 | ||
|
|
5e48ae8bac | ||
|
|
cdd943ded4 | ||
|
|
39b2bf963c | ||
|
|
06827fd437 | ||
|
|
70ccc1cf6d | ||
|
|
f801c47d1e | ||
|
|
01c0e8da93 | ||
|
|
e844ad6db3 | ||
|
|
3f8c042bc3 | ||
|
|
707ad705a4 | ||
|
|
79a780004f | ||
|
|
81b28bc1bd | ||
|
|
e9c4d540b1 | ||
|
|
50d9718c68 | ||
|
|
e39da2b2bb | ||
|
|
f08ec1522a | ||
|
|
e61e93712c | ||
|
|
c9e198e02e | ||
|
|
0ce181b578 | ||
|
|
99950fe448 | ||
|
|
d8daf84a09 | ||
|
|
3d32202b3a | ||
|
|
4f4d562670 | ||
|
|
28fc9c69da | ||
|
|
6edf00e699 | ||
|
|
a0d6445dda | ||
|
|
e74797037c | ||
|
|
3fb125dba7 | ||
|
|
3c8640f9ad | ||
|
|
2e63a4c83f | ||
|
|
9da5bee178 | ||
|
|
2fc6f3b542 | ||
|
|
4754f42e51 | ||
|
|
941fe918fb | ||
|
|
f4e82e972e | ||
|
|
f66dbf111d | ||
|
|
1a2da5c49d | ||
|
|
8327dabb29 | ||
|
|
195ea6c140 | ||
|
|
fcc0707174 | ||
|
|
aa9c3cd634 | ||
|
|
b541341681 | ||
|
|
e5d50aca6d | ||
|
|
b738f4d4ff | ||
|
|
5c38aabf0e | ||
|
|
03e9ed6947 | ||
|
|
63493fad22 | ||
|
|
696b857f91 | ||
|
|
53ae2bbe0d | ||
|
|
01069e919d | ||
|
|
fc0095f505 | ||
|
|
421528e130 | ||
|
|
7b70356515 | ||
|
|
e803505aad | ||
|
|
ad1ff455a0 | ||
|
|
7692cb5c3d | ||
|
|
a94e208db3 | ||
|
|
ba9d5cf3ff | ||
|
|
0dff0d03f9 | ||
|
|
c92aca5d19 | ||
|
|
5762baeed7 | ||
|
|
601cf01222 | ||
|
|
0eef48b516 | ||
|
|
3c1954f329 | ||
|
|
cc29640604 | ||
|
|
d0329460b8 | ||
|
|
717c0c96de | ||
|
|
b3f161efce | ||
|
|
0286940163 | ||
|
|
d4a4ee386f | ||
|
|
33498f9133 | ||
|
|
da3d4d1bef | ||
|
|
c69b8870d2 | ||
|
|
85b55b31b6 | ||
|
|
948919e42b | ||
|
|
85c40090ed | ||
|
|
98b50ec145 | ||
|
|
1ab4f7d2d0 | ||
|
|
98801b6fa6 | ||
|
|
bdd68284b5 | ||
|
|
a61d70ea9a | ||
|
|
e271719dd2 | ||
|
|
a08efa1fc5 | ||
|
|
ffac3600e0 | ||
|
|
6499f8ac24 | ||
|
|
63307cb1d8 | ||
|
|
0a6fb362f6 | ||
|
|
457fcbfb90 | ||
|
|
3b6277b9e2 | ||
|
|
e6e61028b1 | ||
|
|
e9be66126b | ||
|
|
681fe7f2f2 | ||
|
|
0196920533 | ||
|
|
5f5bb3ace0 | ||
|
|
3c970e0122 | ||
|
|
43af6e3b8a | ||
|
|
ac8cfc12fb | ||
|
|
b19472e0f5 | ||
|
|
b4d08044a0 | ||
|
|
b2fe02e63f | ||
|
|
d1a5d30233 | ||
|
|
bba30138e1 | ||
|
|
082546a1e7 | ||
|
|
41ffd58e26 | ||
|
|
b4f24e4e1e | ||
|
|
75c8ffd715 | ||
|
|
688606ff7c | ||
|
|
2e3f9dffa7 | ||
|
|
859033415b | ||
|
|
1f1b52b580 | ||
|
|
4e7bf80447 | ||
|
|
e39df50884 | ||
|
|
8d6a9d45c2 | ||
|
|
0862e85577 | ||
|
|
0b9a37139e | ||
|
|
6357f7b811 | ||
|
|
24197dc422 | ||
|
|
9bc2ab3245 | ||
|
|
bf4e8c490c | ||
|
|
590a4d70ee | ||
|
|
40341d2ddd | ||
|
|
0cd2c41ee3 | ||
|
|
5d65cdb6a8 | ||
|
|
759a15ccbb | ||
|
|
5aead5eebe | ||
|
|
a325a5fdee | ||
|
|
931e91f1a7 | ||
|
|
6e13509720 | ||
|
|
5b4844e71e | ||
|
|
66cbbea9bb | ||
|
|
b65119b8a9 | ||
|
|
86703da917 | ||
|
|
610e9afdf0 | ||
|
|
e3af9f68d3 | ||
|
|
747ac85e7c | ||
|
|
8c23f9e526 | ||
|
|
e6e339fcd3 | ||
|
|
f04680ac47 | ||
|
|
90985cc846 | ||
|
|
63917944f2 | ||
|
|
793605f80f | ||
|
|
93a281c7e3 | ||
|
|
8f1c6c4d74 | ||
|
|
1610dba7ab | ||
|
|
d9d419991c | ||
|
|
f9e86b19aa | ||
|
|
fffb976e43 | ||
|
|
0da566b49f | ||
|
|
da55717d20 | ||
|
|
254836902c | ||
|
|
d01f8d1865 | ||
|
|
a46c3f7007 | ||
|
|
4e58062025 | ||
|
|
aa3be0535f | ||
|
|
8ebf5e007c | ||
|
|
c2957e7f12 | ||
|
|
bf7c26d357 | ||
|
|
0547102bdd | ||
|
|
a07369ce69 | ||
|
|
21c5610431 | ||
|
|
6dbdf72f40 | ||
|
|
76a6bba643 | ||
|
|
b0b8222a96 | ||
|
|
0d87b8fac5 | ||
|
|
5227b1f98b | ||
|
|
c4f7c5c1cd | ||
|
|
33a84a609c | ||
|
|
037111715a | ||
|
|
93271b93e6 | ||
|
|
04488ada06 | ||
|
|
21c7002c68 | ||
|
|
97cae0e355 | ||
|
|
85fc0a59b1 | ||
|
|
eddd45bbc3 | ||
|
|
e2339697b9 | ||
|
|
cfe9b408ce | ||
|
|
83e8018787 | ||
|
|
372d2008a6 | ||
|
|
ab9a36f8c1 | ||
|
|
2458c3a7c6 | ||
|
|
e827e6fa21 | ||
|
|
342f0981d8 | ||
|
|
9c19e88288 | ||
|
|
7329bd4910 | ||
|
|
b9ad62226e | ||
|
|
3bff3bcbe4 | ||
|
|
a06fdad034 | ||
|
|
a49bd98ec6 | ||
|
|
90f41108d3 | ||
|
|
382c31ddf2 | ||
|
|
871ca4dda6 | ||
|
|
fa003f8233 | ||
|
|
12f37bcfad | ||
|
|
e86c712424 | ||
|
|
e8a9935cb2 | ||
|
|
f353131b44 | ||
|
|
7c4a2ba329 | ||
|
|
dfb543bd94 | ||
|
|
c912eef040 | ||
|
|
5f06d3a427 | ||
|
|
a70fa9abc5 | ||
|
|
5956277863 | ||
|
|
d3f37eeba4 | ||
|
|
ea48332f46 | ||
|
|
eb12511646 | ||
|
|
aa11ddf32c | ||
|
|
a348f64833 | ||
|
|
626a96e20f | ||
|
|
60995ff04b | ||
|
|
ba4e711715 | ||
|
|
891b184195 | ||
|
|
5414dc398e | ||
|
|
917559f883 | ||
|
|
9f2fb76309 | ||
|
|
b6692849d6 | ||
|
|
b27f6d5957 | ||
|
|
cda1e28b32 | ||
|
|
8a3e71d3d0 | ||
|
|
149ae2866a | ||
|
|
21707171bb | ||
|
|
2ebdf738ca | ||
|
|
0e871a89aa | ||
|
|
2d4f194f0d | ||
|
|
ce94a9b2df | ||
|
|
bfbb3c7068 | ||
|
|
6d1fd20542 | ||
|
|
bb8cab3a02 | ||
|
|
10435c23c2 | ||
|
|
01142cdc8c | ||
|
|
fc0adfd965 | ||
|
|
8803eeb890 | ||
|
|
25be705bcf | ||
|
|
d8f214a267 | ||
|
|
f74fb846e5 | ||
|
|
8ae110691e | ||
|
|
abff2292c1 | ||
|
|
7d690bbad2 | ||
|
|
7298de646a | ||
|
|
3c2f3ecd8e | ||
|
|
ac2c21e046 | ||
|
|
c817ba9eae | ||
|
|
92827ae647 | ||
|
|
5bdb405635 | ||
|
|
9beae321d7 | ||
|
|
353db678a2 | ||
|
|
9b973ef99c | ||
|
|
308d171dae | ||
|
|
7057bc663e | ||
|
|
d84cff0baf | ||
|
|
645890ccc8 | ||
|
|
cc1336a616 | ||
|
|
9b32f18109 | ||
|
|
a0321376d5 | ||
|
|
0a6e264d09 | ||
|
|
afec07b124 | ||
|
|
8a34fede55 | ||
|
|
686b5f297e | ||
|
|
6609d219f4 | ||
|
|
804998ca69 | ||
|
|
de5254469c | ||
|
|
ef879bab9c | ||
|
|
f729985346 | ||
|
|
1e998b6a3f | ||
|
|
77e9460eea | ||
|
|
81a58186c6 | ||
|
|
ac149be2bb | ||
|
|
a76a163db5 | ||
|
|
4ae59d3f77 | ||
|
|
d83a450260 | ||
|
|
61acc0784e | ||
|
|
f05890719d | ||
|
|
0f4e7921ee | ||
|
|
ec8c96b8e6 | ||
|
|
f0b29e15c3 | ||
|
|
8ad62106e0 | ||
|
|
36eb52424f | ||
|
|
c9ce2f47dc | ||
|
|
5035ed61ee | ||
|
|
a4cc10c41b | ||
|
|
5730ce5f53 | ||
|
|
27524bfc3d | ||
|
|
8843ded1c9 | ||
|
|
64b497589f | ||
|
|
ee48fd7151 | ||
|
|
291cd5e23f | ||
|
|
be668cfd9a | ||
|
|
f889c1c75a | ||
|
|
55c5f3e9fd | ||
|
|
242d335095 | ||
|
|
c763db94ce | ||
|
|
a391732600 | ||
|
|
06b45fcace | ||
|
|
bdac5f7d5b | ||
|
|
74865efddb | ||
|
|
b1f4d16692 | ||
|
|
01b8e2c3f5 | ||
|
|
8c1ef94b26 | ||
|
|
507fbc7abf | ||
|
|
2f8002c567 | ||
|
|
551e28d8e0 | ||
|
|
e84163e838 | ||
|
|
3a64b835fb | ||
|
|
08a44ed4dd | ||
|
|
4b8cc23a86 | ||
|
|
c4b2de8939 | ||
|
|
e2a603dcda | ||
|
|
294d01def6 | ||
|
|
05f289f912 | ||
|
|
4343c4067e | ||
|
|
c167dcc4e9 | ||
|
|
9a67176719 | ||
|
|
42d1a4755a | ||
|
|
1690e6933f | ||
|
|
5bbc15583e | ||
|
|
e03aabd972 | ||
|
|
6f5968eeb0 | ||
|
|
71b6e8f12a | ||
|
|
9c486f6e69 | ||
|
|
2f24588c66 | ||
|
|
6b1ea326a0 | ||
|
|
4512d0dbac | ||
|
|
511c4da6a3 | ||
|
|
af8fdf1dbe | ||
|
|
b7d12de0a7 | ||
|
|
2d870fc84a | ||
|
|
6e87929603 | ||
|
|
2b441df9e9 | ||
|
|
3e672ac178 | ||
|
|
12a24d5c86 | ||
|
|
dec1a0886d | ||
|
|
a82e45ad71 | ||
|
|
82e5750d71 | ||
|
|
6a3eb3f3d7 | ||
|
|
533a739e2b | ||
|
|
b12a8331f1 | ||
|
|
8f4ec036e7 | ||
|
|
cba36f2240 | ||
|
|
b54ffbefe4 | ||
|
|
6d470e4da0 | ||
|
|
4e1ebec8c2 | ||
|
|
e9779258e9 | ||
|
|
5c83f45bc6 | ||
|
|
eb65aca1f4 | ||
|
|
5d7e393c93 | ||
|
|
d6d01102fe | ||
|
|
1ad802b194 | ||
|
|
4a191b65bb | ||
|
|
65cc9f4e1b | ||
|
|
9f4b13b523 | ||
|
|
97e1b62a1e | ||
|
|
3ac966a38b | ||
|
|
6f1fda0a48 | ||
|
|
c00b486864 | ||
|
|
7928fff645 | ||
|
|
0285f5a1ad | ||
|
|
56e5c8be32 | ||
|
|
ef569976cb | ||
|
|
f8ae048d60 | ||
|
|
c51f4df0ca | ||
|
|
84453bf15c | ||
|
|
917350f058 | ||
|
|
0c58662eb6 | ||
|
|
52ca75855e | ||
|
|
49a07651b9 | ||
|
|
90a8ba3789 | ||
|
|
734c3199f0 | ||
|
|
64567646d9 | ||
|
|
1a1638cc7f | ||
|
|
fdf055312c | ||
|
|
b0b8b06b56 | ||
|
|
9c1ffb1adf | ||
|
|
563bafea08 | ||
|
|
efe4c32ffd | ||
|
|
0f003a9a77 | ||
|
|
3eff929652 | ||
|
|
3010ebfef5 | ||
|
|
ff14f47781 | ||
|
|
0b99a5caae | ||
|
|
467b96f2f2 | ||
|
|
18751a05c0 | ||
|
|
9007623d0c | ||
|
|
c1abb7038d | ||
|
|
53f7eebc4d | ||
|
|
d54d29122d | ||
|
|
1d71791b3c | ||
|
|
0c6145d4f2 | ||
|
|
62e273c5bb | ||
|
|
d82f399be7 | ||
|
|
20a7050564 | ||
|
|
b235f411b0 | ||
|
|
99faeeacfc | ||
|
|
08ad4f389d | ||
|
|
edba63d0d9 | ||
|
|
e33f882abc | ||
|
|
53e059f4f7 | ||
|
|
830364e026 | ||
|
|
332714a925 | ||
|
|
1eee6deb22 | ||
|
|
547f138703 | ||
|
|
b6c345fc3c | ||
|
|
29c40a4957 | ||
|
|
72af821e1b | ||
|
|
5fe4d10f38 | ||
|
|
3b36470e84 | ||
|
|
f9e8a4050c | ||
|
|
ce308286df | ||
|
|
b670973226 | ||
|
|
01b11b8a53 | ||
|
|
75c47a8659 | ||
|
|
5b4e0ed483 | ||
|
|
7432a7f346 | ||
|
|
0830fc3b5a | ||
|
|
ab2c901e85 | ||
|
|
3774cc54c7 | ||
|
|
330ed8e4ae | ||
|
|
eddae44d6d | ||
|
|
226488717a | ||
|
|
2f9dabd344 | ||
|
|
cf1b7c0adb | ||
|
|
eb57d0d431 | ||
|
|
8116ee015a | ||
|
|
0fa3cec61f | ||
|
|
eb60464177 | ||
|
|
44b2651a0f | ||
|
|
f2e91b5ed2 | ||
|
|
e72b60c882 | ||
|
|
5263babc9a | ||
|
|
9034b50b3a | ||
|
|
fdd7fe1948 | ||
|
|
8e7b8b70dc | ||
|
|
9bf24bdff5 | ||
|
|
ee53edd96d | ||
|
|
1bc5d7038d | ||
|
|
8a6b8b415c | ||
|
|
86174c81c8 | ||
|
|
374500d7b0 | ||
|
|
319a141967 | ||
|
|
c0d0062ef8 | ||
|
|
aaaa34e119 | ||
|
|
fba9502a9d | ||
|
|
6670cc1534 | ||
|
|
970729dca0 | ||
|
|
6627586d6e | ||
|
|
9f364209af | ||
|
|
c31a39a052 | ||
|
|
36fda90814 | ||
|
|
7ccfbc16e9 | ||
|
|
ad3b527bc4 | ||
|
|
f7eef3f456 | ||
|
|
1870364888 | ||
|
|
d7dfc85cf7 | ||
|
|
c047e5f16a | ||
|
|
8d21f63ec2 | ||
|
|
85b6a91e5c | ||
|
|
c788e30b66 | ||
|
|
a99caed693 | ||
|
|
9589fb5275 | ||
|
|
1a6dc530a4 | ||
|
|
60835871eb |
@@ -1,104 +0,0 @@
|
|||||||
version: 2
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
|
|
||||||
lin-sys:
|
|
||||||
docker:
|
|
||||||
- image: kovidgoyal/kitty-test:latest
|
|
||||||
steps:
|
|
||||||
- checkout
|
|
||||||
- run: if grep -Inr '\s$' kitty kitty_tests kittens docs *.py *.asciidoc *.rst .gitattributes .gitignore; then echo Trailing whitespace found, aborting.; exit 1; fi
|
|
||||||
- run: python3 -m flake8 --count .
|
|
||||||
- run: python3 setup.py build --debug --verbose
|
|
||||||
- run: ./kitty/launcher/kitty +launch test.py
|
|
||||||
- run: make FAIL_WARN=-W man
|
|
||||||
- run: make FAIL_WARN=-W html
|
|
||||||
|
|
||||||
lin-package:
|
|
||||||
docker:
|
|
||||||
- image: kovidgoyal/kitty-test:latest
|
|
||||||
steps:
|
|
||||||
- checkout
|
|
||||||
- run: python3 setup.py linux-package --update-check-interval=0
|
|
||||||
|
|
||||||
lin-35:
|
|
||||||
docker:
|
|
||||||
- image: kovidgoyal/kitty-test:latest
|
|
||||||
environment:
|
|
||||||
CC: gcc
|
|
||||||
CFLAGS: -funsigned-char
|
|
||||||
LD_LIBRARY_PATH: /opt/py3.5/lib
|
|
||||||
ASAN_OPTIONS: leak_check_at_exit=0
|
|
||||||
steps:
|
|
||||||
- checkout
|
|
||||||
- run: /opt/py3.5/bin/python3 setup.py build --debug --verbose --sanitize
|
|
||||||
- run: ./kitty/launcher/kitty +launch test.py
|
|
||||||
|
|
||||||
lin-37:
|
|
||||||
docker:
|
|
||||||
- image: kovidgoyal/kitty-test:latest
|
|
||||||
environment:
|
|
||||||
CC: clang
|
|
||||||
LD_LIBRARY_PATH: /opt/py3.7/lib
|
|
||||||
ASAN_OPTIONS: leak_check_at_exit=0
|
|
||||||
steps:
|
|
||||||
- checkout
|
|
||||||
- run: /opt/py3.7/bin/python3 setup.py build --debug --verbose --sanitize
|
|
||||||
- run: ./kitty/launcher/kitty +launch test.py
|
|
||||||
|
|
||||||
lin-bundle:
|
|
||||||
docker:
|
|
||||||
- image: kovidgoyal/kitty-test:latest
|
|
||||||
environment:
|
|
||||||
ASAN_OPTIONS: leak_check_at_exit=0
|
|
||||||
steps:
|
|
||||||
- checkout
|
|
||||||
- run: echo "export LD_LIBRARY_PATH=$SW/lib" >> $BASH_ENV
|
|
||||||
- run: echo "export PKG_CONFIG_PATH=$SW/lib/pkgconfig" >> $BASH_ENV
|
|
||||||
- run: echo "export PYTHONHOME=$SW" >> $BASH_ENV
|
|
||||||
- run: $SW/bin/python3 setup.py build --debug --verbose
|
|
||||||
- run: ./kitty/launcher/kitty +launch test.py
|
|
||||||
|
|
||||||
mac-bundle:
|
|
||||||
macos:
|
|
||||||
xcode: "10.1.0"
|
|
||||||
environment:
|
|
||||||
LC_ALL: en_US.UTF-8
|
|
||||||
LANG: en_US.UTF-8
|
|
||||||
SW: /Users/Shared/buildbot/sw/sw
|
|
||||||
steps:
|
|
||||||
- checkout
|
|
||||||
- run: mkdir -p $SW
|
|
||||||
- run: curl https://download.calibre-ebook.com/travis/kitty/osx.tar.xz | tar xJ -C $SW
|
|
||||||
- run: echo "export PATH=$SW/bin:$PATH" >> $BASH_ENV
|
|
||||||
- run: python3 setup.py build --debug --verbose
|
|
||||||
- run: ./kitty/launcher/kitty +launch test.py
|
|
||||||
|
|
||||||
mac-brew:
|
|
||||||
macos:
|
|
||||||
xcode: "10.2.0"
|
|
||||||
environment:
|
|
||||||
LC_ALL: en_US.UTF-8
|
|
||||||
LANG: en_US.UTF-8
|
|
||||||
steps:
|
|
||||||
- checkout
|
|
||||||
- run: brew bundle
|
|
||||||
- run: python3 setup.py build --debug --verbose
|
|
||||||
- run: ./kitty/launcher/kitty +launch test.py
|
|
||||||
- run: echo "export PATH=/usr/local/opt/sphinx-doc/bin:$PATH" >> $BASH_ENV
|
|
||||||
- run: python3 setup.py linux-package --verbose
|
|
||||||
- run: python3 setup.py kitty.app --verbose
|
|
||||||
- run: kitty.app/Contents/MacOS/kitty +runpy "from kitty.constants import *; print(kitty_exe())"
|
|
||||||
|
|
||||||
|
|
||||||
workflows:
|
|
||||||
version: 2
|
|
||||||
all_jobs:
|
|
||||||
jobs:
|
|
||||||
- mac-bundle
|
|
||||||
- lin-sys
|
|
||||||
- lin-35
|
|
||||||
- lin-37
|
|
||||||
- lin-package
|
|
||||||
- lin-bundle
|
|
||||||
- mac-brew
|
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
# When changing this file, go to
|
|
||||||
# https://cloud.docker.com/repository/docker/kovidgoyal/kitty-test/builds and
|
|
||||||
# click the "Trigger" button under Automated builds to rebuild
|
|
||||||
FROM ubuntu:latest
|
|
||||||
|
|
||||||
# make Apt non-interactive
|
|
||||||
ENV DEBIAN_FRONTEND=noninteractive
|
|
||||||
RUN echo 'APT::Get::Assume-Yes "true";' > /etc/apt/apt.conf.d/90circleci \
|
|
||||||
&& echo 'DPkg::Options "--force-confnew";' >> /etc/apt/apt.conf.d/90circleci \
|
|
||||||
&& echo 'Acquire::Languages "none";' >> /etc/apt/apt.conf.d/90circleci
|
|
||||||
|
|
||||||
# System setup
|
|
||||||
RUN apt-get update && mkdir -p /usr/share/man/man1 && apt-get install -y python3-flake8 python3-pip python3-pil clang git apt locales sudo openssh-client ca-certificates tar gzip parallel net-tools netcat unzip zip bzip2 gnupg curl wget build-essential apt-utils
|
|
||||||
|
|
||||||
# Setup circleci user
|
|
||||||
RUN groupadd --gid 3434 circleci \
|
|
||||||
&& useradd --uid 3434 --gid circleci --shell /bin/bash --create-home circleci \
|
|
||||||
&& echo 'circleci ALL=NOPASSWD: ALL' >> /etc/sudoers.d/50-circleci \
|
|
||||||
&& echo 'Defaults env_keep += "DEBIAN_FRONTEND"' >> /etc/sudoers.d/env_keep \
|
|
||||||
&& echo 'Defaults env_keep += "SW"' >> /etc/sudoers.d/env_keep \
|
|
||||||
&& echo 'Defaults env_keep += "LANG"' >> /etc/sudoers.d/env_keep
|
|
||||||
|
|
||||||
# Set timezone to UTC by default
|
|
||||||
RUN ln -sf /usr/share/zoneinfo/Etc/UTC /etc/localtime
|
|
||||||
|
|
||||||
# Use unicode
|
|
||||||
RUN locale-gen en_US.UTF-8 || true
|
|
||||||
ENV LANG=en_US.UTF-8
|
|
||||||
|
|
||||||
# Deps needed for building python
|
|
||||||
RUN apt-get install -y libreadline-dev zlib1g-dev libssl-dev libbz2-dev libsqlite3-dev libffi-dev
|
|
||||||
|
|
||||||
# kitty deps
|
|
||||||
RUN apt-get install -y libgl1-mesa-dev libxi-dev libxrandr-dev libxinerama-dev libxcursor-dev libxcb-xkb-dev libdbus-1-dev libxkbcommon-dev libharfbuzz-dev libpng-dev libfontconfig-dev libpython3-dev libxkbcommon-x11-dev python3-pygments libcanberra-dev
|
|
||||||
|
|
||||||
# Needed to build kitty docs
|
|
||||||
RUN pip3 install sphinx
|
|
||||||
|
|
||||||
# Install multiple pythons
|
|
||||||
ADD install-python.py /tmp/install-python.py
|
|
||||||
RUN python3 /tmp/install-python.py py3.5 https://www.python.org/ftp/python/3.5.6/Python-3.5.6.tar.xz
|
|
||||||
RUN python3 /tmp/install-python.py py3.7 https://www.python.org/ftp/python/3.7.2/Python-3.7.2.tar.xz
|
|
||||||
|
|
||||||
# Install kitty bundle
|
|
||||||
ENV SW=/home/circleci/sw
|
|
||||||
RUN python3 /tmp/install-python.py bundle https://download.calibre-ebook.com/travis/kitty/linux-64.tar.xz
|
|
||||||
RUN echo SW=$SW >> /etc/environment
|
|
||||||
|
|
||||||
# Clean unused files
|
|
||||||
RUN apt-get clean -y
|
|
||||||
|
|
||||||
USER circleci
|
|
||||||
|
|
||||||
LABEL com.circleci.preserve-entrypoint=true
|
|
||||||
ENTRYPOINT sleep 2h
|
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
# vim:fileencoding=utf-8
|
|
||||||
# License: GPLv3 Copyright: 2019, Kovid Goyal <kovid at kovidgoyal.net>
|
|
||||||
|
|
||||||
import io
|
|
||||||
import os
|
|
||||||
import shlex
|
|
||||||
import shutil
|
|
||||||
import subprocess
|
|
||||||
import sys
|
|
||||||
import tarfile
|
|
||||||
from urllib.request import urlopen
|
|
||||||
|
|
||||||
PY, URL = sys.argv[1], sys.argv[2]
|
|
||||||
if PY == 'bundle':
|
|
||||||
SW = os.environ['SW']
|
|
||||||
os.mkdir(SW)
|
|
||||||
os.chdir(SW)
|
|
||||||
else:
|
|
||||||
os.chdir('/usr/src')
|
|
||||||
|
|
||||||
|
|
||||||
def run(cmd):
|
|
||||||
cmd = shlex.split(cmd)
|
|
||||||
p = subprocess.Popen(cmd)
|
|
||||||
if p.wait() != 0:
|
|
||||||
raise SystemExit(p.returncode)
|
|
||||||
|
|
||||||
|
|
||||||
with urlopen(URL) as f:
|
|
||||||
data = f.read()
|
|
||||||
|
|
||||||
with tarfile.open(fileobj=io.BytesIO(data), mode='r:xz') as tf:
|
|
||||||
tf.extractall()
|
|
||||||
|
|
||||||
|
|
||||||
def replace_in_file(path, src, dest):
|
|
||||||
with open(path, 'r+') as f:
|
|
||||||
n = f.read().replace(src, dest)
|
|
||||||
f.seek(0), f.truncate()
|
|
||||||
f.write(n)
|
|
||||||
|
|
||||||
|
|
||||||
if PY == 'bundle':
|
|
||||||
replaced = 0
|
|
||||||
for dirpath, dirnames, filenames in os.walk(SW):
|
|
||||||
for f in filenames:
|
|
||||||
if f.endswith('.pc') or (f.endswith('.py') and f.startswith('_sysconfig')):
|
|
||||||
replace_in_file(os.path.join(dirpath, f), '/sw/sw', SW)
|
|
||||||
replaced += 1
|
|
||||||
if replaced < 2:
|
|
||||||
raise SystemExit('Failed to replace path to SW in bundle')
|
|
||||||
else:
|
|
||||||
src = os.path.abspath(tuple(os.listdir('.'))[0])
|
|
||||||
os.chdir(src)
|
|
||||||
run(f'./configure --prefix=/opt/{PY} --enable-shared --with-system-expat --without-ensurepip')
|
|
||||||
run(f'make -j {os.cpu_count()}')
|
|
||||||
run('make install')
|
|
||||||
os.chdir('/')
|
|
||||||
shutil.rmtree(src)
|
|
||||||
21
.editorconfig
Normal file
21
.editorconfig
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
indent_style = spaces
|
||||||
|
indent_size = 4
|
||||||
|
end_of_line = lf
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
|
||||||
|
[{Makefile,*.terminfo}]
|
||||||
|
indent_style = tab
|
||||||
|
|
||||||
|
# Autogenerated files with tabs below this line.
|
||||||
|
|
||||||
|
[kitty/{unicode-data.c,emoji.h,wcwidth-std.h}]
|
||||||
|
indent_style = tab
|
||||||
|
|
||||||
|
[kittens/unicode_input/names.h]
|
||||||
|
indent_style = tab
|
||||||
|
|
||||||
|
[glfw/wayland-*-protocol.{c,h}]
|
||||||
|
indent_style = tab
|
||||||
3
.gitattributes
vendored
3
.gitattributes
vendored
@@ -11,3 +11,6 @@ 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
|
||||||
|
|
||||||
|
*.py text diff=python
|
||||||
|
*.m text diff=objc
|
||||||
|
|||||||
34
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
34
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
---
|
||||||
|
name: Bug report
|
||||||
|
about: Create a bug report
|
||||||
|
title: ''
|
||||||
|
labels: bug
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Describe the bug**
|
||||||
|
A clear and concise description of what the bug is.
|
||||||
|
|
||||||
|
**To Reproduce**
|
||||||
|
Steps to reproduce the behavior:
|
||||||
|
1. XXX
|
||||||
|
2. YYY
|
||||||
|
3. ZZZ
|
||||||
|
4. See error
|
||||||
|
|
||||||
|
**Expected behavior**
|
||||||
|
A clear and concise description of what you expected to happen.
|
||||||
|
|
||||||
|
**Screenshots**
|
||||||
|
If applicable, add screenshots to help explain your problem.
|
||||||
|
|
||||||
|
**Environment details**
|
||||||
|
OS: Name and version of operating system(s)
|
||||||
|
|
||||||
|
```
|
||||||
|
Output of kitty --debug-config
|
||||||
|
```
|
||||||
|
|
||||||
|
**Additional context**
|
||||||
|
Try to reproduce the problem with `kitty --config NONE` if you cannot then post a minimal kitty.conf that reproduces the problem. If the problem involves interaction with some other terminal program post a minimal config for that program to reproduce the problem as well.
|
||||||
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
---
|
||||||
|
name: Feature request
|
||||||
|
about: Suggest an idea for this project
|
||||||
|
title: ''
|
||||||
|
labels: enhancement
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Is your feature request related to a problem? Please describe.**
|
||||||
|
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||||
|
|
||||||
|
**Describe the solution you'd like**
|
||||||
|
A clear and concise description of what you want to happen.
|
||||||
|
|
||||||
|
**Describe alternatives you've considered**
|
||||||
|
A clear and concise description of any alternative solutions or features you've considered.
|
||||||
|
|
||||||
|
**Additional context**
|
||||||
|
Add any other context or screenshots about the feature request here.
|
||||||
129
.github/workflows/ci.py
vendored
Normal file
129
.github/workflows/ci.py
vendored
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# vim:fileencoding=utf-8
|
||||||
|
# License: GPLv3 Copyright: 2020, Kovid Goyal <kovid at kovidgoyal.net>
|
||||||
|
|
||||||
|
import io
|
||||||
|
import os
|
||||||
|
import shlex
|
||||||
|
import shutil
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import tarfile
|
||||||
|
from urllib.request import urlopen
|
||||||
|
|
||||||
|
is_bundle = os.environ.get('KITTY_BUNDLE') == '1'
|
||||||
|
is_macos = 'darwin' in sys.platform.lower()
|
||||||
|
SW = None
|
||||||
|
|
||||||
|
|
||||||
|
def run(*a):
|
||||||
|
if len(a) == 1:
|
||||||
|
a = shlex.split(a[0])
|
||||||
|
print(' '.join(map(shlex.quote, a)))
|
||||||
|
sys.stdout.flush()
|
||||||
|
ret = subprocess.Popen(a).wait()
|
||||||
|
if ret != 0:
|
||||||
|
raise SystemExit(ret)
|
||||||
|
|
||||||
|
|
||||||
|
def install_deps():
|
||||||
|
print('Installing kitty dependencies...')
|
||||||
|
sys.stdout.flush()
|
||||||
|
if is_macos:
|
||||||
|
items = (x.strip() for x in open('Brewfile').readlines() if not x.startswith('#'))
|
||||||
|
run('brew', 'install', *items)
|
||||||
|
else:
|
||||||
|
run('sudo apt-get update')
|
||||||
|
run('sudo apt-get install -y libgl1-mesa-dev libxi-dev libxrandr-dev libxinerama-dev'
|
||||||
|
' libxcursor-dev libxcb-xkb-dev libdbus-1-dev libxkbcommon-dev libharfbuzz-dev'
|
||||||
|
' libpng-dev liblcms2-dev libfontconfig-dev libxkbcommon-x11-dev libcanberra-dev')
|
||||||
|
if is_bundle:
|
||||||
|
install_bundle()
|
||||||
|
else:
|
||||||
|
if is_macos:
|
||||||
|
# needed for zlib for pillow, should not be needed after pillow 8.0
|
||||||
|
os.environ['PKG_CONFIG_PATH'] = '/usr/local/opt/zlib/lib/pkgconfig'
|
||||||
|
run('pip3 install Pillow pygments')
|
||||||
|
|
||||||
|
|
||||||
|
def build_kitty():
|
||||||
|
python = shutil.which('python3') if is_bundle else sys.executable
|
||||||
|
cmd = '{} setup.py build --verbose'.format(python)
|
||||||
|
if os.environ.get('KITTY_SANITIZE') == '1':
|
||||||
|
cmd += ' --debug --sanitize'
|
||||||
|
run(cmd)
|
||||||
|
|
||||||
|
|
||||||
|
def test_kitty():
|
||||||
|
run('./kitty/launcher/kitty +launch test.py')
|
||||||
|
|
||||||
|
|
||||||
|
def package_kitty():
|
||||||
|
py = 'python3' if is_macos else 'python'
|
||||||
|
run(py + ' setup.py linux-package --update-check-interval=0 --verbose')
|
||||||
|
if is_macos:
|
||||||
|
run('python3 setup.py kitty.app --update-check-interval=0 --verbose')
|
||||||
|
run('kitty.app/Contents/MacOS/kitty +runpy "from kitty.constants import *; print(kitty_exe())"')
|
||||||
|
|
||||||
|
|
||||||
|
def replace_in_file(path, src, dest):
|
||||||
|
with open(path, 'r+') as f:
|
||||||
|
n = f.read().replace(src, dest)
|
||||||
|
f.seek(0), f.truncate()
|
||||||
|
f.write(n)
|
||||||
|
|
||||||
|
|
||||||
|
def setup_bundle_env():
|
||||||
|
global SW
|
||||||
|
os.environ['SW'] = SW = '/Users/Shared/kitty-build/sw/sw' if is_macos else os.path.join(os.environ['GITHUB_WORKSPACE'], 'sw')
|
||||||
|
os.environ['PKG_CONFIG_PATH'] = SW + '/lib/pkgconfig'
|
||||||
|
if is_macos:
|
||||||
|
os.environ['PATH'] = '{}:{}'.format('/usr/local/opt/sphinx-doc/bin', os.environ['PATH'])
|
||||||
|
else:
|
||||||
|
os.environ['LD_LIBRARY_PATH'] = SW + '/lib'
|
||||||
|
os.environ['PYTHONHOME'] = SW
|
||||||
|
os.environ['PATH'] = '{}:{}'.format(os.path.join(SW, 'bin'), os.environ['PATH'])
|
||||||
|
|
||||||
|
|
||||||
|
def install_bundle():
|
||||||
|
cwd = os.getcwd()
|
||||||
|
os.makedirs(SW)
|
||||||
|
os.chdir(SW)
|
||||||
|
with urlopen('https://download.calibre-ebook.com/ci/kitty/{}-64.tar.xz'.format(
|
||||||
|
'macos' if is_macos else 'linux')) as f:
|
||||||
|
data = f.read()
|
||||||
|
with tarfile.open(fileobj=io.BytesIO(data), mode='r:xz') as tf:
|
||||||
|
tf.extractall()
|
||||||
|
if not is_macos:
|
||||||
|
replaced = 0
|
||||||
|
for dirpath, dirnames, filenames in os.walk('.'):
|
||||||
|
for f in filenames:
|
||||||
|
if f.endswith('.pc') or (f.endswith('.py') and f.startswith('_sysconfig')):
|
||||||
|
replace_in_file(os.path.join(dirpath, f), '/sw/sw', SW)
|
||||||
|
replaced += 1
|
||||||
|
if replaced < 2:
|
||||||
|
raise SystemExit('Failed to replace path to SW in bundle')
|
||||||
|
os.chdir(cwd)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
if is_bundle:
|
||||||
|
setup_bundle_env()
|
||||||
|
else:
|
||||||
|
if not is_macos and 'pythonLocation' in os.environ:
|
||||||
|
os.environ['LD_LIBRARY_PATH'] = '{}/lib'.format(os.environ['pythonLocation'])
|
||||||
|
action = sys.argv[-1]
|
||||||
|
if action in ('build', 'package'):
|
||||||
|
install_deps()
|
||||||
|
if action == 'build':
|
||||||
|
build_kitty()
|
||||||
|
elif action == 'package':
|
||||||
|
package_kitty()
|
||||||
|
elif action == 'test':
|
||||||
|
test_kitty()
|
||||||
|
else:
|
||||||
|
raise SystemExit('Unknown action: ' + action)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
132
.github/workflows/ci.yml
vendored
Normal file
132
.github/workflows/ci.yml
vendored
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
name: CI
|
||||||
|
on: [push, pull_request]
|
||||||
|
env:
|
||||||
|
CI: 'true'
|
||||||
|
ASAN_OPTIONS: leak_check_at_exit=0
|
||||||
|
LC_ALL: en_US.UTF-8
|
||||||
|
LANG: en_US.UTF-8
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
linux:
|
||||||
|
name: Linux (python=${{ matrix.pyver }} cc=${{ matrix.cc }} sanitize=${{ matrix.sanitize }})
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
env:
|
||||||
|
CC: ${{ matrix.cc }}
|
||||||
|
KITTY_SANITIZE: ${{ matrix.sanitize }}
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
python: [a, b, c]
|
||||||
|
cc: [gcc, clang]
|
||||||
|
include:
|
||||||
|
- python: a
|
||||||
|
pyver: 3.6
|
||||||
|
sanitize: 0
|
||||||
|
|
||||||
|
- python: b
|
||||||
|
pyver: 3.7
|
||||||
|
sanitize: 1
|
||||||
|
|
||||||
|
- python: c
|
||||||
|
pyver: 3.8
|
||||||
|
sanitize: 1
|
||||||
|
|
||||||
|
|
||||||
|
exclude:
|
||||||
|
- python: a
|
||||||
|
cc: clang
|
||||||
|
- python: b
|
||||||
|
cc: clang
|
||||||
|
- python: c
|
||||||
|
cc: gcc
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout source code
|
||||||
|
uses: actions/checkout@master
|
||||||
|
with:
|
||||||
|
fetch-depth: 10
|
||||||
|
- name: Set up Python ${{ matrix.pyver }}
|
||||||
|
uses: actions/setup-python@master
|
||||||
|
with:
|
||||||
|
python-version: ${{ matrix.pyver }}
|
||||||
|
|
||||||
|
- name: Build kitty
|
||||||
|
run: python .github/workflows/ci.py build
|
||||||
|
|
||||||
|
- name: Test kitty
|
||||||
|
run: python .github/workflows/ci.py test
|
||||||
|
|
||||||
|
linux-package:
|
||||||
|
name: Linux package
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
env:
|
||||||
|
CFLAGS: -funsigned-char
|
||||||
|
steps:
|
||||||
|
- name: Checkout source code
|
||||||
|
uses: actions/checkout@master
|
||||||
|
with:
|
||||||
|
fetch-depth: 10
|
||||||
|
|
||||||
|
- name: Test for trailing whitespace
|
||||||
|
run: if grep -Inr '\s$' kitty kitty_tests kittens docs *.py *.asciidoc *.rst .gitattributes .gitignore; then echo Trailing whitespace found, aborting.; exit 1; fi
|
||||||
|
|
||||||
|
- name: Set up Python
|
||||||
|
uses: actions/setup-python@master
|
||||||
|
with:
|
||||||
|
python-version: 3.8
|
||||||
|
|
||||||
|
- name: Install build-only deps
|
||||||
|
run: pip install flake8 mypy sphinx
|
||||||
|
|
||||||
|
- name: Run pyflakes
|
||||||
|
run: python -m flake8 --count .
|
||||||
|
|
||||||
|
- name: Build kitty package
|
||||||
|
run: python .github/workflows/ci.py package
|
||||||
|
|
||||||
|
- name: Run mypy
|
||||||
|
run: python test.py mypy
|
||||||
|
|
||||||
|
- name: Build man page
|
||||||
|
run: make FAIL_WARN=-W man
|
||||||
|
|
||||||
|
- name: Build HTML docs
|
||||||
|
run: make FAIL_WARN=-W html
|
||||||
|
|
||||||
|
bundle:
|
||||||
|
name: Bundle test (${{ matrix.os }})
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-latest, macos-latest]
|
||||||
|
env:
|
||||||
|
KITTY_BUNDLE: 1
|
||||||
|
steps:
|
||||||
|
- name: Checkout source code
|
||||||
|
uses: actions/checkout@master
|
||||||
|
with:
|
||||||
|
fetch-depth: 10
|
||||||
|
|
||||||
|
- name: Build kitty
|
||||||
|
run: which python3 && python3 .github/workflows/ci.py build
|
||||||
|
|
||||||
|
- name: Test kitty
|
||||||
|
run: python3 .github/workflows/ci.py test
|
||||||
|
|
||||||
|
brew:
|
||||||
|
name: macOS Brew
|
||||||
|
runs-on: macos-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout source code
|
||||||
|
uses: actions/checkout@master
|
||||||
|
with:
|
||||||
|
fetch-depth: 10
|
||||||
|
|
||||||
|
- name: Build kitty
|
||||||
|
run: python3 .github/workflows/ci.py build
|
||||||
|
|
||||||
|
- name: Test kitty
|
||||||
|
run: python3 .github/workflows/ci.py test
|
||||||
|
|
||||||
|
- name: Build kitty package
|
||||||
|
run: python3 .github/workflows/ci.py package
|
||||||
41
.github/workflows/codeql-analysis.yml
vendored
Normal file
41
.github/workflows/codeql-analysis.yml
vendored
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
name: "Code scanning - action"
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [master, ]
|
||||||
|
pull_request:
|
||||||
|
# The branches below must be a subset of the branches above
|
||||||
|
branches: [master]
|
||||||
|
schedule:
|
||||||
|
- cron: '0 22 * * 5'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
CodeQL-Build:
|
||||||
|
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
# We must fetch at least the immediate parents so that if this is
|
||||||
|
# a pull request then we can checkout the head.
|
||||||
|
fetch-depth: 2
|
||||||
|
|
||||||
|
# If this run was triggered by a pull request event, then checkout
|
||||||
|
# the head of the pull request instead of the merge commit.
|
||||||
|
- run: git checkout HEAD^2
|
||||||
|
if: ${{ github.event_name == 'pull_request' }}
|
||||||
|
|
||||||
|
# Initializes the CodeQL tools for scanning.
|
||||||
|
- name: Initialize CodeQL
|
||||||
|
uses: github/codeql-action/init@v1
|
||||||
|
# Override language selection by uncommenting this and choosing your languages
|
||||||
|
# with:
|
||||||
|
# languages: go, javascript, csharp, python, cpp, java
|
||||||
|
|
||||||
|
- name: Build kitty
|
||||||
|
run: python3 .github/workflows/ci.py build
|
||||||
|
|
||||||
|
- name: Perform CodeQL Analysis
|
||||||
|
uses: github/codeql-action/analyze@v1
|
||||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -1,6 +1,8 @@
|
|||||||
*.so
|
*.so
|
||||||
*.pyc
|
*.pyc
|
||||||
*.pyo
|
*.pyo
|
||||||
|
*_stub.pyi
|
||||||
|
/.dmypy.json
|
||||||
/tags
|
/tags
|
||||||
/build/
|
/build/
|
||||||
/linux-package/
|
/linux-package/
|
||||||
@@ -14,4 +16,6 @@ __pycache__/
|
|||||||
/glfw/wayland-*-client-protocol.[ch]
|
/glfw/wayland-*-client-protocol.[ch]
|
||||||
/docs/_build/
|
/docs/_build/
|
||||||
/docs/generated/
|
/docs/generated/
|
||||||
|
/.mypy_cache
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
bypy/b
|
||||||
|
|||||||
11
Brewfile
11
Brewfile
@@ -1,5 +1,6 @@
|
|||||||
brew 'pkg-config'
|
pkg-config
|
||||||
brew 'imagemagick'
|
zlib
|
||||||
brew 'harfbuzz'
|
python
|
||||||
brew 'python'
|
imagemagick
|
||||||
brew 'sphinx-doc'
|
harfbuzz
|
||||||
|
sphinx-doc
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
### Reporting bugs
|
### Reporting bugs
|
||||||
|
|
||||||
Please first search existing bug reports (especially closed ones) for a report
|
Please first search existing bug reports (especially closed ones) for a report
|
||||||
that matches your issue.
|
that matches your issue.
|
||||||
|
|
||||||
When reporting a bug, provide full details of your environment, that means, at
|
When reporting a bug, provide full details of your environment, that means, at
|
||||||
a minimum, kitty version, OS and OS version, kitty config (ideally a minimal
|
a minimum, kitty version, OS and OS version, kitty config (ideally a minimal
|
||||||
|
|||||||
@@ -1,7 +1,3 @@
|
|||||||
To build from source:
|
To build from source: <https://sw.kovidgoyal.net/kitty/build.html>
|
||||||
|
|
||||||
https://sw.kovidgoyal.net/kitty/build.html
|
Pre-built binaries: <https://sw.kovidgoyal.net/kitty/binary.html>
|
||||||
|
|
||||||
Pre-built binaries:
|
|
||||||
|
|
||||||
https://sw.kovidgoyal.net/kitty/binary.html
|
|
||||||
|
|||||||
@@ -2,4 +2,4 @@
|
|||||||
|
|
||||||
See https://sw.kovidgoyal.net/kitty/
|
See https://sw.kovidgoyal.net/kitty/
|
||||||
|
|
||||||
image:https://circleci.com/gh/kovidgoyal/kitty.svg?style=svg["Build status", link="https://circleci.com/gh/kovidgoyal/kitty"]
|
image:https://github.com/kovidgoyal/kitty/workflows/CI/badge.svg["Build status", link="https://github.com/kovidgoyal/kitty/actions?query=workflow%3ACI"]
|
||||||
|
|||||||
62
__main__.py
62
__main__.py
@@ -4,54 +4,56 @@
|
|||||||
|
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
|
from typing import List
|
||||||
|
|
||||||
|
|
||||||
def icat(args):
|
def icat(args: List[str]) -> None:
|
||||||
from kittens.runner import run_kitten
|
from kittens.runner import run_kitten as rk
|
||||||
sys.argv = args
|
sys.argv = args
|
||||||
run_kitten('icat')
|
rk('icat')
|
||||||
|
|
||||||
|
|
||||||
def list_fonts(args):
|
def list_fonts(args: List[str]) -> None:
|
||||||
from kitty.fonts.list import main
|
from kitty.fonts.list import main as list_main
|
||||||
main(args)
|
list_main(args)
|
||||||
|
|
||||||
|
|
||||||
def remote_control(args):
|
def remote_control(args: List[str]) -> None:
|
||||||
from kitty.remote_control import main
|
from kitty.remote_control import main as rc_main
|
||||||
main(args)
|
rc_main(args)
|
||||||
|
|
||||||
|
|
||||||
def runpy(args):
|
def runpy(args: List[str]) -> None:
|
||||||
sys.argv = ['kitty'] + args[2:]
|
sys.argv = ['kitty'] + args[2:]
|
||||||
exec(args[1])
|
exec(args[1])
|
||||||
|
|
||||||
|
|
||||||
def hold(args):
|
def hold(args: List[str]) -> None:
|
||||||
import subprocess
|
import subprocess
|
||||||
ret = subprocess.Popen(args[1:]).wait()
|
ret = subprocess.Popen(args[1:]).wait()
|
||||||
sys.stdin.read()
|
sys.stdin.read()
|
||||||
raise SystemExit(ret)
|
raise SystemExit(ret)
|
||||||
|
|
||||||
|
|
||||||
def complete(args):
|
def complete(args: List[str]) -> None:
|
||||||
from kitty.complete import main
|
from kitty.complete import main as complete_main
|
||||||
main(args[1:], entry_points, namespaced_entry_points)
|
complete_main(args[1:], entry_points, namespaced_entry_points)
|
||||||
|
|
||||||
|
|
||||||
def launch(args):
|
def launch(args: List[str]) -> None:
|
||||||
import runpy
|
import runpy
|
||||||
sys.argv = args[1:]
|
sys.argv = args[1:]
|
||||||
exe = args[1]
|
exe = args[1]
|
||||||
if exe.startswith(':'):
|
if exe.startswith(':'):
|
||||||
import shutil
|
import shutil
|
||||||
exe = shutil.which(exe[1:])
|
q = shutil.which(exe[1:])
|
||||||
if not exe:
|
if not q:
|
||||||
raise SystemExit('{} not found in PATH'.format(args[1][1:]))
|
raise SystemExit('{} not found in PATH'.format(args[1][1:]))
|
||||||
|
exe = q
|
||||||
runpy.run_path(exe, run_name='__main__')
|
runpy.run_path(exe, run_name='__main__')
|
||||||
|
|
||||||
|
|
||||||
def run_kitten(args):
|
def run_kitten(args: List[str]) -> None:
|
||||||
try:
|
try:
|
||||||
kitten = args[1]
|
kitten = args[1]
|
||||||
except IndexError:
|
except IndexError:
|
||||||
@@ -59,11 +61,16 @@ def run_kitten(args):
|
|||||||
list_kittens()
|
list_kittens()
|
||||||
raise SystemExit(1)
|
raise SystemExit(1)
|
||||||
sys.argv = args[1:]
|
sys.argv = args[1:]
|
||||||
from kittens.runner import run_kitten
|
from kittens.runner import run_kitten as rk
|
||||||
run_kitten(kitten)
|
rk(kitten)
|
||||||
|
|
||||||
|
|
||||||
def namespaced(args):
|
def edit_config_file(args: List[str]) -> None:
|
||||||
|
from kitty.utils import edit_config_file as f
|
||||||
|
f()
|
||||||
|
|
||||||
|
|
||||||
|
def namespaced(args: List[str]) -> None:
|
||||||
func = namespaced_entry_points[args[1]]
|
func = namespaced_entry_points[args[1]]
|
||||||
func(args[1:])
|
func(args[1:])
|
||||||
|
|
||||||
@@ -75,6 +82,7 @@ entry_points = {
|
|||||||
'runpy': runpy,
|
'runpy': runpy,
|
||||||
'launch': launch,
|
'launch': launch,
|
||||||
'kitten': run_kitten,
|
'kitten': run_kitten,
|
||||||
|
'edit-config': edit_config_file,
|
||||||
|
|
||||||
'@': remote_control,
|
'@': remote_control,
|
||||||
'+': namespaced,
|
'+': namespaced,
|
||||||
@@ -84,7 +92,7 @@ namespaced_entry_points['hold'] = hold
|
|||||||
namespaced_entry_points['complete'] = complete
|
namespaced_entry_points['complete'] = complete
|
||||||
|
|
||||||
|
|
||||||
def setup_openssl_environment():
|
def setup_openssl_environment() -> None:
|
||||||
# Workaround for Linux distros that have still failed to get their heads
|
# Workaround for Linux distros that have still failed to get their heads
|
||||||
# out of their asses and implement a common location for SSL certificates.
|
# out of their asses and implement a common location for SSL certificates.
|
||||||
# It's not that hard people, there exists a wonderful tool called the symlink
|
# It's not that hard people, there exists a wonderful tool called the symlink
|
||||||
@@ -92,13 +100,13 @@ 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'
|
setattr(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'
|
setattr(sys, 'kitty_ssl_env_var', 'SSL_CERT_DIR')
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main() -> None:
|
||||||
if getattr(sys, 'frozen', False) and 'darwin' not in sys.platform.lower():
|
if getattr(sys, 'frozen', False) and 'darwin' not in sys.platform.lower():
|
||||||
setup_openssl_environment()
|
setup_openssl_environment()
|
||||||
first_arg = '' if len(sys.argv) < 2 else sys.argv[1]
|
first_arg = '' if len(sys.argv) < 2 else sys.argv[1]
|
||||||
@@ -109,8 +117,8 @@ def main():
|
|||||||
elif first_arg.startswith('+'):
|
elif first_arg.startswith('+'):
|
||||||
namespaced(['+', first_arg[1:]] + sys.argv[2:])
|
namespaced(['+', first_arg[1:]] + sys.argv[2:])
|
||||||
else:
|
else:
|
||||||
from kitty.main import main
|
from kitty.main import main as kitty_main
|
||||||
main()
|
kitty_main()
|
||||||
else:
|
else:
|
||||||
func(sys.argv[1:])
|
func(sys.argv[1:])
|
||||||
|
|
||||||
|
|||||||
91
bypy/init_env.py
Normal file
91
bypy/init_env.py
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# vim:fileencoding=utf-8
|
||||||
|
# License: GPLv3 Copyright: 2020, Kovid Goyal <kovid at kovidgoyal.net>
|
||||||
|
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import shutil
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
from contextlib import suppress
|
||||||
|
|
||||||
|
from bypy.constants import (
|
||||||
|
LIBDIR, PREFIX, PYTHON, SRC as KITTY_DIR, ismacos, worker_env
|
||||||
|
)
|
||||||
|
from bypy.utils import run_shell
|
||||||
|
|
||||||
|
|
||||||
|
def read_src_file(name):
|
||||||
|
with open(os.path.join(KITTY_DIR, 'kitty', name), 'rb') as f:
|
||||||
|
return f.read().decode('utf-8')
|
||||||
|
|
||||||
|
|
||||||
|
def initialize_constants():
|
||||||
|
kitty_constants = {}
|
||||||
|
src = read_src_file('constants.py')
|
||||||
|
nv = re.search(r'Version\((\d+), (\d+), (\d+)\)', src)
|
||||||
|
kitty_constants['version'] = '%s.%s.%s' % (nv.group(1), nv.group(2), nv.group(3))
|
||||||
|
kitty_constants['appname'] = re.search(
|
||||||
|
r'appname: str\s+=\s+(u{0,1})[\'"]([^\'"]+)[\'"]', src
|
||||||
|
).group(2)
|
||||||
|
return kitty_constants
|
||||||
|
|
||||||
|
|
||||||
|
def run(*args, **extra_env):
|
||||||
|
env = os.environ.copy()
|
||||||
|
env.update(worker_env)
|
||||||
|
env.update(extra_env)
|
||||||
|
env['SW'] = PREFIX
|
||||||
|
env['LD_LIBRARY_PATH'] = LIBDIR
|
||||||
|
if ismacos:
|
||||||
|
env['PKGCONFIG_EXE'] = os.path.join(PREFIX, 'bin', 'pkg-config')
|
||||||
|
cwd = env.pop('cwd', KITTY_DIR)
|
||||||
|
return subprocess.call(list(args), env=env, cwd=cwd)
|
||||||
|
|
||||||
|
|
||||||
|
def build_c_extensions(ext_dir, args):
|
||||||
|
writeable_src_dir = os.path.join(ext_dir, 'src')
|
||||||
|
shutil.copytree(
|
||||||
|
KITTY_DIR, writeable_src_dir, symlinks=True,
|
||||||
|
ignore=shutil.ignore_patterns('b', 'build', 'dist', '*_commands.json', '*.o'))
|
||||||
|
|
||||||
|
# Build the launcher as it is needed for the spawn test
|
||||||
|
with suppress(FileNotFoundError):
|
||||||
|
os.remove(os.path.join(writeable_src_dir, 'kitty', 'launcher', 'kitty'))
|
||||||
|
if run(PYTHON, 'setup.py', 'build-launcher', cwd=writeable_src_dir) != 0:
|
||||||
|
print('Building of kitty launcher failed', file=sys.stderr)
|
||||||
|
os.chdir(KITTY_DIR)
|
||||||
|
run_shell()
|
||||||
|
raise SystemExit('Building of kitty launcher failed')
|
||||||
|
|
||||||
|
cmd = [PYTHON, 'setup.py']
|
||||||
|
bundle = 'macos-freeze' if ismacos else 'linux-freeze'
|
||||||
|
cmd.append(bundle)
|
||||||
|
dest = kitty_constants['appname'] + ('.app' if ismacos else '')
|
||||||
|
dest = os.path.join(ext_dir, dest)
|
||||||
|
cmd += ['--prefix', dest]
|
||||||
|
if run(*cmd, cwd=writeable_src_dir) != 0:
|
||||||
|
print('Building of kitty package failed', file=sys.stderr)
|
||||||
|
os.chdir(KITTY_DIR)
|
||||||
|
run_shell()
|
||||||
|
raise SystemExit('Building of kitty package failed')
|
||||||
|
return ext_dir
|
||||||
|
|
||||||
|
|
||||||
|
def run_tests(path_to_kitty, cwd_on_failure):
|
||||||
|
kw = {'cwd': cwd_on_failure}
|
||||||
|
if not ismacos:
|
||||||
|
# this is needed for the spawn test which starts an interpreter
|
||||||
|
# using the kitty launcher.
|
||||||
|
kw['PYTHONHOME'] = PREFIX
|
||||||
|
ret = run(PYTHON, 'test.py', **kw)
|
||||||
|
if ret != 0:
|
||||||
|
os.chdir(cwd_on_failure)
|
||||||
|
print(
|
||||||
|
'running kitty tests failed with return code:', ret, file=sys.stderr)
|
||||||
|
run_shell()
|
||||||
|
raise SystemExit('running kitty tests failed')
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == 'program':
|
||||||
|
kitty_constants = initialize_constants()
|
||||||
3
bypy/linux.conf
Normal file
3
bypy/linux.conf
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
image 'https://partner-images.canonical.com/core/xenial/current/ubuntu-xenial-core-cloudimg-{}-root.tar.gz'
|
||||||
|
|
||||||
|
deps 'bison flex libxcursor-dev libxrandr-dev libxi-dev libxinerama-dev libgl1-mesa-dev libxcb-xkb-dev libfontconfig1-dev libdbus-1-dev'
|
||||||
209
bypy/linux/__main__.py
Normal file
209
bypy/linux/__main__.py
Normal file
@@ -0,0 +1,209 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# vim:fileencoding=utf-8
|
||||||
|
# License: GPLv3 Copyright: 2020, Kovid Goyal <kovid at kovidgoyal.net>
|
||||||
|
|
||||||
|
import errno
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
import stat
|
||||||
|
import subprocess
|
||||||
|
import tarfile
|
||||||
|
import time
|
||||||
|
|
||||||
|
from bypy.constants import (
|
||||||
|
OUTPUT_DIR, PREFIX, is64bit, python_major_minor_version
|
||||||
|
)
|
||||||
|
from bypy.utils import get_dll_path, py_compile, walk
|
||||||
|
|
||||||
|
j = os.path.join
|
||||||
|
self_dir = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
arch = 'x86_64' if is64bit else 'i686'
|
||||||
|
|
||||||
|
py_ver = '.'.join(map(str, python_major_minor_version()))
|
||||||
|
iv = globals()['init_env']
|
||||||
|
kitty_constants = iv['kitty_constants']
|
||||||
|
|
||||||
|
|
||||||
|
def binary_includes():
|
||||||
|
return tuple(map(get_dll_path, (
|
||||||
|
'expat', 'sqlite3', 'ffi', 'z', 'lzma', 'png16', 'lcms2',
|
||||||
|
|
||||||
|
# dont include freetype because fontconfig is closely coupled to it
|
||||||
|
# and also distros often patch freetype
|
||||||
|
# 'iconv.so.2', 'pcre.so.1', 'graphite2.so.3', 'glib-2.0.so.0', 'freetype.so.6',
|
||||||
|
|
||||||
|
'harfbuzz', 'xkbcommon', 'xkbcommon-x11',
|
||||||
|
'ncursesw', 'readline',
|
||||||
|
))) + (
|
||||||
|
get_dll_path('bz2', 2), get_dll_path('ssl', 2), get_dll_path('crypto', 2),
|
||||||
|
get_dll_path('python' + py_ver, 2),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class Env:
|
||||||
|
|
||||||
|
def __init__(self, package_dir):
|
||||||
|
self.base = package_dir
|
||||||
|
self.lib_dir = j(self.base, 'lib')
|
||||||
|
self.py_dir = j(self.lib_dir, 'python' + py_ver)
|
||||||
|
os.makedirs(self.py_dir)
|
||||||
|
self.bin_dir = j(self.base, 'bin')
|
||||||
|
|
||||||
|
|
||||||
|
def ignore_in_lib(base, items, ignored_dirs=None):
|
||||||
|
ans = []
|
||||||
|
if ignored_dirs is None:
|
||||||
|
ignored_dirs = {'.svn', '.bzr', '.git', 'test', 'tests', 'testing'}
|
||||||
|
for name in items:
|
||||||
|
path = j(base, name)
|
||||||
|
if os.path.isdir(path):
|
||||||
|
if name in ignored_dirs or not os.path.exists(j(path, '__init__.py')):
|
||||||
|
if name != 'plugins':
|
||||||
|
ans.append(name)
|
||||||
|
else:
|
||||||
|
if name.rpartition('.')[-1] not in ('so', 'py'):
|
||||||
|
ans.append(name)
|
||||||
|
return ans
|
||||||
|
|
||||||
|
|
||||||
|
def import_site_packages(srcdir, dest):
|
||||||
|
if not os.path.exists(dest):
|
||||||
|
os.mkdir(dest)
|
||||||
|
for x in os.listdir(srcdir):
|
||||||
|
ext = x.rpartition('.')[-1]
|
||||||
|
f = j(srcdir, x)
|
||||||
|
if ext in ('py', 'so'):
|
||||||
|
shutil.copy2(f, dest)
|
||||||
|
elif ext == 'pth' and x != 'setuptools.pth':
|
||||||
|
for line in open(f, 'rb').read().splitlines():
|
||||||
|
src = os.path.abspath(j(srcdir, line))
|
||||||
|
if os.path.exists(src) and os.path.isdir(src):
|
||||||
|
import_site_packages(src, dest)
|
||||||
|
elif os.path.exists(j(f, '__init__.py')):
|
||||||
|
shutil.copytree(f, j(dest, x), ignore=ignore_in_lib)
|
||||||
|
|
||||||
|
|
||||||
|
def copy_libs(env):
|
||||||
|
print('Copying libs...')
|
||||||
|
|
||||||
|
for x in binary_includes():
|
||||||
|
dest = env.bin_dir if '/bin/' in x else env.lib_dir
|
||||||
|
shutil.copy2(x, dest)
|
||||||
|
|
||||||
|
|
||||||
|
def copy_python(env):
|
||||||
|
print('Copying python...')
|
||||||
|
srcdir = j(PREFIX, 'lib/python' + py_ver)
|
||||||
|
|
||||||
|
for x in os.listdir(srcdir):
|
||||||
|
y = j(srcdir, x)
|
||||||
|
ext = os.path.splitext(x)[1]
|
||||||
|
if os.path.isdir(y) and x not in ('test', 'hotshot', 'distutils', 'tkinter', 'turtledemo',
|
||||||
|
'site-packages', 'idlelib', 'lib2to3', 'dist-packages'):
|
||||||
|
shutil.copytree(y, j(env.py_dir, x), ignore=ignore_in_lib)
|
||||||
|
if os.path.isfile(y) and ext in ('.py', '.so'):
|
||||||
|
shutil.copy2(y, env.py_dir)
|
||||||
|
|
||||||
|
srcdir = j(srcdir, 'site-packages')
|
||||||
|
dest = j(env.py_dir, 'site-packages')
|
||||||
|
import_site_packages(srcdir, dest)
|
||||||
|
py_compile(env.py_dir)
|
||||||
|
py_compile(os.path.join(env.base, 'lib', 'kitty'))
|
||||||
|
|
||||||
|
|
||||||
|
def is_elf(path):
|
||||||
|
with open(path, 'rb') as f:
|
||||||
|
return f.read(4) == b'\x7fELF'
|
||||||
|
|
||||||
|
|
||||||
|
def fix_permissions(files):
|
||||||
|
for path in files:
|
||||||
|
os.chmod(path, 0o755)
|
||||||
|
|
||||||
|
|
||||||
|
STRIPCMD = ['strip']
|
||||||
|
|
||||||
|
|
||||||
|
def find_binaries(env):
|
||||||
|
files = {j(env.bin_dir, x) for x in os.listdir(env.bin_dir)} | {
|
||||||
|
x for x in {
|
||||||
|
j(os.path.dirname(env.bin_dir), x) for x in os.listdir(env.bin_dir)} if os.path.exists(x)}
|
||||||
|
for x in walk(env.lib_dir):
|
||||||
|
x = os.path.realpath(x)
|
||||||
|
if x not in files and is_elf(x):
|
||||||
|
files.add(x)
|
||||||
|
return files
|
||||||
|
|
||||||
|
|
||||||
|
def strip_files(files, argv_max=(256 * 1024)):
|
||||||
|
""" Strip a list of files """
|
||||||
|
while files:
|
||||||
|
cmd = list(STRIPCMD)
|
||||||
|
pathlen = sum(len(s) + 1 for s in cmd)
|
||||||
|
while pathlen < argv_max and files:
|
||||||
|
f = files.pop()
|
||||||
|
cmd.append(f)
|
||||||
|
pathlen += len(f) + 1
|
||||||
|
if len(cmd) > len(STRIPCMD):
|
||||||
|
all_files = cmd[len(STRIPCMD):]
|
||||||
|
unwritable_files = tuple(filter(None, (None if os.access(x, os.W_OK) else (x, os.stat(x).st_mode) for x in all_files)))
|
||||||
|
[os.chmod(x, stat.S_IWRITE | old_mode) for x, old_mode in unwritable_files]
|
||||||
|
subprocess.check_call(cmd)
|
||||||
|
[os.chmod(x, old_mode) for x, old_mode in unwritable_files]
|
||||||
|
|
||||||
|
|
||||||
|
def strip_binaries(files):
|
||||||
|
print('Stripping %d files...' % len(files))
|
||||||
|
before = sum(os.path.getsize(x) for x in files)
|
||||||
|
strip_files(files)
|
||||||
|
after = sum(os.path.getsize(x) for x in files)
|
||||||
|
print('Stripped %.1f MB' % ((before - after) / (1024 * 1024.)))
|
||||||
|
|
||||||
|
|
||||||
|
def create_tarfile(env, compression_level='9'):
|
||||||
|
print('Creating archive...')
|
||||||
|
base = OUTPUT_DIR
|
||||||
|
try:
|
||||||
|
shutil.rmtree(base)
|
||||||
|
except OSError as err:
|
||||||
|
if err.errno != errno.ENOENT:
|
||||||
|
raise
|
||||||
|
os.mkdir(base)
|
||||||
|
dist = os.path.join(base, '%s-%s-%s.tar' % (kitty_constants['appname'], kitty_constants['version'], arch))
|
||||||
|
with tarfile.open(dist, mode='w', format=tarfile.PAX_FORMAT) as tf:
|
||||||
|
cwd = os.getcwd()
|
||||||
|
os.chdir(env.base)
|
||||||
|
try:
|
||||||
|
for x in os.listdir('.'):
|
||||||
|
tf.add(x)
|
||||||
|
finally:
|
||||||
|
os.chdir(cwd)
|
||||||
|
print('Compressing archive...')
|
||||||
|
ans = dist.rpartition('.')[0] + '.txz'
|
||||||
|
start_time = time.time()
|
||||||
|
subprocess.check_call(['xz', '--threads=0', '-f', '-' + compression_level, dist])
|
||||||
|
secs = time.time() - start_time
|
||||||
|
print('Compressed in %d minutes %d seconds' % (secs // 60, secs % 60))
|
||||||
|
os.rename(dist + '.xz', ans)
|
||||||
|
print('Archive %s created: %.2f MB' % (
|
||||||
|
os.path.basename(ans), os.stat(ans).st_size / (1024.**2)))
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
args = globals()['args']
|
||||||
|
ext_dir = globals()['ext_dir']
|
||||||
|
if not args.skip_tests:
|
||||||
|
run_tests = iv['run_tests']
|
||||||
|
run_tests(None, os.path.join(ext_dir, 'src'))
|
||||||
|
env = Env(os.path.join(ext_dir, kitty_constants['appname']))
|
||||||
|
copy_libs(env)
|
||||||
|
copy_python(env)
|
||||||
|
files = find_binaries(env)
|
||||||
|
fix_permissions(files)
|
||||||
|
if not args.dont_strip:
|
||||||
|
strip_binaries(files)
|
||||||
|
create_tarfile(env, args.compression_level)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
6
bypy/macos.conf
Normal file
6
bypy/macos.conf
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
# Requires installation of XCode 10.3 and Python 3 and
|
||||||
|
# python3 -m pip install certifi
|
||||||
|
|
||||||
|
vm_name 'macos-kitty-build'
|
||||||
|
root '/Users/Shared/kitty-build'
|
||||||
|
python '/usr/local/bin/python3'
|
||||||
460
bypy/macos/__main__.py
Normal file
460
bypy/macos/__main__.py
Normal file
@@ -0,0 +1,460 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# vim:fileencoding=utf-8
|
||||||
|
# License: GPLv3 Copyright: 2020, Kovid Goyal <kovid at kovidgoyal.net>
|
||||||
|
|
||||||
|
import glob
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
import stat
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import tempfile
|
||||||
|
import zipfile
|
||||||
|
|
||||||
|
from bypy.constants import PREFIX, PYTHON, SW, python_major_minor_version
|
||||||
|
from bypy.macos_sign import (
|
||||||
|
codesign, create_entitlements_file, make_certificate_useable, notarize_app,
|
||||||
|
verify_signature
|
||||||
|
)
|
||||||
|
from bypy.utils import current_dir, py_compile, run_shell, timeit, walk
|
||||||
|
|
||||||
|
iv = globals()['init_env']
|
||||||
|
kitty_constants = iv['kitty_constants']
|
||||||
|
join = os.path.join
|
||||||
|
basename = os.path.basename
|
||||||
|
abspath = os.path.abspath
|
||||||
|
APPNAME = kitty_constants['appname']
|
||||||
|
VERSION = kitty_constants['version']
|
||||||
|
py_ver = '.'.join(map(str, python_major_minor_version()))
|
||||||
|
|
||||||
|
|
||||||
|
def flush(func):
|
||||||
|
def ff(*args, **kwargs):
|
||||||
|
sys.stdout.flush()
|
||||||
|
sys.stderr.flush()
|
||||||
|
ret = func(*args, **kwargs)
|
||||||
|
sys.stdout.flush()
|
||||||
|
sys.stderr.flush()
|
||||||
|
return ret
|
||||||
|
|
||||||
|
return ff
|
||||||
|
|
||||||
|
|
||||||
|
def flipwritable(fn, mode=None):
|
||||||
|
"""
|
||||||
|
Flip the writability of a file and return the old mode. Returns None
|
||||||
|
if the file is already writable.
|
||||||
|
"""
|
||||||
|
if os.access(fn, os.W_OK):
|
||||||
|
return None
|
||||||
|
old_mode = os.stat(fn).st_mode
|
||||||
|
os.chmod(fn, stat.S_IWRITE | old_mode)
|
||||||
|
return old_mode
|
||||||
|
|
||||||
|
|
||||||
|
STRIPCMD = ('/usr/bin/strip', '-x', '-S', '-')
|
||||||
|
|
||||||
|
|
||||||
|
def strip_files(files, argv_max=(256 * 1024)):
|
||||||
|
"""
|
||||||
|
Strip a list of files
|
||||||
|
"""
|
||||||
|
tostrip = [(fn, flipwritable(fn)) for fn in files if os.path.exists(fn)]
|
||||||
|
while tostrip:
|
||||||
|
cmd = list(STRIPCMD)
|
||||||
|
flips = []
|
||||||
|
pathlen = sum(len(s) + 1 for s in cmd)
|
||||||
|
while pathlen < argv_max:
|
||||||
|
if not tostrip:
|
||||||
|
break
|
||||||
|
added, flip = tostrip.pop()
|
||||||
|
pathlen += len(added) + 1
|
||||||
|
cmd.append(added)
|
||||||
|
flips.append((added, flip))
|
||||||
|
else:
|
||||||
|
cmd.pop()
|
||||||
|
tostrip.append(flips.pop())
|
||||||
|
os.spawnv(os.P_WAIT, cmd[0], cmd)
|
||||||
|
for args in flips:
|
||||||
|
flipwritable(*args)
|
||||||
|
|
||||||
|
|
||||||
|
def files_in(folder):
|
||||||
|
for record in os.walk(folder):
|
||||||
|
for f in record[-1]:
|
||||||
|
yield os.path.join(record[0], f)
|
||||||
|
|
||||||
|
|
||||||
|
def expand_dirs(items, exclude=lambda x: x.endswith('.so')):
|
||||||
|
items = set(items)
|
||||||
|
dirs = set(x for x in items if os.path.isdir(x))
|
||||||
|
items.difference_update(dirs)
|
||||||
|
for x in dirs:
|
||||||
|
items.update({y for y in files_in(x) if not exclude(y)})
|
||||||
|
return items
|
||||||
|
|
||||||
|
|
||||||
|
def do_sign(app_dir):
|
||||||
|
with current_dir(os.path.join(app_dir, 'Contents')):
|
||||||
|
# Sign all .so files
|
||||||
|
so_files = {x for x in files_in('.') if x.endswith('.so')}
|
||||||
|
codesign(so_files)
|
||||||
|
# Sign everything else in Frameworks
|
||||||
|
with current_dir('Frameworks'):
|
||||||
|
fw = set(glob.glob('*.framework'))
|
||||||
|
codesign(fw)
|
||||||
|
items = set(os.listdir('.')) - fw
|
||||||
|
codesign(expand_dirs(items))
|
||||||
|
|
||||||
|
# Now sign the main app
|
||||||
|
codesign(app_dir)
|
||||||
|
verify_signature(app_dir)
|
||||||
|
|
||||||
|
|
||||||
|
def sign_app(app_dir, notarize):
|
||||||
|
# Copied from iTerm2: https://github.com/gnachman/iTerm2/blob/master/iTerm2.entitlements
|
||||||
|
create_entitlements_file({
|
||||||
|
'com.apple.security.automation.apple-events': True,
|
||||||
|
'com.apple.security.cs.allow-jit': True,
|
||||||
|
'com.apple.security.device.audio-input': True,
|
||||||
|
'com.apple.security.device.camera': True,
|
||||||
|
'com.apple.security.personal-information.addressbook': True,
|
||||||
|
'com.apple.security.personal-information.calendars': True,
|
||||||
|
'com.apple.security.personal-information.location': True,
|
||||||
|
'com.apple.security.personal-information.photos-library': True,
|
||||||
|
})
|
||||||
|
with make_certificate_useable():
|
||||||
|
do_sign(app_dir)
|
||||||
|
if notarize:
|
||||||
|
notarize_app(app_dir)
|
||||||
|
|
||||||
|
|
||||||
|
class Freeze(object):
|
||||||
|
|
||||||
|
FID = '@executable_path/../Frameworks'
|
||||||
|
|
||||||
|
def __init__(self, build_dir, dont_strip=False, sign_installers=False, notarize=False):
|
||||||
|
self.build_dir = build_dir
|
||||||
|
self.sign_installers = sign_installers
|
||||||
|
self.notarize = notarize
|
||||||
|
self.dont_strip = dont_strip
|
||||||
|
self.contents_dir = join(self.build_dir, 'Contents')
|
||||||
|
self.resources_dir = join(self.contents_dir, 'Resources')
|
||||||
|
self.frameworks_dir = join(self.contents_dir, 'Frameworks')
|
||||||
|
self.to_strip = []
|
||||||
|
self.warnings = []
|
||||||
|
self.py_ver = py_ver
|
||||||
|
self.python_stdlib = join(self.resources_dir, 'Python', 'lib', 'python' + self.py_ver)
|
||||||
|
self.site_packages = self.python_stdlib # hack to avoid needing to add site-packages to path
|
||||||
|
|
||||||
|
self.run()
|
||||||
|
|
||||||
|
def run_shell(self):
|
||||||
|
with current_dir(self.contents_dir):
|
||||||
|
run_shell()
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
ret = 0
|
||||||
|
self.add_python_framework()
|
||||||
|
self.add_site_packages()
|
||||||
|
self.add_stdlib()
|
||||||
|
self.add_misc_libraries()
|
||||||
|
self.compile_py_modules()
|
||||||
|
self.fix_dependencies_in_kitty()
|
||||||
|
if not self.dont_strip:
|
||||||
|
self.strip_files()
|
||||||
|
# self.run_shell()
|
||||||
|
|
||||||
|
ret = self.makedmg(self.build_dir, APPNAME + '-' + VERSION)
|
||||||
|
|
||||||
|
return ret
|
||||||
|
|
||||||
|
@flush
|
||||||
|
def strip_files(self):
|
||||||
|
print('\nStripping files...')
|
||||||
|
strip_files(self.to_strip)
|
||||||
|
|
||||||
|
@flush
|
||||||
|
def set_id(self, path_to_lib, new_id):
|
||||||
|
old_mode = flipwritable(path_to_lib)
|
||||||
|
subprocess.check_call(
|
||||||
|
['install_name_tool', '-id', new_id, path_to_lib])
|
||||||
|
if old_mode is not None:
|
||||||
|
flipwritable(path_to_lib, old_mode)
|
||||||
|
|
||||||
|
@flush
|
||||||
|
def get_dependencies(self, path_to_lib):
|
||||||
|
install_name = subprocess.check_output(
|
||||||
|
['otool', '-D', path_to_lib]).decode('utf-8').splitlines()[-1].strip()
|
||||||
|
raw = subprocess.check_output(['otool', '-L', path_to_lib]).decode('utf-8')
|
||||||
|
for line in raw.splitlines():
|
||||||
|
if 'compatibility' not in line or line.strip().endswith(':'):
|
||||||
|
continue
|
||||||
|
idx = line.find('(')
|
||||||
|
path = line[:idx].strip()
|
||||||
|
yield path, path == install_name
|
||||||
|
|
||||||
|
@flush
|
||||||
|
def get_local_dependencies(self, path_to_lib):
|
||||||
|
for x, is_id in self.get_dependencies(path_to_lib):
|
||||||
|
for y in (PREFIX + '/lib/', PREFIX + '/python/Python.framework/'):
|
||||||
|
if x.startswith(y):
|
||||||
|
if y == PREFIX + '/python/Python.framework/':
|
||||||
|
y = PREFIX + '/python/'
|
||||||
|
yield x, x[len(y):], is_id
|
||||||
|
break
|
||||||
|
|
||||||
|
@flush
|
||||||
|
def change_dep(self, old_dep, new_dep, is_id, path_to_lib):
|
||||||
|
cmd = ['-id', new_dep] if is_id else ['-change', old_dep, new_dep]
|
||||||
|
subprocess.check_call(['install_name_tool'] + cmd + [path_to_lib])
|
||||||
|
|
||||||
|
@flush
|
||||||
|
def fix_dependencies_in_lib(self, path_to_lib):
|
||||||
|
self.to_strip.append(path_to_lib)
|
||||||
|
old_mode = flipwritable(path_to_lib)
|
||||||
|
for dep, bname, is_id in self.get_local_dependencies(path_to_lib):
|
||||||
|
ndep = self.FID + '/' + bname
|
||||||
|
self.change_dep(dep, ndep, is_id, path_to_lib)
|
||||||
|
ldeps = list(self.get_local_dependencies(path_to_lib))
|
||||||
|
if ldeps:
|
||||||
|
print('\nFailed to fix dependencies in', path_to_lib)
|
||||||
|
print('Remaining local dependencies:', ldeps)
|
||||||
|
raise SystemExit(1)
|
||||||
|
if old_mode is not None:
|
||||||
|
flipwritable(path_to_lib, old_mode)
|
||||||
|
|
||||||
|
@flush
|
||||||
|
def add_python_framework(self):
|
||||||
|
print('\nAdding Python framework')
|
||||||
|
src = join(PREFIX + '/python', 'Python.framework')
|
||||||
|
x = join(self.frameworks_dir, 'Python.framework')
|
||||||
|
curr = os.path.realpath(join(src, 'Versions', 'Current'))
|
||||||
|
currd = join(x, 'Versions', basename(curr))
|
||||||
|
rd = join(currd, 'Resources')
|
||||||
|
os.makedirs(rd)
|
||||||
|
shutil.copy2(join(curr, 'Resources', 'Info.plist'), rd)
|
||||||
|
shutil.copy2(join(curr, 'Python'), currd)
|
||||||
|
self.set_id(
|
||||||
|
join(currd, 'Python'),
|
||||||
|
self.FID + '/Python.framework/Versions/%s/Python' % basename(curr))
|
||||||
|
self.fix_dependencies_in_lib(join(self.contents_dir, 'MacOS', 'kitty'))
|
||||||
|
# The following is needed for codesign
|
||||||
|
with current_dir(x):
|
||||||
|
os.symlink(basename(curr), 'Versions/Current')
|
||||||
|
for y in ('Python', 'Resources'):
|
||||||
|
os.symlink('Versions/Current/%s' % y, y)
|
||||||
|
|
||||||
|
@flush
|
||||||
|
def install_dylib(self, path, set_id=True):
|
||||||
|
shutil.copy2(path, self.frameworks_dir)
|
||||||
|
if set_id:
|
||||||
|
self.set_id(
|
||||||
|
join(self.frameworks_dir, basename(path)),
|
||||||
|
self.FID + '/' + basename(path))
|
||||||
|
self.fix_dependencies_in_lib(join(self.frameworks_dir, basename(path)))
|
||||||
|
|
||||||
|
@flush
|
||||||
|
def add_misc_libraries(self):
|
||||||
|
for x in (
|
||||||
|
'sqlite3.0',
|
||||||
|
'z.1',
|
||||||
|
'harfbuzz.0',
|
||||||
|
'png16.16',
|
||||||
|
'lcms2.2',
|
||||||
|
'crypto.1.1',
|
||||||
|
'ssl.1.1',
|
||||||
|
):
|
||||||
|
print('\nAdding', x)
|
||||||
|
x = 'lib%s.dylib' % x
|
||||||
|
src = join(PREFIX, 'lib', x)
|
||||||
|
shutil.copy2(src, self.frameworks_dir)
|
||||||
|
dest = join(self.frameworks_dir, x)
|
||||||
|
self.set_id(dest, self.FID + '/' + x)
|
||||||
|
self.fix_dependencies_in_lib(dest)
|
||||||
|
base = join(self.frameworks_dir, 'kitty')
|
||||||
|
for lib in walk(base):
|
||||||
|
if lib.endswith('.so'):
|
||||||
|
self.set_id(lib, self.FID + '/' + os.path.relpath(lib, self.frameworks_dir))
|
||||||
|
self.fix_dependencies_in_lib(lib)
|
||||||
|
|
||||||
|
@flush
|
||||||
|
def add_package_dir(self, x, dest=None):
|
||||||
|
def ignore(root, files):
|
||||||
|
ans = []
|
||||||
|
for y in files:
|
||||||
|
ext = os.path.splitext(y)[1]
|
||||||
|
if ext not in ('', '.py', '.so') or \
|
||||||
|
(not ext and not os.path.isdir(join(root, y))):
|
||||||
|
ans.append(y)
|
||||||
|
|
||||||
|
return ans
|
||||||
|
|
||||||
|
if dest is None:
|
||||||
|
dest = self.site_packages
|
||||||
|
dest = join(dest, basename(x))
|
||||||
|
shutil.copytree(x, dest, symlinks=True, ignore=ignore)
|
||||||
|
self.postprocess_package(x, dest)
|
||||||
|
for f in walk(dest):
|
||||||
|
if f.endswith('.so'):
|
||||||
|
self.fix_dependencies_in_lib(f)
|
||||||
|
|
||||||
|
@flush
|
||||||
|
def fix_dependencies_in_kitty(self):
|
||||||
|
for f in walk(join(self.resources_dir, 'kitty')):
|
||||||
|
if f.endswith('.so'):
|
||||||
|
self.fix_dependencies_in_lib(f)
|
||||||
|
|
||||||
|
@flush
|
||||||
|
def postprocess_package(self, src_path, dest_path):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@flush
|
||||||
|
def add_stdlib(self):
|
||||||
|
print('\nAdding python stdlib')
|
||||||
|
src = PREFIX + '/python/Python.framework/Versions/Current/lib/python' + self.py_ver
|
||||||
|
dest = self.python_stdlib
|
||||||
|
if not os.path.exists(dest):
|
||||||
|
os.makedirs(dest)
|
||||||
|
for x in os.listdir(src):
|
||||||
|
if x in ('site-packages', 'config', 'test', 'lib2to3', 'lib-tk',
|
||||||
|
'lib-old', 'idlelib', 'plat-mac', 'plat-darwin',
|
||||||
|
'site.py', 'distutils', 'turtledemo', 'tkinter'):
|
||||||
|
continue
|
||||||
|
x = join(src, x)
|
||||||
|
if os.path.isdir(x):
|
||||||
|
self.add_package_dir(x, dest)
|
||||||
|
elif os.path.splitext(x)[1] in ('.so', '.py'):
|
||||||
|
shutil.copy2(x, dest)
|
||||||
|
dest2 = join(dest, basename(x))
|
||||||
|
if dest2.endswith('.so'):
|
||||||
|
self.fix_dependencies_in_lib(dest2)
|
||||||
|
|
||||||
|
@flush
|
||||||
|
def add_site_packages(self):
|
||||||
|
print('\nAdding site-packages')
|
||||||
|
os.makedirs(self.site_packages)
|
||||||
|
sys_path = json.loads(subprocess.check_output([
|
||||||
|
PYTHON, '-c', 'import sys, json; json.dump(sys.path, sys.stdout)']))
|
||||||
|
paths = reversed(tuple(map(abspath, [x for x in sys_path if x.startswith('/') and not x.startswith('/Library/')])))
|
||||||
|
upaths = []
|
||||||
|
for x in paths:
|
||||||
|
if x not in upaths and (x.endswith('.egg') or x.endswith('/site-packages')):
|
||||||
|
upaths.append(x)
|
||||||
|
for x in upaths:
|
||||||
|
print('\t', x)
|
||||||
|
tdir = None
|
||||||
|
try:
|
||||||
|
if not os.path.isdir(x):
|
||||||
|
zf = zipfile.ZipFile(x)
|
||||||
|
tdir = tempfile.mkdtemp()
|
||||||
|
zf.extractall(tdir)
|
||||||
|
x = tdir
|
||||||
|
self.add_modules_from_dir(x)
|
||||||
|
self.add_packages_from_dir(x)
|
||||||
|
finally:
|
||||||
|
if tdir is not None:
|
||||||
|
shutil.rmtree(tdir)
|
||||||
|
self.remove_bytecode(self.site_packages)
|
||||||
|
|
||||||
|
@flush
|
||||||
|
def add_modules_from_dir(self, src):
|
||||||
|
for x in glob.glob(join(src, '*.py')) + glob.glob(join(src, '*.so')):
|
||||||
|
shutil.copy2(x, self.site_packages)
|
||||||
|
if x.endswith('.so'):
|
||||||
|
self.fix_dependencies_in_lib(x)
|
||||||
|
|
||||||
|
@flush
|
||||||
|
def add_packages_from_dir(self, src):
|
||||||
|
for x in os.listdir(src):
|
||||||
|
x = join(src, x)
|
||||||
|
if os.path.isdir(x) and os.path.exists(join(x, '__init__.py')):
|
||||||
|
if self.filter_package(basename(x)):
|
||||||
|
continue
|
||||||
|
self.add_package_dir(x)
|
||||||
|
|
||||||
|
@flush
|
||||||
|
def filter_package(self, name):
|
||||||
|
return name in ('Cython', 'modulegraph', 'macholib', 'py2app',
|
||||||
|
'bdist_mpkg', 'altgraph')
|
||||||
|
|
||||||
|
@flush
|
||||||
|
def remove_bytecode(self, dest):
|
||||||
|
for x in os.walk(dest):
|
||||||
|
root = x[0]
|
||||||
|
for f in x[-1]:
|
||||||
|
if os.path.splitext(f) == '.pyc':
|
||||||
|
os.remove(join(root, f))
|
||||||
|
|
||||||
|
@flush
|
||||||
|
def compile_py_modules(self):
|
||||||
|
print('\nCompiling Python modules')
|
||||||
|
self.remove_bytecode(join(self.resources_dir, 'Python'))
|
||||||
|
py_compile(join(self.resources_dir, 'Python'))
|
||||||
|
self.remove_bytecode(join(self.resources_dir, 'kitty'))
|
||||||
|
py_compile(join(self.resources_dir, 'kitty'))
|
||||||
|
|
||||||
|
@flush
|
||||||
|
def makedmg(self, d, volname, internet_enable=True, format='ULFO'):
|
||||||
|
''' Copy a directory d into a dmg named volname '''
|
||||||
|
print('\nMaking dmg...')
|
||||||
|
sys.stdout.flush()
|
||||||
|
destdir = os.path.join(SW, 'dist')
|
||||||
|
try:
|
||||||
|
shutil.rmtree(destdir)
|
||||||
|
except FileNotFoundError:
|
||||||
|
pass
|
||||||
|
os.mkdir(destdir)
|
||||||
|
dmg = os.path.join(destdir, volname + '.dmg')
|
||||||
|
if os.path.exists(dmg):
|
||||||
|
os.unlink(dmg)
|
||||||
|
tdir = tempfile.mkdtemp()
|
||||||
|
appdir = os.path.join(tdir, os.path.basename(d))
|
||||||
|
shutil.copytree(d, appdir, symlinks=True)
|
||||||
|
if self.sign_installers:
|
||||||
|
with timeit() as times:
|
||||||
|
sign_app(appdir, self.notarize)
|
||||||
|
print('Signing completed in %d minutes %d seconds' % tuple(times))
|
||||||
|
os.symlink('/Applications', os.path.join(tdir, 'Applications'))
|
||||||
|
size_in_mb = int(
|
||||||
|
subprocess.check_output(['du', '-s', '-k', tdir]).decode('utf-8')
|
||||||
|
.split()[0]) / 1024.
|
||||||
|
cmd = [
|
||||||
|
'/usr/bin/hdiutil', 'create', '-srcfolder', tdir, '-volname',
|
||||||
|
volname, '-format', format
|
||||||
|
]
|
||||||
|
if 190 < size_in_mb < 250:
|
||||||
|
# We need -size 255m because of a bug in hdiutil. When the size of
|
||||||
|
# srcfolder is close to 200MB hdiutil fails with
|
||||||
|
# diskimages-helper: resize request is above maximum size allowed.
|
||||||
|
cmd += ['-size', '255m']
|
||||||
|
print('\nCreating dmg...')
|
||||||
|
with timeit() as times:
|
||||||
|
subprocess.check_call(cmd + [dmg])
|
||||||
|
if internet_enable:
|
||||||
|
subprocess.check_call(
|
||||||
|
['/usr/bin/hdiutil', 'internet-enable', '-yes', dmg])
|
||||||
|
print('dmg created in %d minutes and %d seconds' % tuple(times))
|
||||||
|
shutil.rmtree(tdir)
|
||||||
|
size = os.stat(dmg).st_size / (1024 * 1024.)
|
||||||
|
print('\nInstaller size: %.2fMB\n' % size)
|
||||||
|
return dmg
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
args = globals()['args']
|
||||||
|
ext_dir = globals()['ext_dir']
|
||||||
|
if not args.skip_tests:
|
||||||
|
run_tests = iv['run_tests']
|
||||||
|
run_tests(None, os.path.join(ext_dir, 'src'))
|
||||||
|
Freeze(
|
||||||
|
os.path.join(ext_dir, kitty_constants['appname'] + '.app'),
|
||||||
|
dont_strip=args.dont_strip,
|
||||||
|
sign_installers=args.sign_installers,
|
||||||
|
notarize=args.notarize
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
1
bypy/rsync.conf
Normal file
1
bypy/rsync.conf
Normal file
@@ -0,0 +1 @@
|
|||||||
|
to_vm_excludes '/build /dist /kitty/launcher/kitty /.build-cache /tags __pycache__ /*_commands.json *.so *.pyd *.pyc'
|
||||||
264
bypy/sources.json
Normal file
264
bypy/sources.json
Normal file
@@ -0,0 +1,264 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"name": "zlib",
|
||||||
|
"unix": {
|
||||||
|
"filename": "zlib-1.2.11.tar.xz",
|
||||||
|
"hash": "sha256:4ff941449631ace0d4d203e3483be9dbc9da454084111f97ea0a2114e19bf066",
|
||||||
|
"urls": ["https://zlib.net/{filename}"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"name": "bzip2",
|
||||||
|
"os": "linux",
|
||||||
|
"unix": {
|
||||||
|
"filename": "bzip2-1.0.8.tar.gz",
|
||||||
|
"hash": "sha256:ab5a03176ee106d3f0fa90e381da478ddae405918153cca248e682cd0c4a2269",
|
||||||
|
"urls": ["https://www.sourceware.org/pub/bzip2/bzip2-latest.tar.gz"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"name": "pkg-config",
|
||||||
|
"os": "macos",
|
||||||
|
"unix": {
|
||||||
|
"filename": "pkg-config-0.29.2.tar.gz",
|
||||||
|
"hash": "sha256:6fc69c01688c9458a57eb9a1664c9aba372ccda420a02bf4429fe610e7e7d591",
|
||||||
|
"urls": ["https://pkg-config.freedesktop.org/releases/{filename}"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
{
|
||||||
|
"name": "expat",
|
||||||
|
"unix": {
|
||||||
|
"filename": "expat-2.2.6.tar.bz2",
|
||||||
|
"hash": "sha256:17b43c2716d521369f82fc2dc70f359860e90fa440bea65b3b85f0b246ea81f2",
|
||||||
|
"urls": ["https://github.com/libexpat/libexpat/releases/download/R_2_2_6/{filename}"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
{
|
||||||
|
"name": "xkbcommon",
|
||||||
|
"os": "linux",
|
||||||
|
"unix": {
|
||||||
|
"filename": "libxkbcommon-0.10.0.tar.xz",
|
||||||
|
"hash": "sha256:57c3630cdc38fb4734cd57fa349e92244f5ae3862813e533cedbd86721a0b6f2",
|
||||||
|
"urls": ["http://xkbcommon.org/download/{filename}"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"name": "sqlite",
|
||||||
|
"unix": {
|
||||||
|
"filename": "sqlite-autoconf-3310100.tar.gz",
|
||||||
|
"hash": "sha1:0c30f5b22152a8166aa3bebb0f4bc1f3e9cc508b",
|
||||||
|
"urls": ["https://www.sqlite.org/2020/{filename}"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
{
|
||||||
|
"name": "libffi",
|
||||||
|
"unix": {
|
||||||
|
"filename": "libffi-3.2.1.tar.gz",
|
||||||
|
"hash": "sha1:280c265b789e041c02e5c97815793dfc283fb1e6",
|
||||||
|
"urls": ["ftp://sourceware.org/pub/libffi/{filename}"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"name": "openssl",
|
||||||
|
"unix": {
|
||||||
|
"filename": "openssl-1.1.1g.tar.gz",
|
||||||
|
"hash": "sha256:ddb04774f1e32f0c49751e21b67216ac87852ceb056b75209af2443400636d46",
|
||||||
|
"urls": ["https://www.openssl.org/source/{filename}"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"name": "ncurses",
|
||||||
|
"os": "linux",
|
||||||
|
"unix": {
|
||||||
|
"filename": "ncurses-6.2.tar.gz",
|
||||||
|
"hash": "sha256:30306e0c76e0f9f1f0de987cf1c82a5c21e1ce6568b9227f7da5b71cbea86c9d",
|
||||||
|
"urls": ["https://invisible-mirror.net/archives/ncurses/{filename}"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"name": "readline",
|
||||||
|
"os": "linux",
|
||||||
|
"unix": {
|
||||||
|
"filename": "readline-8.0.tar.gz",
|
||||||
|
"hash": "sha256:e339f51971478d369f8a053a330a190781acb9864cf4c541060f12078948e461",
|
||||||
|
"urls": ["http://ftp.gnu.org/gnu/readline/{filename}"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"name": "xz",
|
||||||
|
"os": "macos,linux",
|
||||||
|
"unix": {
|
||||||
|
"filename": "xz-5.2.5.tar.gz",
|
||||||
|
"hash": "sha256:f6f4910fd033078738bd82bfba4f49219d03b17eb0794eb91efbae419f4aba10",
|
||||||
|
"urls": ["https://tukaani.org/xz/{filename}"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"name": "python",
|
||||||
|
"unix": {
|
||||||
|
"filename": "Python-3.8.3.tar.xz",
|
||||||
|
"hash": "sha256:dfab5ec723c218082fe3d5d7ae17ecbdebffa9a1aea4d64aa3a2ecdd2e795864",
|
||||||
|
"urls": ["https://www.python.org/ftp/python/3.8.3/{filename}"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"name": "setuptools",
|
||||||
|
"unix": {
|
||||||
|
"filename": "setuptools-41.0.1.zip",
|
||||||
|
"hash": "sha256:a222d126f5471598053c9a77f4b5d4f26eaa1f150ad6e01dcf1a42e185d05613",
|
||||||
|
"urls": ["pypi"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"name": "pygments",
|
||||||
|
"unix": {
|
||||||
|
"filename": "Pygments-2.6.1.tar.gz",
|
||||||
|
"hash": "sha256:647344a061c249a3b74e230c739f434d7ea4d8b1d5f3721bc0f3558049b38f44",
|
||||||
|
"urls": ["pypi"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"name": "cmake",
|
||||||
|
"os": "macos",
|
||||||
|
"unix": {
|
||||||
|
"filename": "cmake-3.6.0.tar.gz",
|
||||||
|
"hash": "sha1:6b0d2d7d93c2e74f8890c4b8b824deb3b36d24b6",
|
||||||
|
"urls": ["https://cmake.org/files/v3.6/{filename}"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"name": "libpng",
|
||||||
|
"unix": {
|
||||||
|
"filename": "libpng-1.6.37.tar.xz",
|
||||||
|
"hash": "sha256:505e70834d35383537b6491e7ae8641f1a4bed1876dbfe361201fc80868d88ca",
|
||||||
|
"urls": ["http://downloads.sourceforge.net/sourceforge/libpng/{filename}"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"name": "lcms2",
|
||||||
|
"unix": {
|
||||||
|
"filename": "lcms2-2.11.tar.gz",
|
||||||
|
"hash": "sha256:478c9c3938d7a91b1171de4616f8b04308a8676d73eadc19505b7ace41327f28",
|
||||||
|
"urls": ["https://github.com/mm2/Little-CMS/archive/2.11/{filename}"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"name": "graphite",
|
||||||
|
"os": "linux",
|
||||||
|
"unix": {
|
||||||
|
"filename": "graphite2-1.3.5.tgz",
|
||||||
|
"hash": "md5:5b8d22a8bbf031838e31432868c0109c",
|
||||||
|
"urls": ["http://downloads.sourceforge.net/silgraphite/{filename}"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"name": "pcre",
|
||||||
|
"os": "linux",
|
||||||
|
"unix": {
|
||||||
|
"filename": "pcre-8.42.tar.bz2",
|
||||||
|
"hash": "md5:085b6aa253e0f91cae70b3cdbe8c1ac2",
|
||||||
|
"urls": ["https://ftp.pcre.org/pub/pcre/{filename}"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"name": "iconv",
|
||||||
|
"os": "linux",
|
||||||
|
"unix": {
|
||||||
|
"filename": "libiconv-1.16.tar.gz",
|
||||||
|
"hash": "sha256:e6a1b1b589654277ee790cce3734f07876ac4ccfaecbee8afa0b649cf529cc04",
|
||||||
|
"urls": ["https://ftp.gnu.org/pub/gnu/libiconv/{filename}"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"name": "glib",
|
||||||
|
"os": "linux",
|
||||||
|
"unix": {
|
||||||
|
"filename": "glib-2.65.1.tar.xz",
|
||||||
|
"hash": "sha256:bc63bf6c32713e0ee1dddc28e03f23b4a20c78bcb9a2c5b0f4eea41e46fb9cee",
|
||||||
|
"urls": ["https://ftp.gnome.org/pub/GNOME/sources/glib/2.65/{filename}"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"name": "freetype",
|
||||||
|
"os": "linux",
|
||||||
|
"unix": {
|
||||||
|
"filename": "freetype-2.9.1.tar.bz2",
|
||||||
|
"hash": "md5:60ef7d8160cd4bf8cb118ee9d65367ca",
|
||||||
|
"urls": ["https://download.savannah.gnu.org/releases/freetype/{filename}"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"name": "fontconfig",
|
||||||
|
"os": "linux",
|
||||||
|
"unix": {
|
||||||
|
"filename": "fontconfig-2.12.0.tar.bz2",
|
||||||
|
"hash": "sha256:b433e4efff1f68fdd8aac221ed1df3ff1e580ffedbada020a703fe64017d8224",
|
||||||
|
"urls": ["http://www.fontconfig.org/release/{filename}"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"name": "harfbuzz",
|
||||||
|
"unix": {
|
||||||
|
"filename": "harfbuzz-1.7.2.tar.bz2",
|
||||||
|
"hash": "sha256:a790585e35c1a87f0dcc23580c84b7cc2324e6f67a2946178d278c2a36c790cb",
|
||||||
|
"urls": ["https://www.freedesktop.org/software/harfbuzz/release/{filename}"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"name": "libxml2",
|
||||||
|
"os": "linux",
|
||||||
|
"unix": {
|
||||||
|
"filename": "libxml2-2.9.4.tar.gz",
|
||||||
|
"hash": "sha1:958ae70baf186263a4bd801a81dd5d682aedd1db",
|
||||||
|
"urls": ["ftp://xmlsoft.org/libxml2/{filename}"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"name": "wayland",
|
||||||
|
"os": "linux",
|
||||||
|
"unix": {
|
||||||
|
"filename": "wayland-1.18.0.tar.xz",
|
||||||
|
"hash": "sha256:4675a79f091020817a98fd0484e7208c8762242266967f55a67776936c2e294d",
|
||||||
|
"urls": ["https://wayland.freedesktop.org/releases/{filename}"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"name": "wayland-protocols",
|
||||||
|
"os": "linux",
|
||||||
|
"unix": {
|
||||||
|
"filename": "wayland-protocols-1.20.tar.xz",
|
||||||
|
"hash": "sha256:9782b7a1a863d82d7c92478497d13c758f52e7da4f197aa16443f73de77e4de7",
|
||||||
|
"urls": ["https://wayland.freedesktop.org/releases/{filename}"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
]
|
||||||
@@ -46,7 +46,7 @@ particular desktop, but it should work for most major desktop environments.
|
|||||||
# Place the kitty.desktop file somewhere it can be found by the OS
|
# Place the kitty.desktop file somewhere it can be found by the OS
|
||||||
cp ~/.local/kitty.app/share/applications/kitty.desktop ~/.local/share/applications
|
cp ~/.local/kitty.app/share/applications/kitty.desktop ~/.local/share/applications
|
||||||
# Update the path to the kitty icon in the kitty.desktop file
|
# Update the path to the kitty icon in the kitty.desktop file
|
||||||
sed -i "s/Icon\=kitty/Icon\=\/home\/$USER\/.local\/kitty.app\/share\/icons\/hicolor\/256x256\/apps\/kitty.png/g" ~/.local/share/applications/kitty.desktop
|
sed -i "s|Icon=kitty|Icon=/home/$USER/.local/kitty.app/share/icons/hicolor/256x256/apps/kitty.png|g" ~/.local/share/applications/kitty.desktop
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
Building kitty from source
|
Building kitty from source
|
||||||
==============================
|
==============================
|
||||||
|
|
||||||
.. image:: https://circleci.com/gh/kovidgoyal/kitty.svg?style=svg
|
.. image:: https://github.com/kovidgoyal/kitty/workflows/CI/badge.svg
|
||||||
:alt: Build status
|
:alt: Build status
|
||||||
:target: https://circleci.com/gh/kovidgoyal/kitty
|
:target: https://github.com/kovidgoyal/kitty/actions?query=workflow%3ACI
|
||||||
|
|
||||||
|
|
||||||
|kitty| is designed to run from source, for easy hackability. Make sure
|
|kitty| is designed to run from source, for easy hackability. Make sure
|
||||||
@@ -18,6 +18,7 @@ Run-time dependencies:
|
|||||||
* harfbuzz >= 1.5.0
|
* harfbuzz >= 1.5.0
|
||||||
* zlib
|
* zlib
|
||||||
* libpng
|
* libpng
|
||||||
|
* liblcms2
|
||||||
* freetype (not needed on macOS)
|
* freetype (not needed on macOS)
|
||||||
* fontconfig (not needed on macOS)
|
* fontconfig (not needed on macOS)
|
||||||
* libcanberra (not needed on macOS)
|
* libcanberra (not needed on macOS)
|
||||||
@@ -63,10 +64,32 @@ This :file:`kitty.app` unlike the released one does not include its own copy of
|
|||||||
python and the other dependencies. So if you ever un-install/upgrade those dependencies
|
python and the other dependencies. So if you ever un-install/upgrade those dependencies
|
||||||
you might have to rebuild the app.
|
you might have to rebuild the app.
|
||||||
|
|
||||||
Note that the released :file:`kitty.dmg` includes all dependencies, unlike the
|
.. note::
|
||||||
:file:`kitty.app` built above and is built automatically by using the :file:`kitty` branch of
|
The released :file:`kitty.dmg` includes all dependencies, unlike the
|
||||||
`build-calibre <https://github.com/kovidgoyal/build-calibre>`_ however, that
|
:file:`kitty.app` built above and is built automatically by using the
|
||||||
is designed to run on Linux and is not for the faint of heart.
|
:file:`kitty` branch of `build-calibre
|
||||||
|
<https://github.com/kovidgoyal/build-calibre>`_ however, that is designed to
|
||||||
|
run on Linux and is not for the faint of heart.
|
||||||
|
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
Apple disallows certain functionality, such as notifications for unsigned applications.
|
||||||
|
If you need this functionality, you can try signing the built kitty.app with
|
||||||
|
a self signed certificate, see for example, `here
|
||||||
|
<https://stackoverflow.com/questions/27474751/how-can-i-codesign-an-app-without-being-in-the-mac-developer-program/27474942>`_.
|
||||||
|
|
||||||
|
Build and run from source with Nix
|
||||||
|
-------------------------------------------
|
||||||
|
|
||||||
|
On NixOS or any other Linux or macOS system with the Nix package manager
|
||||||
|
installed, execute `nix-shell
|
||||||
|
<https://nixos.org/guides/nix-pills/developing-with-nix-shell.html>`_ to create
|
||||||
|
the correct environment to build kitty or use ``nix-shell --pure`` instead to
|
||||||
|
eliminate most of the influence of the outside system, e.g. globally installed
|
||||||
|
packages. ``nix-shell`` will automatically fetch all required dependencies and
|
||||||
|
make them available in the newly spawned shell.
|
||||||
|
|
||||||
|
Then proceed with ``make`` or ``make app`` according to the platform specific instructions above.
|
||||||
|
|
||||||
|
|
||||||
Note for Linux/macOS packagers
|
Note for Linux/macOS packagers
|
||||||
|
|||||||
@@ -4,6 +4,494 @@ 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.19.2 [2020-11-13]
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
- A new :doc:`kittens/query_terminal` kitten to easily query the running kitty
|
||||||
|
via escape codes to detect its version, and the values of
|
||||||
|
configuration options that enable or disable terminal features.
|
||||||
|
|
||||||
|
- Options to control mouse pointer shape, :opt:`default_pointer_shape`, and
|
||||||
|
:opt:`pointer_shape_when_dragging` (:pull:`3041`)
|
||||||
|
|
||||||
|
- Font independent rendering for braille characters, which ensures they are properly
|
||||||
|
aligned at all font sizes.
|
||||||
|
|
||||||
|
- Fix a regression in 0.19.0 that caused borders not to be drawn when setting
|
||||||
|
:opt:`window_margin_width` and keeping :opt:`draw_minimal_borders` on
|
||||||
|
(:iss:`3017`)
|
||||||
|
|
||||||
|
- Fix a regression in 0.19.0 that broke rendering of one-eight bar unicode
|
||||||
|
characters at very small font sizes (:iss:`3025`)
|
||||||
|
|
||||||
|
- Wayland: Fix a crash under GNOME when using multiple OS windows
|
||||||
|
(:pull:`3066`)
|
||||||
|
|
||||||
|
- Fix selections created by dragging upwards not being auto-cleared when
|
||||||
|
screen contents change (:pull:`3028`)
|
||||||
|
|
||||||
|
- macOS: Fix kitty not being added to PATH automatically when using pre-built
|
||||||
|
binaries (:iss:`3063`)
|
||||||
|
|
||||||
|
- Allow adding MIME definitions to kitty by placing a ``mime.types`` file in
|
||||||
|
the kitty config directory (:iss:`3056`)
|
||||||
|
|
||||||
|
- Dont ignore :option:`--title` when using a session file that defines no
|
||||||
|
windows (:iss:`3055`)
|
||||||
|
|
||||||
|
- Fix the send_text action not working in URL handlers (:iss:`3081`)
|
||||||
|
|
||||||
|
- Fix last character of URL not being detected if it is the only character on a
|
||||||
|
new line (:iss:`3088`)
|
||||||
|
|
||||||
|
- Don't restrict the ICH,DCH,REP control codes to only the current scroll region (:iss:`3090`, :iss:`3096`)
|
||||||
|
|
||||||
|
|
||||||
|
0.19.1 [2020-10-06]
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
- hints kitten: Add an ``ip`` type for easy selection of IP addresses
|
||||||
|
(:pull:`3009`)
|
||||||
|
|
||||||
|
- Fix a regression that caused a segfault when using
|
||||||
|
:opt:`scrollback_pager_history_size` and it needs to be expanded (:iss:`3011`)
|
||||||
|
|
||||||
|
- Fix update available notifications repeating (:pull:`3006`)
|
||||||
|
|
||||||
|
|
||||||
|
0.19.0 [2020-10-04]
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
- Add support for `hyperlinks from terminal programs
|
||||||
|
<https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda>`_.
|
||||||
|
Controlled via :opt:`allow_hyperlinks` (:iss:`68`)
|
||||||
|
|
||||||
|
- Add support for easily editing or downloading files over SSH sessions
|
||||||
|
without the need for any special software, see :doc:`kittens/remote_file`
|
||||||
|
|
||||||
|
- A new :doc:`kittens/hyperlinked_grep` kitten to easily search files and open
|
||||||
|
the results at the matched line by clicking on them.
|
||||||
|
|
||||||
|
- Allow customizing the :doc:`actions kitty takes <open_actions>` when clicking on URLs
|
||||||
|
|
||||||
|
- Improve rendering of borders when using minimal borders. Use less space and
|
||||||
|
do not display a box around active windows
|
||||||
|
|
||||||
|
- Add a new extensible escape code to allow terminal programs to trigger
|
||||||
|
desktop notifications. See :ref:`desktop_notifications` (:iss:`1474`)
|
||||||
|
|
||||||
|
- Implement special rendering for various characters from the set of "Symbols
|
||||||
|
for Legacy Computing" from the Unicode 13 standard
|
||||||
|
|
||||||
|
- Unicode input kitten: Allow choosing symbols from the NERD font as well.
|
||||||
|
These are mostly Private Use symbols not in any standard, however are common. (:iss:`2972`)
|
||||||
|
|
||||||
|
- Allow specifying border sizes in either pts or pixels. Change the default to
|
||||||
|
0.5pt borders as this works best with the new minimal border style
|
||||||
|
|
||||||
|
- Add support for displaying correct colors with non-sRGB PNG files (Adds a
|
||||||
|
dependency on liblcms2)
|
||||||
|
|
||||||
|
- hints kitten: Add a new :option:`kitty +kitten hints --type` of ``hyperlink`` useful
|
||||||
|
for activating hyperlinks using just the keyboard
|
||||||
|
|
||||||
|
- Allow tracking focus change events in watchers (:iss:`2918`)
|
||||||
|
|
||||||
|
- Allow specifying watchers in session files and via a command line argument
|
||||||
|
(:iss:`2933`)
|
||||||
|
|
||||||
|
- Add a setting :opt:`tab_activity_symbol` to show a symbol in the tab title
|
||||||
|
if one of the windows has some activity after it was last focused
|
||||||
|
(:iss:`2515`)
|
||||||
|
|
||||||
|
- macOS: Switch to using the User Notifications framework for notifications.
|
||||||
|
The current notifications framework has been deprecated in Big Sur. The new
|
||||||
|
framework only allows notifications from signed and notarized applications,
|
||||||
|
so people using kitty from homebrew/source are out of luck. Complain to
|
||||||
|
Apple.
|
||||||
|
|
||||||
|
- When in the main screen and a program grabs the mouse, do not use the scroll
|
||||||
|
wheel events to scroll the scrollback buffer, instead send them to the
|
||||||
|
program (:iss:`2939`)
|
||||||
|
|
||||||
|
- Fix unfocused windows in which a bell occurs not changing their border color
|
||||||
|
to red until a relayout
|
||||||
|
|
||||||
|
- Linux: Fix automatic detection of bold/italic faces for fonts such as IBM
|
||||||
|
Plex Mono that have the regular face with a full name that is the same as the
|
||||||
|
family name (:iss:`2951`)
|
||||||
|
|
||||||
|
- Fix a regression that broke :opt:`kitten_alias` (:iss:`2952`)
|
||||||
|
|
||||||
|
- Fix a regression that broke the ``move_window_to_top`` action (:pull:`2953`)
|
||||||
|
|
||||||
|
- Fix a memory leak when changing font sizes
|
||||||
|
|
||||||
|
- Fix some lines in the scrollback buffer not being properly rendered after a
|
||||||
|
window resize/font size change (:iss:`2619`)
|
||||||
|
|
||||||
|
|
||||||
|
0.18.3 [2020-08-11]
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
- hints kitten: Allow customizing hint colors (:pull:`2894`)
|
||||||
|
|
||||||
|
- Wayland: Fix a typo in the previous release that broke reading mouse cursor size (:iss:`2895`)
|
||||||
|
|
||||||
|
- Fix a regression in the previous release that could cause an exception during
|
||||||
|
startup in rare circumstances (:iss:`2896`)
|
||||||
|
|
||||||
|
- Fix image leaving behind a black rectangle when switch away and back to
|
||||||
|
alternate screen (:iss:`2901`)
|
||||||
|
|
||||||
|
- Fix one pixel mis-alignment of rounded corners when either the cell
|
||||||
|
dimensions or the thickness of the line is an odd number of pixels
|
||||||
|
(:iss:`2907`)
|
||||||
|
|
||||||
|
- Fix a regression that broke specifying OS window size in the session file
|
||||||
|
(:iss:`2908`)
|
||||||
|
|
||||||
|
|
||||||
|
0.18.2 [2020-07-28]
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
- X11: Improve handling of multiple keyboards. Now pressing a modifier key in
|
||||||
|
one keyboard and a normal key in another works (:iss:`2362`). Don't rebuild
|
||||||
|
keymaps on new keyboard events that only change geometry (:iss:`2787`).
|
||||||
|
Better handling of multiple keyboards with incompatible layouts (:iss:`2726`)
|
||||||
|
|
||||||
|
- Improve anti-aliasing of triangular box drawing characters, noticeable on
|
||||||
|
low-resolution screens (:iss:`2844`)
|
||||||
|
|
||||||
|
- Fix ``kitty @ send-text`` not working reliably when using a socket for remote
|
||||||
|
control (:iss:`2852`)
|
||||||
|
|
||||||
|
- Implement support for box drawing rounded-corners characters (:iss:`2240`)
|
||||||
|
|
||||||
|
- Allow setting the class for new OS windows in a session file
|
||||||
|
|
||||||
|
- When a character from the Unicode Dingbat block is followed by a space, use
|
||||||
|
the extra space to render a larger version of the character (:iss:`2850`)
|
||||||
|
|
||||||
|
- macOS: Fix the LC_CTYPE env var being set to UTF-8 on systems in which the
|
||||||
|
language and country code do not form a valid locale (:iss:`1233`)
|
||||||
|
|
||||||
|
- macOS: Fix :kbd:`cmd+plus` not changing font size (:iss:`2839`)
|
||||||
|
|
||||||
|
- Make neighboring window selection in grid and splits layouts more intelligent
|
||||||
|
(:pull:`2840`)
|
||||||
|
|
||||||
|
- Allow passing the current selection to kittens (:iss:`2796`)
|
||||||
|
|
||||||
|
- Fix pre-edit text not always being cleared with ibus input (:iss:`2862`)
|
||||||
|
|
||||||
|
- Allow setting the :opt:`background_opacity` of new OS windows created via
|
||||||
|
:option:`kitty --single-instance` using the :option:`kitty --override` command line
|
||||||
|
argument (:iss:`2806`)
|
||||||
|
|
||||||
|
- Fix the CSI J (Erase in display ED) escape code not removing line continued
|
||||||
|
markers (:iss:`2809`)
|
||||||
|
|
||||||
|
- hints kitten: In linenumber mode expand paths that starts with ~
|
||||||
|
(:iss:`2822`)
|
||||||
|
|
||||||
|
- Fix ``launch --location=last`` not working (:iss:`2841`)
|
||||||
|
|
||||||
|
- Fix incorrect centering when a PUA or symbol glyph is followed by more than one space
|
||||||
|
|
||||||
|
- Have the :opt:`confirm_os_window_close` option also apply when closing tabs
|
||||||
|
with multiple windows (:iss:`2857`)
|
||||||
|
|
||||||
|
- Add support for legacy DECSET codes 47, 1047 and 1048 (:pull:`2871`)
|
||||||
|
|
||||||
|
- macOS: no longer render emoji 20% below the baseline. This caused some emoji
|
||||||
|
to be cut-off and also look misaligned with very high cells (:iss:`2873`)
|
||||||
|
|
||||||
|
- macOS: Make the window id of OS windows available in the ``WINDOWID``
|
||||||
|
environment variable (:pull:`2877`)
|
||||||
|
|
||||||
|
- Wayland: Fix a regression in 0.18.0 that could cause crashes related to mouse
|
||||||
|
cursors in some rare circumstances (:iss:`2810`)
|
||||||
|
|
||||||
|
- Fix change in window size that does not change number of cells not being
|
||||||
|
reported to the kernel (:iss:`2880`)
|
||||||
|
|
||||||
|
|
||||||
|
0.18.1 [2020-06-23]
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
- macOS: Fix for diff kitten not working with python 3.8 (:iss:`2780`)
|
||||||
|
|
||||||
|
|
||||||
|
0.18.0 [2020-06-20]
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
- Allow multiple overlay windows per normal window
|
||||||
|
|
||||||
|
- Add an option :opt:`confirm_os_window_close` to ask for confirmation
|
||||||
|
when closing an OS window with multiple kitty windows.
|
||||||
|
|
||||||
|
- Tall and Fat layouts: Add a ``mirrored`` option to put the full size window
|
||||||
|
on the opposite edge of the screen (:iss:`2654`)
|
||||||
|
|
||||||
|
- Tall and Fat layouts: Add mappable actions to increase or decrease the number
|
||||||
|
of full size windows (:iss:`2688`)
|
||||||
|
|
||||||
|
- Allow sending arbitrary signals to the current foreground process in a window
|
||||||
|
using either a mapping in kitty.conf or via remote control (:iss:`2778`)
|
||||||
|
|
||||||
|
- Allow sending the back and forward mouse buttons to terminal applications
|
||||||
|
(:pull:`2742`)
|
||||||
|
|
||||||
|
- **Backwards incompatibility**: The numbers used to encode mouse buttons
|
||||||
|
for the ``send_mouse_event`` function that can be used in kittens have
|
||||||
|
been changed (see :ref:`send_mouse_event`).
|
||||||
|
|
||||||
|
- Add a new mappable ``quit`` action to quit kitty completely.
|
||||||
|
|
||||||
|
- Fix marks using different colors with regexes using only a single color
|
||||||
|
(:pull:`2663`)
|
||||||
|
|
||||||
|
- Linux: Workaround for broken Nvidia drivers for old cards (:iss:`456`)
|
||||||
|
|
||||||
|
- Wayland: Fix kitty being killed on some Wayland compositors if a hidden window
|
||||||
|
has a lot of output (:iss:`2329`)
|
||||||
|
|
||||||
|
- BSD: Fix controlling terminal not being established (:pull:`2686`)
|
||||||
|
|
||||||
|
- Add support for the CSI REP escape code (:pull:`2702`)
|
||||||
|
|
||||||
|
- Wayland: Fix mouse cursor rendering on HiDPI screens (:pull:`2709`)
|
||||||
|
|
||||||
|
- X11: Recompile keymaps on XkbNewKeyboardNotify events (:iss:`2726`)
|
||||||
|
|
||||||
|
- X11: Reduce startup time by ~25% by only querying GLX for framebuffer
|
||||||
|
configurations once (:iss:`2754`)
|
||||||
|
|
||||||
|
- macOS: Notarize the kitty application bundle (:iss:`2040`)
|
||||||
|
|
||||||
|
- Fix the kitty shell launched via a mapping needlessly requiring
|
||||||
|
:opt:`allow_remote_control` to be turned on.
|
||||||
|
|
||||||
|
|
||||||
|
0.17.4 [2020-05-09]
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
- Allow showing the name of the current layout and the number of windows
|
||||||
|
in tab titles (:iss:`2634`)
|
||||||
|
|
||||||
|
- macOS: Fix a regression in the previous release that caused ligatures to be
|
||||||
|
not be centered horizontally (:iss:`2591`)
|
||||||
|
|
||||||
|
- By default, double clicking no longer considers the : as part of words, see
|
||||||
|
:opt:`select_by_word_characters` (:iss:`2602`)
|
||||||
|
|
||||||
|
- Fix a regression that caused clicking in the padding/margins of windows in
|
||||||
|
the stack layout to switch the window to the first window (:iss:`2604`)
|
||||||
|
|
||||||
|
- macOS: Fix a regression that broke drag and drop (:iss:`2605`)
|
||||||
|
|
||||||
|
- Report modifier key state when sending wheel events to the terminal program
|
||||||
|
|
||||||
|
- Fix kitty @ send-text not working with text larger than 1024 bytes when using
|
||||||
|
:option:`kitty --listen-on` (:iss:`2607`)
|
||||||
|
|
||||||
|
- Wayland: Fix OS window title not updating for hidden windows (:iss:`2629`)
|
||||||
|
|
||||||
|
- Fix :opt:`background_tint` making the window semi-transparent (:iss:`2618`)
|
||||||
|
|
||||||
|
|
||||||
|
0.17.3 [2020-04-23]
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
- Allow individually setting margins and padding for each edge (left, right,
|
||||||
|
top, bottom). Margins can also be controlled per window via remote control
|
||||||
|
(:iss:`2546`)
|
||||||
|
|
||||||
|
- Fix reverse video not being rendered correctly when using transparency or a
|
||||||
|
background image (:iss:`2419`)
|
||||||
|
|
||||||
|
- Allow mapping arbitrary remote control commands to key presses in
|
||||||
|
:file:`kitty.conf`
|
||||||
|
|
||||||
|
- X11: Fix crash when doing drag and drop from some applications (:iss:`2505`)
|
||||||
|
|
||||||
|
- Fix :option:`launch --stdin-add-formatting` not working (:iss:`2512`)
|
||||||
|
|
||||||
|
- Update to Unicode 13.0 (:iss:`2513`)
|
||||||
|
|
||||||
|
- Render country flags designated by a pair of unicode codepoints
|
||||||
|
in two cells instead of four.
|
||||||
|
|
||||||
|
- diff kitten: New option to control the background color for filler lines in
|
||||||
|
the margin (:iss:`2518`)
|
||||||
|
|
||||||
|
- Fix specifying options for layouts in the startup session file not working
|
||||||
|
(:iss:`2520`)
|
||||||
|
|
||||||
|
- macOS: Fix incorrect horizontal positioning of some full-width East Asian characters
|
||||||
|
(:iss:`1457`)
|
||||||
|
|
||||||
|
- macOS: Render multi-cell PUA characters centered, matching behavior on other
|
||||||
|
platforms
|
||||||
|
|
||||||
|
- Linux: Ignore keys if they are designated as layout/group/mode switch keys
|
||||||
|
(:iss:`2519`)
|
||||||
|
|
||||||
|
- Marks: Fix marks not handling wide characters and tab characters correctly
|
||||||
|
(:iss:`2534`)
|
||||||
|
|
||||||
|
- Add a new :opt:`listen_on` option in kitty.conf to set :option:`kitty --listen-on`
|
||||||
|
globally. Also allow using environment variables in this option (:iss:`2569`).
|
||||||
|
|
||||||
|
- Allow sending mouse events in kittens (:pull:`2538`)
|
||||||
|
|
||||||
|
- icat kitten: Fix display of 16-bit depth images (:iss:`2542`)
|
||||||
|
|
||||||
|
- Add ncurses specific terminfo definitions for strikethrough (:pull:`2567`)
|
||||||
|
|
||||||
|
- Fix a regression in 0.17 that broke displaying graphics over SSH
|
||||||
|
(:iss:`2568`)
|
||||||
|
|
||||||
|
- Fix :option:`--title` not being applied at window creation time (:iss:`2570`)
|
||||||
|
|
||||||
|
0.17.2 [2020-03-29]
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
- Add a :option:`launch --watcher` option that allows defining callbacks
|
||||||
|
that are called for various events in the window's life-cycle (:iss:`2440`)
|
||||||
|
|
||||||
|
- Fix a regression in 0.17 that broke drawing of borders with non-minimal
|
||||||
|
borders (:iss:`2474`)
|
||||||
|
|
||||||
|
- Hints kitten: Allow copying to primary selection as well as clipboard
|
||||||
|
(:pull:`2487`)
|
||||||
|
|
||||||
|
- Add a new mappable action ``close_other_windows_in_tab`` to close all but the
|
||||||
|
active window (:iss:`2484`)
|
||||||
|
|
||||||
|
- Hints kitten: Adjust the default regex used to detect line numbers to handle
|
||||||
|
line+column numbers (:iss:`2268`)
|
||||||
|
|
||||||
|
- Fix blank space at the start of tab bar in the powerline style when first tab is
|
||||||
|
inactive (:iss:`2478`)
|
||||||
|
|
||||||
|
- Fix regression causing incorrect rendering of separators in tab bar when
|
||||||
|
defining a tab bar background color (:pull:`2480`)
|
||||||
|
|
||||||
|
- Fix a regression in 0.17 that broke the kitty @ launch remote command and
|
||||||
|
also broke the --tab-title option when creating a new tab. (:iss:`2488`)
|
||||||
|
|
||||||
|
- Linux: Fix selection of fonts with multiple width variants not preferring
|
||||||
|
the normal width faces (:iss:`2491`)
|
||||||
|
|
||||||
|
|
||||||
|
0.17.1 [2020-03-24]
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
- Fix :opt:`cursor_underline_thickness` not working (:iss:`2465`)
|
||||||
|
|
||||||
|
- Fix a regression in 0.17 that caused tab bar background to be rendered after
|
||||||
|
the last tab as well (:iss:`2464`)
|
||||||
|
|
||||||
|
- macOS: Fix a regression in 0.17 that caused incorrect variants to be
|
||||||
|
automatically selected for some fonts (:iss:`2462`)
|
||||||
|
|
||||||
|
- Fix a regression in 0.17 that caused kitty @ set-colors to require setting
|
||||||
|
cursor_text_color (:iss:`2470`)
|
||||||
|
|
||||||
|
|
||||||
|
0.17.0 [2020-03-24]
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
- :ref:`splits_layout` to arrange windows in arbitrary splits
|
||||||
|
(:iss:`2308`)
|
||||||
|
|
||||||
|
- Add support for specifying a background image, see :opt:`background_image`
|
||||||
|
(:iss:`163` and :pull:`2326`; thanks to Fredrick Brennan.)
|
||||||
|
|
||||||
|
- A new :opt:`background_tint` option to darken the background under the text
|
||||||
|
area when using background images and/or transparent windows.
|
||||||
|
|
||||||
|
- Allow selection of single cells with the mouse. Also improve mouse selection
|
||||||
|
to follow semantics common to most programs (:iss:`945`)
|
||||||
|
|
||||||
|
- New options :opt:`cursor_beam_thickness` and :opt:`cursor_underline_thickness` to control the thickness of the
|
||||||
|
beam and underline cursors (:iss:`2337` and :pull:`2342`)
|
||||||
|
|
||||||
|
- When the application running in the terminal grabs the mouse, pass middle
|
||||||
|
clicks to the application unless :opt:`terminal_select_modifiers` are
|
||||||
|
pressed (:iss:`2368`)
|
||||||
|
|
||||||
|
- A new ``copy_and_clear_or_interrupt`` function (:iss:`2403`)
|
||||||
|
|
||||||
|
- X11: Fix arrow mouse cursor using right pointing instead of the default left
|
||||||
|
pointing arrow (:iss:`2341`)
|
||||||
|
|
||||||
|
- Allow passing the currently active kitty window id in the launch command
|
||||||
|
(:iss:`2391`)
|
||||||
|
|
||||||
|
- unicode input kitten: Allow pressing :kbd:`ctrl+tab` to change the input mode
|
||||||
|
(:iss:`2343`)
|
||||||
|
|
||||||
|
- Fix a bug that prevented using custom functions with the new marks feature
|
||||||
|
(:iss:`2344`)
|
||||||
|
|
||||||
|
- Make the set of URL prefixes that are recognized while hovering with the
|
||||||
|
mouse configurable (:iss:`2416`)
|
||||||
|
|
||||||
|
- Fix border/margin/padding sizes not being recalculated on DPI change
|
||||||
|
(:iss:`2346`)
|
||||||
|
|
||||||
|
- diff kitten: Fix directory diffing with removed binary files failing
|
||||||
|
(:iss:`2378`)
|
||||||
|
|
||||||
|
- macOS: Fix menubar title not updating on OS Window focus change (:iss:`2350`)
|
||||||
|
|
||||||
|
- Fix rendering of combining characters with fonts that have glyphs for
|
||||||
|
precomposed characters but not decomposed versions (:iss:`2365`)
|
||||||
|
|
||||||
|
- Fix incorrect rendering of selection when using rectangular select and
|
||||||
|
scrolling (:iss:`2351`)
|
||||||
|
|
||||||
|
- Allow setting WM_CLASS and WM_NAME when creating new OS windows with the
|
||||||
|
launch command (:option:`launch --os-window-class`)
|
||||||
|
|
||||||
|
- macOS: When switching input method while a pending multi-key input is in
|
||||||
|
progress, clear the pending input (:iss:`2358`)
|
||||||
|
|
||||||
|
- Fix a regression in the previous release that broke switching to neighboring windows
|
||||||
|
in the Grid layout when there are less than four windows (:iss:`2377`)
|
||||||
|
|
||||||
|
- Fix colors in scrollback pager off if the window has redefined terminal
|
||||||
|
colors using escape codes (:iss:`2381`)
|
||||||
|
|
||||||
|
- Fix selection not updating properly while scrolling (:iss:`2442`)
|
||||||
|
|
||||||
|
- Allow extending selections by dragging with right button pressed
|
||||||
|
(:iss:`2445`)
|
||||||
|
|
||||||
|
- Workaround for bug in less that causes colors to reset at wrapped lines
|
||||||
|
(:iss:`2381`)
|
||||||
|
|
||||||
|
- X11/Wayland: Allow drag and drop of text/plain in addition to text/uri-list
|
||||||
|
(:iss:`2441`)
|
||||||
|
|
||||||
|
- Dont strip :code:`&` and :code:`-` from the end of URLs (:iss:`2436`)
|
||||||
|
|
||||||
|
- Fix ``@selection`` placeholder not working with launch command (:iss:`2417`)
|
||||||
|
|
||||||
|
- Drop support for python 3.5
|
||||||
|
|
||||||
|
- Wayland: Fix a crash when drag and dropping into kitty (:iss:`2432`)
|
||||||
|
|
||||||
|
- diff kitten: Fix images lingering as blank rectangles after the kitten quits
|
||||||
|
(:iss:`2449`)
|
||||||
|
|
||||||
|
- diff kitten: Fix images losing position when scrolling using mouse
|
||||||
|
wheel/touchpad
|
||||||
|
|
||||||
|
|
||||||
0.16.0 [2020-01-28]
|
0.16.0 [2020-01-28]
|
||||||
--------------------
|
--------------------
|
||||||
|
|
||||||
|
|||||||
122
docs/conf.py
122
docs/conf.py
@@ -7,28 +7,34 @@
|
|||||||
# full list see the documentation:
|
# full list see the documentation:
|
||||||
# https://www.sphinx-doc.org/en/master/config
|
# https://www.sphinx-doc.org/en/master/config
|
||||||
|
|
||||||
import importlib
|
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
from functools import partial
|
from functools import partial
|
||||||
|
from typing import (
|
||||||
|
Any, Callable, Dict, Iterable, List, Match, Optional, Sequence, Tuple,
|
||||||
|
Union
|
||||||
|
)
|
||||||
|
|
||||||
from docutils import nodes
|
from docutils import nodes
|
||||||
from docutils.parsers.rst.roles import set_classes
|
from docutils.parsers.rst.roles import set_classes
|
||||||
from pygments.lexer import RegexLexer, bygroups
|
from pygments.lexer import RegexLexer, bygroups # type: ignore
|
||||||
from pygments.token import (
|
from pygments.token import ( # type: ignore
|
||||||
Comment, Keyword, Literal, Name, Number, String, Whitespace
|
Comment, Keyword, Literal, Name, Number, String, Whitespace
|
||||||
)
|
)
|
||||||
from sphinx import addnodes
|
from sphinx import addnodes # type: ignore
|
||||||
from sphinx.environment.adapters.toctree import TocTree
|
from sphinx.environment.adapters.toctree import TocTree # type: ignore
|
||||||
from sphinx.util.logging import getLogger
|
from sphinx.util.logging import getLogger # type: ignore
|
||||||
|
|
||||||
kitty_src = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
kitty_src = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||||
if kitty_src not in sys.path:
|
if kitty_src not in sys.path:
|
||||||
sys.path.insert(0, kitty_src)
|
sys.path.insert(0, kitty_src)
|
||||||
str_version = importlib.import_module('kitty.constants').str_version
|
|
||||||
|
from kitty.conf.definition import Option, Shortcut # noqa
|
||||||
|
from kitty.constants import str_version # noqa
|
||||||
|
|
||||||
|
|
||||||
# config {{{
|
# config {{{
|
||||||
# -- Project information -----------------------------------------------------
|
# -- Project information -----------------------------------------------------
|
||||||
@@ -77,7 +83,7 @@ master_doc = 'index'
|
|||||||
#
|
#
|
||||||
# This is also used if you do content translation via gettext catalogs.
|
# This is also used if you do content translation via gettext catalogs.
|
||||||
# Usually you set "language" from the command line for these cases.
|
# Usually you set "language" from the command line for these cases.
|
||||||
language = None
|
language: Optional[str] = None
|
||||||
|
|
||||||
# List of patterns, relative to source directory, that match files and
|
# List of patterns, relative to source directory, that match files and
|
||||||
# directories to ignore when looking for source files.
|
# directories to ignore when looking for source files.
|
||||||
@@ -184,7 +190,7 @@ texinfo_documents = [
|
|||||||
|
|
||||||
# GitHub linking inline roles {{{
|
# GitHub linking inline roles {{{
|
||||||
|
|
||||||
def num_role(which, name, rawtext, text, lineno, inliner, options={}, content=[]):
|
def num_role(which: str, name: str, rawtext: str, text: str, lineno: int, inliner: Any, options: Any = {}, content: Any = []) -> Tuple[List, List]:
|
||||||
' Link to a github issue '
|
' Link to a github issue '
|
||||||
try:
|
try:
|
||||||
issue_num = int(text)
|
issue_num = int(text)
|
||||||
@@ -202,10 +208,11 @@ def num_role(which, name, rawtext, text, lineno, inliner, options={}, content=[]
|
|||||||
return [node], []
|
return [node], []
|
||||||
|
|
||||||
|
|
||||||
def commit_role(name, rawtext, text, lineno, inliner, options={}, content=[]):
|
def commit_role(name: str, rawtext: str, text: str, lineno: int, inliner: Any, options: Any = {}, content: Any = []) -> Tuple[List, List]:
|
||||||
' Link to a github commit '
|
' Link to a github commit '
|
||||||
try:
|
try:
|
||||||
commit_id = subprocess.check_output(f'git rev-list --max-count=1 --skip=# {text}'.split()).decode('utf-8').strip()
|
commit_id = subprocess.check_output(
|
||||||
|
f'git rev-list --max-count=1 --skip=# {text}'.split()).decode('utf-8').strip()
|
||||||
except Exception:
|
except Exception:
|
||||||
msg = inliner.reporter.error(
|
msg = inliner.reporter.error(
|
||||||
f'GitHub commit id "{text}" not recognized.', line=lineno)
|
f'GitHub commit id "{text}" not recognized.', line=lineno)
|
||||||
@@ -213,21 +220,22 @@ def commit_role(name, rawtext, text, lineno, inliner, options={}, content=[]):
|
|||||||
return [prb], [msg]
|
return [prb], [msg]
|
||||||
url = f'https://github.com/kovidgoyal/kitty/commit/{commit_id}'
|
url = f'https://github.com/kovidgoyal/kitty/commit/{commit_id}'
|
||||||
set_classes(options)
|
set_classes(options)
|
||||||
short_id = subprocess.check_output(f'git rev-list --max-count=1 --abbrev-commit --skip=# {commit_id}'.split()).decode('utf-8').strip()
|
short_id = subprocess.check_output(
|
||||||
|
f'git rev-list --max-count=1 --abbrev-commit --skip=# {commit_id}'.split()).decode('utf-8').strip()
|
||||||
node = nodes.reference(rawtext, f'commit: {short_id}', refuri=url, **options)
|
node = nodes.reference(rawtext, f'commit: {short_id}', refuri=url, **options)
|
||||||
return [node], []
|
return [node], []
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
|
|
||||||
# Sidebar ToC {{{
|
# Sidebar ToC {{{
|
||||||
def create_toc(app, pagename):
|
def create_toc(app: Any, pagename: str) -> Optional[Any]:
|
||||||
tt = TocTree(app.env)
|
tt = TocTree(app.env)
|
||||||
toctree = tt.get_toc_for(pagename, app.builder)
|
toctree = tt.get_toc_for(pagename, app.builder)
|
||||||
if toctree is not None:
|
if toctree is not None:
|
||||||
subtree = toctree[toctree.first_child_matching_class(nodes.list_item)]
|
subtree = toctree[toctree.first_child_matching_class(nodes.list_item)]
|
||||||
bl = subtree.first_child_matching_class(nodes.bullet_list)
|
bl = subtree.first_child_matching_class(nodes.bullet_list)
|
||||||
if bl is None:
|
if bl is None:
|
||||||
return # Empty ToC
|
return None # Empty ToC
|
||||||
subtree = subtree[bl]
|
subtree = subtree[bl]
|
||||||
# for li in subtree.traverse(nodes.list_item):
|
# for li in subtree.traverse(nodes.list_item):
|
||||||
# modify_li(li)
|
# modify_li(li)
|
||||||
@@ -235,14 +243,14 @@ def create_toc(app, pagename):
|
|||||||
return app.builder.render_partial(subtree)['fragment']
|
return app.builder.render_partial(subtree)['fragment']
|
||||||
|
|
||||||
|
|
||||||
def add_html_context(app, pagename, templatename, context, *args):
|
def add_html_context(app: Any, pagename: str, templatename: str, context: Any, *args: Any) -> None:
|
||||||
if 'toc' in context:
|
if 'toc' in context:
|
||||||
context['toc'] = create_toc(app, pagename) or context['toc']
|
context['toc'] = create_toc(app, pagename) or context['toc']
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
|
|
||||||
# CLI docs {{{
|
# CLI docs {{{
|
||||||
def write_cli_docs(all_kitten_names):
|
def write_cli_docs(all_kitten_names: Iterable[str]) -> None:
|
||||||
from kitty.launch import options_spec as launch_options_spec
|
from kitty.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:
|
with open('generated/launch.rst', 'w') as f:
|
||||||
@@ -258,16 +266,17 @@ if you specify a program-to-run you can use the special placeholder
|
|||||||
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'))
|
||||||
as_rst = partial(option_spec_as_rst, heading_char='_')
|
as_rst = partial(option_spec_as_rst, heading_char='_')
|
||||||
from kitty.remote_control import global_options_spec, cli_msg, cmap, all_commands
|
from kitty.rc.base import all_command_names, command_for_name
|
||||||
|
from kitty.remote_control import global_options_spec, cli_msg
|
||||||
with open('generated/cli-kitty-at.rst', 'w') as f:
|
with open('generated/cli-kitty-at.rst', 'w') as f:
|
||||||
p = partial(print, file=f)
|
p = partial(print, file=f)
|
||||||
p('kitty @\n' + '-' * 80)
|
p('kitty @\n' + '-' * 80)
|
||||||
p('.. program::', 'kitty @')
|
p('.. program::', 'kitty @')
|
||||||
p('\n\n' + as_rst(
|
p('\n\n' + as_rst(
|
||||||
global_options_spec, message=cli_msg, usage='command ...', appname='kitty @'))
|
global_options_spec, message=cli_msg, usage='command ...', appname='kitty @'))
|
||||||
from kitty.cmds import cli_params_for
|
from kitty.rc.base import cli_params_for
|
||||||
for cmd_name in all_commands:
|
for cmd_name in sorted(all_command_names()):
|
||||||
func = cmap[cmd_name]
|
func = command_for_name(cmd_name)
|
||||||
p(f'.. _at_{func.name}:\n')
|
p(f'.. _at_{func.name}:\n')
|
||||||
p('kitty @', func.name + '\n' + '-' * 120)
|
p('kitty @', func.name + '\n' + '-' * 120)
|
||||||
p('.. program::', 'kitty @', func.name)
|
p('.. program::', 'kitty @', func.name)
|
||||||
@@ -286,14 +295,14 @@ if you specify a program-to-run you can use the special placeholder
|
|||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
|
|
||||||
def write_remote_control_protocol_docs(): # {{{
|
def write_remote_control_protocol_docs() -> None: # {{{
|
||||||
from kitty.cmds import cmap
|
from kitty.rc.base import all_command_names, command_for_name, RemoteCommand
|
||||||
field_pat = re.compile(r'\s*([a-zA-Z0-9_+]+)\s*:\s*(.+)')
|
field_pat = re.compile(r'\s*([a-zA-Z0-9_+]+)\s*:\s*(.+)')
|
||||||
|
|
||||||
def format_cmd(p, name, cmd):
|
def format_cmd(p: Callable, name: str, cmd: RemoteCommand) -> None:
|
||||||
p(name)
|
p(name)
|
||||||
p('-' * 80)
|
p('-' * 80)
|
||||||
lines = cmd.__doc__.strip().splitlines()
|
lines = (cmd.__doc__ or '').strip().splitlines()
|
||||||
fields = []
|
fields = []
|
||||||
for line in lines:
|
for line in lines:
|
||||||
m = field_pat.match(line)
|
m = field_pat.match(line)
|
||||||
@@ -317,10 +326,10 @@ def write_remote_control_protocol_docs(): # {{{
|
|||||||
p(' ', desc), p()
|
p(' ', desc), p()
|
||||||
p(), p()
|
p(), p()
|
||||||
|
|
||||||
with open(f'generated/rc.rst', 'w') as f:
|
with open('generated/rc.rst', 'w') as f:
|
||||||
p = partial(print, file=f)
|
p = partial(print, file=f)
|
||||||
for name in sorted(cmap):
|
for name in sorted(all_command_names()):
|
||||||
cmd = cmap[name]
|
cmd = command_for_name(name)
|
||||||
if not cmd.__doc__:
|
if not cmd.__doc__:
|
||||||
continue
|
continue
|
||||||
name = name.replace('_', '-')
|
name = name.replace('_', '-')
|
||||||
@@ -383,7 +392,7 @@ class SessionLexer(RegexLexer):
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def link_role(name, rawtext, text, lineno, inliner, options={}, content=[]):
|
def link_role(name: str, rawtext: str, text: str, lineno: int, inliner: Any, options: Any = {}, content: Any = []) -> Tuple[List, List]:
|
||||||
m = re.match(r'(.+)\s+<(.+?)>', text)
|
m = re.match(r'(.+)\s+<(.+?)>', text)
|
||||||
if m is None:
|
if m is None:
|
||||||
msg = inliner.reporter.error(f'link "{text}" not recognized', line=lineno)
|
msg = inliner.reporter.error(f'link "{text}" not recognized', line=lineno)
|
||||||
@@ -395,24 +404,24 @@ def link_role(name, rawtext, text, lineno, inliner, options={}, content=[]):
|
|||||||
return [node], []
|
return [node], []
|
||||||
|
|
||||||
|
|
||||||
def expand_opt_references(conf_name, text):
|
def expand_opt_references(conf_name: str, text: str) -> str:
|
||||||
conf_name += '.'
|
conf_name += '.'
|
||||||
|
|
||||||
def expand(m):
|
def expand(m: Match) -> str:
|
||||||
ref = m.group(1)
|
ref = m.group(1)
|
||||||
if '<' not in ref and '.' not in ref:
|
if '<' not in ref and '.' not in ref:
|
||||||
full_ref = conf_name + ref
|
full_ref = conf_name + ref
|
||||||
return ':opt:`{} <{}>`'.format(ref, full_ref)
|
return ':opt:`{} <{}>`'.format(ref, full_ref)
|
||||||
return m.group()
|
return str(m.group())
|
||||||
|
|
||||||
return re.sub(r':opt:`(.+?)`', expand, text)
|
return re.sub(r':opt:`(.+?)`', expand, text)
|
||||||
|
|
||||||
|
|
||||||
opt_aliases = {}
|
opt_aliases: Dict[str, str] = {}
|
||||||
shortcut_slugs = {}
|
shortcut_slugs: Dict[str, Tuple[str, str]] = {}
|
||||||
|
|
||||||
|
|
||||||
def parse_opt_node(env, sig, signode):
|
def parse_opt_node(env: Any, sig: str, signode: Any) -> str:
|
||||||
"""Transform an option description into RST nodes."""
|
"""Transform an option description into RST nodes."""
|
||||||
count = 0
|
count = 0
|
||||||
firstname = ''
|
firstname = ''
|
||||||
@@ -434,22 +443,22 @@ def parse_opt_node(env, sig, signode):
|
|||||||
return firstname
|
return firstname
|
||||||
|
|
||||||
|
|
||||||
def parse_shortcut_node(env, sig, signode):
|
def parse_shortcut_node(env: Any, sig: str, signode: Any) -> str:
|
||||||
"""Transform a shortcut description into RST nodes."""
|
"""Transform a shortcut description into RST nodes."""
|
||||||
conf_name, text = sig.split('.', 1)
|
conf_name, text = sig.split('.', 1)
|
||||||
signode += addnodes.desc_name(text, text)
|
signode += addnodes.desc_name(text, text)
|
||||||
return sig
|
return sig
|
||||||
|
|
||||||
|
|
||||||
def render_conf(conf_name, all_options):
|
def render_conf(conf_name: str, all_options: Iterable[Union['Option', Sequence['Shortcut']]]) -> str:
|
||||||
from kitty.conf.definition import merged_opts, Option
|
from kitty.conf.definition import merged_opts, Option, Group
|
||||||
ans = ['.. default-domain:: conf', '']
|
ans = ['.. default-domain:: conf', '']
|
||||||
a = ans.append
|
a = ans.append
|
||||||
current_group = None
|
current_group: Optional[Group] = None
|
||||||
all_options = list(all_options)
|
all_options_ = list(all_options)
|
||||||
kitty_mod = 'kitty_mod'
|
kitty_mod = 'kitty_mod'
|
||||||
|
|
||||||
def render_group(group):
|
def render_group(group: Group) -> None:
|
||||||
a('')
|
a('')
|
||||||
a(f'.. _conf-{conf_name}-{group.name}:')
|
a(f'.. _conf-{conf_name}-{group.name}:')
|
||||||
a('')
|
a('')
|
||||||
@@ -461,11 +470,12 @@ def render_conf(conf_name, all_options):
|
|||||||
a(group.start_text)
|
a(group.start_text)
|
||||||
a('')
|
a('')
|
||||||
|
|
||||||
def handle_group_end(group):
|
def handle_group_end(group: Group) -> None:
|
||||||
if group.end_text:
|
if group.end_text:
|
||||||
|
assert current_group is not None
|
||||||
a(''), a(current_group.end_text)
|
a(''), a(current_group.end_text)
|
||||||
|
|
||||||
def handle_group(new_group, new_group_is_shortcut=False):
|
def handle_group(new_group: Group, new_group_is_shortcut: bool = False) -> None:
|
||||||
nonlocal current_group
|
nonlocal current_group
|
||||||
if new_group is not current_group:
|
if new_group is not current_group:
|
||||||
if current_group:
|
if current_group:
|
||||||
@@ -473,14 +483,14 @@ def render_conf(conf_name, all_options):
|
|||||||
current_group = new_group
|
current_group = new_group
|
||||||
render_group(current_group)
|
render_group(current_group)
|
||||||
|
|
||||||
def handle_option(i, opt):
|
def handle_option(i: int, opt: Option) -> None:
|
||||||
nonlocal kitty_mod
|
nonlocal kitty_mod
|
||||||
if not opt.long_text or not opt.add_to_docs:
|
if not opt.long_text or not opt.add_to_docs:
|
||||||
return
|
return
|
||||||
handle_group(opt.group)
|
handle_group(opt.group)
|
||||||
if opt.name == 'kitty_mod':
|
if opt.name == 'kitty_mod':
|
||||||
kitty_mod = opt.defval_as_string
|
kitty_mod = opt.defval_as_string
|
||||||
mopts = list(merged_opts(all_options, opt, i))
|
mopts = list(merged_opts(all_options_, opt, i))
|
||||||
a('.. opt:: ' + ', '.join(conf_name + '.' + mo.name for mo in mopts))
|
a('.. opt:: ' + ', '.join(conf_name + '.' + mo.name for mo in mopts))
|
||||||
a('.. code-block:: conf')
|
a('.. code-block:: conf')
|
||||||
a('')
|
a('')
|
||||||
@@ -492,7 +502,7 @@ def render_conf(conf_name, all_options):
|
|||||||
a(expand_opt_references(conf_name, opt.long_text))
|
a(expand_opt_references(conf_name, opt.long_text))
|
||||||
a('')
|
a('')
|
||||||
|
|
||||||
def handle_shortcuts(shortcuts):
|
def handle_shortcuts(shortcuts: Sequence[Shortcut]) -> None:
|
||||||
sc = shortcuts[0]
|
sc = shortcuts[0]
|
||||||
handle_group(sc.group, True)
|
handle_group(sc.group, True)
|
||||||
sc_text = f'{conf_name}.{sc.short_text}'
|
sc_text = f'{conf_name}.{sc.short_text}'
|
||||||
@@ -510,7 +520,7 @@ def render_conf(conf_name, all_options):
|
|||||||
a(expand_opt_references(conf_name, sc.long_text))
|
a(expand_opt_references(conf_name, sc.long_text))
|
||||||
a('')
|
a('')
|
||||||
|
|
||||||
for i, opt in enumerate(all_options):
|
for i, opt in enumerate(all_options_):
|
||||||
if isinstance(opt, Option):
|
if isinstance(opt, Option):
|
||||||
handle_option(i, opt)
|
handle_option(i, opt)
|
||||||
else:
|
else:
|
||||||
@@ -521,7 +531,7 @@ def render_conf(conf_name, all_options):
|
|||||||
return '\n'.join(ans)
|
return '\n'.join(ans)
|
||||||
|
|
||||||
|
|
||||||
def process_opt_link(env, refnode, has_explicit_title, title, target):
|
def process_opt_link(env: Any, refnode: Any, has_explicit_title: bool, title: str, target: str) -> Tuple[str, str]:
|
||||||
conf_name, opt = target.partition('.')[::2]
|
conf_name, opt = target.partition('.')[::2]
|
||||||
if not opt:
|
if not opt:
|
||||||
conf_name, opt = 'kitty', conf_name
|
conf_name, opt = 'kitty', conf_name
|
||||||
@@ -529,7 +539,7 @@ def process_opt_link(env, refnode, has_explicit_title, title, target):
|
|||||||
return title, opt_aliases.get(full_name, full_name)
|
return title, opt_aliases.get(full_name, full_name)
|
||||||
|
|
||||||
|
|
||||||
def process_shortcut_link(env, refnode, has_explicit_title, title, target):
|
def process_shortcut_link(env: Any, refnode: Any, has_explicit_title: bool, title: str, target: str) -> Tuple[str, str]:
|
||||||
conf_name, slug = target.partition('.')[::2]
|
conf_name, slug = target.partition('.')[::2]
|
||||||
if not slug:
|
if not slug:
|
||||||
conf_name, slug = 'kitty', conf_name
|
conf_name, slug = 'kitty', conf_name
|
||||||
@@ -544,8 +554,8 @@ def process_shortcut_link(env, refnode, has_explicit_title, title, target):
|
|||||||
return title, target
|
return title, target
|
||||||
|
|
||||||
|
|
||||||
def write_conf_docs(app, all_kitten_names):
|
def write_conf_docs(app: Any, all_kitten_names: Iterable[str]) -> None:
|
||||||
app.add_lexer('conf', ConfLexer())
|
app.add_lexer('conf', ConfLexer)
|
||||||
app.add_object_type(
|
app.add_object_type(
|
||||||
'opt', 'opt',
|
'opt', 'opt',
|
||||||
indextemplate="pair: %s; Config Setting",
|
indextemplate="pair: %s; Config Setting",
|
||||||
@@ -565,7 +575,7 @@ def write_conf_docs(app, all_kitten_names):
|
|||||||
sc_role.warn_dangling = True
|
sc_role.warn_dangling = True
|
||||||
sc_role.process_link = process_shortcut_link
|
sc_role.process_link = process_shortcut_link
|
||||||
|
|
||||||
def generate_default_config(all_options, name):
|
def generate_default_config(all_options: Dict[str, Union[Option, Sequence[Shortcut]]], name: str) -> None:
|
||||||
from kitty.conf.definition import as_conf_file
|
from kitty.conf.definition import as_conf_file
|
||||||
with open(f'generated/conf-{name}.rst', 'w', encoding='utf-8') as f:
|
with open(f'generated/conf-{name}.rst', 'w', encoding='utf-8') as f:
|
||||||
print('.. highlight:: conf\n', file=f)
|
print('.. highlight:: conf\n', file=f)
|
||||||
@@ -587,14 +597,14 @@ def write_conf_docs(app, all_kitten_names):
|
|||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
|
|
||||||
def setup(app):
|
def setup(app: Any) -> None:
|
||||||
os.makedirs('generated/conf', exist_ok=True)
|
os.makedirs('generated/conf', exist_ok=True)
|
||||||
from kittens.runner import all_kitten_names
|
from kittens.runner import all_kitten_names
|
||||||
all_kitten_names = all_kitten_names()
|
kn = all_kitten_names()
|
||||||
write_cli_docs(all_kitten_names)
|
write_cli_docs(kn)
|
||||||
write_remote_control_protocol_docs()
|
write_remote_control_protocol_docs()
|
||||||
write_conf_docs(app, all_kitten_names)
|
write_conf_docs(app, kn)
|
||||||
app.add_lexer('session', SessionLexer())
|
app.add_lexer('session', SessionLexer)
|
||||||
app.add_role('link', link_role)
|
app.add_role('link', link_role)
|
||||||
app.add_role('iss', partial(num_role, 'issues'))
|
app.add_role('iss', partial(num_role, 'issues'))
|
||||||
app.add_role('pull', partial(num_role, 'pull'))
|
app.add_role('pull', partial(num_role, 'pull'))
|
||||||
|
|||||||
40
docs/faq.rst
40
docs/faq.rst
@@ -165,11 +165,14 @@ kitty is not able to use my favorite font?
|
|||||||
|kitty| achieves its stellar performance by caching alpha masks of each rendered
|
|kitty| achieves its stellar performance by caching alpha masks of each rendered
|
||||||
character on the GPU, so that every character needs to be rendered only once.
|
character on the GPU, so that every character needs to be rendered only once.
|
||||||
This means it is a strictly character cell based display. As such it can use
|
This means it is a strictly character cell based display. As such it can use
|
||||||
only monospace fonts, since every cell in the grid has to be the same size. If
|
only monospace fonts, since every cell in the grid has to be the same size.
|
||||||
your font is not listed in ``kitty list-fonts`` it means that it is not
|
Furthermore, it needs fonts to be freely resizable, so it does not support
|
||||||
monospace. On Linux you can list all monospace fonts with::
|
bitmapped fonts.
|
||||||
|
|
||||||
fc-list : family spacing | grep -e spacing=100 -e spacing=90
|
If your font is not listed in ``kitty list-fonts`` it means that it is not
|
||||||
|
monospace or is a bitmapped font. On Linux you can list all monospace fonts with::
|
||||||
|
|
||||||
|
fc-list : family spacing outline scalable | grep -e spacing=100 -e spacing=90 | grep -e outline=True | grep -e scalable=True
|
||||||
|
|
||||||
Note that the spacing property is calculated by fontconfig based on actual
|
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
|
glyph widths in the font. If for some reason fontconfig concludes your favorite
|
||||||
@@ -179,7 +182,7 @@ following :file:`~/.config/fontconfig/fonts.conf`::
|
|||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
|
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
|
||||||
<fontconfig>
|
<fontconfig>
|
||||||
<match target="scan">
|
<match target="font">
|
||||||
<test name="family">
|
<test name="family">
|
||||||
<string>Your Font Family Name</string>
|
<string>Your Font Family Name</string>
|
||||||
</test>
|
</test>
|
||||||
@@ -232,3 +235,30 @@ available. The manual way to figure it out is:
|
|||||||
This shows the hex value, ``13`` in this case.
|
This shows the hex value, ``13`` in this case.
|
||||||
|
|
||||||
3. Use ``\x(hexval)`` in your ``send_text`` command in kitty. So in this example, ``\x13``
|
3. Use ``\x(hexval)`` in your ``send_text`` command in kitty. So in this example, ``\x13``
|
||||||
|
|
||||||
|
|
||||||
|
I am using tmux and have a problem
|
||||||
|
--------------------------------------
|
||||||
|
|
||||||
|
First, terminal multiplexers are `a bad idea
|
||||||
|
<https://github.com/kovidgoyal/kitty/issues/391#issuecomment-638320745>`_, do
|
||||||
|
not use them, if at all possible. kitty contains features that do all of what
|
||||||
|
tmux does, but better, with the exception of remote persistence (:iss:`391`).
|
||||||
|
If you still want to use tmux, read on.
|
||||||
|
|
||||||
|
Image display will not work, see `tmux issue
|
||||||
|
<https://github.com/tmux/tmux/issues/1391>`_.
|
||||||
|
|
||||||
|
If you are using tmux with multiple terminals or you start it under one
|
||||||
|
terminal and then switch to another and these terminals have different TERM
|
||||||
|
variables, tmux will break. You will need to restart it as tmux does not
|
||||||
|
support multiple terminfo definitions.
|
||||||
|
|
||||||
|
Copying to clipboard via OSC 52 will not work, because tmux does not support
|
||||||
|
the extended version of that protocol, you will need to add ``no-append`` to
|
||||||
|
:opt:`clipboard_control` in kitty.conf.
|
||||||
|
|
||||||
|
If you use any of the advanced features that kitty has innovated, such as
|
||||||
|
styled underlines, desktop notifications, extended keyboard support, etc.
|
||||||
|
they may or may not work, depending on the whims of tmux's maintainer, your
|
||||||
|
version of tmux, etc.
|
||||||
|
|||||||
@@ -30,12 +30,14 @@ alpha-blending and text over graphics.
|
|||||||
|
|
||||||
Some programs that use the kitty graphics protocol:
|
Some programs that use the kitty graphics protocol:
|
||||||
|
|
||||||
* `termpdf <https://github.com/dsanson/termpdf>`_ - a terminal PDF/DJVU/CBR viewer
|
* `termpdf.py <https://github.com/dsanson/termpdf.py>`_ - a terminal PDF/DJVU/CBR viewer
|
||||||
* `ranger <https://github.com/ranger/ranger>`_ - a terminal file manager, with
|
* `ranger <https://github.com/ranger/ranger>`_ - a terminal file manager, with
|
||||||
image previews, see this `PR <https://github.com/ranger/ranger/pull/1077>`_
|
image previews, see this `PR <https://github.com/ranger/ranger/pull/1077>`_
|
||||||
* :doc:`kitty-diff <kittens/diff>` - a side-by-side terminal diff program with support for images
|
* :doc:`kitty-diff <kittens/diff>` - a side-by-side terminal diff program with support for images
|
||||||
|
* `pixcat <https://github.com/mirukana/pixcat>`_ - a third party CLI and python library that wraps the graphics protocol
|
||||||
* `neofetch <https://github.com/dylanaraps/neofetch>`_ - A command line system
|
* `neofetch <https://github.com/dylanaraps/neofetch>`_ - A command line system
|
||||||
information tool
|
information tool
|
||||||
|
* `viu <https://github.com/atanunq/viu>`_ - a terminal image viewer
|
||||||
|
|
||||||
|
|
||||||
.. contents::
|
.. contents::
|
||||||
@@ -53,27 +55,34 @@ In C:
|
|||||||
|
|
||||||
.. code-block:: c
|
.. code-block:: c
|
||||||
|
|
||||||
struct ttysize ts;
|
#include <stdio.h>
|
||||||
ioctl(0, TIOCGWINSZ, &ts);
|
#include <sys/ioctl.h>
|
||||||
printf("number of columns: %i, number of rows: %i, screen width: %i, screen height: %i\n", sz.ws_col, sz.ws_row, sz.ws_xpixel, sz.ws_ypixel);
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
struct winsize sz;
|
||||||
|
ioctl(0, TIOCGWINSZ, &sz);
|
||||||
|
printf("number of rows: %i, number of columns: %i, screen width: %i, screen height: %i\n", sz.ws_row, sz.ws_col, sz.ws_xpixel, sz.ws_ypixel);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
In Python:
|
In Python:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
import array, fcntl, termios
|
import array, fcntl, sys, termios
|
||||||
buf = array.array('H', [0, 0, 0, 0])
|
buf = array.array('H', [0, 0, 0, 0])
|
||||||
fcntl.ioctl(sys.stdout, termios.TIOCGWINSZ, buf)
|
fcntl.ioctl(sys.stdout, termios.TIOCGWINSZ, buf)
|
||||||
print('number of columns: {}, number of rows: {}, screen width: {}, screen height: {}'.format(*buf))
|
print('number of rows: {}, number of columns: {}, screen width: {}, screen height: {}'.format(*buf))
|
||||||
|
|
||||||
Note that some terminals return ``0`` for the width and height values. Such
|
Note that some terminals return ``0`` for the width and height values. Such
|
||||||
terminals should be modified to return the correct values. Examples of
|
terminals should be modified to return the correct values. Examples of
|
||||||
terminals that return correct values: ``kitty, xterm``
|
terminals that return correct values: ``kitty, xterm``
|
||||||
|
|
||||||
You can also use the *CSI t* escape code to get the screen size. Send
|
You can also use the *CSI t* escape code to get the screen size. Send
|
||||||
``<ESC>[14t`` to *stdout* and kitty will reply on *stdin* with
|
``<ESC>[14t`` to ``STDOUT`` and kitty will reply on ``STDIN`` with
|
||||||
``<ESC>[4;<height>;<width>t`` where *height* and *width* are the window size in
|
``<ESC>[4;<height>;<width>t`` where ``height`` and ``width`` are the window
|
||||||
pixels. This escape code is supported in many terminals, not just kitty.
|
size in pixels. This escape code is supported in many terminals, not just
|
||||||
|
kitty.
|
||||||
|
|
||||||
A minimal example
|
A minimal example
|
||||||
------------------
|
------------------
|
||||||
@@ -153,9 +162,10 @@ of transmitting paletted images.
|
|||||||
RGB and RGBA data
|
RGB and RGBA data
|
||||||
~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
In these formats the pixel data is stored directly as 3 or 4 bytes per pixel, respectively.
|
In these formats the pixel data is stored directly as 3 or 4 bytes per pixel,
|
||||||
When specifying images in this format, the image dimensions **must** be sent in the control data.
|
respectively. The colors in the data **must** be in the *sRGB color space*. When
|
||||||
For example::
|
specifying images in this format, the image dimensions **must** be sent in the
|
||||||
|
control data. For example::
|
||||||
|
|
||||||
<ESC>_Gf=24,s=10,v=20;<payload><ESC>\
|
<ESC>_Gf=24,s=10,v=20;<payload><ESC>\
|
||||||
|
|
||||||
@@ -262,8 +272,8 @@ received. Finally, terminals must not display anything, until the entire sequenc
|
|||||||
received and validated.
|
received and validated.
|
||||||
|
|
||||||
|
|
||||||
Detecting available transmission mediums
|
Querying support and available transmission mediums
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
Since a client has no a-priori knowledge of whether it shares a filesystem/shared memory
|
Since a client has no a-priori knowledge of whether it shares a filesystem/shared memory
|
||||||
with the terminal emulator, it can send an id with the control data, using the ``i`` key
|
with the terminal emulator, it can send an id with the control data, using the ``i`` key
|
||||||
@@ -289,6 +299,27 @@ use the *query action*, set ``a=q``. Then the terminal emulator will try to load
|
|||||||
the image and respond with either OK or an error, as above, but it will not
|
the image and respond with either OK or an error, as above, but it will not
|
||||||
replace an existing image with the same id, nor will it store the image.
|
replace an existing image with the same id, nor will it store the image.
|
||||||
|
|
||||||
|
While as of May 2020, kitty is the only terminal emulator to support this
|
||||||
|
graphics protocol, we intend that any terminal emulator that wishes to support
|
||||||
|
it can. To check if a terminal emulator supports the graphics protocol the best way
|
||||||
|
is to send the above *query action* followed by a request for the
|
||||||
|
`primary device attributes <https://vt100.net/docs/vt510-rm/DA1.html>`. If you
|
||||||
|
get back an answer for the device attributes without getting back an answer for
|
||||||
|
the *query action* the terminal emulator does not support the graphics
|
||||||
|
protocol.
|
||||||
|
|
||||||
|
This means that terminal emulators that support the graphics protocol, **must**
|
||||||
|
reply to *query actions* immediately without processing other input. Most
|
||||||
|
terminal emulators handle input in a FIFO manner, anyway.
|
||||||
|
|
||||||
|
So for example, you could send::
|
||||||
|
|
||||||
|
<ESC>_Gi=31,s=1,v=1,a=q,t=d,f=24;<NUL><NUL><NUL><ESC>\<ESC>[c
|
||||||
|
|
||||||
|
If you get back a response to the graphics query, the terminal emulator supports
|
||||||
|
the protocol, if you get back a response to the device attributes query without
|
||||||
|
a response to the graphics query, it does not.
|
||||||
|
|
||||||
|
|
||||||
Display images on screen
|
Display images on screen
|
||||||
-----------------------------
|
-----------------------------
|
||||||
@@ -368,10 +399,10 @@ Value of ``d`` Meaning
|
|||||||
|
|
||||||
Some examples::
|
Some examples::
|
||||||
|
|
||||||
<ESC>_Ga=d<ESC>\ # delete all visible images
|
<ESC>_Ga=d<ESC>\ # delete all visible images
|
||||||
<ESC>_Ga=d,i=10<ESC>\ # delete the image with id=10
|
<ESC>_Ga=d,d=i,i=10<ESC>\ # delete the image with id=10, without freeing data
|
||||||
<ESC>_Ga=Z,z=-1<ESC>\ # delete the images with z-index -1, also freeing up image data
|
<ESC>_Ga=d,d=Z,z=-1<ESC>\ # delete the images with z-index -1, also freeing up image data
|
||||||
<ESC>_Ga=P,x=3,y=4<ESC>\ # delete all images that intersect the cell at (3, 4)
|
<ESC>_Ga=d,d=p,x=3,y=4<ESC>\ # delete all images that intersect the cell at (3, 4), without freeing data
|
||||||
|
|
||||||
Image persistence and storage quotas
|
Image persistence and storage quotas
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|||||||
107
docs/index.rst
107
docs/index.rst
@@ -10,10 +10,12 @@ kitty - the fast, featureful, GPU based terminal emulator
|
|||||||
buttery smooth scrolling. Uses threaded rendering to minimize input latency.
|
buttery smooth scrolling. Uses threaded rendering to minimize input latency.
|
||||||
|
|
||||||
* Supports all modern terminal features: :doc:`graphics (images)
|
* Supports all modern terminal features: :doc:`graphics (images)
|
||||||
<graphics-protocol>`, unicode, true-color, OpenType ligatures, mouse
|
<graphics-protocol>`, unicode, `true-color
|
||||||
protocol, focus tracking, `bracketed paste
|
<https://gist.github.com/XVilka/8346728>`_,
|
||||||
<https://cirw.in/blog/bracketed-paste>`_ and several :doc:`new terminal
|
OpenType ligatures, mouse protocol, :doc:`hyperlinks <open_actions>`,
|
||||||
protocol extensions <protocol-extensions>`.
|
focus tracking, `bracketed paste <https://cirw.in/blog/bracketed-paste>`_
|
||||||
|
and several :doc:`new terminal protocol extensions
|
||||||
|
<protocol-extensions>`.
|
||||||
|
|
||||||
* Supports tiling multiple terminal windows side by side in different
|
* Supports tiling multiple terminal windows side by side in different
|
||||||
:ref:`layouts <layouts>` without needing to use an extra program like tmux
|
:ref:`layouts <layouts>` without needing to use an extra program like tmux
|
||||||
@@ -65,7 +67,7 @@ You can also use your favorite package manager to install the |kitty| package.
|
|||||||
`openSUSE <https://build.opensuse.org/package/show/X11:terminals/kitty>`_,
|
`openSUSE <https://build.opensuse.org/package/show/X11:terminals/kitty>`_,
|
||||||
`Arch Linux <https://www.archlinux.org/packages/community/x86_64/kitty/>`_,
|
`Arch Linux <https://www.archlinux.org/packages/community/x86_64/kitty/>`_,
|
||||||
`Gentoo <https://packages.gentoo.org/packages/x11-terms/kitty>`_,
|
`Gentoo <https://packages.gentoo.org/packages/x11-terms/kitty>`_,
|
||||||
`Fedora <https://copr.fedorainfracloud.org/coprs/gagbo/kitty-latest/>`_,
|
`Fedora <https://src.fedoraproject.org/rpms/kitty>`_,
|
||||||
`Void Linux <https://github.com/void-linux/void-packages/blob/master/srcpkgs/kitty/template>`_,
|
`Void Linux <https://github.com/void-linux/void-packages/blob/master/srcpkgs/kitty/template>`_,
|
||||||
and `Solus <https://dev.getsol.us/source/kitty/>`_.
|
and `Solus <https://dev.getsol.us/source/kitty/>`_.
|
||||||
|
|
||||||
@@ -178,14 +180,25 @@ previously active windows for negative numbers.
|
|||||||
You can define shortcuts to detach the current window and
|
You can define shortcuts to detach the current window and
|
||||||
move it to another tab or another OS window::
|
move it to another tab or another OS window::
|
||||||
|
|
||||||
map ctrl+f2 detach_window # moves the window into a new OS 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+f2 detach_window
|
||||||
map ctrl+f4 detach_window ask # asks which tab to move the window into
|
# moves the window into a new Tab
|
||||||
|
map ctrl+f3 detach_window new-tab
|
||||||
|
# asks which tab to move the window into
|
||||||
|
map ctrl+f4 detach_window ask
|
||||||
|
|
||||||
Similarly, you can detach the current tab, with::
|
Similarly, you can detach the current tab, with::
|
||||||
|
|
||||||
map ctrl+f2 detach_tab # moves the tab into a new OS window
|
# moves the tab into a new OS window
|
||||||
map ctrl+f4 detach_tab ask # asks which OS Window to move the tab into
|
map ctrl+f2 detach_tab
|
||||||
|
# asks which OS Window to move the tab into
|
||||||
|
map ctrl+f4 detach_tab ask
|
||||||
|
|
||||||
|
Finally, you can define a shortcut to close all windows in a tab other than
|
||||||
|
the currently active window::
|
||||||
|
|
||||||
|
map f9 close_other_windows_in_tab
|
||||||
|
|
||||||
|
|
||||||
Other keyboard shortcuts
|
Other keyboard shortcuts
|
||||||
----------------------------------
|
----------------------------------
|
||||||
@@ -219,57 +232,26 @@ Reset background opacity :sc:`reset_background_opacity`
|
|||||||
Layouts
|
Layouts
|
||||||
----------
|
----------
|
||||||
|
|
||||||
A layout is an arrangement of multiple *windows*. You can create a new window
|
A layout is an arrangement of multiple kitty *windows* inside a top-level OS window. You can create a new window
|
||||||
using the :sc:`new_window` key combination.
|
using the :sc:`new_window` key combination.
|
||||||
|
|
||||||
Currently, there are five layouts available,
|
Currently, there are six layouts available:
|
||||||
|
|
||||||
* **Fat** -- One (or optionally more) windows are shown full width on the top, the rest of the windows are shown side-by-side on the bottom
|
* **Fat** -- One (or optionally more) windows are shown full width on the top, the rest of the windows are shown side-by-side on the bottom
|
||||||
* **Grid** -- All windows are shown in a grid
|
* **Grid** -- All windows are shown in a grid
|
||||||
* **Horizontal** -- All windows are shown side-by-side
|
* **Horizontal** -- All windows are shown side-by-side
|
||||||
|
* **Splits** -- Windows arranged in arbitrary patterns created using horizontal and vertical splits
|
||||||
* **Stack** -- Only a single maximized window is shown at a time
|
* **Stack** -- Only a single maximized window is shown at a time
|
||||||
* **Tall** -- One (or optionally more) windows are shown full height on the left, the rest of the windows are shown one below the other on the right
|
* **Tall** -- One (or optionally more) windows are shown full height on the left, the rest of the windows are shown one below the other on the right
|
||||||
* **Vertical** -- All windows are shown one below the other
|
* **Vertical** -- All windows are shown one below the other
|
||||||
|
|
||||||
You can switch between layouts using the :sc:`next_layout` key combination. You can
|
By default, all layouts are enabled and you can switch between layouts using
|
||||||
also create shortcuts to select particular layouts, and choose which layouts
|
the :sc:`next_layout` key combination. You can also create shortcuts to select
|
||||||
you want to enable/disable, see :ref:`conf-kitty-shortcuts.layout` for examples.
|
particular layouts, and choose which layouts you want to enable/disable, see
|
||||||
|
:ref:`conf-kitty-shortcuts.layout` for examples. The first layout listed in
|
||||||
|
:opt:`enabled_layouts` becomes the default layout.
|
||||||
|
|
||||||
You can resize windows inside layouts. Press :sc:`start_resizing_window` (also :kbd:`⌘+r` on macOS) to
|
For more details on the layouts and how to use them see :doc:`layouts`.
|
||||||
enter resizing mode and follow the on-screen instructions. In a given window
|
|
||||||
layout only some operations may be possible for a particular window. For
|
|
||||||
example, in the Tall layout you can make the first window wider/narrower, but
|
|
||||||
not taller/shorter. Note that what you are resizing is actually not a window,
|
|
||||||
but a row/column in the layout, all windows in that row/column will be resized.
|
|
||||||
|
|
||||||
You can also define shortcuts in :file:`kitty.conf` to make the active window
|
|
||||||
wider, narrower, taller, or shorter by mapping to the ``resize_window``
|
|
||||||
action, for example::
|
|
||||||
|
|
||||||
map ctrl+left resize_window narrower
|
|
||||||
map ctrl+right resize_window wider
|
|
||||||
map ctrl+up resize_window taller
|
|
||||||
map ctrl+down resize_window shorter 3
|
|
||||||
|
|
||||||
The ``resize_window`` action has a second, optional argument to control
|
|
||||||
the resizing increment (a positive integer that defaults to 1).
|
|
||||||
|
|
||||||
|
|
||||||
Some layouts take options to control their behavior. For example, the ``fat``
|
|
||||||
and ``tall`` layouts accept the ``bias`` and ``full_size`` options to control
|
|
||||||
how the available space is split up.
|
|
||||||
To specify the option, in :opt:`kitty.conf <enabled_layouts>` use::
|
|
||||||
|
|
||||||
enabled_layouts tall:bias=70;full_size=2
|
|
||||||
|
|
||||||
This will have ``2`` instead of a single tall window, that occupy ``70%``
|
|
||||||
instead of ``50%`` of available width. ``bias`` can be any number between 10
|
|
||||||
and 90.
|
|
||||||
|
|
||||||
Writing a new layout only requires about a hundred lines of code, so if there
|
|
||||||
is some layout you want, take a look at `layout.py
|
|
||||||
<https://github.com/kovidgoyal/kitty/blob/master/kitty/layout.py>`_ and submit
|
|
||||||
a pull request!
|
|
||||||
|
|
||||||
.. _kittens:
|
.. _kittens:
|
||||||
|
|
||||||
@@ -366,11 +348,22 @@ For example:
|
|||||||
new_os_window
|
new_os_window
|
||||||
# set new window size to 80x25 cells
|
# set new window size to 80x25 cells
|
||||||
os_window_size 80c 25c
|
os_window_size 80c 25c
|
||||||
|
# set the --class for the new OS window
|
||||||
|
os_window_class mywindow
|
||||||
launch sh
|
launch sh
|
||||||
# Make the current window the active (focused) window
|
# Make the current window the active (focused) window
|
||||||
focus
|
focus
|
||||||
launch emacs
|
launch emacs
|
||||||
|
|
||||||
|
# Add a watcher that will be called with various events that occur
|
||||||
|
# on all subsequent windows. See the documentation of the launch command
|
||||||
|
# for details on watchers.
|
||||||
|
watcher /some/python/file.py
|
||||||
|
launch mpd
|
||||||
|
launch irssi
|
||||||
|
# Remove the watcher for further windows
|
||||||
|
watcher clear
|
||||||
|
|
||||||
|
|
||||||
Mouse features
|
Mouse features
|
||||||
-------------------
|
-------------------
|
||||||
@@ -380,11 +373,12 @@ Mouse features
|
|||||||
* You can triple click to select a line and then drag to select more lines.
|
* You can triple click to select a line and then drag to select more lines.
|
||||||
* You can right click to extend a previous selection.
|
* You can right click to extend a previous selection.
|
||||||
* You can hold down :kbd:`ctrl+alt` and drag with the mouse to select in
|
* You can hold down :kbd:`ctrl+alt` and drag with the mouse to select in
|
||||||
columns.
|
columns (see also :opt:`rectangle_select_modifiers`).
|
||||||
* Selecting text automatically copies it to the primary clipboard (on
|
* Selecting text automatically copies it to the primary clipboard (on
|
||||||
platforms with a primary clipboard).
|
platforms with a primary clipboard).
|
||||||
* You can select text with kitty even when a terminal program has grabbed
|
* You can select text with kitty even when a terminal program has grabbed
|
||||||
the mouse by holding down the :kbd:`shift` key.
|
the mouse by holding down the :kbd:`shift` key (see also
|
||||||
|
:opt:`terminal_select_modifiers`).
|
||||||
|
|
||||||
|
|
||||||
Font control
|
Font control
|
||||||
@@ -458,6 +452,15 @@ The list of Frequently Asked Questions (*FAQ*) is :doc:`available here <faq>`.
|
|||||||
|
|
||||||
.. _completion:
|
.. _completion:
|
||||||
|
|
||||||
|
|
||||||
|
Cool integrations for kitty with other CLI tools
|
||||||
|
--------------------------------------------------
|
||||||
|
|
||||||
|
kitty provides extremely powerful interfaces such as :doc:`remote-control` and
|
||||||
|
:doc:`kittens/custom` and :doc:`kittens/icat`
|
||||||
|
that allow it to be integrated with other tools seamlessly. For a list of such
|
||||||
|
user created integrations, see: :doc:`integrations`.
|
||||||
|
|
||||||
Completion for kitty
|
Completion for kitty
|
||||||
---------------------------------
|
---------------------------------
|
||||||
|
|
||||||
|
|||||||
125
docs/integrations.rst
Normal file
125
docs/integrations.rst
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
Integrations with other tools
|
||||||
|
================================
|
||||||
|
|
||||||
|
kitty provides extremely powerful interfaces such as :doc:`remote-control` and
|
||||||
|
:doc:`kittens/custom` and :doc:`kittens/icat`
|
||||||
|
that allow it to be integrated with other tools seamlessly.
|
||||||
|
|
||||||
|
|
||||||
|
Image and document viewers
|
||||||
|
----------------------------
|
||||||
|
|
||||||
|
Powered by kitty's :doc:`graphics-protocol` there exist many tools for viewing
|
||||||
|
images and other types of documents directly in your terminal, even over SSH.
|
||||||
|
|
||||||
|
`termpdf.py <https://github.com/dsanson/termpdf.py>`_
|
||||||
|
a terminal PDF/DJVU/CBR viewer
|
||||||
|
|
||||||
|
`mdcat <https://github.com/lunaryorn/mdcat>`_
|
||||||
|
Display markdown files nicely formatted with images in the terminal
|
||||||
|
|
||||||
|
`ranger <https://github.com/ranger/ranger>`_
|
||||||
|
a terminal file manager, with previews of file contents powered by kitty's graphics protocol.
|
||||||
|
|
||||||
|
`nnn <https://github.com/jarun/nnn/>`_
|
||||||
|
another terminal file manager, with previews of file contents powered by kitty's graphics protocol.
|
||||||
|
|
||||||
|
`hunter <https://github.com/rabite0/hunter>`_
|
||||||
|
another terminal file manager, with previews of file contents powered by kitty's graphics protocol.
|
||||||
|
|
||||||
|
`koneko <https://github.com/twenty5151/koneko>`_
|
||||||
|
browse images from the pixiv artist community directly in kitty
|
||||||
|
|
||||||
|
`viu <https://github.com/atanunq/viu>`_
|
||||||
|
view images in the terminal, similar to kitty's icat, however also supports
|
||||||
|
displaying animated GIFs
|
||||||
|
|
||||||
|
|
||||||
|
System and data visualisation tools
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
`neofetch <https://github.com/dylanaraps/neofetch>`_
|
||||||
|
A command line system information tool that shows images using kitty's graphics protocol
|
||||||
|
|
||||||
|
`matplotlib <https://github.com/jktr/matplotlib-backend-kitty>`_
|
||||||
|
show matplotlib plots directly in kitty
|
||||||
|
|
||||||
|
`KittyTerminalImages.jl <https://github.com/simonschoelly/KittyTerminalImages.jl>`_
|
||||||
|
show images from Julia directly in kitty
|
||||||
|
|
||||||
|
`gnuplot <http://www.gnuplot.info/>`_
|
||||||
|
a graphing and data visualization tool that can be made to display its
|
||||||
|
output in kitty with the following bash snippet::
|
||||||
|
|
||||||
|
function iplot {
|
||||||
|
cat <<EOF | gnuplot
|
||||||
|
set terminal pngcairo enhanced font 'Fira Sans,10'
|
||||||
|
set autoscale
|
||||||
|
set samples 1000
|
||||||
|
set output '|kitty +kitten icat --stdin yes'
|
||||||
|
set object 1 rectangle from screen 0,0 to screen 1,1 fillcolor rgb"#fdf6e3" behind
|
||||||
|
plot $@
|
||||||
|
set output '/dev/null'
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
Add this to bashrc and then to plot a function, simply do::
|
||||||
|
|
||||||
|
iplot 'sin(x*3)*exp(x*.2)'
|
||||||
|
|
||||||
|
`onefetch <https://github.com/o2sh/onefetch>`_
|
||||||
|
a tool to fetch information about your git repositories
|
||||||
|
|
||||||
|
|
||||||
|
Editor integration
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
kitty can be integrated into many different terminal editors to add features
|
||||||
|
such a split windows, previews, REPLs etc.
|
||||||
|
|
||||||
|
|
||||||
|
`kakoune <https://kakoune.org/>`_
|
||||||
|
integrates with kitty to use native kitty windows for its windows/panels and REPLs.
|
||||||
|
|
||||||
|
`vim-slime <https://github.com/jpalardy/vim-slime#kitty>`_
|
||||||
|
uses kitty remote control for a Lisp REPL.
|
||||||
|
|
||||||
|
`vim-kitty-navigator <https://github.com/knubie/vim-kitty-navigator>`_
|
||||||
|
allows you to navigate seamlessly between vim and kitty splits using a consistent set of hotkeys.
|
||||||
|
|
||||||
|
`vim-test <https://github.com/vim-test/vim-test>`_
|
||||||
|
allows easily running tests in a terminal window
|
||||||
|
|
||||||
|
|
||||||
|
Scrollback manipulation
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
`kitty-search <https://github.com/trygveaa/kitty-kitten-search>`_
|
||||||
|
Live incremental search of the scrollback buffer.
|
||||||
|
|
||||||
|
`kitty-grab <https://github.com/yurikhan/kitty_grab>`_
|
||||||
|
keyboard based text selection for the kitty scrollback buffer.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Miscellaneous
|
||||||
|
------------------
|
||||||
|
|
||||||
|
`kitty-smart-tab <https://github.com/yurikhan/kitty-smart-tab>`_
|
||||||
|
use keys to either control tabs or pass them onto running applications if
|
||||||
|
no tabs are present
|
||||||
|
|
||||||
|
`kitty-smart-scroll <https://github.com/yurikhan/kitty-smart-scroll>`_
|
||||||
|
use keys to either scroll or pass them onto running applications if
|
||||||
|
no scrollback buffer is present
|
||||||
|
|
||||||
|
`reload keybindings <https://github.com/kovidgoyal/kitty/issues/1292#issuecomment-582388769>`_
|
||||||
|
reload key bindings from :file:`kitty.conf` without needing to restart
|
||||||
|
kitty
|
||||||
|
|
||||||
|
`kitti3 <https://github.com/LandingEllipse/kitti3>`_
|
||||||
|
allow using kitty as a drop-down terminal under the i3 window manager
|
||||||
|
|
||||||
|
`weechat-hints <https://github.com/GermainZ/kitty-weechat-hints>`_
|
||||||
|
URL hints kitten for WeeChat that works without having to use WeeChat's
|
||||||
|
raw-mode.
|
||||||
@@ -20,24 +20,24 @@ your machine).
|
|||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
def main(args):
|
def main(args: List[str]) -> str:
|
||||||
# this is the main entry point of the kitten, it will be executed in
|
# this is the main entry point of the kitten, it will be executed in
|
||||||
# the overlay window when the kitten is launched
|
# the overlay window when the kitten is launched
|
||||||
answer = input('Enter some text: ')
|
answer = input('Enter some text: ')
|
||||||
# whatever this function returns will be available in the
|
# whatever this function returns will be available in the
|
||||||
# handle_result() function
|
# handle_result() function
|
||||||
return answer
|
return answer
|
||||||
|
|
||||||
def handle_result(args, answer, target_window_id, boss):
|
def handle_result(args: List[str], answer: str, target_window_id: int, boss: kitty.boss.Boss) -> None:
|
||||||
# get the kitty window into which to paste answer
|
# get the kitty window into which to paste answer
|
||||||
w = boss.window_id_map.get(target_window_id)
|
w = boss.window_id_map.get(target_window_id)
|
||||||
if w is not None:
|
if w is not None:
|
||||||
w.paste(answer)
|
w.paste(answer)
|
||||||
|
|
||||||
|
|
||||||
Now in :file:`kitty.conf` add the lines::
|
Now in :file:`kitty.conf` add the lines::
|
||||||
|
|
||||||
map ctrl+k kitten mykitten.py
|
map ctrl+k kitten mykitten.py
|
||||||
|
|
||||||
|
|
||||||
Start kitty and press :kbd:`ctrl+k` and you should see the kitten running.
|
Start kitty and press :kbd:`ctrl+k` and you should see the kitten running.
|
||||||
@@ -53,12 +53,13 @@ Passing arguments to kittens
|
|||||||
You can pass arguments to kittens by defining them in the map directive in
|
You can pass arguments to kittens by defining them in the map directive in
|
||||||
:file:`kitty.conf`. For example::
|
:file:`kitty.conf`. For example::
|
||||||
|
|
||||||
map ctrl+k kitten mykitten.py arg1 arg2
|
map ctrl+k kitten mykitten.py arg1 arg2
|
||||||
|
|
||||||
These will be available as the ``args`` parameter in the ``main()`` and
|
These will be available as the ``args`` parameter in the ``main()`` and
|
||||||
``handle_result()`` functions. Note also that the current working directory
|
``handle_result()`` functions. Note also that the current working directory
|
||||||
of the kitten is set to the working directory of whatever program is
|
of the kitten is set to the working directory of whatever program is
|
||||||
running in the active kitty window.
|
running in the active kitty window. The special argument ``@selection``
|
||||||
|
is replaced by the currently selected text in the active kitty window.
|
||||||
|
|
||||||
|
|
||||||
Passing the contents of the screen to the kitten
|
Passing the contents of the screen to the kitten
|
||||||
@@ -70,23 +71,25 @@ function, telling kitty what kind of input your kitten would like. For example:
|
|||||||
|
|
||||||
.. code-block:: py
|
.. code-block:: py
|
||||||
|
|
||||||
# in main, STDIN is for the kitten process and will contain
|
# in main, STDIN is for the kitten process and will contain
|
||||||
# the contents of the screen
|
# the contents of the screen
|
||||||
def main(args):
|
def main(args):
|
||||||
return sys.stdin.read()
|
return sys.stdin.read()
|
||||||
|
|
||||||
# in handle_result, STDIN is for the kitty process itself, rather
|
# in handle_result, STDIN is for the kitty process itself, rather
|
||||||
# than the kitten process and should not be read from.
|
# than the kitten process and should not be read from.
|
||||||
def handle_result(args, stdin_data, target_window_id, boss):
|
from kittens.tui.handler import result_handler
|
||||||
pass
|
@result_handler(type_of_input='text')
|
||||||
|
def handle_result(args, stdin_data, target_window_id, boss):
|
||||||
|
pass
|
||||||
|
|
||||||
handle_result.type_of_input = 'text'
|
|
||||||
|
|
||||||
This will send the plain text of the active window to the kitten's
|
This will send the plain text of the active window to the kitten's
|
||||||
:file:`STDIN`. For text with formatting escape codes, use ``ansi``
|
:file:`STDIN`. For text with formatting escape codes, use ``ansi``
|
||||||
instead. If you want line wrap markers as well, use ``screen-ansi``
|
instead. If you want line wrap markers as well, use ``screen-ansi``
|
||||||
or just ``screen``. For the scrollback buffer as well, use
|
or just ``screen``. For the scrollback buffer as well, use
|
||||||
``history``, ``ansi-history`` or ``screen-history``.
|
``history``, ``ansi-history`` or ``screen-history``. To get
|
||||||
|
the currently selected text, use ``selection``.
|
||||||
|
|
||||||
|
|
||||||
Using kittens to script kitty, without any terminal UI
|
Using kittens to script kitty, without any terminal UI
|
||||||
@@ -103,23 +106,23 @@ Create a file in the kitty config folder, :file:`~/.config/kitty/zoom_toggle.py`
|
|||||||
|
|
||||||
.. code-block:: py
|
.. code-block:: py
|
||||||
|
|
||||||
def main(args):
|
def main(args):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def handle_result(args, answer, target_window_id, boss):
|
from kittens.tui.handler import result_handler
|
||||||
tab = boss.active_tab
|
@result_handler(no_ui=True)
|
||||||
if tab is not None:
|
def handle_result(args, answer, target_window_id, boss):
|
||||||
if tab.current_layout.name == 'stack':
|
tab = boss.active_tab
|
||||||
tab.last_used_layout()
|
if tab is not None:
|
||||||
else:
|
if tab.current_layout.name == 'stack':
|
||||||
tab.goto_layout('stack')
|
tab.last_used_layout()
|
||||||
|
else:
|
||||||
handle_result.no_ui = True
|
tab.goto_layout('stack')
|
||||||
|
|
||||||
|
|
||||||
Now in kitty.conf add::
|
Now in kitty.conf add::
|
||||||
|
|
||||||
map f11 kitten zoom_toggle.py
|
map f11 kitten zoom_toggle.py
|
||||||
|
|
||||||
Pressing :kbd:`F11` will now act as a zoom toggle function. You can get even
|
Pressing :kbd:`F11` will now act as a zoom toggle function. You can get even
|
||||||
more fancy, switching the kitty OS window to fullscreen as well as changing the
|
more fancy, switching the kitty OS window to fullscreen as well as changing the
|
||||||
@@ -131,6 +134,35 @@ layout, by simply adding the line::
|
|||||||
To the ``handle_result()`` function, above.
|
To the ``handle_result()`` function, above.
|
||||||
|
|
||||||
|
|
||||||
|
.. _send_mouse_event:
|
||||||
|
|
||||||
|
Sending mouse events
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
If the program running in a window is receiving mouse events you can simulate
|
||||||
|
those using::
|
||||||
|
|
||||||
|
from kitty.fast_data_types import send_mouse_event
|
||||||
|
send_mouse_event(screen, x, y, button, action, mods)
|
||||||
|
|
||||||
|
``screen`` is the ``screen`` attribute of the window you want to send the event
|
||||||
|
to. ``x`` and ``y`` are the 0-indexed coordinates. ``button`` is a number using
|
||||||
|
the same numbering as X11 (left: ``1``, middle: ``2``, right: ``3``, scroll up:
|
||||||
|
``4``, scroll down: ``5``, scroll left: ``6``, scroll right: ``7``, back:
|
||||||
|
``8``, forward: ``9``). ``action`` is one of ``PRESS``, ``RELEASE``, ``DRAG``
|
||||||
|
or ``MOVE``. ``mods`` is a bitmask of ``GLFW_MOD_{mod}`` where ``{mod}`` is one
|
||||||
|
of ``SHIFT``, ``CONTROL`` or ``ALT``. All the mentioned constants are imported
|
||||||
|
from ``kitty.fast_data_types``.
|
||||||
|
|
||||||
|
For example, to send a left click at position x: 2, y: 3 to the active window::
|
||||||
|
|
||||||
|
from kitty.fast_data_types import send_mouse_event, PRESS
|
||||||
|
send_mouse_event(boss.active_window.screen, 2, 3, 1, PRESS, 0)
|
||||||
|
|
||||||
|
The function will only send the event if the program is receiving events of
|
||||||
|
that type, and will return ``True`` if it sent the event, and ``False`` if not.
|
||||||
|
|
||||||
|
|
||||||
Debugging kittens
|
Debugging kittens
|
||||||
--------------------
|
--------------------
|
||||||
|
|
||||||
@@ -156,11 +188,15 @@ Kittens created by kitty users
|
|||||||
---------------------------------------------
|
---------------------------------------------
|
||||||
|
|
||||||
`vim-kitty-navigator <https://github.com/knubie/vim-kitty-navigator>`_
|
`vim-kitty-navigator <https://github.com/knubie/vim-kitty-navigator>`_
|
||||||
Allows you to navigate seamlessly between vim and kitty splits using a consistent set of hotkeys.
|
Allows you to navigate seamlessly between vim and kitty splits using a consistent set of hotkeys.
|
||||||
|
|
||||||
`smart-scroll <https://github.com/yurikhan/kitty-smart-scroll>`_
|
`smart-scroll <https://github.com/yurikhan/kitty-smart-scroll>`_
|
||||||
Makes the kitty scroll bindings work in full screen applications
|
Makes the kitty scroll bindings work in full screen applications
|
||||||
|
|
||||||
`insert password <https://github.com/kovidgoyal/kitty/issues/1222>`_
|
`insert password <https://github.com/kovidgoyal/kitty/issues/1222>`_
|
||||||
Insert a password from a CLI password manager, taking care to only do it at
|
Insert a password from a CLI password manager, taking care to only do it at
|
||||||
a password prompt.
|
a password prompt.
|
||||||
|
|
||||||
|
`weechat-hints <https://github.com/GermainZ/kitty-weechat-hints>`_
|
||||||
|
URL hints kitten for WeeChat that works without having to use WeeChat's
|
||||||
|
raw-mode.
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ like a path or filename followed by a colon and a line number and open
|
|||||||
the file in vim at the specified line number. The patterns and editor
|
the file in vim at the specified line number. The patterns and editor
|
||||||
to be used can be modified using options passed to the kitten. For example::
|
to be used can be modified using options passed to the kitten. For example::
|
||||||
|
|
||||||
map ctrl+g kitten hints --type=linenum --linenum-action=tab nvim +{line} +{path}
|
map ctrl+g kitten hints --type=linenum --linenum-action=tab nvim +{line} {path}
|
||||||
|
|
||||||
will open the selected file in a new tab inside neovim when you press
|
will open the selected file in a new tab inside neovim when you press
|
||||||
:kbd:`ctrl+g`.
|
:kbd:`ctrl+g`.
|
||||||
|
|||||||
68
docs/kittens/hyperlinked_grep.rst
Normal file
68
docs/kittens/hyperlinked_grep.rst
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
Hyperlinked grep
|
||||||
|
=================
|
||||||
|
|
||||||
|
This kitten allows you to search your files using `ripgrep
|
||||||
|
<https://www.google.com/search?q=ripgrep>`_ and open the results
|
||||||
|
directly in your favorite editor in the terminal, at the line containing
|
||||||
|
the search result, simply by clicking on the result you want.
|
||||||
|
|
||||||
|
To set it up, first create :file:`~/.config/kitty/open-actions.conf` with the
|
||||||
|
following contents:
|
||||||
|
|
||||||
|
.. code:: conf
|
||||||
|
|
||||||
|
# Open any file with a fragment in vim, fragments are generated
|
||||||
|
# by the hyperlink_grep kitten and nothing else so far.
|
||||||
|
protocol file
|
||||||
|
fragment_matches [0-9]+
|
||||||
|
action launch --type=overlay vim +${FRAGMENT} ${FILE_PATH}
|
||||||
|
|
||||||
|
# Open text files without fragments in the editor
|
||||||
|
protocol file
|
||||||
|
mime text/*
|
||||||
|
action launch --type=overlay ${EDITOR} ${FILE_PATH}
|
||||||
|
|
||||||
|
|
||||||
|
Now, run a search with::
|
||||||
|
|
||||||
|
kitty +kitten hyperlinked_grep something
|
||||||
|
|
||||||
|
Hold down the :kbd:`ctrl+shift` keys and click on any of the
|
||||||
|
result lines, to open the file in vim at the matching line. If
|
||||||
|
you use some editor other than vim, you should adjust the
|
||||||
|
:file:`open-actions.conf` file accordingly.
|
||||||
|
|
||||||
|
Finally, add an alias to your shell's rc files to invoke the kitten as ``hg``::
|
||||||
|
|
||||||
|
alias hg='kitty +kitten hyperlinked_grep'
|
||||||
|
|
||||||
|
|
||||||
|
You can now run searches with::
|
||||||
|
|
||||||
|
hg some-search-term
|
||||||
|
|
||||||
|
If you want to enable completion, for the kitten, you can delegate completion
|
||||||
|
to rg. For that, instead of using an alias create a simple wrapper script named
|
||||||
|
:file:`hg` somewhere in your ``PATH``:
|
||||||
|
|
||||||
|
.. code-block:: sh
|
||||||
|
|
||||||
|
#!/bin/sh
|
||||||
|
exec kitty +kitten hyperlinked_grep "$@"
|
||||||
|
|
||||||
|
Then, for example, for ZSH, add the following to :file:`.zshrc`::
|
||||||
|
|
||||||
|
compdef _rg hg
|
||||||
|
|
||||||
|
To learn more about kitty's powerful framework for customizing URL click
|
||||||
|
actions, :doc:`see here <../open_actions>`.
|
||||||
|
|
||||||
|
Hopefully, someday this functionality will make it into some `upstream grep
|
||||||
|
<https://github.com/BurntSushi/ripgrep/issues/665>`_
|
||||||
|
program directly removing the need for this kitten.
|
||||||
|
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
While you can pass any of ripgrep's comand line options to the kitten and
|
||||||
|
they will be forwarded to rg, do not use options that change the output
|
||||||
|
formatting as the kitten works by parsing the output from ripgrep.
|
||||||
@@ -21,6 +21,12 @@ Then you can simply use ``icat image.png`` to view images.
|
|||||||
`ImageMagick <https://www.imagemagick.org>`_ must be installed for ``icat`` to
|
`ImageMagick <https://www.imagemagick.org>`_ must be installed for ``icat`` to
|
||||||
work.
|
work.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
kitty's image display protocol may not work when used within a terminal
|
||||||
|
multiplexer such as ``screen`` or ``tmux``, depending on whether the
|
||||||
|
multiplexer has added support for it or not.
|
||||||
|
|
||||||
|
|
||||||
.. program:: kitty +kitten icat
|
.. program:: kitty +kitten icat
|
||||||
|
|
||||||
|
|||||||
21
docs/kittens/query_terminal.rst
Normal file
21
docs/kittens/query_terminal.rst
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
Query terminal
|
||||||
|
=================
|
||||||
|
|
||||||
|
Used to query kitty from terminal programs about version, values of various
|
||||||
|
runtime options controlling its features, etc.
|
||||||
|
|
||||||
|
The querying is done using the (*semi*) standard XTGETTCAP escape sequence
|
||||||
|
pioneered by XTerm, so it works over SSH as well. The downside is that it
|
||||||
|
is slow, since it requires a roundtrip to the terminal emulator and back.
|
||||||
|
|
||||||
|
If you want to do some of the same querying in your terminal program without
|
||||||
|
depending on the kitten, you can do so, by processing the same escape codes.
|
||||||
|
Search `this page <https://invisible-island.net/xterm/ctlseqs/ctlseqs.html>`_
|
||||||
|
for *XTGETTCAP* to see the syntax for the escape code and read the source
|
||||||
|
of this kitten to find the values of the keys for the various queries.
|
||||||
|
|
||||||
|
|
||||||
|
Command Line Interface
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
.. include:: ../generated/cli-kitten-query_terminal.rst
|
||||||
35
docs/kittens/remote_file.rst
Normal file
35
docs/kittens/remote_file.rst
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
Remote files
|
||||||
|
==============
|
||||||
|
|
||||||
|
|kitty| has the ability to easily *Edit*, *Open* or *Download* files
|
||||||
|
from a computer into which you are SSHed. In your SSH session run::
|
||||||
|
|
||||||
|
ls --hyperlink=auto
|
||||||
|
|
||||||
|
Then hold down :kbd:`ctrl+shift` and click the name of the file.
|
||||||
|
|
||||||
|
.. figure:: ../screenshots/remote_file.png
|
||||||
|
:alt: Remote file actions
|
||||||
|
:align: center
|
||||||
|
:scale: 100%
|
||||||
|
|
||||||
|
Remote file actions
|
||||||
|
|
||||||
|
|kitty| will ask you what you want to do with the remote file. You can choose
|
||||||
|
to *Edit* it in which case kitty will download it and open it locally in your
|
||||||
|
``EDITOR``. As you make changes to the file, they are automatically transferred
|
||||||
|
to the remote computer. Note that this happens without needing to install *any*
|
||||||
|
special software on the server, beyond ``ls`` that supports hyperlinks.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
Nested SSH sessions are not supported. The kitten will always try to copy
|
||||||
|
remote files from the first SSH host. This is because there is no way for
|
||||||
|
|kitty| to detect and follow a nested SSH session robustly.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
If you have not setup automatic password-less SSH access, then, when
|
||||||
|
editing starts you will be asked to enter your password just once,
|
||||||
|
thereafter the SSH connection will be re-used.
|
||||||
|
|
||||||
|
Similarly, you can choose to save the file to the local computer or download
|
||||||
|
and open it in its default file handler.
|
||||||
@@ -23,6 +23,10 @@ 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.
|
||||||
|
|
||||||
|
You can switch between modes using either the function keys or by pressing
|
||||||
|
:kbd:`Ctrl+[` and :kbd:`Ctrl+]`.
|
||||||
|
|
||||||
|
|
||||||
Command Line Interface
|
Command Line Interface
|
||||||
-------------------------
|
-------------------------
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ Launching programs in new windows/tabs
|
|||||||
|
|
||||||
|
|
||||||
|kitty| has a :code:`launch` action that can be used to run arbitrary programs
|
|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.
|
in new windows/tabs. It can be mapped to user defined shortcuts in kitty.conf.
|
||||||
It is very powerful and allows sending the contents of
|
It is very powerful and allows sending the contents of
|
||||||
the current window to the launched program, as well as many other options.
|
the current window to the launched program, as well as many other options.
|
||||||
|
|
||||||
@@ -50,6 +50,49 @@ being the top left corner and ``{lines},{columns}`` being the number of rows
|
|||||||
and columns of the screen.
|
and columns of the screen.
|
||||||
|
|
||||||
|
|
||||||
|
Special arguments
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
There are a few special placeholder arguments that can be specified as part of
|
||||||
|
the command line. Namely ``@selection`` which is replaced by the current
|
||||||
|
selection and ``@active-kitty-window-id`` which is replaced by the id of the
|
||||||
|
currently active kitty window. For example::
|
||||||
|
|
||||||
|
map f1 launch my-program @active-kitty-window-id
|
||||||
|
|
||||||
|
|
||||||
|
Watching launched windows
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
The :option:`launch --watcher` option allows you to specify python functions
|
||||||
|
that will be called at specific events, such as when the window is resized or
|
||||||
|
closed. Simply specify the path to a python module that specifies callback
|
||||||
|
functions for the events you are interested in, for example:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
def on_resize(boss, window, data):
|
||||||
|
# Here data will contain old_geometry and new_geometry
|
||||||
|
|
||||||
|
def on_focus_change(boss, window, data):
|
||||||
|
# Here data kill contain focused
|
||||||
|
|
||||||
|
def on_close(boss, window, data):
|
||||||
|
# called when window is closed, typically when the program running in
|
||||||
|
# it exits.
|
||||||
|
|
||||||
|
|
||||||
|
Every callback is passed a reference to the global ``Boss`` object as well as
|
||||||
|
the ``Window`` object the action is occurring on. The ``data`` object is
|
||||||
|
mapping that contains event dependent data. Some useful methods and attributes
|
||||||
|
for the ``Window`` object are: ``as_text(as_ans=False, add_history=False,
|
||||||
|
add_wrap_markers=False, alternate_screen=False)`` with which you can get the
|
||||||
|
contents of the window and its scrollback buffer. Similarly,
|
||||||
|
``window.child.pid`` is the PID of the processes that was launched
|
||||||
|
in the window and ``window.id`` is the internal kitty ``id`` of the
|
||||||
|
window.
|
||||||
|
|
||||||
|
|
||||||
Syntax reference
|
Syntax reference
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
|
|||||||
258
docs/layouts.rst
Normal file
258
docs/layouts.rst
Normal file
@@ -0,0 +1,258 @@
|
|||||||
|
Layouts
|
||||||
|
============
|
||||||
|
|
||||||
|
kitty has the ability to define its own windows that can be tiled next to each
|
||||||
|
other in arbitrary arrangements, based on *Layouts*, see below for examples:
|
||||||
|
|
||||||
|
|
||||||
|
.. figure:: screenshots/screenshot.png
|
||||||
|
:alt: Screenshot, showing three programs in the 'Tall' layout
|
||||||
|
:align: center
|
||||||
|
:scale: 100%
|
||||||
|
|
||||||
|
Screenshot, showing vim, tig and git running in |kitty| with the 'Tall' layout
|
||||||
|
|
||||||
|
|
||||||
|
.. figure:: screenshots/splits.png
|
||||||
|
:alt: Screenshot, showing windows in the 'Splits' layout
|
||||||
|
:align: center
|
||||||
|
:scale: 100%
|
||||||
|
|
||||||
|
Screenshot, showing windows with arbitrary arrangement in the 'Splits'
|
||||||
|
layout
|
||||||
|
|
||||||
|
|
||||||
|
There are many different layouts available. They are all enabled by default,
|
||||||
|
you can switch layouts using :sc:`next_layout`. To control which layouts
|
||||||
|
are available use :opt:`enabled_layouts`, the first listed layout becomes
|
||||||
|
the default. Individual layouts and how to use them are described below.
|
||||||
|
|
||||||
|
.. contents::
|
||||||
|
|
||||||
|
|
||||||
|
The Stack Layout
|
||||||
|
------------------
|
||||||
|
|
||||||
|
This is the simplest layout it displays a single window using all available
|
||||||
|
space, other windows are hidden behind it. It has no options::
|
||||||
|
|
||||||
|
enabled_layouts stack
|
||||||
|
|
||||||
|
|
||||||
|
The Tall Layout
|
||||||
|
------------------
|
||||||
|
|
||||||
|
Displays one (or optionally more) full height windows on the left half of the
|
||||||
|
screen. Remaining windows are tiled vertically on the right half of the screen.
|
||||||
|
There are options to control how the screen is split horizontally ``bias``
|
||||||
|
(an integer between ``10`` and ``90``) and options to control how many
|
||||||
|
full-height windows there are ``full_size`` (a positive integer). The
|
||||||
|
``mirrored`` option when set to ``true`` will cause the short windows to be
|
||||||
|
on the left side of the screen instead of the right. The syntax
|
||||||
|
for the options is shown below::
|
||||||
|
|
||||||
|
enabled_layouts tall:bias=50;full_size=1;mirrored=false
|
||||||
|
|
||||||
|
┌──────────────┬───────────────┐
|
||||||
|
│ │ │
|
||||||
|
│ │ │
|
||||||
|
│ │ │
|
||||||
|
│ ├───────────────┤
|
||||||
|
│ │ │
|
||||||
|
│ │ │
|
||||||
|
│ │ │
|
||||||
|
│ ├───────────────┤
|
||||||
|
│ │ │
|
||||||
|
│ │ │
|
||||||
|
│ │ │
|
||||||
|
└──────────────┴───────────────┘
|
||||||
|
|
||||||
|
In addition, you can map keys to increase or decrease the number of full size
|
||||||
|
windows, for example::
|
||||||
|
|
||||||
|
map ctrl+[ layout_action decrease_num_full_size_windows
|
||||||
|
map ctrl+] layout_action increase_num_full_size_windows
|
||||||
|
|
||||||
|
|
||||||
|
The Fat Layout
|
||||||
|
----------------
|
||||||
|
|
||||||
|
Displays one (or optionally more) full width windows on the top half of the
|
||||||
|
screen. Remaining windows are tiled horizontally on the bottom half of the screen.
|
||||||
|
There are options to control how the screen is split vertically ``bias``
|
||||||
|
(an integer between ``10`` and ``90``) and options to control how many
|
||||||
|
full-height windows there are ``full_size`` (a positive integer). The
|
||||||
|
``mirrored`` option when set to ``true`` will cause the narrow windows to be
|
||||||
|
on the top of the screen instead of the bottom. The syntax for the options is
|
||||||
|
shown below::
|
||||||
|
|
||||||
|
enabled_layouts fat:bias=50;full_size=1;mirrored=false
|
||||||
|
|
||||||
|
┌──────────────────────────────┐
|
||||||
|
│ │
|
||||||
|
│ │
|
||||||
|
│ │
|
||||||
|
│ │
|
||||||
|
├─────────┬──────────┬─────────┤
|
||||||
|
│ │ │ │
|
||||||
|
│ │ │ │
|
||||||
|
│ │ │ │
|
||||||
|
│ │ │ │
|
||||||
|
│ │ │ │
|
||||||
|
└─────────┴──────────┴─────────┘
|
||||||
|
|
||||||
|
|
||||||
|
The Grid Layout
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
Display windows in a balanced grid with all windows the same size except the
|
||||||
|
last column if there are not enough windows to fill the grid. Has no options::
|
||||||
|
|
||||||
|
enabled_layouts grid
|
||||||
|
|
||||||
|
┌─────────┬──────────┬─────────┐
|
||||||
|
│ │ │ │
|
||||||
|
│ │ │ │
|
||||||
|
│ │ │ │
|
||||||
|
│ │ │ │
|
||||||
|
├─────────┼──────────┼─────────┤
|
||||||
|
│ │ │ │
|
||||||
|
│ │ │ │
|
||||||
|
│ │ │ │
|
||||||
|
│ │ │ │
|
||||||
|
└─────────┴──────────┴─────────┘
|
||||||
|
|
||||||
|
|
||||||
|
.. _splits_layout:
|
||||||
|
|
||||||
|
The Splits Layout
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
This is the most flexible layout. You can create any arrangement of windows
|
||||||
|
by splitting exiting windows repeatedly. To best use this layout you should
|
||||||
|
define a few extra keybindings in :file:`kitty.conf`::
|
||||||
|
|
||||||
|
map F5 launch --location=hsplit
|
||||||
|
map F6 launch --location=vsplit
|
||||||
|
map F7 layout_action rotate
|
||||||
|
|
||||||
|
map shift+up move_window up
|
||||||
|
map shift+left move_window left
|
||||||
|
map shift+right move_window right
|
||||||
|
map shift+down move_window down
|
||||||
|
|
||||||
|
map ctrl+left neighboring_window left
|
||||||
|
map ctrl+right neighboring_window right
|
||||||
|
map ctrl+up neighboring_window up
|
||||||
|
map ctrl+down neighboring_window down
|
||||||
|
|
||||||
|
Now you can create horizontal and vertical splits by using :kbd:`F5` and
|
||||||
|
:kbd:`F6`. You can move them around using :kbd:`shift+arrow keys`
|
||||||
|
and you can move focus to neighboring windows using :kbd:`ctrl+arrow keys`.
|
||||||
|
You can switch an existing split from horizontal to vertical and vice versa
|
||||||
|
using :kbd:`F7`. Finally, windows can be resized using :ref:`window_resizing`.
|
||||||
|
|
||||||
|
This layout takes one option, ``split_axis`` that controls whether new windows
|
||||||
|
are placed into vertical or horizontal splits, by default::
|
||||||
|
|
||||||
|
enabled_layouts splits:split_axis=horizontal
|
||||||
|
|
||||||
|
┌──────────────┬───────────────┐
|
||||||
|
│ │ │
|
||||||
|
│ │ │
|
||||||
|
│ │ │
|
||||||
|
│ ├───────┬───────┤
|
||||||
|
│ │ │ │
|
||||||
|
│ │ │ │
|
||||||
|
│ │ │ │
|
||||||
|
│ ├───────┴───────┤
|
||||||
|
│ │ │
|
||||||
|
│ │ │
|
||||||
|
│ │ │
|
||||||
|
└──────────────┴───────────────┘
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
The Horizontal Layout
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
All windows are shown side by side. Has no options::
|
||||||
|
|
||||||
|
enabled_layouts horizontal
|
||||||
|
|
||||||
|
┌─────────┬──────────┬─────────┐
|
||||||
|
│ │ │ │
|
||||||
|
│ │ │ │
|
||||||
|
│ │ │ │
|
||||||
|
│ │ │ │
|
||||||
|
│ │ │ │
|
||||||
|
│ │ │ │
|
||||||
|
│ │ │ │
|
||||||
|
│ │ │ │
|
||||||
|
│ │ │ │
|
||||||
|
└─────────┴──────────┴─────────┘
|
||||||
|
|
||||||
|
|
||||||
|
The Vertical Layout
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
All windows are shown one below the other. Has no options::
|
||||||
|
|
||||||
|
enabled_layouts vertical
|
||||||
|
|
||||||
|
┌──────────────────────────────┐
|
||||||
|
│ │
|
||||||
|
│ │
|
||||||
|
│ │
|
||||||
|
├──────────────────────────────┤
|
||||||
|
│ │
|
||||||
|
│ │
|
||||||
|
│ │
|
||||||
|
├──────────────────────────────┤
|
||||||
|
│ │
|
||||||
|
│ │
|
||||||
|
│ │
|
||||||
|
└──────────────────────────────┘
|
||||||
|
|
||||||
|
|
||||||
|
.. _window_resizing:
|
||||||
|
|
||||||
|
Resizing windows
|
||||||
|
------------------
|
||||||
|
|
||||||
|
You can resize windows inside layouts. Press :sc:`start_resizing_window` (also
|
||||||
|
:kbd:`⌘+r` on macOS) to enter resizing mode and follow the on-screen
|
||||||
|
instructions. In a given window layout only some operations may be possible
|
||||||
|
for a particular window. For example, in the Tall layout you can make the first
|
||||||
|
window wider/narrower, but not taller/shorter. Note that what you are resizing
|
||||||
|
is actually not a window, but a row/column in the layout, all windows in that
|
||||||
|
row/column will be resized.
|
||||||
|
|
||||||
|
You can also define shortcuts in :file:`kitty.conf` to make the active window
|
||||||
|
wider, narrower, taller, or shorter by mapping to the ``resize_window``
|
||||||
|
action, for example::
|
||||||
|
|
||||||
|
map ctrl+left resize_window narrower
|
||||||
|
map ctrl+right resize_window wider
|
||||||
|
map ctrl+up resize_window taller
|
||||||
|
map ctrl+down resize_window shorter 3
|
||||||
|
|
||||||
|
The ``resize_window`` action has a second, optional argument to control
|
||||||
|
the resizing increment (a positive integer that defaults to 1).
|
||||||
|
|
||||||
|
|
||||||
|
Some layouts take options to control their behavior. For example, the ``fat``
|
||||||
|
and ``tall`` layouts accept the ``bias`` and ``full_size`` options to control
|
||||||
|
how the available space is split up.
|
||||||
|
To specify the option, in :opt:`kitty.conf <enabled_layouts>` use::
|
||||||
|
|
||||||
|
enabled_layouts tall:bias=70;full_size=2
|
||||||
|
|
||||||
|
This will have ``2`` instead of a single tall window, that occupy ``70%``
|
||||||
|
instead of ``50%`` of available width. ``bias`` can be any number between 10
|
||||||
|
and 90.
|
||||||
|
|
||||||
|
Writing a new layout only requires about two hundred lines of code, so if there
|
||||||
|
is some layout you want, take a look at one of the existing layouts in the
|
||||||
|
`layout <https://github.com/kovidgoyal/kitty/tree/master/kitty/layout>`_
|
||||||
|
package and submit a pull request!
|
||||||
@@ -51,7 +51,10 @@ If you want to create markers dynamically rather than pre-defining them in
|
|||||||
map f2 remove_marker
|
map f2 remove_marker
|
||||||
|
|
||||||
Then pressing :kbd:`F1` will allow you to enter the marker definition and set
|
Then pressing :kbd:`F1` will allow you to enter the marker definition and set
|
||||||
it and pressing :kbd:`F2` will remove the marker.
|
it and pressing :kbd:`F2` will remove the marker. ``create_marker`` accepts
|
||||||
|
the same syntax as ``toggle_marker`` above. Note that while creating
|
||||||
|
markers, the prompt has history so you can easily re-use previous marker
|
||||||
|
expressions.
|
||||||
|
|
||||||
You can also use the facilities for :doc:`remote-control` to dynamically
|
You can also use the facilities for :doc:`remote-control` to dynamically
|
||||||
add/remove markers.
|
add/remove markers.
|
||||||
|
|||||||
95
docs/open_actions.rst
Normal file
95
docs/open_actions.rst
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
Customizing the actions taken when clicking on links
|
||||||
|
======================================================
|
||||||
|
|
||||||
|
|kitty| has support for `terminal hyperlinks <https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda>`_. These
|
||||||
|
are generated by many terminal programs, such as ``ls``, ``gcc``, ``systemd``,
|
||||||
|
``mdcat``, etc. You can customize exactly what happens when clicking on these hyperlinks
|
||||||
|
in |kitty|.
|
||||||
|
|
||||||
|
You can tell kitty to take arbitrarily many, complex actions
|
||||||
|
when a link is clicked. Let us illustrate with some examples, first. Create
|
||||||
|
the file :file:`~/.config/kitty/open-actions.conf` with the following:
|
||||||
|
|
||||||
|
.. code:: conf
|
||||||
|
|
||||||
|
# Open any image in the full kitty window by clicking on it
|
||||||
|
protocol file
|
||||||
|
mime image/*
|
||||||
|
action launch --type=overlay kitty +kitten icat --hold ${FILE_PATH}
|
||||||
|
|
||||||
|
Now, run ``ls --hyperlink=auto`` in kitty and click on the filename of an
|
||||||
|
image, holding down :kbd:`ctrl+shift`. It will be opened over the current
|
||||||
|
window. Press any key to close it.
|
||||||
|
|
||||||
|
Each entry in :file:`open-actions.conf` consists of one or more
|
||||||
|
:ref:`matching_criteria`, such as ``protocol`` and ``mime`` and one or more
|
||||||
|
``action`` entries. In the example above kitty uses the :doc:`launch <launch>`
|
||||||
|
action which can be used to run external programs. Entries are separated by
|
||||||
|
blank lines.
|
||||||
|
|
||||||
|
Actions are very powerful, anything that you can map to a key combination in
|
||||||
|
`kitty.conf` can be used as an action. You can specify more than one action per
|
||||||
|
entry if you like, for example:
|
||||||
|
|
||||||
|
|
||||||
|
.. code:: conf
|
||||||
|
|
||||||
|
# Tail a log file (*.log) in a new OS Window and reduce its font size
|
||||||
|
protocol file
|
||||||
|
ext log
|
||||||
|
action launch --title ${FILE} --type=os-window tail -f ${FILE_PATH}
|
||||||
|
action change_font_size current -2
|
||||||
|
|
||||||
|
|
||||||
|
In the action specification you can expand environment variables, as shown in
|
||||||
|
the examples above. In addition to regular environment variables, there are
|
||||||
|
some special variables, documented below:
|
||||||
|
|
||||||
|
``URL``
|
||||||
|
The full URL being opened
|
||||||
|
|
||||||
|
``FILE_PATH``
|
||||||
|
The path portion of the URL (unquoted)
|
||||||
|
|
||||||
|
``FILE``
|
||||||
|
The file portion of the path of the URL (unquoted)
|
||||||
|
|
||||||
|
``FRAGMENT``
|
||||||
|
The fragment (unquoted), if any of the URL or the empty string.
|
||||||
|
|
||||||
|
.. _matching_criteria:
|
||||||
|
|
||||||
|
Matching criteria
|
||||||
|
------------------
|
||||||
|
|
||||||
|
An entry in :file:`open-actions.conf` must have one or more matching criteria.
|
||||||
|
URLs that match all criteria for an entry will trigger that entries' actions.
|
||||||
|
Processing stops at the first matching entry, so put more specific matching
|
||||||
|
criteria at the start of the list. Entries in the file are separated by blank
|
||||||
|
lines. The various available criteria are:
|
||||||
|
|
||||||
|
``protocol``
|
||||||
|
A comma separated list of protocols, for example: ``http, https``. If
|
||||||
|
absent, there is no constraint on protocol
|
||||||
|
|
||||||
|
``url``
|
||||||
|
A regular expression that must match against the entire (unquoted) URL
|
||||||
|
|
||||||
|
``fragment_matches``
|
||||||
|
A regular expression that must match against the fragment (part after #) in
|
||||||
|
the URL
|
||||||
|
|
||||||
|
``mime``
|
||||||
|
A comma separated list of MIME types, for example: ``text/*, image/*,
|
||||||
|
application/pdf``. You can add MIME types to kitty by creating the
|
||||||
|
:file:`mime.types` in the kitty configuration directory. Useful if your
|
||||||
|
system MIME database does not have definitions you need. This file is
|
||||||
|
in the standard format of one definition per line, like: ``text/plain rst
|
||||||
|
md``.
|
||||||
|
|
||||||
|
``ext``
|
||||||
|
A comma separated list of file extensions, for example: ``jpeg, tar.gz``
|
||||||
|
|
||||||
|
``file``
|
||||||
|
A shell glob pattern that must match the filename, for example:
|
||||||
|
``image-??.png``
|
||||||
@@ -219,7 +219,136 @@ first, for example::
|
|||||||
<ESC>]52;c;!<ESC>\
|
<ESC>]52;c;!<ESC>\
|
||||||
|
|
||||||
Here ``!`` is not valid base64 encoded text, so it clears the clipboard.
|
Here ``!`` is not valid base64 encoded text, so it clears the clipboard.
|
||||||
|
Further, since it is invalid, it should be ignored by terminal emulators
|
||||||
|
that do not support this extension, thereby making it safe to use, simply
|
||||||
|
always send it before starting a new OSC 52 paste, even if you aren't chunking
|
||||||
|
up large pastes, that way kitty won't concatenate your paste, and it will have
|
||||||
|
no ill-effects in other terminal emulators.
|
||||||
|
|
||||||
In case you're using software that can't be easily adapted to this
|
In case you're using software that can't be easily adapted to this
|
||||||
protocol extension, it can be disabled by specifying ``no-append`` to the
|
protocol extension, it can be disabled by specifying ``no-append`` to the
|
||||||
:opt:`clipboard_control` setting.
|
:opt:`clipboard_control` setting.
|
||||||
|
|
||||||
|
|
||||||
|
.. _desktop_notifications:
|
||||||
|
|
||||||
|
|
||||||
|
Desktop notifications
|
||||||
|
---------------------------------
|
||||||
|
|
||||||
|
|kitty| implements an extensible escape code (OSC 99) to show desktop
|
||||||
|
notifications. It is easy to use from shell scripts and fully extensible to
|
||||||
|
show title and body. Clicking on the notification can optionally focus the
|
||||||
|
window it came from, and/or send an escape code back to the application running
|
||||||
|
in that window.
|
||||||
|
|
||||||
|
The design of the escape code is partially based on the discussion in
|
||||||
|
the defunct
|
||||||
|
`terminal-wg <https://gitlab.freedesktop.org/terminal-wg/specifications/-/issues/13>`_
|
||||||
|
|
||||||
|
The escape code has the form::
|
||||||
|
|
||||||
|
<OSC> 99 ; metadata ; payload <terminator>
|
||||||
|
|
||||||
|
Here ``<OSC>`` is :code:`<ESC>]` and ``<terminator>`` is
|
||||||
|
:code:`<ESC><backslash>`. The metadata is a section of colon separated
|
||||||
|
:code:`key=value` pairs. Every key must be a single character from the set
|
||||||
|
:code:`a-zA-Z` and every value must be a word consisting of characters from
|
||||||
|
the set :code:`a-zA-Z0-9-_/\+.,(){}[]*&^%$#@!`~`. The payload must be
|
||||||
|
interpreted based on the metadata section. The two semi-colons *must* always be
|
||||||
|
present even when no metadata is present.
|
||||||
|
|
||||||
|
Before going into details, lets see how one can display a simple, single line
|
||||||
|
notification from a shell script::
|
||||||
|
|
||||||
|
printf '\x1b]99;;Hello world\x1b\\'
|
||||||
|
|
||||||
|
To show a message with a title and a body::
|
||||||
|
|
||||||
|
printf '\x1b]99;i=1:d=0;Hello world\x1b\\'
|
||||||
|
printf '\x1b]99;i=1:d=1:p=body;This is cool\x1b\\'
|
||||||
|
|
||||||
|
The most important key in the metadata is the ``p`` key, it controls how the
|
||||||
|
payload is interpreted. A value of ``title`` means the payload is setting the
|
||||||
|
title for the notification. A value of ``body`` means it is setting the body,
|
||||||
|
and so on, see the table below for full details.
|
||||||
|
|
||||||
|
The design of the escape code is fundamentally chunked, this is because
|
||||||
|
different terminal emulators have different limits on how large a single escape
|
||||||
|
code can be. Chunking is accomplished by the ``i`` and ``d`` keys. The ``i``
|
||||||
|
key is the *notification id* which can be any string containing the characters
|
||||||
|
``[a-zA-Z0-9_-+.]``. The ``d`` key stands for *done* and
|
||||||
|
can only take the values ``0`` and ``1``. A value of ``0`` means the
|
||||||
|
notification is not yet done and the terminal emulator should hold off
|
||||||
|
displaying it. A value of ``1`` means the notification is done, and should be
|
||||||
|
displayed. You can specify the title or body multiple times and the terminal
|
||||||
|
emulator will concatenate them, thereby allowing arbitrarily long text
|
||||||
|
(terminal emulators are free to impose a sensible limit to avoid
|
||||||
|
Denial-of-Service attacks).
|
||||||
|
|
||||||
|
Both the ``title`` and ``body`` payloads must be either UTF-8 encoded plain
|
||||||
|
text with no embedded escape codes, or UTF-8 text that is base64 encoded, in
|
||||||
|
which case there must be an ``e=1`` key in the metadata to indicate the payload
|
||||||
|
is base64 encoded.
|
||||||
|
|
||||||
|
When the user clicks the notification, a couple of things can happen, the
|
||||||
|
terminal emulator can focus the window from which the notification came, and/or
|
||||||
|
it can send back an escape code to the application indicating the notification
|
||||||
|
was activated. This is controlled by the ``a`` key which takes a comma
|
||||||
|
separated set of values, ``report`` and ``focus``. The value ``focus`` means
|
||||||
|
focus the window from which the notification was issued and is the default.
|
||||||
|
``report`` means send an escape code back to the application. The format of the
|
||||||
|
returned escape code is::
|
||||||
|
|
||||||
|
<OSC> 99 ; i=identifier ; <terminator>
|
||||||
|
|
||||||
|
The value of ``identifier`` comes from the ``i`` key in the escape code sent by
|
||||||
|
the application. If the application sends no identifier, then the terminal
|
||||||
|
*must* use ``i=0``. Actions can be preceded by a negative sign to turn them
|
||||||
|
off, so for example if you do not want any action, turn off the default
|
||||||
|
``focus`` action with::
|
||||||
|
|
||||||
|
a=-focus
|
||||||
|
|
||||||
|
Complete specification of all the metadata keys is in the table below. If a
|
||||||
|
terminal emulator encounters a key in the metadata it does not understand,
|
||||||
|
the key *must* be ignored, to allow for future extensibility of this escape
|
||||||
|
code. Similarly if values for known keys are unknown, the terminal emulator
|
||||||
|
*should* either ignore the entire escape code or perform a best guess effort
|
||||||
|
to display it based on what it does understand.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
It is possible to extend this escape code to allow specifying an icon for
|
||||||
|
the notification, however, given that some platforms, such as macOS, dont
|
||||||
|
allow displaying custom icons on a notification, at all, it was decided to
|
||||||
|
leave it out of the spec for the time being.
|
||||||
|
|
||||||
|
Similarly, features such as scheduled notifications could be added in future
|
||||||
|
revisions.
|
||||||
|
|
||||||
|
|
||||||
|
======= ==================== ========= =================
|
||||||
|
Key Value Default Description
|
||||||
|
======= ==================== ========= =================
|
||||||
|
``a`` Comma separated list ``focus`` What action to perform when the
|
||||||
|
of ``report``, notification is clicked
|
||||||
|
``focus``, with
|
||||||
|
optional leading
|
||||||
|
``-``
|
||||||
|
|
||||||
|
``d`` ``0`` or ``1`` ``1`` Indicates if the notification is
|
||||||
|
complete or not.
|
||||||
|
|
||||||
|
``e`` ``0`` or ``1`` ``0`` If set to ``1`` means the payload is base64 encoded UTF-8,
|
||||||
|
otherwise it is plain UTF-8 text with no C0 control codes in it
|
||||||
|
|
||||||
|
``i`` ``[a-zA-Z0-9-_+.]`` ``0`` Identifier for the notification
|
||||||
|
|
||||||
|
``p`` One of ``title`` or ``title`` Whether the payload is the notification title or body. If a
|
||||||
|
``body``. notification has no title, the body will be used as title.
|
||||||
|
======= ==================== ========= =================
|
||||||
|
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|kitty| also supports the legacy OSC 9 protocol developed by iTerm2 for
|
||||||
|
desktop notifications.
|
||||||
|
|||||||
@@ -10,18 +10,18 @@ form::
|
|||||||
Where ``<ESC>`` is the byte ``0x1b``. The JSON object has the form::
|
Where ``<ESC>`` is the byte ``0x1b``. The JSON object has the form::
|
||||||
|
|
||||||
{
|
{
|
||||||
'cmd': "command name",
|
"cmd": "command name",
|
||||||
'version': "kitty version",
|
"version": <kitty version>,
|
||||||
'no_response': Optional Boolean,
|
"no_response": Optional Boolean,
|
||||||
'payload': <Optional JSON object>,
|
"payload": <Optional JSON object>,
|
||||||
}
|
}
|
||||||
|
|
||||||
The ``version`` above is a string of the form :code:`0.14.2`. If you are developing a
|
The ``version`` above is an array of the form :code:`[0, 14, 2]`. If you are developing a
|
||||||
standalone client, use the kitty version that you are developing against. Using
|
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 don't 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.
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ In order for control to work, :opt:`allow_remote_control` must be enabled in
|
|||||||
|
|
||||||
Now, in the new |kitty| window, enter the command::
|
Now, in the new |kitty| window, enter the command::
|
||||||
|
|
||||||
kitty @ new-window --title Output --keep-focus cat
|
kitty @ launch --title Output --keep-focus cat
|
||||||
|
|
||||||
This will open a new window, running the ``cat`` program that will appear next
|
This will open a new window, running the ``cat`` program that will appear next
|
||||||
to the current window.
|
to the current window.
|
||||||
@@ -54,7 +54,7 @@ window. Type ``Ctrl+D`` when you are ready to stop.
|
|||||||
|
|
||||||
Now, let's open a new tab::
|
Now, let's open a new tab::
|
||||||
|
|
||||||
kitty @ new-window --new-tab --tab-title "My Tab" --keep-focus bash
|
kitty @ launch --type=tab --tab-title "My Tab" --keep-focus bash
|
||||||
|
|
||||||
This will open a new tab running the bash shell with the title "My Tab".
|
This will open a new tab running the bash shell with the title "My Tab".
|
||||||
We can change the title of the tab with::
|
We can change the title of the tab with::
|
||||||
@@ -134,6 +134,20 @@ still write to the pipes of any other program on the same computer and
|
|||||||
therefore can control |kitty|. It can, however, be useful to block programs
|
therefore can control |kitty|. It can, however, be useful to block programs
|
||||||
running on other computers (for example, over ssh) or as other users.
|
running on other computers (for example, over ssh) or as other users.
|
||||||
|
|
||||||
|
Mapping key presses to remote control commands
|
||||||
|
--------------------------------------------------
|
||||||
|
|
||||||
|
If you wish to trigger a remote control command easily with just a keypress,
|
||||||
|
you can map it in :file:`kitty.conf`. For example::
|
||||||
|
|
||||||
|
map F1 remote_control set-spacing margin=30
|
||||||
|
|
||||||
|
Then pressing the :kbd:`F1` key will set the active window margins to 30.
|
||||||
|
The syntax for what follows :code:`remote_control` is exactly the same
|
||||||
|
as the syntax for what follows :code:`kitty @` above. You do not need
|
||||||
|
to enable remote control to use these mappings.
|
||||||
|
|
||||||
|
|
||||||
Documentation for the remote control protocol
|
Documentation for the remote control protocol
|
||||||
-----------------------------------------------
|
-----------------------------------------------
|
||||||
|
|
||||||
|
|||||||
BIN
docs/screenshots/remote_file.png
Normal file
BIN
docs/screenshots/remote_file.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 55 KiB |
BIN
docs/screenshots/splits.png
Normal file
BIN
docs/screenshots/splits.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 42 KiB |
@@ -4,18 +4,23 @@
|
|||||||
|
|
||||||
import subprocess
|
import subprocess
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
|
from typing import Any, DefaultDict, Dict, FrozenSet, List, Tuple, Union
|
||||||
|
|
||||||
|
KeymapType = Dict[str, Tuple[str, Union[FrozenSet[str], str]]]
|
||||||
|
|
||||||
|
|
||||||
def resolve_keys(keymap):
|
def resolve_keys(keymap: KeymapType) -> DefaultDict[str, List[str]]:
|
||||||
ans = defaultdict(list)
|
ans: DefaultDict[str, List[str]] = defaultdict(list)
|
||||||
for ch, (attr, atype) in keymap.items():
|
for ch, (attr, atype) in keymap.items():
|
||||||
if atype not in ('int', 'uint'):
|
if isinstance(atype, str) and atype in ('int', 'uint'):
|
||||||
atype = 'flag'
|
q = atype
|
||||||
ans[atype].append(ch)
|
else:
|
||||||
|
q = 'flag'
|
||||||
|
ans[q].append(ch)
|
||||||
return ans
|
return ans
|
||||||
|
|
||||||
|
|
||||||
def enum(keymap):
|
def enum(keymap: KeymapType) -> str:
|
||||||
lines = []
|
lines = []
|
||||||
for ch, (attr, atype) in keymap.items():
|
for ch, (attr, atype) in keymap.items():
|
||||||
lines.append(f"{attr}='{ch}'")
|
lines.append(f"{attr}='{ch}'")
|
||||||
@@ -26,15 +31,15 @@ def enum(keymap):
|
|||||||
'''.format(',\n'.join(lines))
|
'''.format(',\n'.join(lines))
|
||||||
|
|
||||||
|
|
||||||
def parse_key(keymap):
|
def parse_key(keymap: KeymapType) -> str:
|
||||||
lines = []
|
lines = []
|
||||||
for attr, atype in keymap.values():
|
for attr, atype in keymap.values():
|
||||||
vs = atype.upper() if atype in ('uint', 'int') else 'FLAG'
|
vs = atype.upper() if isinstance(atype, str) and atype in ('uint', 'int') else 'FLAG'
|
||||||
lines.append(f'case {attr}: value_state = {vs}; break;')
|
lines.append(f'case {attr}: value_state = {vs}; break;')
|
||||||
return ' \n'.join(lines)
|
return ' \n'.join(lines)
|
||||||
|
|
||||||
|
|
||||||
def parse_flag(keymap, type_map, command_class):
|
def parse_flag(keymap: KeymapType, type_map: Dict[str, Any], command_class: str) -> str:
|
||||||
lines = []
|
lines = []
|
||||||
for ch in type_map['flag']:
|
for ch in type_map['flag']:
|
||||||
attr, allowed_values = keymap[ch]
|
attr, allowed_values = keymap[ch]
|
||||||
@@ -52,14 +57,14 @@ def parse_flag(keymap, type_map, command_class):
|
|||||||
return ' \n'.join(lines)
|
return ' \n'.join(lines)
|
||||||
|
|
||||||
|
|
||||||
def parse_number(keymap):
|
def parse_number(keymap: KeymapType) -> Tuple[str, str]:
|
||||||
int_keys = [f'I({attr})' for attr, atype in keymap.values() if atype == 'int']
|
int_keys = [f'I({attr})' for attr, atype in keymap.values() if atype == 'int']
|
||||||
uint_keys = [f'U({attr})' for attr, atype in keymap.values() if atype == 'uint']
|
uint_keys = [f'U({attr})' for attr, atype in keymap.values() if atype == 'uint']
|
||||||
return '; '.join(int_keys), '; '.join(uint_keys)
|
return '; '.join(int_keys), '; '.join(uint_keys)
|
||||||
|
|
||||||
|
|
||||||
def cmd_for_report(report_name, keymap, type_map, payload_allowed):
|
def cmd_for_report(report_name: str, keymap: KeymapType, type_map: Dict[str, Any], payload_allowed: bool) -> str:
|
||||||
def group(atype, conv):
|
def group(atype: str, conv: str) -> Tuple[str, str]:
|
||||||
flag_fmt, flag_attrs = [], []
|
flag_fmt, flag_attrs = [], []
|
||||||
cv = {'flag': 'c', 'int': 'i', 'uint': 'I'}[atype]
|
cv = {'flag': 'c', 'int': 'i', 'uint': 'I'}[atype]
|
||||||
for ch in type_map[atype]:
|
for ch in type_map[atype]:
|
||||||
@@ -84,7 +89,15 @@ def cmd_for_report(report_name, keymap, type_map, payload_allowed):
|
|||||||
return '\n'.join(ans)
|
return '\n'.join(ans)
|
||||||
|
|
||||||
|
|
||||||
def generate(function_name, callback_name, report_name, keymap, command_class, initial_key='a', payload_allowed=True):
|
def generate(
|
||||||
|
function_name: str,
|
||||||
|
callback_name: str,
|
||||||
|
report_name: str,
|
||||||
|
keymap: KeymapType,
|
||||||
|
command_class: str,
|
||||||
|
initial_key: str = 'a',
|
||||||
|
payload_allowed: bool = True
|
||||||
|
) -> str:
|
||||||
type_map = resolve_keys(keymap)
|
type_map = resolve_keys(keymap)
|
||||||
keys_enum = enum(keymap)
|
keys_enum = enum(keymap)
|
||||||
handle_key = parse_key(keymap)
|
handle_key = parse_key(keymap)
|
||||||
@@ -124,6 +137,7 @@ static inline void
|
|||||||
{parr}
|
{parr}
|
||||||
{keys_enum}
|
{keys_enum}
|
||||||
enum KEYS key = '{initial_key}';
|
enum KEYS key = '{initial_key}';
|
||||||
|
if (screen->parser_buf[pos] == ';') state = AFTER_VALUE;
|
||||||
|
|
||||||
while (pos < screen->parser_buf_pos) {{
|
while (pos < screen->parser_buf_pos) {{
|
||||||
switch(state) {{
|
switch(state) {{
|
||||||
@@ -225,7 +239,7 @@ static inline void
|
|||||||
'''
|
'''
|
||||||
|
|
||||||
|
|
||||||
def write_header(text, path):
|
def write_header(text: str, path: str) -> None:
|
||||||
with open(path, 'w') as f:
|
with open(path, 'w') as f:
|
||||||
print(f'// This file is generated by {__file__} do not edit!', file=f, end='\n\n')
|
print(f'// This file is generated by {__file__} do not edit!', file=f, end='\n\n')
|
||||||
print('#pragma once', file=f)
|
print('#pragma once', file=f)
|
||||||
@@ -233,9 +247,9 @@ def write_header(text, path):
|
|||||||
subprocess.check_call(['clang-format', '-i', path])
|
subprocess.check_call(['clang-format', '-i', path])
|
||||||
|
|
||||||
|
|
||||||
def graphics_parser():
|
def graphics_parser() -> None:
|
||||||
flag = frozenset
|
flag = frozenset
|
||||||
keymap = {
|
keymap: KeymapType = {
|
||||||
'a': ('action', flag('tTqpd')),
|
'a': ('action', flag('tTqpd')),
|
||||||
'd': ('delete_action', flag('aAiIcCpPqQxXyYzZ')),
|
'd': ('delete_action', flag('aAiIcCpPqQxXyYzZ')),
|
||||||
't': ('transmission_type', flag('dfts')),
|
't': ('transmission_type', flag('dfts')),
|
||||||
|
|||||||
235
gen-wcwidth.py
235
gen-wcwidth.py
@@ -12,6 +12,10 @@ from functools import partial
|
|||||||
from html.entities import html5
|
from html.entities import html5
|
||||||
from itertools import groupby
|
from itertools import groupby
|
||||||
from operator import itemgetter
|
from operator import itemgetter
|
||||||
|
from typing import (
|
||||||
|
Callable, DefaultDict, Dict, FrozenSet, Generator, Iterable, List,
|
||||||
|
Optional, Set, Tuple, Union
|
||||||
|
)
|
||||||
from urllib.request import urlopen
|
from urllib.request import urlopen
|
||||||
|
|
||||||
os.chdir(os.path.dirname(os.path.abspath(__file__)))
|
os.chdir(os.path.dirname(os.path.abspath(__file__)))
|
||||||
@@ -24,7 +28,7 @@ if len(non_characters) != 66:
|
|||||||
emoji_skin_tone_modifiers = frozenset(range(0x1f3fb, 0x1F3FF + 1))
|
emoji_skin_tone_modifiers = frozenset(range(0x1f3fb, 0x1F3FF + 1))
|
||||||
|
|
||||||
|
|
||||||
def get_data(fname, folder='UCD'):
|
def get_data(fname: str, folder: str = 'UCD') -> Iterable[str]:
|
||||||
url = f'https://www.unicode.org/Public/{folder}/latest/{fname}'
|
url = f'https://www.unicode.org/Public/{folder}/latest/{fname}'
|
||||||
bn = os.path.basename(url)
|
bn = os.path.basename(url)
|
||||||
local = os.path.join('/tmp', bn)
|
local = os.path.join('/tmp', bn)
|
||||||
@@ -42,24 +46,25 @@ 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: Dict[str, Set[int]] = {}
|
||||||
all_symbols = set()
|
all_symbols: Set[int] = set()
|
||||||
name_map = {}
|
name_map: Dict[int, str] = {}
|
||||||
word_search_map = defaultdict(set)
|
word_search_map: DefaultDict[str, Set[int]] = defaultdict(set)
|
||||||
zwj = 0x200d
|
zwj = 0x200d
|
||||||
marks = set(emoji_skin_tone_modifiers) | {zwj}
|
flag_codepoints = frozenset(range(0x1F1E6, 0x1F1E6 + 26))
|
||||||
|
marks = set(emoji_skin_tone_modifiers) | {zwj} | flag_codepoints
|
||||||
not_assigned = set(range(0, sys.maxunicode))
|
not_assigned = set(range(0, sys.maxunicode))
|
||||||
|
|
||||||
|
|
||||||
def parse_ucd():
|
def parse_ucd() -> None:
|
||||||
|
|
||||||
def add_word(w, c):
|
def add_word(w: str, c: int) -> None:
|
||||||
if c <= 32 or c == 127 or 128 <= c <= 159:
|
if c <= 32 or c == 127 or 128 <= c <= 159:
|
||||||
return
|
return
|
||||||
if len(w) > 1:
|
if len(w) > 1:
|
||||||
word_search_map[w.lower()].add(c)
|
word_search_map[w.lower()].add(c)
|
||||||
|
|
||||||
first = None
|
first: Optional[int] = None
|
||||||
for word, c in html5.items():
|
for word, c in html5.items():
|
||||||
if len(c) == 1:
|
if len(c) == 1:
|
||||||
add_word(word.rstrip(';'), ord(c))
|
add_word(word.rstrip(';'), ord(c))
|
||||||
@@ -77,7 +82,7 @@ def parse_ucd():
|
|||||||
category = parts[2]
|
category = parts[2]
|
||||||
s = class_maps.setdefault(category, set())
|
s = class_maps.setdefault(category, set())
|
||||||
desc = parts[1]
|
desc = parts[1]
|
||||||
codepoints = (codepoint,)
|
codepoints: Union[Tuple[int, ...], Iterable[int]] = (codepoint,)
|
||||||
if first is None:
|
if first is None:
|
||||||
if desc.endswith(', First>'):
|
if desc.endswith(', First>'):
|
||||||
first = codepoint
|
first = codepoint
|
||||||
@@ -93,49 +98,115 @@ def parse_ucd():
|
|||||||
elif category.startswith('S'):
|
elif category.startswith('S'):
|
||||||
all_symbols.add(codepoint)
|
all_symbols.add(codepoint)
|
||||||
|
|
||||||
|
with open('nerd-fonts-glyphs.txt') as f:
|
||||||
|
for line in f:
|
||||||
|
line = line.strip()
|
||||||
|
if not line or line.startswith('#'):
|
||||||
|
continue
|
||||||
|
code, category, name = line.split(' ', 2)
|
||||||
|
codepoint = int(code, 16)
|
||||||
|
if name and codepoint not in name_map:
|
||||||
|
name_map[codepoint] = name.upper()
|
||||||
|
for word in name.lower().split():
|
||||||
|
add_word(word, codepoint)
|
||||||
|
|
||||||
# Some common synonyms
|
# Some common synonyms
|
||||||
word_search_map['bee'] |= word_search_map['honeybee']
|
word_search_map['bee'] |= word_search_map['honeybee']
|
||||||
word_search_map['lambda'] |= word_search_map['lamda']
|
word_search_map['lambda'] |= word_search_map['lamda']
|
||||||
word_search_map['lamda'] |= word_search_map['lambda']
|
word_search_map['lamda'] |= word_search_map['lambda']
|
||||||
|
|
||||||
|
|
||||||
def split_two(line):
|
def parse_range_spec(spec: str) -> Set[int]:
|
||||||
spec, rest = line.split(';', 1)
|
spec = spec.strip()
|
||||||
spec, rest = spec.strip(), rest.strip().split(' ', 1)[0].strip()
|
|
||||||
if '..' in spec:
|
if '..' in spec:
|
||||||
chars = tuple(map(lambda x: int(x, 16), filter(None, spec.split('.'))))
|
chars_ = tuple(map(lambda x: int(x, 16), filter(None, spec.split('.'))))
|
||||||
chars = set(range(chars[0], chars[1] + 1))
|
chars = set(range(chars_[0], chars_[1] + 1))
|
||||||
else:
|
else:
|
||||||
chars = {int(spec, 16)}
|
chars = {int(spec, 16)}
|
||||||
return chars, rest
|
return chars
|
||||||
|
|
||||||
|
|
||||||
all_emoji = set()
|
def split_two(line: str) -> Tuple[Set[int], str]:
|
||||||
emoji_categories = {}
|
spec, rest = line.split(';', 1)
|
||||||
emoji_presentation_bases = set()
|
spec, rest = spec.strip(), rest.strip().split(' ', 1)[0].strip()
|
||||||
|
return parse_range_spec(spec), rest
|
||||||
|
|
||||||
|
|
||||||
def parse_emoji():
|
all_emoji: Set[int] = set()
|
||||||
for line in get_data('emoji-data.txt', 'emoji'):
|
emoji_presentation_bases: Set[int] = set()
|
||||||
chars, rest = split_two(line)
|
narrow_emoji: Set[int] = set()
|
||||||
s = emoji_categories.setdefault(rest, set())
|
wide_emoji: Set[int] = set()
|
||||||
s.update(chars)
|
flags: Dict[int, List[int]] = {}
|
||||||
all_emoji.update(chars)
|
|
||||||
for line in get_data('emoji-variation-sequences.txt', 'emoji'):
|
|
||||||
base, var, *rest = line.split()
|
def parse_basic_emoji(spec: str) -> None:
|
||||||
if base.startswith('#'):
|
parts = list(filter(None, spec.split()))
|
||||||
|
has_emoji_presentation = len(parts) < 2
|
||||||
|
chars = parse_range_spec(parts[0])
|
||||||
|
all_emoji.update(chars)
|
||||||
|
emoji_presentation_bases.update(chars)
|
||||||
|
(wide_emoji if has_emoji_presentation else narrow_emoji).update(chars)
|
||||||
|
|
||||||
|
|
||||||
|
def parse_keycap_sequence(spec: str) -> None:
|
||||||
|
base, fe0f, cc = list(filter(None, spec.split()))
|
||||||
|
chars = parse_range_spec(base)
|
||||||
|
all_emoji.update(chars)
|
||||||
|
emoji_presentation_bases.update(chars)
|
||||||
|
narrow_emoji.update(chars)
|
||||||
|
|
||||||
|
|
||||||
|
def parse_flag_emoji_sequence(spec: str) -> None:
|
||||||
|
a, b = list(filter(None, spec.split()))
|
||||||
|
left, right = int(a, 16), int(b, 16)
|
||||||
|
chars = {left, right}
|
||||||
|
all_emoji.update(chars)
|
||||||
|
wide_emoji.update(chars)
|
||||||
|
emoji_presentation_bases.update(chars)
|
||||||
|
flags.setdefault(left, []).append(right)
|
||||||
|
|
||||||
|
|
||||||
|
def parse_emoji_tag_sequence(spec: str) -> None:
|
||||||
|
a = int(spec.split()[0], 16)
|
||||||
|
all_emoji.add(a)
|
||||||
|
wide_emoji.add(a)
|
||||||
|
emoji_presentation_bases.add(a)
|
||||||
|
|
||||||
|
|
||||||
|
def parse_emoji_modifier_sequence(spec: str) -> None:
|
||||||
|
a, b = list(filter(None, spec.split()))
|
||||||
|
char, mod = int(a, 16), int(b, 16)
|
||||||
|
mod
|
||||||
|
all_emoji.add(char)
|
||||||
|
wide_emoji.add(char)
|
||||||
|
emoji_presentation_bases.add(char)
|
||||||
|
|
||||||
|
|
||||||
|
def parse_emoji() -> None:
|
||||||
|
for line in get_data('emoji-sequences.txt', 'emoji'):
|
||||||
|
parts = [x.strip() for x in line.split(';')]
|
||||||
|
if len(parts) < 2:
|
||||||
continue
|
continue
|
||||||
base = int(base, 16)
|
data, etype = parts[:2]
|
||||||
if var.upper() == 'FE0F':
|
if etype == 'Basic_Emoji':
|
||||||
emoji_presentation_bases.add(base)
|
parse_basic_emoji(data)
|
||||||
|
elif etype == 'Emoji_Keycap_Sequence':
|
||||||
|
parse_keycap_sequence(data)
|
||||||
|
elif etype == 'RGI_Emoji_Flag_Sequence':
|
||||||
|
parse_flag_emoji_sequence(data)
|
||||||
|
elif etype == 'RGI_Emoji_Tag_Sequence':
|
||||||
|
parse_emoji_tag_sequence(data)
|
||||||
|
elif etype == 'RGI_Emoji_Modifier_Sequence':
|
||||||
|
parse_emoji_modifier_sequence(data)
|
||||||
|
|
||||||
|
|
||||||
doublewidth, ambiguous = set(), set()
|
doublewidth: Set[int] = set()
|
||||||
|
ambiguous: Set[int] = set()
|
||||||
|
|
||||||
|
|
||||||
def parse_eaw():
|
def parse_eaw() -> None:
|
||||||
global doublewidth, ambiguous
|
global doublewidth, ambiguous
|
||||||
seen = set()
|
seen: Set[int] = set()
|
||||||
for line in get_data('ucd/EastAsianWidth.txt'):
|
for line in get_data('ucd/EastAsianWidth.txt'):
|
||||||
chars, eaw = split_two(line)
|
chars, eaw = split_two(line)
|
||||||
if eaw == 'A':
|
if eaw == 'A':
|
||||||
@@ -151,7 +222,7 @@ def parse_eaw():
|
|||||||
doublewidth |= set(range(0x30000, 0x3FFFD + 1)) - seen
|
doublewidth |= set(range(0x30000, 0x3FFFD + 1)) - seen
|
||||||
|
|
||||||
|
|
||||||
def get_ranges(items):
|
def get_ranges(items: List[int]) -> Generator[Union[int, Tuple[int, int]], None, None]:
|
||||||
items.sort()
|
items.sort()
|
||||||
for k, g in groupby(enumerate(items), lambda m: m[0]-m[1]):
|
for k, g in groupby(enumerate(items), lambda m: m[0]-m[1]):
|
||||||
group = tuple(map(itemgetter(1), g))
|
group = tuple(map(itemgetter(1), g))
|
||||||
@@ -162,7 +233,7 @@ def get_ranges(items):
|
|||||||
yield a, b
|
yield a, b
|
||||||
|
|
||||||
|
|
||||||
def write_case(spec, p):
|
def write_case(spec: Union[Tuple, int], p: Callable) -> None:
|
||||||
if isinstance(spec, tuple):
|
if isinstance(spec, tuple):
|
||||||
p('\t\tcase 0x{:x} ... 0x{:x}:'.format(*spec))
|
p('\t\tcase 0x{:x} ... 0x{:x}:'.format(*spec))
|
||||||
else:
|
else:
|
||||||
@@ -170,7 +241,7 @@ def write_case(spec, p):
|
|||||||
|
|
||||||
|
|
||||||
@contextmanager
|
@contextmanager
|
||||||
def create_header(path, include_data_types=True):
|
def create_header(path: str, include_data_types: bool = True) -> Generator[Callable, None, None]:
|
||||||
with open(path, 'w') as f:
|
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())
|
||||||
@@ -187,7 +258,7 @@ def create_header(path, include_data_types=True):
|
|||||||
p('END_ALLOW_CASE_RANGE')
|
p('END_ALLOW_CASE_RANGE')
|
||||||
|
|
||||||
|
|
||||||
def gen_emoji():
|
def gen_emoji() -> None:
|
||||||
with create_header('kitty/emoji.h') as p:
|
with create_header('kitty/emoji.h') as p:
|
||||||
p('static inline bool\nis_emoji(char_type code) {')
|
p('static inline bool\nis_emoji(char_type code) {')
|
||||||
p('\tswitch(code) {')
|
p('\tswitch(code) {')
|
||||||
@@ -198,15 +269,6 @@ def gen_emoji():
|
|||||||
p('\t}')
|
p('\t}')
|
||||||
p('\treturn false;\n}')
|
p('\treturn false;\n}')
|
||||||
|
|
||||||
p('static inline bool\nis_emoji_modifier(char_type code) {')
|
|
||||||
p('\tswitch(code) {')
|
|
||||||
for spec in get_ranges(list(emoji_categories['Emoji_Modifier'])):
|
|
||||||
write_case(spec, p)
|
|
||||||
p('\t\t\treturn true;')
|
|
||||||
p('\t\tdefault: return false;')
|
|
||||||
p('\t}')
|
|
||||||
p('\treturn false;\n}')
|
|
||||||
|
|
||||||
p('static inline bool\nis_symbol(char_type code) {')
|
p('static inline bool\nis_symbol(char_type code) {')
|
||||||
p('\tswitch(code) {')
|
p('\tswitch(code) {')
|
||||||
for spec in get_ranges(list(all_symbols)):
|
for spec in get_ranges(list(all_symbols)):
|
||||||
@@ -217,24 +279,39 @@ def gen_emoji():
|
|||||||
p('\treturn false;\n}')
|
p('\treturn false;\n}')
|
||||||
|
|
||||||
|
|
||||||
def category_test(name, p, classes, comment, static=False, extra_chars=frozenset(), exclude=frozenset()):
|
def category_test(
|
||||||
static = 'static inline ' if static else ''
|
name: str,
|
||||||
chars = set()
|
p: Callable,
|
||||||
|
classes: Iterable[str],
|
||||||
|
comment: str,
|
||||||
|
use_static: bool = False,
|
||||||
|
extra_chars: Union[FrozenSet[int], Set[int]] = frozenset(),
|
||||||
|
exclude: Union[Set[int], FrozenSet[int]] = frozenset(),
|
||||||
|
least_check_return: Optional[str] = None,
|
||||||
|
ascii_range: Optional[str] = None
|
||||||
|
) -> None:
|
||||||
|
static = 'static inline ' if use_static else ''
|
||||||
|
chars: Set[int] = set()
|
||||||
for c in classes:
|
for c in classes:
|
||||||
chars |= class_maps[c]
|
chars |= class_maps[c]
|
||||||
chars |= extra_chars
|
chars |= extra_chars
|
||||||
chars -= exclude
|
chars -= exclude
|
||||||
p(f'{static}bool\n{name}(char_type code) {{')
|
p(f'{static}bool\n{name}(char_type code) {{')
|
||||||
p(f'\t// {comment} ({len(chars)} codepoints)' + ' {{' '{')
|
p(f'\t// {comment} ({len(chars)} codepoints)' + ' {{' '{')
|
||||||
|
if least_check_return is not None:
|
||||||
|
least = min(chars)
|
||||||
|
p(f'\tif (LIKELY(code < {least})) return {least_check_return};')
|
||||||
|
if ascii_range is not None:
|
||||||
|
p(f'\tif (LIKELY(0x20 <= code && code <= 0x7e)) return {ascii_range};')
|
||||||
p('\tswitch(code) {')
|
p('\tswitch(code) {')
|
||||||
for spec in get_ranges(list(chars)):
|
for spec in get_ranges(list(chars)):
|
||||||
write_case(spec, p)
|
write_case(spec, p)
|
||||||
p(f'\t\t\treturn true;')
|
p('\t\t\treturn true;')
|
||||||
p('\t} // }}}\n')
|
p('\t} // }}}\n')
|
||||||
p('\treturn false;\n}\n')
|
p('\treturn false;\n}\n')
|
||||||
|
|
||||||
|
|
||||||
def codepoint_to_mark_map(p, mark_map):
|
def codepoint_to_mark_map(p: Callable, mark_map: List[int]) -> Dict[int, int]:
|
||||||
p('\tswitch(c) { // {{{')
|
p('\tswitch(c) { // {{{')
|
||||||
rmap = {c: m for m, c in enumerate(mark_map)}
|
rmap = {c: m for m, c in enumerate(mark_map)}
|
||||||
for spec in get_ranges(mark_map):
|
for spec in get_ranges(mark_map):
|
||||||
@@ -249,14 +326,14 @@ def codepoint_to_mark_map(p, mark_map):
|
|||||||
return rmap
|
return rmap
|
||||||
|
|
||||||
|
|
||||||
def classes_to_regex(classes, exclude=''):
|
def classes_to_regex(classes: Iterable[str], exclude: str = '') -> Iterable[str]:
|
||||||
chars = set()
|
chars: Set[int] = set()
|
||||||
for c in classes:
|
for c in classes:
|
||||||
chars |= class_maps[c]
|
chars |= class_maps[c]
|
||||||
for c in map(ord, exclude):
|
for x in map(ord, exclude):
|
||||||
chars.discard(c)
|
chars.discard(x)
|
||||||
|
|
||||||
def as_string(codepoint):
|
def as_string(codepoint: int) -> str:
|
||||||
if codepoint < 256:
|
if codepoint < 256:
|
||||||
return r'\x{:02x}'.format(codepoint)
|
return r'\x{:02x}'.format(codepoint)
|
||||||
if codepoint <= 0xffff:
|
if codepoint <= 0xffff:
|
||||||
@@ -270,7 +347,7 @@ def classes_to_regex(classes, exclude=''):
|
|||||||
yield as_string(spec)
|
yield as_string(spec)
|
||||||
|
|
||||||
|
|
||||||
def gen_ucd():
|
def gen_ucd() -> None:
|
||||||
cz = {c for c in class_maps if c[0] in 'CZ'}
|
cz = {c for c in class_maps if c[0] in 'CZ'}
|
||||||
with create_header('kitty/unicode-data.c') as p:
|
with create_header('kitty/unicode-data.c') as p:
|
||||||
p('#include "unicode-data.h"')
|
p('#include "unicode-data.h"')
|
||||||
@@ -279,11 +356,15 @@ def gen_ucd():
|
|||||||
{c for c in class_maps if c.startswith('M')},
|
{c for c in class_maps if c.startswith('M')},
|
||||||
'M category (marks)',
|
'M category (marks)',
|
||||||
# See https://github.com/harfbuzz/harfbuzz/issues/169
|
# See https://github.com/harfbuzz/harfbuzz/issues/169
|
||||||
extra_chars=emoji_skin_tone_modifiers | {zwj}
|
extra_chars=emoji_skin_tone_modifiers | {zwj},
|
||||||
|
least_check_return='false'
|
||||||
)
|
)
|
||||||
category_test(
|
category_test(
|
||||||
'is_ignored_char', p, 'Cc Cf Cs'.split(),
|
'is_ignored_char', p, 'Cc Cf Cs'.split(),
|
||||||
'Control characters and non-characters', extra_chars=non_characters, exclude={zwj})
|
'Control characters and non-characters',
|
||||||
|
extra_chars=non_characters, exclude={zwj},
|
||||||
|
ascii_range='false'
|
||||||
|
)
|
||||||
category_test('is_word_char', p, {c for c in class_maps if c[0] in 'LN'}, 'L and N categories')
|
category_test('is_word_char', p, {c for c in class_maps if c[0] in 'LN'}, 'L and N categories')
|
||||||
category_test('is_CZ_category', p, cz, 'C and Z categories')
|
category_test('is_CZ_category', p, cz, 'C and Z categories')
|
||||||
category_test('is_P_category', p, {c for c in class_maps if c[0] == 'P'}, 'P category (punctuation)')
|
category_test('is_P_category', p, {c for c in class_maps if c[0] == 'P'}, 'P category (punctuation)')
|
||||||
@@ -298,7 +379,9 @@ def gen_ucd():
|
|||||||
p('}\n')
|
p('}\n')
|
||||||
with open('kitty/unicode-data.h') as f:
|
with open('kitty/unicode-data.h') as f:
|
||||||
unicode_data = f.read()
|
unicode_data = f.read()
|
||||||
expected = int(re.search(r'^#define VS15 (\d+)', unicode_data, re.M).group(1))
|
m = re.search(r'^#define VS15 (\d+)', unicode_data, re.M)
|
||||||
|
if m is not None:
|
||||||
|
expected = int(m.group(1))
|
||||||
if rmap[0xfe0e] != expected:
|
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]
|
||||||
@@ -307,7 +390,7 @@ def gen_ucd():
|
|||||||
f.write("url_delimiters = '{}' # noqa".format(''.join(classes_to_regex(cz, exclude='\n'))))
|
f.write("url_delimiters = '{}' # noqa".format(''.join(classes_to_regex(cz, exclude='\n'))))
|
||||||
|
|
||||||
|
|
||||||
def gen_names():
|
def gen_names() -> None:
|
||||||
with create_header('kittens/unicode_input/names.h') as p:
|
with create_header('kittens/unicode_input/names.h') as p:
|
||||||
mark_to_cp = list(sorted(name_map))
|
mark_to_cp = list(sorted(name_map))
|
||||||
cp_to_mark = {cp: m for m, cp in enumerate(mark_to_cp)}
|
cp_to_mark = {cp: m for m, cp in enumerate(mark_to_cp)}
|
||||||
@@ -361,29 +444,29 @@ def gen_names():
|
|||||||
p('}; // }}}\n')
|
p('}; // }}}\n')
|
||||||
|
|
||||||
# The trie
|
# The trie
|
||||||
p(f'typedef struct {{ uint32_t children_offset; uint32_t match_offset; }} word_trie;\n')
|
p('typedef struct { uint32_t children_offset; uint32_t match_offset; } word_trie;\n')
|
||||||
all_trie_nodes = []
|
all_trie_nodes: List['TrieNode'] = [] # noqa
|
||||||
|
|
||||||
class TrieNode:
|
class TrieNode:
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self) -> None:
|
||||||
self.match_offset = 0
|
self.match_offset = 0
|
||||||
self.children_offset = 0
|
self.children_offset = 0
|
||||||
self.children = {}
|
self.children: Dict[int, int] = {}
|
||||||
|
|
||||||
def add_letter(self, letter):
|
def add_letter(self, letter: int) -> int:
|
||||||
if letter not in self.children:
|
if letter not in self.children:
|
||||||
self.children[letter] = len(all_trie_nodes)
|
self.children[letter] = len(all_trie_nodes)
|
||||||
all_trie_nodes.append(TrieNode())
|
all_trie_nodes.append(TrieNode())
|
||||||
return self.children[letter]
|
return self.children[letter]
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self) -> str:
|
||||||
return f'{{ .children_offset={self.children_offset}, .match_offset={self.match_offset} }}'
|
return f'{{ .children_offset={self.children_offset}, .match_offset={self.match_offset} }}'
|
||||||
|
|
||||||
root = TrieNode()
|
root = TrieNode()
|
||||||
all_trie_nodes.append(root)
|
all_trie_nodes.append(root)
|
||||||
|
|
||||||
def add_word(word_idx, word):
|
def add_word(word_idx: int, word: str) -> None:
|
||||||
parent = root
|
parent = root
|
||||||
for letter in map(ord, word):
|
for letter in map(ord, word):
|
||||||
idx = parent.add_letter(letter)
|
idx = parent.add_letter(letter)
|
||||||
@@ -408,10 +491,10 @@ def gen_names():
|
|||||||
p('}; // }}}\n')
|
p('}; // }}}\n')
|
||||||
|
|
||||||
|
|
||||||
def gen_wcwidth():
|
def gen_wcwidth() -> None:
|
||||||
seen = set()
|
seen: Set[int] = set()
|
||||||
|
|
||||||
def add(p, comment, chars_, ret):
|
def add(p: Callable, comment: str, chars_: Union[Set[int], FrozenSet[int]], ret: int) -> None:
|
||||||
chars = chars_ - seen
|
chars = chars_ - seen
|
||||||
seen.update(chars)
|
seen.update(chars)
|
||||||
p(f'\t\t// {comment} ({len(chars)} codepoints)' + ' {{' '{')
|
p(f'\t\t// {comment} ({len(chars)} codepoints)' + ' {{' '{')
|
||||||
@@ -422,16 +505,18 @@ def gen_wcwidth():
|
|||||||
|
|
||||||
with create_header('kitty/wcwidth-std.h') as p:
|
with create_header('kitty/wcwidth-std.h') as p:
|
||||||
p('static int\nwcwidth_std(int32_t code) {')
|
p('static int\nwcwidth_std(int32_t code) {')
|
||||||
|
p('\tif (LIKELY(0x20 <= code && code <= 0x7e)) return 1;')
|
||||||
p('\tswitch(code) {')
|
p('\tswitch(code) {')
|
||||||
|
|
||||||
non_printing = class_maps['Cc'] | class_maps['Cf'] | class_maps['Cs']
|
non_printing = class_maps['Cc'] | class_maps['Cf'] | class_maps['Cs']
|
||||||
|
add(p, 'Flags', flag_codepoints, 2)
|
||||||
add(p, 'Marks', marks | {0}, 0)
|
add(p, 'Marks', marks | {0}, 0)
|
||||||
add(p, 'Non-printing characters', non_printing, -1)
|
add(p, 'Non-printing characters', non_printing, -1)
|
||||||
add(p, 'Private use', class_maps['Co'], -3)
|
add(p, 'Private use', class_maps['Co'], -3)
|
||||||
add(p, 'Text Presentation', emoji_categories['Emoji'] - emoji_categories['Emoji_Presentation'], 1)
|
add(p, 'Text Presentation', narrow_emoji, 1)
|
||||||
add(p, 'East Asian ambiguous width', ambiguous, -2)
|
add(p, 'East Asian ambiguous width', ambiguous, -2)
|
||||||
add(p, 'East Asian double width', doublewidth, 2)
|
add(p, 'East Asian double width', doublewidth, 2)
|
||||||
add(p, 'Emoji Presentation', emoji_categories['Emoji_Presentation'], 2)
|
add(p, 'Emoji Presentation', wide_emoji, 2)
|
||||||
|
|
||||||
add(p, 'Not assigned in the unicode character database', not_assigned, -4)
|
add(p, 'Not assigned in the unicode character database', not_assigned, -4)
|
||||||
|
|
||||||
@@ -439,7 +524,7 @@ def gen_wcwidth():
|
|||||||
p('\t}')
|
p('\t}')
|
||||||
p('\treturn 1;\n}')
|
p('\treturn 1;\n}')
|
||||||
|
|
||||||
p('static bool\nis_emoji_presentation_base(uint32_t code) {')
|
p('static inline bool\nis_emoji_presentation_base(uint32_t code) {')
|
||||||
p('\tswitch(code) {')
|
p('\tswitch(code) {')
|
||||||
for spec in get_ranges(list(emoji_presentation_bases)):
|
for spec in get_ranges(list(emoji_presentation_bases)):
|
||||||
write_case(spec, p)
|
write_case(spec, p)
|
||||||
|
|||||||
0
glfw/__init__.py
Normal file
0
glfw/__init__.py
Normal file
59
glfw/backend_utils.c
vendored
59
glfw/backend_utils.c
vendored
@@ -333,53 +333,20 @@ pollForEvents(EventLoopData *eld, monotonic_t timeout, watch_callback_func displ
|
|||||||
return read_ok;
|
return read_ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Splits and translates a text/uri-list into separate file paths
|
// Duplicate a UTF-8 encoded string
|
||||||
// NOTE: This function destroys the provided string
|
// but cut it so that it has at most max_length bytes plus the null byte.
|
||||||
//
|
// This does not take combining characters into account.
|
||||||
char** parseUriList(char* text, int* count)
|
GLFWAPI char* utf_8_strndup(const char* source, size_t max_length) {
|
||||||
{
|
if (!source) return NULL;
|
||||||
const char* prefix = "file://";
|
size_t length = strnlen(source, max_length);
|
||||||
char** paths = NULL;
|
if (length >= max_length) {
|
||||||
char* line;
|
for (length = max_length; length > 0; length--) {
|
||||||
|
if ((source[length] & 0xC0) != 0x80) break;
|
||||||
*count = 0;
|
|
||||||
|
|
||||||
while ((line = strtok(text, "\r\n")))
|
|
||||||
{
|
|
||||||
text = NULL;
|
|
||||||
|
|
||||||
if (line[0] == '#')
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (strncmp(line, prefix, strlen(prefix)) == 0)
|
|
||||||
{
|
|
||||||
line += strlen(prefix);
|
|
||||||
// TODO: Validate hostname
|
|
||||||
while (*line != '/')
|
|
||||||
line++;
|
|
||||||
}
|
|
||||||
|
|
||||||
(*count)++;
|
|
||||||
|
|
||||||
char* path = calloc(strlen(line) + 1, 1);
|
|
||||||
paths = realloc(paths, *count * sizeof(char*));
|
|
||||||
paths[*count - 1] = path;
|
|
||||||
|
|
||||||
while (*line)
|
|
||||||
{
|
|
||||||
if (line[0] == '%' && line[1] && line[2])
|
|
||||||
{
|
|
||||||
const char digits[3] = { line[1], line[2], '\0' };
|
|
||||||
*path = strtol(digits, NULL, 16);
|
|
||||||
line += 2;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
*path = *line;
|
|
||||||
|
|
||||||
path++;
|
|
||||||
line++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return paths;
|
char* result = malloc(length + 1);
|
||||||
|
memcpy(result, source, length);
|
||||||
|
result[length] = 0;
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
2
glfw/backend_utils.h
vendored
2
glfw/backend_utils.h
vendored
@@ -94,5 +94,5 @@ int pollForEvents(EventLoopData *eld, monotonic_t timeout, watch_callback_func);
|
|||||||
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);
|
||||||
char** parseUriList(char* text, int* count);
|
|
||||||
void wakeupEventLoop(EventLoopData *eld);
|
void wakeupEventLoop(EventLoopData *eld);
|
||||||
|
char* utf_8_strndup(const char* source, size_t max_length);
|
||||||
|
|||||||
@@ -424,11 +424,7 @@ display_reconfigured(CGDirectDisplayID display UNUSED, CGDisplayChangeSummaryFla
|
|||||||
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
|
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
|
||||||
{
|
{
|
||||||
(void)sender;
|
(void)sender;
|
||||||
_GLFWwindow* window;
|
if (_glfw.callbacks.application_close) _glfw.callbacks.application_close(0);
|
||||||
|
|
||||||
for (window = _glfw.windowListHead; window; window = window->next)
|
|
||||||
_glfwInputWindowCloseRequest(window);
|
|
||||||
|
|
||||||
return NSTerminateCancel;
|
return NSTerminateCancel;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -673,8 +669,6 @@ int _glfwPlatformInit(void)
|
|||||||
if (!initializeTIS())
|
if (!initializeTIS())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
_glfwInitJoysticksNS();
|
|
||||||
|
|
||||||
_glfwPollMonitorsNS();
|
_glfwPollMonitorsNS();
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
@@ -727,7 +721,6 @@ void _glfwPlatformTerminate(void)
|
|||||||
free(_glfw.ns.clipboardString);
|
free(_glfw.ns.clipboardString);
|
||||||
|
|
||||||
_glfwTerminateNSGL();
|
_glfwTerminateNSGL();
|
||||||
_glfwTerminateJoysticksNS();
|
|
||||||
|
|
||||||
} // autoreleasepool
|
} // autoreleasepool
|
||||||
}
|
}
|
||||||
|
|||||||
4
glfw/cocoa_joystick.h
vendored
4
glfw/cocoa_joystick.h
vendored
@@ -44,7 +44,3 @@ typedef struct _GLFWjoystickNS
|
|||||||
CFMutableArrayRef hats;
|
CFMutableArrayRef hats;
|
||||||
} _GLFWjoystickNS;
|
} _GLFWjoystickNS;
|
||||||
|
|
||||||
|
|
||||||
void _glfwInitJoysticksNS(void);
|
|
||||||
void _glfwTerminateJoysticksNS(void);
|
|
||||||
|
|
||||||
|
|||||||
@@ -233,6 +233,19 @@ static void matchCallback(void* context UNUSED,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (page == kHIDPage_Simulation)
|
||||||
|
{
|
||||||
|
switch (usage)
|
||||||
|
{
|
||||||
|
case kHIDUsage_Sim_Accelerator:
|
||||||
|
case kHIDUsage_Sim_Brake:
|
||||||
|
case kHIDUsage_Sim_Throttle:
|
||||||
|
case kHIDUsage_Sim_Rudder:
|
||||||
|
case kHIDUsage_Sim_Steering:
|
||||||
|
target = axes;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
else if (page == kHIDPage_Button || page == kHIDPage_Consumer)
|
else if (page == kHIDPage_Button || page == kHIDPage_Consumer)
|
||||||
target = buttons;
|
target = buttons;
|
||||||
|
|
||||||
@@ -291,12 +304,10 @@ static void removeCallback(void* context UNUSED,
|
|||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
////// GLFW internal API //////
|
////// GLFW platform API //////
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
// Initialize joystick interface
|
bool _glfwPlatformInitJoysticks(void)
|
||||||
//
|
|
||||||
void _glfwInitJoysticksNS(void)
|
|
||||||
{
|
{
|
||||||
CFMutableArrayRef matching;
|
CFMutableArrayRef matching;
|
||||||
const long usages[] =
|
const long usages[] =
|
||||||
@@ -315,7 +326,7 @@ void _glfwInitJoysticksNS(void)
|
|||||||
if (!matching)
|
if (!matching)
|
||||||
{
|
{
|
||||||
_glfwInputError(GLFW_PLATFORM_ERROR, "Cocoa: Failed to create array");
|
_glfwInputError(GLFW_PLATFORM_ERROR, "Cocoa: Failed to create array");
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < sizeof(usages) / sizeof(long); i++)
|
for (size_t i = 0; i < sizeof(usages) / sizeof(long); i++)
|
||||||
@@ -370,26 +381,24 @@ void _glfwInitJoysticksNS(void)
|
|||||||
// Execute the run loop once in order to register any initially-attached
|
// Execute the run loop once in order to register any initially-attached
|
||||||
// joysticks
|
// joysticks
|
||||||
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, false);
|
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, false);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close all opened joystick handles
|
void _glfwPlatformTerminateJoysticks(void)
|
||||||
//
|
|
||||||
void _glfwTerminateJoysticksNS(void)
|
|
||||||
{
|
{
|
||||||
int jid;
|
int jid;
|
||||||
|
|
||||||
for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++)
|
for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++)
|
||||||
closeJoystick(_glfw.joysticks + jid);
|
closeJoystick(_glfw.joysticks + jid);
|
||||||
|
|
||||||
CFRelease(_glfw.ns.hidManager);
|
if (_glfw.ns.hidManager)
|
||||||
_glfw.ns.hidManager = NULL;
|
{
|
||||||
|
CFRelease(_glfw.ns.hidManager);
|
||||||
|
_glfw.ns.hidManager = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
|
||||||
////// GLFW platform API //////
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
int _glfwPlatformPollJoystick(_GLFWjoystick* js, int mode)
|
int _glfwPlatformPollJoystick(_GLFWjoystick* js, int mode)
|
||||||
{
|
{
|
||||||
if (mode & _GLFW_POLL_AXES)
|
if (mode & _GLFW_POLL_AXES)
|
||||||
|
|||||||
@@ -236,26 +236,71 @@ static bool refreshMonitorScreen(_GLFWmonitor* monitor)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns a fallback refresh rate for when Core Graphics says it is zero
|
// Returns the display refresh rate queried from the I/O registry
|
||||||
//
|
//
|
||||||
static double getFallbackRefreshRate(_GLFWmonitor* monitor)
|
static double getFallbackRefreshRate(CGDirectDisplayID displayID)
|
||||||
{
|
{
|
||||||
CGDisplayModeRef mode = CGDisplayCopyDisplayMode(monitor->ns.displayID);
|
double refreshRate = 60.0;
|
||||||
double refreshRate = CGDisplayModeGetRefreshRate(mode);
|
|
||||||
CGDisplayModeRelease(mode);
|
|
||||||
|
|
||||||
if (refreshRate == 0.0)
|
io_iterator_t it;
|
||||||
|
io_service_t service;
|
||||||
|
|
||||||
|
if (IOServiceGetMatchingServices(kIOMasterPortDefault,
|
||||||
|
IOServiceMatching("IOFramebuffer"),
|
||||||
|
&it) != 0)
|
||||||
{
|
{
|
||||||
CVDisplayLinkRef link = NULL;
|
return refreshRate;
|
||||||
CVDisplayLinkCreateWithCGDisplay(monitor->ns.displayID, &link);
|
|
||||||
|
|
||||||
const CVTime time = CVDisplayLinkGetNominalOutputVideoRefreshPeriod(link);
|
|
||||||
if (!(time.flags & kCVTimeIsIndefinite))
|
|
||||||
refreshRate = (int) (time.timeScale / (double) time.timeValue);
|
|
||||||
|
|
||||||
CVDisplayLinkRelease(link);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
while ((service = IOIteratorNext(it)) != 0)
|
||||||
|
{
|
||||||
|
const CFNumberRef indexRef =
|
||||||
|
IORegistryEntryCreateCFProperty(service,
|
||||||
|
CFSTR("IOFramebufferOpenGLIndex"),
|
||||||
|
kCFAllocatorDefault,
|
||||||
|
kNilOptions);
|
||||||
|
if (!indexRef)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
uint32_t index = 0;
|
||||||
|
CFNumberGetValue(indexRef, kCFNumberIntType, &index);
|
||||||
|
CFRelease(indexRef);
|
||||||
|
|
||||||
|
if (CGOpenGLDisplayMaskToDisplayID(1 << index) != displayID)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const CFNumberRef clockRef =
|
||||||
|
IORegistryEntryCreateCFProperty(service,
|
||||||
|
CFSTR("IOFBCurrentPixelClock"),
|
||||||
|
kCFAllocatorDefault,
|
||||||
|
kNilOptions);
|
||||||
|
const CFNumberRef countRef =
|
||||||
|
IORegistryEntryCreateCFProperty(service,
|
||||||
|
CFSTR("IOFBCurrentPixelCount"),
|
||||||
|
kCFAllocatorDefault,
|
||||||
|
kNilOptions);
|
||||||
|
|
||||||
|
uint32_t clock = 0, count = 0;
|
||||||
|
|
||||||
|
if (clockRef)
|
||||||
|
{
|
||||||
|
CFNumberGetValue(clockRef, kCFNumberIntType, &clock);
|
||||||
|
CFRelease(clockRef);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (countRef)
|
||||||
|
{
|
||||||
|
CFNumberGetValue(countRef, kCFNumberIntType, &count);
|
||||||
|
CFRelease(countRef);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clock > 0 && count > 0)
|
||||||
|
refreshRate = clock / (double) count;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
IOObjectRelease(it);
|
||||||
return refreshRate;
|
return refreshRate;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -351,11 +396,15 @@ void _glfwPollMonitorsNS(void)
|
|||||||
_GLFWmonitor* monitor = _glfwAllocMonitor(name, (int)size.width, (int)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;
|
||||||
monitor->ns.fallbackRefreshRate = getFallbackRefreshRate(monitor);
|
|
||||||
createDisplayLink(monitor->ns.displayID);
|
createDisplayLink(monitor->ns.displayID);
|
||||||
|
|
||||||
free(name);
|
free(name);
|
||||||
|
|
||||||
|
CGDisplayModeRef mode = CGDisplayCopyDisplayMode(displays[i]);
|
||||||
|
if (CGDisplayModeGetRefreshRate(mode) == 0.0)
|
||||||
|
monitor->ns.fallbackRefreshRate = getFallbackRefreshRate(displays[i]);
|
||||||
|
CGDisplayModeRelease(mode);
|
||||||
|
|
||||||
_glfwInputMonitor(monitor, GLFW_CONNECTED, _GLFW_INSERT_LAST);
|
_glfwInputMonitor(monitor, GLFW_CONNECTED, _GLFW_INSERT_LAST);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -480,7 +529,6 @@ void _glfwPlatformGetMonitorWorkarea(_GLFWmonitor* monitor,
|
|||||||
*width = (int)frameRect.size.width;
|
*width = (int)frameRect.size.width;
|
||||||
if (height)
|
if (height)
|
||||||
*height = (int)frameRect.size.height;
|
*height = (int)frameRect.size.height;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count)
|
GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count)
|
||||||
|
|||||||
5
glfw/cocoa_platform.h
vendored
5
glfw/cocoa_platform.h
vendored
@@ -96,16 +96,11 @@ typedef VkResult (APIENTRY *PFN_vkCreateMetalSurfaceEXT)(VkInstance,const VkMeta
|
|||||||
#include "posix_thread.h"
|
#include "posix_thread.h"
|
||||||
#include "cocoa_joystick.h"
|
#include "cocoa_joystick.h"
|
||||||
#include "nsgl_context.h"
|
#include "nsgl_context.h"
|
||||||
#include "egl_context.h"
|
|
||||||
#include "osmesa_context.h"
|
|
||||||
|
|
||||||
#define _glfw_dlopen(name) dlopen(name, RTLD_LAZY | RTLD_LOCAL)
|
#define _glfw_dlopen(name) dlopen(name, RTLD_LAZY | RTLD_LOCAL)
|
||||||
#define _glfw_dlclose(handle) dlclose(handle)
|
#define _glfw_dlclose(handle) dlclose(handle)
|
||||||
#define _glfw_dlsym(handle, name) dlsym(handle, name)
|
#define _glfw_dlsym(handle, name) dlsym(handle, name)
|
||||||
|
|
||||||
#define _GLFW_EGL_NATIVE_WINDOW ((EGLNativeWindowType) window->ns.view)
|
|
||||||
#define _GLFW_EGL_NATIVE_DISPLAY EGL_DEFAULT_DISPLAY
|
|
||||||
|
|
||||||
#define _GLFW_PLATFORM_WINDOW_STATE _GLFWwindowNS ns
|
#define _GLFW_PLATFORM_WINDOW_STATE _GLFWwindowNS ns
|
||||||
#define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryNS ns
|
#define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryNS ns
|
||||||
#define _GLFW_PLATFORM_LIBRARY_TIMER_STATE _GLFWtimerNS ns
|
#define _GLFW_PLATFORM_LIBRARY_TIMER_STATE _GLFWtimerNS ns
|
||||||
|
|||||||
@@ -659,6 +659,7 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
|
|||||||
NSTrackingArea* trackingArea;
|
NSTrackingArea* trackingArea;
|
||||||
NSMutableAttributedString* markedText;
|
NSMutableAttributedString* markedText;
|
||||||
NSRect markedRect;
|
NSRect markedRect;
|
||||||
|
NSString *input_source_at_last_key_event;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) removeGLFWWindow;
|
- (void) removeGLFWWindow;
|
||||||
@@ -677,6 +678,7 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
|
|||||||
trackingArea = nil;
|
trackingArea = nil;
|
||||||
markedText = [[NSMutableAttributedString alloc] init];
|
markedText = [[NSMutableAttributedString alloc] init];
|
||||||
markedRect = NSMakeRect(0.0, 0.0, 0.0, 0.0);
|
markedRect = NSMakeRect(0.0, 0.0, 0.0, 0.0);
|
||||||
|
input_source_at_last_key_event = nil;
|
||||||
|
|
||||||
[self updateTrackingAreas];
|
[self updateTrackingAreas];
|
||||||
[self registerForDraggedTypes:@[NSPasteboardTypeFileURL, NSPasteboardTypeString]];
|
[self registerForDraggedTypes:@[NSPasteboardTypeFileURL, NSPasteboardTypeString]];
|
||||||
@@ -689,6 +691,7 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
|
|||||||
{
|
{
|
||||||
[trackingArea release];
|
[trackingArea release];
|
||||||
[markedText release];
|
[markedText release];
|
||||||
|
if (input_source_at_last_key_event) [input_source_at_last_key_event release];
|
||||||
[super dealloc];
|
[super dealloc];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -965,12 +968,19 @@ is_ascii_control_char(char x) {
|
|||||||
|
|
||||||
- (void)keyDown:(NSEvent *)event
|
- (void)keyDown:(NSEvent *)event
|
||||||
{
|
{
|
||||||
|
const bool previous_has_marked_text = [self hasMarkedText];
|
||||||
|
bool input_source_changed = false;
|
||||||
|
NSTextInputContext *inpctx = [NSTextInputContext currentInputContext];
|
||||||
|
if (inpctx && (!input_source_at_last_key_event || ![input_source_at_last_key_event isEqualToString:inpctx.selectedKeyboardInputSource])) {
|
||||||
|
input_source_at_last_key_event = [inpctx.selectedKeyboardInputSource retain];
|
||||||
|
input_source_changed = true;
|
||||||
|
}
|
||||||
|
|
||||||
const unsigned int keycode = [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(keycode, true);
|
const int key = translateKey(keycode, true);
|
||||||
const bool process_text = !window->ns.textInputFilterCallback || window->ns.textInputFilterCallback(key, mods, keycode, 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];
|
|
||||||
[self unmarkText];
|
[self unmarkText];
|
||||||
_glfw.ns.text[0] = 0;
|
_glfw.ns.text[0] = 0;
|
||||||
GLFWkeyevent glfw_keyevent;
|
GLFWkeyevent glfw_keyevent;
|
||||||
@@ -984,6 +994,14 @@ is_ascii_control_char(char x) {
|
|||||||
[self interpretKeyEvents:[NSArray arrayWithObject:event]];
|
[self interpretKeyEvents:[NSArray arrayWithObject:event]];
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
if (input_source_changed) {
|
||||||
|
debug_key(@"Input source changed, clearing pre-edit text and resetting deadkey state\n");
|
||||||
|
glfw_keyevent.text = NULL;
|
||||||
|
glfw_keyevent.ime_state = 1;
|
||||||
|
window->ns.deadKeyState = 0;
|
||||||
|
_glfwInputKeyboard(window, &glfw_keyevent); // clear pre-edit text
|
||||||
|
}
|
||||||
|
|
||||||
static UniChar text[256];
|
static UniChar text[256];
|
||||||
UniCharCount char_count = 0;
|
UniCharCount char_count = 0;
|
||||||
const bool in_compose_sequence = window->ns.deadKeyState != 0;
|
const bool in_compose_sequence = window->ns.deadKeyState != 0;
|
||||||
@@ -1115,7 +1133,7 @@ is_ascii_control_char(char x) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
_glfwInputScroll(window, deltaX, deltaY, flags);
|
_glfwInputScroll(window, deltaX, deltaY, flags, translateFlags([event modifierFlags]));
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
|
- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
|
||||||
@@ -1141,27 +1159,20 @@ is_ascii_control_char(char x) {
|
|||||||
const NSUInteger count = [objs count];
|
const NSUInteger count = [objs count];
|
||||||
if (count)
|
if (count)
|
||||||
{
|
{
|
||||||
char** paths = calloc(count, sizeof(char*));
|
|
||||||
|
|
||||||
for (NSUInteger i = 0; i < count; i++)
|
for (NSUInteger i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
id obj = objs[i];
|
id obj = objs[i];
|
||||||
if ([obj isKindOfClass:[NSURL class]]) {
|
if ([obj isKindOfClass:[NSURL class]]) {
|
||||||
paths[i] = _glfw_strdup([obj fileSystemRepresentation]);
|
const char *path = [obj fileSystemRepresentation];
|
||||||
|
_glfwInputDrop(window, "text/plain;charset=utf-8", path, strlen(path));
|
||||||
} else if ([obj isKindOfClass:[NSString class]]) {
|
} else if ([obj isKindOfClass:[NSString class]]) {
|
||||||
paths[i] = _glfw_strdup([obj UTF8String]);
|
const char *text = [obj UTF8String];
|
||||||
|
_glfwInputDrop(window, "text/plain;charset=utf-8", text, strlen(text));
|
||||||
} else {
|
} else {
|
||||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
"Cocoa: Object is neither a URL nor a string");
|
"Cocoa: Object is neither a URL nor a string");
|
||||||
paths[i] = _glfw_strdup("");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_glfwInputDrop(window, (int) count, (const char**) paths);
|
|
||||||
|
|
||||||
for (NSUInteger i = 0; i < count; i++)
|
|
||||||
free(paths[i]);
|
|
||||||
free(paths);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return YES;
|
return YES;
|
||||||
@@ -1449,6 +1460,11 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window,
|
|||||||
}
|
}
|
||||||
else if (ctxconfig->source == GLFW_EGL_CONTEXT_API)
|
else if (ctxconfig->source == GLFW_EGL_CONTEXT_API)
|
||||||
{
|
{
|
||||||
|
// EGL implementation on macOS use CALayer* EGLNativeWindowType so we
|
||||||
|
// need to get the layer for EGL window surface creation.
|
||||||
|
[window->ns.view setWantsLayer:YES];
|
||||||
|
window->ns.layer = [window->ns.view layer];
|
||||||
|
|
||||||
if (!_glfwInitEGL())
|
if (!_glfwInitEGL())
|
||||||
return false;
|
return false;
|
||||||
if (!_glfwCreateContextEGL(window, ctxconfig, fbconfig))
|
if (!_glfwCreateContextEGL(window, ctxconfig, fbconfig))
|
||||||
@@ -1511,7 +1527,8 @@ void _glfwPlatformSetWindowTitle(_GLFWwindow* window UNUSED, const char* title)
|
|||||||
void _glfwPlatformSetWindowIcon(_GLFWwindow* window UNUSED,
|
void _glfwPlatformSetWindowIcon(_GLFWwindow* window UNUSED,
|
||||||
int count UNUSED, const GLFWimage* images UNUSED)
|
int count UNUSED, const GLFWimage* images UNUSED)
|
||||||
{
|
{
|
||||||
// Regular windows do not have icons
|
_glfwInputError(GLFW_FEATURE_UNAVAILABLE,
|
||||||
|
"Cocoa: Regular windows do not have icons on macOS");
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos)
|
void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos)
|
||||||
@@ -1578,10 +1595,10 @@ void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window,
|
|||||||
|
|
||||||
void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window, int numer, int denom)
|
void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window, int numer, int denom)
|
||||||
{
|
{
|
||||||
if (numer != GLFW_DONT_CARE && denom != GLFW_DONT_CARE)
|
if (numer == GLFW_DONT_CARE || denom == GLFW_DONT_CARE)
|
||||||
[window->ns.object setContentAspectRatio:NSMakeSize(numer, denom)];
|
|
||||||
else
|
|
||||||
[window->ns.object setResizeIncrements:NSMakeSize(1.0, 1.0)];
|
[window->ns.object setResizeIncrements:NSMakeSize(1.0, 1.0)];
|
||||||
|
else
|
||||||
|
[window->ns.object setContentAspectRatio:NSMakeSize(numer, denom)];
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformSetWindowSizeIncrements(_GLFWwindow* window, int widthincr, int heightincr)
|
void _glfwPlatformSetWindowSizeIncrements(_GLFWwindow* window, int widthincr, int heightincr)
|
||||||
@@ -1837,6 +1854,11 @@ void _glfwPlatformSetWindowFloating(_GLFWwindow* window, bool enabled)
|
|||||||
[window->ns.object setLevel:NSNormalWindowLevel];
|
[window->ns.object setLevel:NSNormalWindowLevel];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _glfwPlatformSetWindowMousePassthrough(_GLFWwindow* window, bool enabled)
|
||||||
|
{
|
||||||
|
[window->ns.object setIgnoresMouseEvents:enabled];
|
||||||
|
}
|
||||||
|
|
||||||
float _glfwPlatformGetWindowOpacity(_GLFWwindow* window)
|
float _glfwPlatformGetWindowOpacity(_GLFWwindow* window)
|
||||||
{
|
{
|
||||||
return (float) [window->ns.object alphaValue];
|
return (float) [window->ns.object alphaValue];
|
||||||
@@ -1847,6 +1869,17 @@ void _glfwPlatformSetWindowOpacity(_GLFWwindow* window, float opacity)
|
|||||||
[window->ns.object setAlphaValue:opacity];
|
[window->ns.object setAlphaValue:opacity];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _glfwPlatformSetRawMouseMotion(_GLFWwindow *window UNUSED, bool enabled UNUSED)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_FEATURE_UNIMPLEMENTED,
|
||||||
|
"Cocoa: Raw mouse motion not yet implemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _glfwPlatformRawMouseMotionSupported(void)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
_glfwDispatchRenderFrame(CGDirectDisplayID displayID) {
|
_glfwDispatchRenderFrame(CGDirectDisplayID displayID) {
|
||||||
_GLFWwindow *w = _glfw.windowListHead;
|
_GLFWwindow *w = _glfw.windowListHead;
|
||||||
@@ -1961,8 +1994,10 @@ int _glfwPlatformCreateCursor(_GLFWcursor* cursor,
|
|||||||
bitmapFormat:NSBitmapFormatAlphaNonpremultiplied
|
bitmapFormat:NSBitmapFormatAlphaNonpremultiplied
|
||||||
bytesPerRow:src->width * 4
|
bytesPerRow:src->width * 4
|
||||||
bitsPerPixel:32];
|
bitsPerPixel:32];
|
||||||
if (rep == nil)
|
if (rep == nil) {
|
||||||
|
[native release];
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
memcpy([rep bitmapData], src->pixels, src->width * src->height * 4);
|
memcpy([rep bitmapData], src->pixels, src->width * src->height * 4);
|
||||||
[native addRepresentation:rep];
|
[native addRepresentation:rep];
|
||||||
@@ -2077,6 +2112,47 @@ const char* _glfwPlatformGetClipboardString(void)
|
|||||||
return _glfw.ns.clipboardString;
|
return _glfw.ns.clipboardString;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EGLenum _glfwPlatformGetEGLPlatform(EGLint** attribs)
|
||||||
|
{
|
||||||
|
if (_glfw.egl.ANGLE_platform_angle)
|
||||||
|
{
|
||||||
|
int type = 0;
|
||||||
|
|
||||||
|
if (_glfw.egl.ANGLE_platform_angle_opengl)
|
||||||
|
{
|
||||||
|
if (_glfw.hints.init.angleType == GLFW_ANGLE_PLATFORM_TYPE_OPENGL)
|
||||||
|
type = EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_glfw.egl.ANGLE_platform_angle_metal)
|
||||||
|
{
|
||||||
|
if (_glfw.hints.init.angleType == GLFW_ANGLE_PLATFORM_TYPE_METAL)
|
||||||
|
type = EGL_PLATFORM_ANGLE_TYPE_METAL_ANGLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type)
|
||||||
|
{
|
||||||
|
*attribs = calloc(3, sizeof(EGLint));
|
||||||
|
(*attribs)[0] = EGL_PLATFORM_ANGLE_TYPE_ANGLE;
|
||||||
|
(*attribs)[1] = type;
|
||||||
|
(*attribs)[2] = EGL_NONE;
|
||||||
|
return EGL_PLATFORM_ANGLE_ANGLE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
EGLNativeDisplayType _glfwPlatformGetEGLNativeDisplay(void)
|
||||||
|
{
|
||||||
|
return EGL_DEFAULT_DISPLAY;
|
||||||
|
}
|
||||||
|
|
||||||
|
EGLNativeWindowType _glfwPlatformGetEGLNativeWindow(_GLFWwindow* window)
|
||||||
|
{
|
||||||
|
return window->ns.layer;
|
||||||
|
}
|
||||||
|
|
||||||
void _glfwPlatformGetRequiredInstanceExtensions(char** extensions)
|
void _glfwPlatformGetRequiredInstanceExtensions(char** extensions)
|
||||||
{
|
{
|
||||||
if (_glfw.vk.KHR_surface && _glfw.vk.EXT_metal_surface)
|
if (_glfw.vk.KHR_surface && _glfw.vk.EXT_metal_surface)
|
||||||
@@ -2372,7 +2448,7 @@ START_ALLOW_CASE_RANGE
|
|||||||
END_ALLOW_CASE_RANGE
|
END_ALLOW_CASE_RANGE
|
||||||
}
|
}
|
||||||
if (utf_16_key != 0) {
|
if (utf_16_key != 0) {
|
||||||
strncpy(cocoa_key, [[NSString stringWithCharacters:&utf_16_key length:1] UTF8String], key_sz - 1);
|
strncpy(cocoa_key, [[NSString stringWithCharacters:&utf_16_key length:1] UTF8String], key_sz - 1);
|
||||||
} else {
|
} else {
|
||||||
unsigned str_pos = 0;
|
unsigned str_pos = 0;
|
||||||
for (unsigned i = 0; i < 4 && str_pos < key_sz - 1; i++) {
|
for (unsigned i = 0; i < 4 && str_pos < key_sz - 1; i++) {
|
||||||
|
|||||||
168
glfw/context.c
vendored
168
glfw/context.c
vendored
@@ -173,174 +173,6 @@ bool _glfwIsValidContextConfig(const _GLFWctxconfig* ctxconfig)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Chooses the framebuffer config that best matches the desired one
|
|
||||||
//
|
|
||||||
const _GLFWfbconfig* _glfwChooseFBConfig(const _GLFWfbconfig* desired,
|
|
||||||
const _GLFWfbconfig* alternatives,
|
|
||||||
unsigned int count)
|
|
||||||
{
|
|
||||||
unsigned int i;
|
|
||||||
unsigned int missing, leastMissing = UINT_MAX;
|
|
||||||
unsigned int colorDiff, leastColorDiff = UINT_MAX;
|
|
||||||
unsigned int extraDiff, leastExtraDiff = UINT_MAX;
|
|
||||||
const _GLFWfbconfig* current;
|
|
||||||
const _GLFWfbconfig* closest = NULL;
|
|
||||||
|
|
||||||
for (i = 0; i < count; i++)
|
|
||||||
{
|
|
||||||
current = alternatives + i;
|
|
||||||
|
|
||||||
if (desired->stereo > 0 && current->stereo == 0)
|
|
||||||
{
|
|
||||||
// Stereo is a hard constraint
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (desired->doublebuffer != current->doublebuffer)
|
|
||||||
{
|
|
||||||
// Double buffering is a hard constraint
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Count number of missing buffers
|
|
||||||
{
|
|
||||||
missing = 0;
|
|
||||||
|
|
||||||
if (desired->alphaBits > 0 && current->alphaBits == 0)
|
|
||||||
missing++;
|
|
||||||
|
|
||||||
if (desired->depthBits > 0 && current->depthBits == 0)
|
|
||||||
missing++;
|
|
||||||
|
|
||||||
if (desired->stencilBits > 0 && current->stencilBits == 0)
|
|
||||||
missing++;
|
|
||||||
|
|
||||||
if (desired->auxBuffers > 0 &&
|
|
||||||
current->auxBuffers < desired->auxBuffers)
|
|
||||||
{
|
|
||||||
missing += desired->auxBuffers - current->auxBuffers;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (desired->samples > 0 && current->samples == 0)
|
|
||||||
{
|
|
||||||
// Technically, several multisampling buffers could be
|
|
||||||
// involved, but that's a lower level implementation detail and
|
|
||||||
// not important to us here, so we count them as one
|
|
||||||
missing++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (desired->transparent != current->transparent)
|
|
||||||
missing++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// These polynomials make many small channel size differences matter
|
|
||||||
// less than one large channel size difference
|
|
||||||
|
|
||||||
// Calculate color channel size difference value
|
|
||||||
{
|
|
||||||
colorDiff = 0;
|
|
||||||
|
|
||||||
if (desired->redBits != GLFW_DONT_CARE)
|
|
||||||
{
|
|
||||||
colorDiff += (desired->redBits - current->redBits) *
|
|
||||||
(desired->redBits - current->redBits);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (desired->greenBits != GLFW_DONT_CARE)
|
|
||||||
{
|
|
||||||
colorDiff += (desired->greenBits - current->greenBits) *
|
|
||||||
(desired->greenBits - current->greenBits);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (desired->blueBits != GLFW_DONT_CARE)
|
|
||||||
{
|
|
||||||
colorDiff += (desired->blueBits - current->blueBits) *
|
|
||||||
(desired->blueBits - current->blueBits);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculate non-color channel size difference value
|
|
||||||
{
|
|
||||||
extraDiff = 0;
|
|
||||||
|
|
||||||
if (desired->alphaBits != GLFW_DONT_CARE)
|
|
||||||
{
|
|
||||||
extraDiff += (desired->alphaBits - current->alphaBits) *
|
|
||||||
(desired->alphaBits - current->alphaBits);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (desired->depthBits != GLFW_DONT_CARE)
|
|
||||||
{
|
|
||||||
extraDiff += (desired->depthBits - current->depthBits) *
|
|
||||||
(desired->depthBits - current->depthBits);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (desired->stencilBits != GLFW_DONT_CARE)
|
|
||||||
{
|
|
||||||
extraDiff += (desired->stencilBits - current->stencilBits) *
|
|
||||||
(desired->stencilBits - current->stencilBits);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (desired->accumRedBits != GLFW_DONT_CARE)
|
|
||||||
{
|
|
||||||
extraDiff += (desired->accumRedBits - current->accumRedBits) *
|
|
||||||
(desired->accumRedBits - current->accumRedBits);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (desired->accumGreenBits != GLFW_DONT_CARE)
|
|
||||||
{
|
|
||||||
extraDiff += (desired->accumGreenBits - current->accumGreenBits) *
|
|
||||||
(desired->accumGreenBits - current->accumGreenBits);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (desired->accumBlueBits != GLFW_DONT_CARE)
|
|
||||||
{
|
|
||||||
extraDiff += (desired->accumBlueBits - current->accumBlueBits) *
|
|
||||||
(desired->accumBlueBits - current->accumBlueBits);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (desired->accumAlphaBits != GLFW_DONT_CARE)
|
|
||||||
{
|
|
||||||
extraDiff += (desired->accumAlphaBits - current->accumAlphaBits) *
|
|
||||||
(desired->accumAlphaBits - current->accumAlphaBits);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (desired->samples != GLFW_DONT_CARE)
|
|
||||||
{
|
|
||||||
extraDiff += (desired->samples - current->samples) *
|
|
||||||
(desired->samples - current->samples);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (desired->sRGB && !current->sRGB)
|
|
||||||
extraDiff++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Figure out if the current one is better than the best one found so far
|
|
||||||
// Least number of missing buffers is the most important heuristic,
|
|
||||||
// then color buffer size match and lastly size match for other buffers
|
|
||||||
|
|
||||||
if (missing < leastMissing)
|
|
||||||
closest = current;
|
|
||||||
else if (missing == leastMissing)
|
|
||||||
{
|
|
||||||
if ((colorDiff < leastColorDiff) ||
|
|
||||||
(colorDiff == leastColorDiff && extraDiff < leastExtraDiff))
|
|
||||||
{
|
|
||||||
closest = current;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (current == closest)
|
|
||||||
{
|
|
||||||
leastMissing = missing;
|
|
||||||
leastColorDiff = colorDiff;
|
|
||||||
leastExtraDiff = extraDiff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return closest;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Retrieves the attributes of the current context
|
// Retrieves the attributes of the current context
|
||||||
//
|
//
|
||||||
bool _glfwRefreshContextAttribs(_GLFWwindow* window,
|
bool _glfwRefreshContextAttribs(_GLFWwindow* window,
|
||||||
|
|||||||
182
glfw/egl_context.c
vendored
182
glfw/egl_context.c
vendored
@@ -76,6 +76,7 @@ static const char* getEGLErrorString(EGLint error)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef _GLFW_X11
|
||||||
// Returns the specified attribute of the specified EGLConfig
|
// Returns the specified attribute of the specified EGLConfig
|
||||||
//
|
//
|
||||||
static int getEGLConfigAttrib(EGLConfig config, int attrib)
|
static int getEGLConfigAttrib(EGLConfig config, int attrib)
|
||||||
@@ -84,6 +85,7 @@ static int getEGLConfigAttrib(EGLConfig config, int attrib)
|
|||||||
eglGetConfigAttrib(_glfw.egl.display, config, attrib, &value);
|
eglGetConfigAttrib(_glfw.egl.display, config, attrib, &value);
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// Return the EGLConfig most closely matching the specified hints
|
// Return the EGLConfig most closely matching the specified hints
|
||||||
//
|
//
|
||||||
@@ -91,39 +93,44 @@ static bool chooseEGLConfig(const _GLFWctxconfig* ctxconfig,
|
|||||||
const _GLFWfbconfig* desired,
|
const _GLFWfbconfig* desired,
|
||||||
EGLConfig* result)
|
EGLConfig* result)
|
||||||
{
|
{
|
||||||
EGLConfig* nativeConfigs;
|
EGLConfig configs[512];
|
||||||
_GLFWfbconfig* usableConfigs;
|
int i = 0, nativeCount = 0, ans_idx = 0;
|
||||||
const _GLFWfbconfig* closest;
|
EGLint attributes[64];
|
||||||
int i, nativeCount, usableCount;
|
#define ATTR(k, v) { attributes[i++] = k; attributes[i++] = v; }
|
||||||
|
ATTR(EGL_COLOR_BUFFER_TYPE, EGL_RGB_BUFFER);
|
||||||
|
ATTR(EGL_SURFACE_TYPE, EGL_WINDOW_BIT);
|
||||||
|
if (ctxconfig->client == GLFW_OPENGL_ES_API) {
|
||||||
|
if (ctxconfig->major == 1) ATTR(EGL_RENDERABLE_TYPE, EGL_OPENGL_ES_BIT)
|
||||||
|
else ATTR(EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT);
|
||||||
|
}
|
||||||
|
else if (ctxconfig->client == GLFW_OPENGL_API) ATTR(EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT);
|
||||||
|
if (desired->samples > 0) ATTR(EGL_SAMPLES, desired->samples);
|
||||||
|
if (desired->depthBits > 0) ATTR(EGL_DEPTH_SIZE, desired->depthBits);
|
||||||
|
if (desired->stencilBits > 0) ATTR(EGL_STENCIL_SIZE, desired->stencilBits);
|
||||||
|
if (desired->redBits > 0) ATTR(EGL_RED_SIZE, desired->redBits);
|
||||||
|
if (desired->greenBits > 0) ATTR(EGL_GREEN_SIZE, desired->greenBits);
|
||||||
|
if (desired->blueBits > 0) ATTR(EGL_BLUE_SIZE, desired->blueBits);
|
||||||
|
if (desired->alphaBits > 0) ATTR(EGL_ALPHA_SIZE, desired->alphaBits);
|
||||||
|
ATTR(EGL_NONE, EGL_NONE);
|
||||||
|
#undef ATTR
|
||||||
|
if (!eglChooseConfig(_glfw.egl.display, attributes, configs, sizeof(configs)/sizeof(configs[0]), &nativeCount)) {
|
||||||
|
_glfwInputError(GLFW_API_UNAVAILABLE, "EGL: eglChooseConfig failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
eglGetConfigs(_glfw.egl.display, NULL, 0, &nativeCount);
|
|
||||||
if (!nativeCount)
|
if (!nativeCount)
|
||||||
{
|
{
|
||||||
_glfwInputError(GLFW_API_UNAVAILABLE, "EGL: No EGLConfigs returned");
|
_glfwInputError(GLFW_API_UNAVAILABLE, "EGL: No EGLConfigs returned");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
nativeConfigs = calloc(nativeCount, sizeof(EGLConfig));
|
|
||||||
eglGetConfigs(_glfw.egl.display, nativeConfigs, nativeCount, &nativeCount);
|
|
||||||
|
|
||||||
usableConfigs = calloc(nativeCount, sizeof(_GLFWfbconfig));
|
|
||||||
usableCount = 0;
|
|
||||||
|
|
||||||
for (i = 0; i < nativeCount; i++)
|
for (i = 0; i < nativeCount; i++)
|
||||||
{
|
{
|
||||||
const EGLConfig n = nativeConfigs[i];
|
|
||||||
_GLFWfbconfig* u = usableConfigs + usableCount;
|
|
||||||
|
|
||||||
// Only consider RGB(A) EGLConfigs
|
|
||||||
if (getEGLConfigAttrib(n, EGL_COLOR_BUFFER_TYPE) != EGL_RGB_BUFFER)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// Only consider window EGLConfigs
|
|
||||||
if (!(getEGLConfigAttrib(n, EGL_SURFACE_TYPE) & EGL_WINDOW_BIT))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
#if defined(_GLFW_X11)
|
#if defined(_GLFW_X11)
|
||||||
{
|
{
|
||||||
|
const EGLConfig n = configs[i];
|
||||||
XVisualInfo vi = {0};
|
XVisualInfo vi = {0};
|
||||||
|
|
||||||
// Only consider EGLConfigs with associated Visuals
|
// Only consider EGLConfigs with associated Visuals
|
||||||
@@ -138,55 +145,18 @@ static bool chooseEGLConfig(const _GLFWctxconfig* ctxconfig,
|
|||||||
XGetVisualInfo(_glfw.x11.display, VisualIDMask, &vi, &count);
|
XGetVisualInfo(_glfw.x11.display, VisualIDMask, &vi, &count);
|
||||||
if (vis)
|
if (vis)
|
||||||
{
|
{
|
||||||
u->transparent = _glfwIsVisualTransparentX11(vis[0].visual);
|
bool transparent = _glfwIsVisualTransparentX11(vis[0].visual);
|
||||||
XFree(vis);
|
XFree(vis);
|
||||||
|
if (!transparent) continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif // _GLFW_X11
|
#endif // _GLFW_X11
|
||||||
|
ans_idx = i;
|
||||||
if (ctxconfig->client == GLFW_OPENGL_ES_API)
|
break;
|
||||||
{
|
|
||||||
if (ctxconfig->major == 1)
|
|
||||||
{
|
|
||||||
if (!(getEGLConfigAttrib(n, EGL_RENDERABLE_TYPE) & EGL_OPENGL_ES_BIT))
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (!(getEGLConfigAttrib(n, EGL_RENDERABLE_TYPE) & EGL_OPENGL_ES2_BIT))
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (ctxconfig->client == GLFW_OPENGL_API)
|
|
||||||
{
|
|
||||||
if (!(getEGLConfigAttrib(n, EGL_RENDERABLE_TYPE) & EGL_OPENGL_BIT))
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
u->redBits = getEGLConfigAttrib(n, EGL_RED_SIZE);
|
|
||||||
u->greenBits = getEGLConfigAttrib(n, EGL_GREEN_SIZE);
|
|
||||||
u->blueBits = getEGLConfigAttrib(n, EGL_BLUE_SIZE);
|
|
||||||
|
|
||||||
u->alphaBits = getEGLConfigAttrib(n, EGL_ALPHA_SIZE);
|
|
||||||
u->depthBits = getEGLConfigAttrib(n, EGL_DEPTH_SIZE);
|
|
||||||
u->stencilBits = getEGLConfigAttrib(n, EGL_STENCIL_SIZE);
|
|
||||||
|
|
||||||
u->samples = getEGLConfigAttrib(n, EGL_SAMPLES);
|
|
||||||
u->doublebuffer = true;
|
|
||||||
|
|
||||||
u->handle = (uintptr_t) n;
|
|
||||||
usableCount++;
|
|
||||||
}
|
}
|
||||||
|
*result = configs[ans_idx];
|
||||||
closest = _glfwChooseFBConfig(desired, usableConfigs, usableCount);
|
return true;
|
||||||
if (closest)
|
|
||||||
*result = (EGLConfig) closest->handle;
|
|
||||||
|
|
||||||
free(nativeConfigs);
|
|
||||||
free(usableConfigs);
|
|
||||||
|
|
||||||
return closest != NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void makeContextCurrentEGL(_GLFWwindow* window)
|
static void makeContextCurrentEGL(_GLFWwindow* window)
|
||||||
@@ -303,6 +273,8 @@ static void destroyContextEGL(_GLFWwindow* window)
|
|||||||
bool _glfwInitEGL(void)
|
bool _glfwInitEGL(void)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
EGLint* attribs = NULL;
|
||||||
|
const char* extensions;
|
||||||
const char* sonames[] =
|
const char* sonames[] =
|
||||||
{
|
{
|
||||||
#if defined(_GLFW_EGL_LIBRARY)
|
#if defined(_GLFW_EGL_LIBRARY)
|
||||||
@@ -340,6 +312,7 @@ bool _glfwInitEGL(void)
|
|||||||
|
|
||||||
glfw_dlsym(_glfw.egl.GetConfigAttrib, _glfw.egl.handle, "eglGetConfigAttrib");
|
glfw_dlsym(_glfw.egl.GetConfigAttrib, _glfw.egl.handle, "eglGetConfigAttrib");
|
||||||
glfw_dlsym(_glfw.egl.GetConfigs, _glfw.egl.handle, "eglGetConfigs");
|
glfw_dlsym(_glfw.egl.GetConfigs, _glfw.egl.handle, "eglGetConfigs");
|
||||||
|
glfw_dlsym(_glfw.egl.ChooseConfig, _glfw.egl.handle, "eglChooseConfig");
|
||||||
glfw_dlsym(_glfw.egl.GetDisplay, _glfw.egl.handle, "eglGetDisplay");
|
glfw_dlsym(_glfw.egl.GetDisplay, _glfw.egl.handle, "eglGetDisplay");
|
||||||
glfw_dlsym(_glfw.egl.GetError, _glfw.egl.handle, "eglGetError");
|
glfw_dlsym(_glfw.egl.GetError, _glfw.egl.handle, "eglGetError");
|
||||||
glfw_dlsym(_glfw.egl.Initialize, _glfw.egl.handle, "eglInitialize");
|
glfw_dlsym(_glfw.egl.Initialize, _glfw.egl.handle, "eglInitialize");
|
||||||
@@ -357,6 +330,7 @@ bool _glfwInitEGL(void)
|
|||||||
|
|
||||||
if (!_glfw.egl.GetConfigAttrib ||
|
if (!_glfw.egl.GetConfigAttrib ||
|
||||||
!_glfw.egl.GetConfigs ||
|
!_glfw.egl.GetConfigs ||
|
||||||
|
!_glfw.egl.ChooseConfig ||
|
||||||
!_glfw.egl.GetDisplay ||
|
!_glfw.egl.GetDisplay ||
|
||||||
!_glfw.egl.GetError ||
|
!_glfw.egl.GetError ||
|
||||||
!_glfw.egl.Initialize ||
|
!_glfw.egl.Initialize ||
|
||||||
@@ -379,7 +353,51 @@ bool _glfwInitEGL(void)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
_glfw.egl.display = eglGetDisplay(_GLFW_EGL_NATIVE_DISPLAY);
|
extensions = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
|
||||||
|
if (extensions && eglGetError() == EGL_SUCCESS)
|
||||||
|
_glfw.egl.EXT_client_extensions = true;
|
||||||
|
|
||||||
|
if (_glfw.egl.EXT_client_extensions)
|
||||||
|
{
|
||||||
|
_glfw.egl.EXT_platform_base =
|
||||||
|
_glfwStringInExtensionString("EGL_EXT_platform_base", extensions);
|
||||||
|
_glfw.egl.EXT_platform_x11 =
|
||||||
|
_glfwStringInExtensionString("EGL_EXT_platform_x11", extensions);
|
||||||
|
_glfw.egl.EXT_platform_wayland =
|
||||||
|
_glfwStringInExtensionString("EGL_EXT_platform_wayland", extensions);
|
||||||
|
_glfw.egl.ANGLE_platform_angle =
|
||||||
|
_glfwStringInExtensionString("EGL_ANGLE_platform_angle", extensions);
|
||||||
|
_glfw.egl.ANGLE_platform_angle_opengl =
|
||||||
|
_glfwStringInExtensionString("EGL_ANGLE_platform_angle_opengl", extensions);
|
||||||
|
_glfw.egl.ANGLE_platform_angle_d3d =
|
||||||
|
_glfwStringInExtensionString("EGL_ANGLE_platform_angle_d3d", extensions);
|
||||||
|
_glfw.egl.ANGLE_platform_angle_vulkan =
|
||||||
|
_glfwStringInExtensionString("EGL_ANGLE_platform_angle_vulkan", extensions);
|
||||||
|
_glfw.egl.ANGLE_platform_angle_metal =
|
||||||
|
_glfwStringInExtensionString("EGL_ANGLE_platform_angle_metal", extensions);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_glfw.egl.EXT_platform_base)
|
||||||
|
{
|
||||||
|
_glfw.egl.GetPlatformDisplayEXT = (PFNEGLGETPLATFORMDISPLAYEXTPROC)
|
||||||
|
eglGetProcAddress("eglGetPlatformDisplayEXT");
|
||||||
|
_glfw.egl.CreatePlatformWindowSurfaceEXT = (PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC)
|
||||||
|
eglGetProcAddress("eglCreatePlatformWindowSurfaceEXT");
|
||||||
|
}
|
||||||
|
|
||||||
|
_glfw.egl.platform = _glfwPlatformGetEGLPlatform(&attribs);
|
||||||
|
if (_glfw.egl.platform)
|
||||||
|
{
|
||||||
|
_glfw.egl.display =
|
||||||
|
eglGetPlatformDisplayEXT(_glfw.egl.platform,
|
||||||
|
_glfwPlatformGetEGLNativeDisplay(),
|
||||||
|
attribs);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
_glfw.egl.display = eglGetDisplay(_glfwPlatformGetEGLNativeDisplay());
|
||||||
|
|
||||||
|
free(attribs);
|
||||||
|
|
||||||
if (_glfw.egl.display == EGL_NO_DISPLAY)
|
if (_glfw.egl.display == EGL_NO_DISPLAY)
|
||||||
{
|
{
|
||||||
_glfwInputError(GLFW_API_UNAVAILABLE,
|
_glfwInputError(GLFW_API_UNAVAILABLE,
|
||||||
@@ -447,6 +465,7 @@ bool _glfwCreateContextEGL(_GLFWwindow* window,
|
|||||||
EGLint attribs[40];
|
EGLint attribs[40];
|
||||||
EGLConfig config;
|
EGLConfig config;
|
||||||
EGLContext share = NULL;
|
EGLContext share = NULL;
|
||||||
|
EGLNativeWindowType native;
|
||||||
int index = 0;
|
int index = 0;
|
||||||
|
|
||||||
if (!_glfw.egl.display)
|
if (!_glfw.egl.display)
|
||||||
@@ -572,23 +591,30 @@ bool _glfwCreateContextEGL(_GLFWwindow* window,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Set up attributes for surface creation
|
// Set up attributes for surface creation
|
||||||
|
index = 0;
|
||||||
|
|
||||||
|
if (fbconfig->sRGB)
|
||||||
{
|
{
|
||||||
int index = 0;
|
if (_glfw.egl.KHR_gl_colorspace)
|
||||||
|
setAttrib(EGL_GL_COLORSPACE_KHR, EGL_GL_COLORSPACE_SRGB_KHR);
|
||||||
if (fbconfig->sRGB)
|
}
|
||||||
{
|
|
||||||
if (_glfw.egl.KHR_gl_colorspace)
|
setAttrib(EGL_NONE, EGL_NONE);
|
||||||
setAttrib(EGL_GL_COLORSPACE_KHR, EGL_GL_COLORSPACE_SRGB_KHR);
|
|
||||||
}
|
native = _glfwPlatformGetEGLNativeWindow(window);
|
||||||
|
// HACK: ANGLE does not implement eglCreatePlatformWindowSurfaceEXT
|
||||||
setAttrib(EGL_NONE, EGL_NONE);
|
// despite reporting EGL_EXT_platform_base
|
||||||
|
if (_glfw.egl.platform && _glfw.egl.platform != EGL_PLATFORM_ANGLE_ANGLE)
|
||||||
|
{
|
||||||
|
window->context.egl.surface =
|
||||||
|
eglCreatePlatformWindowSurfaceEXT(_glfw.egl.display, config, native, attribs);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
window->context.egl.surface =
|
||||||
|
eglCreateWindowSurface(_glfw.egl.display, config, native, attribs);
|
||||||
}
|
}
|
||||||
|
|
||||||
window->context.egl.surface =
|
|
||||||
eglCreateWindowSurface(_glfw.egl.display,
|
|
||||||
config,
|
|
||||||
_GLFW_EGL_NATIVE_WINDOW,
|
|
||||||
attribs);
|
|
||||||
if (window->context.egl.surface == EGL_NO_SURFACE)
|
if (window->context.egl.surface == EGL_NO_SURFACE)
|
||||||
{
|
{
|
||||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
|||||||
57
glfw/egl_context.h
vendored
57
glfw/egl_context.h
vendored
@@ -25,26 +25,10 @@
|
|||||||
//
|
//
|
||||||
//========================================================================
|
//========================================================================
|
||||||
|
|
||||||
#if defined(_GLFW_USE_EGLPLATFORM_H)
|
#if defined(_GLFW_WIN32)
|
||||||
#include <EGL/eglplatform.h>
|
|
||||||
#elif defined(_GLFW_WIN32)
|
|
||||||
#define EGLAPIENTRY __stdcall
|
#define EGLAPIENTRY __stdcall
|
||||||
typedef HDC EGLNativeDisplayType;
|
|
||||||
typedef HWND EGLNativeWindowType;
|
|
||||||
#elif defined(_GLFW_COCOA)
|
|
||||||
#define EGLAPIENTRY
|
|
||||||
typedef void* EGLNativeDisplayType;
|
|
||||||
typedef id EGLNativeWindowType;
|
|
||||||
#elif defined(_GLFW_X11)
|
|
||||||
#define EGLAPIENTRY
|
|
||||||
typedef Display* EGLNativeDisplayType;
|
|
||||||
typedef Window EGLNativeWindowType;
|
|
||||||
#elif defined(_GLFW_WAYLAND)
|
|
||||||
#define EGLAPIENTRY
|
|
||||||
typedef struct wl_display* EGLNativeDisplayType;
|
|
||||||
typedef struct wl_egl_window* EGLNativeWindowType;
|
|
||||||
#else
|
#else
|
||||||
#error "No supported EGL platform selected"
|
#define EGLAPIENTRY
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define EGL_SUCCESS 0x3000
|
#define EGL_SUCCESS 0x3000
|
||||||
@@ -108,6 +92,17 @@ typedef struct wl_egl_window* EGLNativeWindowType;
|
|||||||
#define EGL_CONTEXT_RELEASE_BEHAVIOR_KHR 0x2097
|
#define EGL_CONTEXT_RELEASE_BEHAVIOR_KHR 0x2097
|
||||||
#define EGL_CONTEXT_RELEASE_BEHAVIOR_NONE_KHR 0
|
#define EGL_CONTEXT_RELEASE_BEHAVIOR_NONE_KHR 0
|
||||||
#define EGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_KHR 0x2098
|
#define EGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_KHR 0x2098
|
||||||
|
#define EGL_PLATFORM_X11_EXT 0x31d5
|
||||||
|
#define EGL_PLATFORM_WAYLAND_EXT 0x31d8
|
||||||
|
#define EGL_PLATFORM_ANGLE_ANGLE 0x3202
|
||||||
|
#define EGL_PLATFORM_ANGLE_TYPE_ANGLE 0x3203
|
||||||
|
#define EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE 0x320d
|
||||||
|
#define EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE 0x320e
|
||||||
|
#define EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE 0x3207
|
||||||
|
#define EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE 0x3208
|
||||||
|
#define EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE 0x3450
|
||||||
|
#define EGL_PLATFORM_ANGLE_TYPE_METAL_ANGLE 0x3489
|
||||||
|
#define EGL_PLATFORM_ANGLE_NATIVE_PLATFORM_TYPE_ANGLE 0x348f
|
||||||
|
|
||||||
typedef int EGLint;
|
typedef int EGLint;
|
||||||
typedef unsigned int EGLBoolean;
|
typedef unsigned int EGLBoolean;
|
||||||
@@ -117,9 +112,13 @@ typedef void* EGLContext;
|
|||||||
typedef void* EGLDisplay;
|
typedef void* EGLDisplay;
|
||||||
typedef void* EGLSurface;
|
typedef void* EGLSurface;
|
||||||
|
|
||||||
|
typedef void* EGLNativeDisplayType;
|
||||||
|
typedef void* EGLNativeWindowType;
|
||||||
|
|
||||||
// EGL function pointer typedefs
|
// EGL function pointer typedefs
|
||||||
typedef EGLBoolean (EGLAPIENTRY * PFN_eglGetConfigAttrib)(EGLDisplay,EGLConfig,EGLint,EGLint*);
|
typedef EGLBoolean (EGLAPIENTRY * PFN_eglGetConfigAttrib)(EGLDisplay,EGLConfig,EGLint,EGLint*);
|
||||||
typedef EGLBoolean (EGLAPIENTRY * PFN_eglGetConfigs)(EGLDisplay,EGLConfig*,EGLint,EGLint*);
|
typedef EGLBoolean (EGLAPIENTRY * PFN_eglGetConfigs)(EGLDisplay,EGLConfig*,EGLint,EGLint*);
|
||||||
|
typedef EGLBoolean (EGLAPIENTRY * PFN_eglChooseConfig)(EGLDisplay,EGLint const*,EGLConfig*,EGLint,EGLint*);
|
||||||
typedef EGLDisplay (EGLAPIENTRY * PFN_eglGetDisplay)(EGLNativeDisplayType);
|
typedef EGLDisplay (EGLAPIENTRY * PFN_eglGetDisplay)(EGLNativeDisplayType);
|
||||||
typedef EGLint (EGLAPIENTRY * PFN_eglGetError)(void);
|
typedef EGLint (EGLAPIENTRY * PFN_eglGetError)(void);
|
||||||
typedef EGLBoolean (EGLAPIENTRY * PFN_eglInitialize)(EGLDisplay,EGLint*,EGLint*);
|
typedef EGLBoolean (EGLAPIENTRY * PFN_eglInitialize)(EGLDisplay,EGLint*,EGLint*);
|
||||||
@@ -136,6 +135,7 @@ typedef const char* (EGLAPIENTRY * PFN_eglQueryString)(EGLDisplay,EGLint);
|
|||||||
typedef GLFWglproc (EGLAPIENTRY * PFN_eglGetProcAddress)(const char*);
|
typedef GLFWglproc (EGLAPIENTRY * PFN_eglGetProcAddress)(const char*);
|
||||||
#define eglGetConfigAttrib _glfw.egl.GetConfigAttrib
|
#define eglGetConfigAttrib _glfw.egl.GetConfigAttrib
|
||||||
#define eglGetConfigs _glfw.egl.GetConfigs
|
#define eglGetConfigs _glfw.egl.GetConfigs
|
||||||
|
#define eglChooseConfig _glfw.egl.ChooseConfig
|
||||||
#define eglGetDisplay _glfw.egl.GetDisplay
|
#define eglGetDisplay _glfw.egl.GetDisplay
|
||||||
#define eglGetError _glfw.egl.GetError
|
#define eglGetError _glfw.egl.GetError
|
||||||
#define eglInitialize _glfw.egl.Initialize
|
#define eglInitialize _glfw.egl.Initialize
|
||||||
@@ -151,9 +151,10 @@ typedef GLFWglproc (EGLAPIENTRY * PFN_eglGetProcAddress)(const char*);
|
|||||||
#define eglQueryString _glfw.egl.QueryString
|
#define eglQueryString _glfw.egl.QueryString
|
||||||
#define eglGetProcAddress _glfw.egl.GetProcAddress
|
#define eglGetProcAddress _glfw.egl.GetProcAddress
|
||||||
|
|
||||||
#define _GLFW_EGL_CONTEXT_STATE _GLFWcontextEGL egl
|
typedef EGLDisplay (EGLAPIENTRY * PFNEGLGETPLATFORMDISPLAYEXTPROC)(EGLenum,void*,const EGLint*);
|
||||||
#define _GLFW_EGL_LIBRARY_CONTEXT_STATE _GLFWlibraryEGL egl
|
typedef EGLSurface (EGLAPIENTRY * PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC)(EGLDisplay,EGLConfig,void*,const EGLint*);
|
||||||
|
#define eglGetPlatformDisplayEXT _glfw.egl.GetPlatformDisplayEXT
|
||||||
|
#define eglCreatePlatformWindowSurfaceEXT _glfw.egl.CreatePlatformWindowSurfaceEXT
|
||||||
|
|
||||||
// EGL-specific per-context data
|
// EGL-specific per-context data
|
||||||
//
|
//
|
||||||
@@ -171,6 +172,7 @@ typedef struct _GLFWcontextEGL
|
|||||||
//
|
//
|
||||||
typedef struct _GLFWlibraryEGL
|
typedef struct _GLFWlibraryEGL
|
||||||
{
|
{
|
||||||
|
EGLenum platform;
|
||||||
EGLDisplay display;
|
EGLDisplay display;
|
||||||
EGLint major, minor;
|
EGLint major, minor;
|
||||||
bool prefix;
|
bool prefix;
|
||||||
@@ -180,11 +182,21 @@ typedef struct _GLFWlibraryEGL
|
|||||||
bool KHR_gl_colorspace;
|
bool KHR_gl_colorspace;
|
||||||
bool KHR_get_all_proc_addresses;
|
bool KHR_get_all_proc_addresses;
|
||||||
bool KHR_context_flush_control;
|
bool KHR_context_flush_control;
|
||||||
|
bool EXT_client_extensions;
|
||||||
|
bool EXT_platform_base;
|
||||||
|
bool EXT_platform_x11;
|
||||||
|
bool EXT_platform_wayland;
|
||||||
|
bool ANGLE_platform_angle;
|
||||||
|
bool ANGLE_platform_angle_opengl;
|
||||||
|
bool ANGLE_platform_angle_d3d;
|
||||||
|
bool ANGLE_platform_angle_vulkan;
|
||||||
|
bool ANGLE_platform_angle_metal;
|
||||||
|
|
||||||
void* handle;
|
void* handle;
|
||||||
|
|
||||||
PFN_eglGetConfigAttrib GetConfigAttrib;
|
PFN_eglGetConfigAttrib GetConfigAttrib;
|
||||||
PFN_eglGetConfigs GetConfigs;
|
PFN_eglGetConfigs GetConfigs;
|
||||||
|
PFN_eglChooseConfig ChooseConfig;
|
||||||
PFN_eglGetDisplay GetDisplay;
|
PFN_eglGetDisplay GetDisplay;
|
||||||
PFN_eglGetError GetError;
|
PFN_eglGetError GetError;
|
||||||
PFN_eglInitialize Initialize;
|
PFN_eglInitialize Initialize;
|
||||||
@@ -200,6 +212,9 @@ typedef struct _GLFWlibraryEGL
|
|||||||
PFN_eglQueryString QueryString;
|
PFN_eglQueryString QueryString;
|
||||||
PFN_eglGetProcAddress GetProcAddress;
|
PFN_eglGetProcAddress GetProcAddress;
|
||||||
|
|
||||||
|
PFNEGLGETPLATFORMDISPLAYEXTPROC GetPlatformDisplayEXT;
|
||||||
|
PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC CreatePlatformWindowSurfaceEXT;
|
||||||
|
|
||||||
} _GLFWlibraryEGL;
|
} _GLFWlibraryEGL;
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
77
glfw/glfw.py
77
glfw/glfw.py
@@ -6,20 +6,58 @@ import json
|
|||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
|
from typing import Callable, Dict, List, Optional, Tuple
|
||||||
|
|
||||||
_plat = sys.platform.lower()
|
_plat = sys.platform.lower()
|
||||||
is_linux = 'linux' in _plat
|
is_linux = 'linux' in _plat
|
||||||
|
is_openbsd = 'openbsd' in _plat
|
||||||
base = os.path.dirname(os.path.abspath(__file__))
|
base = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
|
||||||
|
|
||||||
def wayland_protocol_file_name(base, ext='c'):
|
class Env:
|
||||||
|
|
||||||
|
cc: str = ''
|
||||||
|
cppflags: List[str] = []
|
||||||
|
cflags: List[str] = []
|
||||||
|
ldflags: List[str] = []
|
||||||
|
library_paths: Dict[str, List[str]] = {}
|
||||||
|
ldpaths: List[str] = []
|
||||||
|
ccver: Tuple[int, int]
|
||||||
|
|
||||||
|
# glfw stuff
|
||||||
|
all_headers: List[str] = []
|
||||||
|
sources: List[str] = []
|
||||||
|
wayland_packagedir: str = ''
|
||||||
|
wayland_scanner: str = ''
|
||||||
|
wayland_scanner_code: str = ''
|
||||||
|
wayland_protocols: Tuple[str, ...] = ()
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self, cc: str = '', cppflags: List[str] = [], cflags: List[str] = [], ldflags: List[str] = [],
|
||||||
|
library_paths: Dict[str, List[str]] = {}, ldpaths: Optional[List[str]] = None, ccver: Tuple[int, int] = (0, 0)
|
||||||
|
):
|
||||||
|
self.cc, self.cppflags, self.cflags, self.ldflags, self.library_paths = cc, cppflags, cflags, ldflags, library_paths
|
||||||
|
self.ldpaths, self.ccver = [] if ldpaths is None else ldpaths, ccver
|
||||||
|
|
||||||
|
def copy(self) -> 'Env':
|
||||||
|
ans = Env(self.cc, list(self.cppflags), list(self.cflags), list(self.ldflags), dict(self.library_paths), list(self.ldpaths), self.ccver)
|
||||||
|
ans.all_headers = list(self.all_headers)
|
||||||
|
ans.sources = list(self.sources)
|
||||||
|
ans.wayland_packagedir = self.wayland_packagedir
|
||||||
|
ans.wayland_scanner = self.wayland_scanner
|
||||||
|
ans.wayland_scanner_code = self.wayland_scanner_code
|
||||||
|
ans.wayland_protocols = self.wayland_protocols
|
||||||
|
return ans
|
||||||
|
|
||||||
|
|
||||||
|
def wayland_protocol_file_name(base: str, ext: str = 'c') -> str:
|
||||||
base = os.path.basename(base).rpartition('.')[0]
|
base = os.path.basename(base).rpartition('.')[0]
|
||||||
return 'wayland-{}-client-protocol.{}'.format(base, ext)
|
return 'wayland-{}-client-protocol.{}'.format(base, ext)
|
||||||
|
|
||||||
|
|
||||||
def init_env(env, pkg_config, at_least_version, test_compile, module='x11'):
|
def init_env(env: Env, pkg_config: Callable, at_least_version: Callable, test_compile: Callable, module: str = 'x11') -> Env:
|
||||||
ans = env.copy()
|
ans = env.copy()
|
||||||
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')
|
||||||
|
|
||||||
@@ -35,8 +73,9 @@ def init_env(env, pkg_config, at_least_version, test_compile, module='x11'):
|
|||||||
|
|
||||||
if module in ('x11', 'wayland'):
|
if module in ('x11', 'wayland'):
|
||||||
ans.cflags.append('-pthread')
|
ans.cflags.append('-pthread')
|
||||||
ans.ldpaths.append('-pthread')
|
ans.ldpaths.extend('-pthread -lm'.split())
|
||||||
ans.ldpaths.extend('-lrt -lm -ldl'.split())
|
if not is_openbsd:
|
||||||
|
ans.ldpaths.extend('-lrt -ldl'.split())
|
||||||
at_least_version('xkbcommon', 0, 5)
|
at_least_version('xkbcommon', 0, 5)
|
||||||
|
|
||||||
if module == 'x11':
|
if module == 'x11':
|
||||||
@@ -46,8 +85,8 @@ def init_env(env, pkg_config, at_least_version, test_compile, module='x11'):
|
|||||||
|
|
||||||
elif module == 'cocoa':
|
elif module == 'cocoa':
|
||||||
ans.cppflags.append('-DGL_SILENCE_DEPRECATION')
|
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_))
|
||||||
|
|
||||||
elif module == 'wayland':
|
elif module == 'wayland':
|
||||||
at_least_version('wayland-protocols', *sinfo['wayland_protocols'])
|
at_least_version('wayland-protocols', *sinfo['wayland_protocols'])
|
||||||
@@ -59,7 +98,7 @@ def init_env(env, pkg_config, at_least_version, test_compile, module='x11'):
|
|||||||
for p in ans.wayland_protocols:
|
for p in ans.wayland_protocols:
|
||||||
ans.sources.append(wayland_protocol_file_name(p))
|
ans.sources.append(wayland_protocol_file_name(p))
|
||||||
ans.all_headers.append(wayland_protocol_file_name(p, 'h'))
|
ans.all_headers.append(wayland_protocol_file_name(p, 'h'))
|
||||||
for dep in 'wayland-egl wayland-client wayland-cursor xkbcommon dbus-1'.split():
|
for dep in 'wayland-client wayland-cursor xkbcommon dbus-1'.split():
|
||||||
ans.cflags.extend(pkg_config(dep, '--cflags-only-I'))
|
ans.cflags.extend(pkg_config(dep, '--cflags-only-I'))
|
||||||
ans.ldpaths.extend(pkg_config(dep, '--libs'))
|
ans.ldpaths.extend(pkg_config(dep, '--libs'))
|
||||||
has_memfd_create = test_compile(env.cc, '-Werror', src='''#define _GNU_SOURCE
|
has_memfd_create = test_compile(env.cc, '-Werror', src='''#define _GNU_SOURCE
|
||||||
@@ -74,7 +113,7 @@ def init_env(env, pkg_config, at_least_version, test_compile, module='x11'):
|
|||||||
return ans
|
return ans
|
||||||
|
|
||||||
|
|
||||||
def build_wayland_protocols(env, Command, parallel_run, emphasis, newer, dest_dir):
|
def build_wayland_protocols(env: Env, Command: Callable, parallel_run: Callable, emphasis: Callable, newer: Callable, dest_dir: str) -> None:
|
||||||
items = []
|
items = []
|
||||||
for protocol in env.wayland_protocols:
|
for protocol in env.wayland_protocols:
|
||||||
src = os.path.join(env.wayland_packagedir, protocol)
|
src = os.path.join(env.wayland_packagedir, protocol)
|
||||||
@@ -95,7 +134,7 @@ def build_wayland_protocols(env, Command, parallel_run, emphasis, newer, dest_di
|
|||||||
|
|
||||||
class Arg:
|
class Arg:
|
||||||
|
|
||||||
def __init__(self, decl):
|
def __init__(self, decl: str):
|
||||||
self.type, self.name = decl.rsplit(' ', 1)
|
self.type, self.name = decl.rsplit(' ', 1)
|
||||||
self.type = self.type.strip()
|
self.type = self.type.strip()
|
||||||
self.name = self.name.strip()
|
self.name = self.name.strip()
|
||||||
@@ -103,13 +142,13 @@ class Arg:
|
|||||||
self.name = self.name[1:]
|
self.name = self.name[1:]
|
||||||
self.type = self.type + '*'
|
self.type = self.type + '*'
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self) -> str:
|
||||||
return 'Arg({}, {})'.format(self.type, self.name)
|
return 'Arg({}, {})'.format(self.type, self.name)
|
||||||
|
|
||||||
|
|
||||||
class Function:
|
class Function:
|
||||||
|
|
||||||
def __init__(self, declaration, check_fail=True):
|
def __init__(self, declaration: str, check_fail: bool = True):
|
||||||
self.check_fail = check_fail
|
self.check_fail = check_fail
|
||||||
m = re.match(
|
m = re.match(
|
||||||
r'(.+?)\s+(glfw[A-Z][a-zA-Z0-9]+)[(](.+)[)]$', declaration
|
r'(.+?)\s+(glfw[A-Z][a-zA-Z0-9]+)[(](.+)[)]$', declaration
|
||||||
@@ -128,14 +167,14 @@ class Function:
|
|||||||
if not self.args:
|
if not self.args:
|
||||||
self.args = [Arg('void v')]
|
self.args = [Arg('void v')]
|
||||||
|
|
||||||
def declaration(self):
|
def declaration(self) -> str:
|
||||||
return 'typedef {restype} (*{name}_func)({args});\n{name}_func {name}_impl;\n#define {name} {name}_impl'.format(
|
return 'typedef {restype} (*{name}_func)({args});\nGFW_EXTERN {name}_func {name}_impl;\n#define {name} {name}_impl'.format(
|
||||||
restype=self.restype,
|
restype=self.restype,
|
||||||
name=self.name,
|
name=self.name,
|
||||||
args=', '.join(a.type for a in self.args)
|
args=', '.join(a.type for a in self.args)
|
||||||
)
|
)
|
||||||
|
|
||||||
def load(self):
|
def load(self) -> str:
|
||||||
ans = '*(void **) (&{name}_impl) = dlsym(handle, "{name}");'.format(
|
ans = '*(void **) (&{name}_impl) = dlsym(handle, "{name}");'.format(
|
||||||
name=self.name
|
name=self.name
|
||||||
)
|
)
|
||||||
@@ -146,7 +185,7 @@ class Function:
|
|||||||
return ans
|
return ans
|
||||||
|
|
||||||
|
|
||||||
def generate_wrappers(glfw_header):
|
def generate_wrappers(glfw_header: str) -> None:
|
||||||
with open(glfw_header) as f:
|
with open(glfw_header) as f:
|
||||||
src = f.read()
|
src = f.read()
|
||||||
functions = []
|
functions = []
|
||||||
@@ -197,6 +236,9 @@ const char *action_text, int32_t timeout, GLFWDBusnotificationcreatedfun callbac
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include "monotonic.h"
|
#include "monotonic.h"
|
||||||
|
|
||||||
|
#ifndef GFW_EXTERN
|
||||||
|
#define GFW_EXTERN extern
|
||||||
|
#endif
|
||||||
{}
|
{}
|
||||||
|
|
||||||
typedef int (* GLFWcocoatextinputfilterfun)(int,int,unsigned int,unsigned long);
|
typedef int (* GLFWcocoatextinputfilterfun)(int,int,unsigned int,unsigned long);
|
||||||
@@ -215,6 +257,7 @@ const char* load_glfw(const char* path);
|
|||||||
f.write(header)
|
f.write(header)
|
||||||
|
|
||||||
code = '''
|
code = '''
|
||||||
|
#define GFW_EXTERN
|
||||||
#include "data-types.h"
|
#include "data-types.h"
|
||||||
#include "glfw-wrapper.h"
|
#include "glfw-wrapper.h"
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
@@ -244,7 +287,7 @@ unload_glfw(void) {
|
|||||||
f.write(code)
|
f.write(code)
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main() -> None:
|
||||||
os.chdir(os.path.dirname(os.path.abspath(__file__)))
|
os.chdir(os.path.dirname(os.path.abspath(__file__)))
|
||||||
generate_wrappers('glfw3.h')
|
generate_wrappers('glfw3.h')
|
||||||
|
|
||||||
|
|||||||
239
glfw/glfw3.h
vendored
239
glfw/glfw3.h
vendored
@@ -195,7 +195,38 @@ extern "C" {
|
|||||||
|
|
||||||
#endif /*__APPLE__*/
|
#endif /*__APPLE__*/
|
||||||
|
|
||||||
#elif !defined(GLFW_INCLUDE_NONE)
|
#elif defined(GLFW_INCLUDE_GLU)
|
||||||
|
|
||||||
|
#if defined(__APPLE__)
|
||||||
|
|
||||||
|
#if defined(GLFW_INCLUDE_GLU)
|
||||||
|
#include <OpenGL/glu.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#else /*__APPLE__*/
|
||||||
|
|
||||||
|
#if defined(GLFW_INCLUDE_GLU)
|
||||||
|
#include <GL/glu.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /*__APPLE__*/
|
||||||
|
|
||||||
|
#elif !defined(GLFW_INCLUDE_NONE) && \
|
||||||
|
!defined(__gl_h_) && \
|
||||||
|
!defined(__gles1_gl_h_) && \
|
||||||
|
!defined(__gles2_gl2_h_) && \
|
||||||
|
!defined(__gles2_gl3_h_) && \
|
||||||
|
!defined(__gles2_gl31_h_) && \
|
||||||
|
!defined(__gles2_gl32_h_) && \
|
||||||
|
!defined(__gl_glcorearb_h_) && \
|
||||||
|
!defined(__gl2_h_) /*legacy*/ && \
|
||||||
|
!defined(__gl3_h_) /*legacy*/ && \
|
||||||
|
!defined(__gl31_h_) /*legacy*/ && \
|
||||||
|
!defined(__gl32_h_) /*legacy*/ && \
|
||||||
|
!defined(__glcorearb_h_) /*legacy*/ && \
|
||||||
|
!defined(__GL_H__) /*non-standard*/ && \
|
||||||
|
!defined(__gltypes_h_) /*non-standard*/ && \
|
||||||
|
!defined(__glee_h_) /*non-standard*/
|
||||||
|
|
||||||
#if defined(__APPLE__)
|
#if defined(__APPLE__)
|
||||||
|
|
||||||
@@ -203,9 +234,6 @@ extern "C" {
|
|||||||
#define GL_GLEXT_LEGACY
|
#define GL_GLEXT_LEGACY
|
||||||
#endif
|
#endif
|
||||||
#include <OpenGL/gl.h>
|
#include <OpenGL/gl.h>
|
||||||
#if defined(GLFW_INCLUDE_GLU)
|
|
||||||
#include <OpenGL/glu.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#else /*__APPLE__*/
|
#else /*__APPLE__*/
|
||||||
|
|
||||||
@@ -213,9 +241,6 @@ extern "C" {
|
|||||||
#if defined(GLFW_INCLUDE_GLEXT)
|
#if defined(GLFW_INCLUDE_GLEXT)
|
||||||
#include <GL/glext.h>
|
#include <GL/glext.h>
|
||||||
#endif
|
#endif
|
||||||
#if defined(GLFW_INCLUDE_GLU)
|
|
||||||
#include <GL/glu.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /*__APPLE__*/
|
#endif /*__APPLE__*/
|
||||||
|
|
||||||
@@ -806,6 +831,33 @@ extern "C" {
|
|||||||
* @analysis Application programmer error. Fix the offending call.
|
* @analysis Application programmer error. Fix the offending call.
|
||||||
*/
|
*/
|
||||||
#define GLFW_NO_WINDOW_CONTEXT 0x0001000A
|
#define GLFW_NO_WINDOW_CONTEXT 0x0001000A
|
||||||
|
/*! @brief The requested feature is not provided by the platform.
|
||||||
|
*
|
||||||
|
* The requested feature is not provided by the platform, so GLFW is unable to
|
||||||
|
* implement it. The documentation for each function notes if it could emit
|
||||||
|
* this error.
|
||||||
|
*
|
||||||
|
* @analysis Platform or platform version limitation. The error can be ignored
|
||||||
|
* unless the feature is critical to the application.
|
||||||
|
*
|
||||||
|
* @par
|
||||||
|
* A function call that emits this error has no effect other than the error and
|
||||||
|
* updating any existing out parameters.
|
||||||
|
*/
|
||||||
|
#define GLFW_FEATURE_UNAVAILABLE 0x0001000C
|
||||||
|
/*! @brief The requested feature is not implemented for the platform.
|
||||||
|
*
|
||||||
|
* The requested feature has not yet been implemented in GLFW for this platform.
|
||||||
|
*
|
||||||
|
* @analysis An incomplete implementation of GLFW for this platform, hopefully
|
||||||
|
* fixed in a future release. The error can be ignored unless the feature is
|
||||||
|
* critical to the application.
|
||||||
|
*
|
||||||
|
* @par
|
||||||
|
* A function call that emits this error has no effect other than the error and
|
||||||
|
* updating any existing out parameters.
|
||||||
|
*/
|
||||||
|
#define GLFW_FEATURE_UNIMPLEMENTED 0x0001000D
|
||||||
/*! @} */
|
/*! @} */
|
||||||
|
|
||||||
/*! @addtogroup window
|
/*! @addtogroup window
|
||||||
@@ -880,11 +932,19 @@ extern "C" {
|
|||||||
* [window attribute](@ref GLFW_FOCUS_ON_SHOW_attrib).
|
* [window attribute](@ref GLFW_FOCUS_ON_SHOW_attrib).
|
||||||
*/
|
*/
|
||||||
#define GLFW_FOCUS_ON_SHOW 0x0002000C
|
#define GLFW_FOCUS_ON_SHOW 0x0002000C
|
||||||
|
|
||||||
|
/*! @brief Mouse input transparency window hint and attribute
|
||||||
|
*
|
||||||
|
* Mouse input transparency [window hint](@ref GLFW_MOUSE_PASSTHROUGH_hint) or
|
||||||
|
* [window attribute](@ref GLFW_MOUSE_PASSTHROUGH_attrib).
|
||||||
|
*/
|
||||||
|
#define GLFW_MOUSE_PASSTHROUGH 0x0002000D
|
||||||
|
|
||||||
/*! @brief Occlusion window attribute
|
/*! @brief Occlusion window attribute
|
||||||
*
|
*
|
||||||
* Occlusion [window attribute](@ref GLFW_OCCLUDED_attrib).
|
* Occlusion [window attribute](@ref GLFW_OCCLUDED_attrib).
|
||||||
*/
|
*/
|
||||||
#define GLFW_OCCLUDED 0x0002000D
|
#define GLFW_OCCLUDED 0x0002000E
|
||||||
/*! @brief Framebuffer bit depth hint.
|
/*! @brief Framebuffer bit depth hint.
|
||||||
*
|
*
|
||||||
* Framebuffer bit depth [hint](@ref GLFW_RED_BITS).
|
* Framebuffer bit depth [hint](@ref GLFW_RED_BITS).
|
||||||
@@ -1002,12 +1062,17 @@ extern "C" {
|
|||||||
* and [attribute](@ref GLFW_OPENGL_FORWARD_COMPAT_attrib).
|
* and [attribute](@ref GLFW_OPENGL_FORWARD_COMPAT_attrib).
|
||||||
*/
|
*/
|
||||||
#define GLFW_OPENGL_FORWARD_COMPAT 0x00022006
|
#define GLFW_OPENGL_FORWARD_COMPAT 0x00022006
|
||||||
/*! @brief OpenGL debug context hint and attribute.
|
/*! @brief Debug mode context hint and attribute.
|
||||||
*
|
*
|
||||||
* OpenGL debug context [hint](@ref GLFW_OPENGL_DEBUG_CONTEXT_hint) and
|
* Debug mode context [hint](@ref GLFW_CONTEXT_DEBUG_hint) and
|
||||||
* [attribute](@ref GLFW_OPENGL_DEBUG_CONTEXT_attrib).
|
* [attribute](@ref GLFW_CONTEXT_DEBUG_attrib).
|
||||||
*/
|
*/
|
||||||
#define GLFW_OPENGL_DEBUG_CONTEXT 0x00022007
|
#define GLFW_CONTEXT_DEBUG 0x00022007
|
||||||
|
/*! @brief Legacy name for compatibility.
|
||||||
|
*
|
||||||
|
* This is an alias for compatibility with earlier versions.
|
||||||
|
*/
|
||||||
|
#define GLFW_OPENGL_DEBUG_CONTEXT GLFW_CONTEXT_DEBUG
|
||||||
/*! @brief OpenGL profile hint and attribute.
|
/*! @brief OpenGL profile hint and attribute.
|
||||||
*
|
*
|
||||||
* OpenGL profile [hint](@ref GLFW_OPENGL_PROFILE_hint) and
|
* OpenGL profile [hint](@ref GLFW_OPENGL_PROFILE_hint) and
|
||||||
@@ -1076,6 +1141,7 @@ extern "C" {
|
|||||||
#define GLFW_STICKY_KEYS 0x00033002
|
#define GLFW_STICKY_KEYS 0x00033002
|
||||||
#define GLFW_STICKY_MOUSE_BUTTONS 0x00033003
|
#define GLFW_STICKY_MOUSE_BUTTONS 0x00033003
|
||||||
#define GLFW_LOCK_KEY_MODS 0x00033004
|
#define GLFW_LOCK_KEY_MODS 0x00033004
|
||||||
|
#define GLFW_RAW_MOUSE_MOTION 0x00033005
|
||||||
|
|
||||||
#define GLFW_CURSOR_NORMAL 0x00034001
|
#define GLFW_CURSOR_NORMAL 0x00034001
|
||||||
#define GLFW_CURSOR_HIDDEN 0x00034002
|
#define GLFW_CURSOR_HIDDEN 0x00034002
|
||||||
@@ -1089,6 +1155,14 @@ extern "C" {
|
|||||||
#define GLFW_EGL_CONTEXT_API 0x00036002
|
#define GLFW_EGL_CONTEXT_API 0x00036002
|
||||||
#define GLFW_OSMESA_CONTEXT_API 0x00036003
|
#define GLFW_OSMESA_CONTEXT_API 0x00036003
|
||||||
|
|
||||||
|
#define GLFW_ANGLE_PLATFORM_TYPE_NONE 0x00037001
|
||||||
|
#define GLFW_ANGLE_PLATFORM_TYPE_OPENGL 0x00037002
|
||||||
|
#define GLFW_ANGLE_PLATFORM_TYPE_OPENGLES 0x00037003
|
||||||
|
#define GLFW_ANGLE_PLATFORM_TYPE_D3D9 0x00037004
|
||||||
|
#define GLFW_ANGLE_PLATFORM_TYPE_D3D11 0x00037005
|
||||||
|
#define GLFW_ANGLE_PLATFORM_TYPE_VULKAN 0x00037007
|
||||||
|
#define GLFW_ANGLE_PLATFORM_TYPE_METAL 0x00037008
|
||||||
|
|
||||||
/*! @defgroup shapes Standard cursor shapes
|
/*! @defgroup shapes Standard cursor shapes
|
||||||
* @brief Standard system cursor shapes.
|
* @brief Standard system cursor shapes.
|
||||||
*
|
*
|
||||||
@@ -1122,8 +1196,12 @@ typedef enum {
|
|||||||
* Joystick hat buttons [init hint](@ref GLFW_JOYSTICK_HAT_BUTTONS).
|
* Joystick hat buttons [init hint](@ref GLFW_JOYSTICK_HAT_BUTTONS).
|
||||||
*/
|
*/
|
||||||
#define GLFW_JOYSTICK_HAT_BUTTONS 0x00050001
|
#define GLFW_JOYSTICK_HAT_BUTTONS 0x00050001
|
||||||
#define GLFW_DEBUG_KEYBOARD 0x00050002
|
/*! @brief ANGLE rendering backend init hint.
|
||||||
#define GLFW_ENABLE_JOYSTICKS 0x00050003
|
*
|
||||||
|
* ANGLE rendering backend [init hint](@ref GLFW_ANGLE_PLATFORM_TYPE_hint).
|
||||||
|
*/
|
||||||
|
#define GLFW_ANGLE_PLATFORM_TYPE 0x00050002
|
||||||
|
#define GLFW_DEBUG_KEYBOARD 0x00050003
|
||||||
/*! @brief macOS specific init hint.
|
/*! @brief macOS specific init hint.
|
||||||
*
|
*
|
||||||
* macOS specific [init hint](@ref GLFW_COCOA_CHDIR_RESOURCES_hint).
|
* macOS specific [init hint](@ref GLFW_COCOA_CHDIR_RESOURCES_hint).
|
||||||
@@ -1319,6 +1397,22 @@ typedef void (* GLFWwindowsizefun)(GLFWwindow*,int,int);
|
|||||||
*/
|
*/
|
||||||
typedef void (* GLFWwindowclosefun)(GLFWwindow*);
|
typedef void (* GLFWwindowclosefun)(GLFWwindow*);
|
||||||
|
|
||||||
|
/*! @brief The function pointer type for application close callbacks.
|
||||||
|
*
|
||||||
|
* This is the function pointer type for application close callbacks. A application
|
||||||
|
* close callback function has the following signature:
|
||||||
|
* @code
|
||||||
|
* void function_name(int flags)
|
||||||
|
* @endcode
|
||||||
|
*
|
||||||
|
* @param[in] flags 0 for a user requested application quit, 1 if a fatal error occurred and application should quit ASAP
|
||||||
|
*
|
||||||
|
* @sa @ref glfwSetApplicationCloseCallback
|
||||||
|
*
|
||||||
|
* @ingroup window
|
||||||
|
*/
|
||||||
|
typedef void (* GLFWapplicationclosefun)(int);
|
||||||
|
|
||||||
/*! @brief The function pointer type for window content refresh callbacks.
|
/*! @brief The function pointer type for window content refresh callbacks.
|
||||||
*
|
*
|
||||||
* This is the function pointer type for window content refresh callbacks.
|
* This is the function pointer type for window content refresh callbacks.
|
||||||
@@ -1408,7 +1502,7 @@ typedef void (* GLFWwindowiconifyfun)(GLFWwindow*,int);
|
|||||||
* @endcode
|
* @endcode
|
||||||
*
|
*
|
||||||
* @param[in] window The window that was maximized or restored.
|
* @param[in] window The window that was maximized or restored.
|
||||||
* @param[in] iconified `true` if the window was maximized, or
|
* @param[in] maximized `true` if the window was maximized, or
|
||||||
* `false` if it was restored.
|
* `false` if it was restored.
|
||||||
*
|
*
|
||||||
* @sa @ref window_maximize
|
* @sa @ref window_maximize
|
||||||
@@ -1550,6 +1644,7 @@ typedef void (* GLFWcursorenterfun)(GLFWwindow*,int);
|
|||||||
* value 2 for stationary momentum scrolling, value 3 for momentum scrolling
|
* value 2 for stationary momentum scrolling, value 3 for momentum scrolling
|
||||||
* in progress, value 4 for momentum scrolling ended, value 5 for momentum
|
* in progress, value 4 for momentum scrolling ended, value 5 for momentum
|
||||||
* scrolling cancelled and value 6 if scrolling may begin soon.
|
* scrolling cancelled and value 6 if scrolling may begin soon.
|
||||||
|
* @param[int] mods The keyboard modifiers
|
||||||
*
|
*
|
||||||
* @sa @ref scrolling
|
* @sa @ref scrolling
|
||||||
* @sa @ref glfwSetScrollCallback
|
* @sa @ref glfwSetScrollCallback
|
||||||
@@ -1559,7 +1654,7 @@ typedef void (* GLFWcursorenterfun)(GLFWwindow*,int);
|
|||||||
*
|
*
|
||||||
* @ingroup input
|
* @ingroup input
|
||||||
*/
|
*/
|
||||||
typedef void (* GLFWscrollfun)(GLFWwindow*,double,double,int);
|
typedef void (* GLFWscrollfun)(GLFWwindow*,double,double,int,int);
|
||||||
|
|
||||||
/*! @brief The function pointer type for key callbacks.
|
/*! @brief The function pointer type for key callbacks.
|
||||||
*
|
*
|
||||||
@@ -1593,19 +1688,22 @@ typedef void (* GLFWscrollfun)(GLFWwindow*,double,double,int);
|
|||||||
*/
|
*/
|
||||||
typedef void (* GLFWkeyboardfun)(GLFWwindow*, GLFWkeyevent*);
|
typedef void (* GLFWkeyboardfun)(GLFWwindow*, GLFWkeyevent*);
|
||||||
|
|
||||||
/*! @brief The function pointer type for path drop callbacks.
|
/*! @brief The function pointer type for drag and drop callbacks.
|
||||||
*
|
*
|
||||||
* This is the function pointer type for path drop callbacks. A path drop
|
* This is the function pointer type for drop callbacks. A drop
|
||||||
* callback function has the following signature:
|
* callback function has the following signature:
|
||||||
* @code
|
* @code
|
||||||
* void function_name(GLFWwindow* window, int path_count, const char* paths[])
|
* int function_name(GLFWwindow* window, const char* mime, const char* text)
|
||||||
* @endcode
|
* @endcode
|
||||||
*
|
*
|
||||||
* @param[in] window The window that received the event.
|
* @param[in] window The window that received the event.
|
||||||
* @param[in] path_count The number of dropped paths.
|
* @param[in] mime The UTF-8 encoded drop mime-type
|
||||||
* @param[in] paths The UTF-8 encoded file and/or directory path names.
|
* @param[in] data The dropped data or NULL for drag enter events
|
||||||
|
* @param[in] sz The size of the dropped data
|
||||||
|
* @return For drag events should return the priority for the specified mime type. A priority of zero
|
||||||
|
* or lower means the mime type is not accepted. Highest priority will be the finally accepted mime-type.
|
||||||
*
|
*
|
||||||
* @pointer_lifetime The path array and its strings are valid until the
|
* @pointer_lifetime The text is valid until the
|
||||||
* callback function returns.
|
* callback function returns.
|
||||||
*
|
*
|
||||||
* @sa @ref path_drop
|
* @sa @ref path_drop
|
||||||
@@ -1615,7 +1713,7 @@ typedef void (* GLFWkeyboardfun)(GLFWwindow*, GLFWkeyevent*);
|
|||||||
*
|
*
|
||||||
* @ingroup input
|
* @ingroup input
|
||||||
*/
|
*/
|
||||||
typedef void (* GLFWdropfun)(GLFWwindow*,int,const char*[]);
|
typedef int (* GLFWdropfun)(GLFWwindow*, const char *, const char*, size_t);
|
||||||
|
|
||||||
typedef void (* GLFWliveresizefun)(GLFWwindow*, bool);
|
typedef void (* GLFWliveresizefun)(GLFWwindow*, bool);
|
||||||
|
|
||||||
@@ -1832,6 +1930,8 @@ GLFWAPI void glfwRemoveTimer(unsigned long long);
|
|||||||
* call this function, as it is called by @ref glfwInit before it returns
|
* call this function, as it is called by @ref glfwInit before it returns
|
||||||
* failure.
|
* failure.
|
||||||
*
|
*
|
||||||
|
* This function has no effect if GLFW is not initialized.
|
||||||
|
*
|
||||||
* @errors Possible errors include @ref GLFW_PLATFORM_ERROR.
|
* @errors Possible errors include @ref GLFW_PLATFORM_ERROR.
|
||||||
*
|
*
|
||||||
* @remark This function may be called before @ref glfwInit.
|
* @remark This function may be called before @ref glfwInit.
|
||||||
@@ -2829,21 +2929,21 @@ GLFWAPI void glfwSetWindowTitle(GLFWwindow* window, const char* title);
|
|||||||
* @param[in] images The images to create the icon from. This is ignored if
|
* @param[in] images The images to create the icon from. This is ignored if
|
||||||
* count is zero.
|
* count is zero.
|
||||||
*
|
*
|
||||||
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
|
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref
|
||||||
* GLFW_PLATFORM_ERROR.
|
* GLFW_PLATFORM_ERROR and @ref GLFW_FEATURE_UNAVAILABLE (see remarks).
|
||||||
*
|
*
|
||||||
* @pointer_lifetime The specified image data is copied before this function
|
* @pointer_lifetime The specified image data is copied before this function
|
||||||
* returns.
|
* returns.
|
||||||
*
|
*
|
||||||
* @remark @macos The GLFW window has no icon, as it is not a document
|
* @remark @macos Regular windows do not have icons on macOS. This function
|
||||||
* window, so this function does nothing. The dock icon will be the same as
|
* will emit @ref GLFW_FEATURE_UNAVAILABLE. The dock icon will be the same as
|
||||||
* the application bundle's icon. For more information on bundles, see the
|
* the application bundle's icon. For more information on bundles, see the
|
||||||
* [Bundle Programming Guide](https://developer.apple.com/library/mac/documentation/CoreFoundation/Conceptual/CFBundles/)
|
* [Bundle Programming Guide](https://developer.apple.com/library/mac/documentation/CoreFoundation/Conceptual/CFBundles/)
|
||||||
* in the Mac Developer Library.
|
* in the Mac Developer Library.
|
||||||
*
|
*
|
||||||
* @remark @wayland There is no existing protocol to change an icon, the
|
* @remark @wayland There is no existing protocol to change an icon, the
|
||||||
* window will thus inherit the one defined in the application's desktop file.
|
* window will thus inherit the one defined in the application's desktop file.
|
||||||
* This function always emits @ref GLFW_PLATFORM_ERROR.
|
* This function will emit @ref GLFW_FEATURE_UNAVAILABLE.
|
||||||
*
|
*
|
||||||
* @thread_safety This function must only be called from the main thread.
|
* @thread_safety This function must only be called from the main thread.
|
||||||
*
|
*
|
||||||
@@ -2869,12 +2969,12 @@ GLFWAPI void glfwSetWindowIcon(GLFWwindow* window, int count, const GLFWimage* i
|
|||||||
* @param[out] ypos Where to store the y-coordinate of the upper-left corner of
|
* @param[out] ypos Where to store the y-coordinate of the upper-left corner of
|
||||||
* the content area, or `NULL`.
|
* the content area, or `NULL`.
|
||||||
*
|
*
|
||||||
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
|
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref
|
||||||
* GLFW_PLATFORM_ERROR.
|
* GLFW_PLATFORM_ERROR and @ref GLFW_FEATURE_UNAVAILABLE (see remarks).
|
||||||
*
|
*
|
||||||
* @remark @wayland There is no way for an application to retrieve the global
|
* @remark @wayland There is no way for an application to retrieve the global
|
||||||
* position of its windows, this function will always emit @ref
|
* position of its windows. This function will emit @ref
|
||||||
* GLFW_PLATFORM_ERROR.
|
* GLFW_FEATURE_UNAVAILABLE.
|
||||||
*
|
*
|
||||||
* @thread_safety This function must only be called from the main thread.
|
* @thread_safety This function must only be called from the main thread.
|
||||||
*
|
*
|
||||||
@@ -2903,12 +3003,12 @@ GLFWAPI void glfwGetWindowPos(GLFWwindow* window, int* xpos, int* ypos);
|
|||||||
* @param[in] xpos The x-coordinate of the upper-left corner of the content area.
|
* @param[in] xpos The x-coordinate of the upper-left corner of the content area.
|
||||||
* @param[in] ypos The y-coordinate of the upper-left corner of the content area.
|
* @param[in] ypos The y-coordinate of the upper-left corner of the content area.
|
||||||
*
|
*
|
||||||
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
|
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref
|
||||||
* GLFW_PLATFORM_ERROR.
|
* GLFW_PLATFORM_ERROR and @ref GLFW_FEATURE_UNAVAILABLE (see remarks).
|
||||||
*
|
*
|
||||||
* @remark @wayland There is no way for an application to set the global
|
* @remark @wayland There is no way for an application to set the global
|
||||||
* position of its windows, this function will always emit @ref
|
* position of its windows. This function will emit @ref
|
||||||
* GLFW_PLATFORM_ERROR.
|
* GLFW_FEATURE_UNAVAILABLE.
|
||||||
*
|
*
|
||||||
* @thread_safety This function must only be called from the main thread.
|
* @thread_safety This function must only be called from the main thread.
|
||||||
*
|
*
|
||||||
@@ -3286,8 +3386,11 @@ GLFWAPI float glfwGetWindowOpacity(GLFWwindow* window);
|
|||||||
* @param[in] window The window to set the opacity for.
|
* @param[in] window The window to set the opacity for.
|
||||||
* @param[in] opacity The desired opacity of the specified window.
|
* @param[in] opacity The desired opacity of the specified window.
|
||||||
*
|
*
|
||||||
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
|
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref
|
||||||
* GLFW_PLATFORM_ERROR.
|
* GLFW_PLATFORM_ERROR and @ref GLFW_FEATURE_UNAVAILABLE (see remarks).
|
||||||
|
*
|
||||||
|
* @remark @wayland There is no way to set an opacity factor for a window.
|
||||||
|
* This function will emit @ref GLFW_FEATURE_UNAVAILABLE.
|
||||||
*
|
*
|
||||||
* @thread_safety This function must only be called from the main thread.
|
* @thread_safety This function must only be called from the main thread.
|
||||||
*
|
*
|
||||||
@@ -3454,11 +3557,11 @@ GLFWAPI void glfwHideWindow(GLFWwindow* window);
|
|||||||
*
|
*
|
||||||
* @param[in] window The window to give input focus.
|
* @param[in] window The window to give input focus.
|
||||||
*
|
*
|
||||||
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
|
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref
|
||||||
* GLFW_PLATFORM_ERROR.
|
* GLFW_PLATFORM_ERROR and @ref GLFW_FEATURE_UNAVAILABLE (see remarks).
|
||||||
*
|
*
|
||||||
* @remark @wayland It is not possible for an application to bring its windows
|
* @remark @wayland It is not possible for an application to set the input
|
||||||
* to front, this function will always emit @ref GLFW_PLATFORM_ERROR.
|
* focus. This function will emit @ref GLFW_FEATURE_UNAVAILABLE.
|
||||||
*
|
*
|
||||||
* @thread_safety This function must only be called from the main thread.
|
* @thread_safety This function must only be called from the main thread.
|
||||||
*
|
*
|
||||||
@@ -3645,6 +3748,7 @@ GLFWAPI int glfwGetWindowAttrib(GLFWwindow* window, int attrib);
|
|||||||
* [GLFW_FLOATING](@ref GLFW_FLOATING_attrib),
|
* [GLFW_FLOATING](@ref GLFW_FLOATING_attrib),
|
||||||
* [GLFW_AUTO_ICONIFY](@ref GLFW_AUTO_ICONIFY_attrib) and
|
* [GLFW_AUTO_ICONIFY](@ref GLFW_AUTO_ICONIFY_attrib) and
|
||||||
* [GLFW_FOCUS_ON_SHOW](@ref GLFW_FOCUS_ON_SHOW_attrib).
|
* [GLFW_FOCUS_ON_SHOW](@ref GLFW_FOCUS_ON_SHOW_attrib).
|
||||||
|
* [GLFW_MOUSE_PASSTHROUGH](@ref GLFW_MOUSE_PASSTHROUGH_attrib)
|
||||||
*
|
*
|
||||||
* Some of these attributes are ignored for full screen windows. The new
|
* Some of these attributes are ignored for full screen windows. The new
|
||||||
* value will take effect if the window is later made windowed.
|
* value will take effect if the window is later made windowed.
|
||||||
@@ -3823,6 +3927,7 @@ GLFWAPI GLFWwindowsizefun glfwSetWindowSizeCallback(GLFWwindow* window, GLFWwind
|
|||||||
* @ingroup window
|
* @ingroup window
|
||||||
*/
|
*/
|
||||||
GLFWAPI GLFWwindowclosefun glfwSetWindowCloseCallback(GLFWwindow* window, GLFWwindowclosefun callback);
|
GLFWAPI GLFWwindowclosefun glfwSetWindowCloseCallback(GLFWwindow* window, GLFWwindowclosefun callback);
|
||||||
|
GLFWAPI GLFWapplicationclosefun glfwSetApplicationCloseCallback(GLFWapplicationclosefun callback);
|
||||||
|
|
||||||
/*! @brief Sets the refresh callback for the specified window.
|
/*! @brief Sets the refresh callback for the specified window.
|
||||||
*
|
*
|
||||||
@@ -4072,11 +4177,13 @@ GLFWAPI void glfwPostEmptyEvent(void);
|
|||||||
*
|
*
|
||||||
* This function returns the value of an input option for the specified window.
|
* This function returns the value of an input option for the specified window.
|
||||||
* The mode must be one of @ref GLFW_CURSOR, @ref GLFW_STICKY_KEYS,
|
* The mode must be one of @ref GLFW_CURSOR, @ref GLFW_STICKY_KEYS,
|
||||||
* @ref GLFW_STICKY_MOUSE_BUTTONS or @ref GLFW_LOCK_KEY_MODS.
|
* @ref GLFW_STICKY_MOUSE_BUTTONS, @ref GLFW_LOCK_KEY_MODS or
|
||||||
|
* @ref GLFW_RAW_MOUSE_MOTION.
|
||||||
*
|
*
|
||||||
* @param[in] window The window to query.
|
* @param[in] window The window to query.
|
||||||
* @param[in] mode One of `GLFW_CURSOR`, `GLFW_STICKY_KEYS`,
|
* @param[in] mode One of `GLFW_CURSOR`, `GLFW_STICKY_KEYS`,
|
||||||
* `GLFW_STICKY_MOUSE_BUTTONS` or `GLFW_LOCK_KEY_MODS`.
|
* `GLFW_STICKY_MOUSE_BUTTONS`, `GLFW_LOCK_KEY_MODS` or
|
||||||
|
* `GLFW_RAW_MOUSE_MOTION`.
|
||||||
*
|
*
|
||||||
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
|
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
|
||||||
* GLFW_INVALID_ENUM.
|
* GLFW_INVALID_ENUM.
|
||||||
@@ -4095,7 +4202,8 @@ GLFWAPI int glfwGetInputMode(GLFWwindow* window, int mode);
|
|||||||
*
|
*
|
||||||
* This function sets an input mode option for the specified window. The mode
|
* This function sets an input mode option for the specified window. The mode
|
||||||
* must be one of @ref GLFW_CURSOR, @ref GLFW_STICKY_KEYS,
|
* must be one of @ref GLFW_CURSOR, @ref GLFW_STICKY_KEYS,
|
||||||
* @ref GLFW_STICKY_MOUSE_BUTTONS or @ref GLFW_LOCK_KEY_MODS.
|
* @ref GLFW_STICKY_MOUSE_BUTTONS, @ref GLFW_LOCK_KEY_MODS or
|
||||||
|
* @ref GLFW_RAW_MOUSE_MOTION.
|
||||||
*
|
*
|
||||||
* If the mode is `GLFW_CURSOR`, the value must be one of the following cursor
|
* If the mode is `GLFW_CURSOR`, the value must be one of the following cursor
|
||||||
* modes:
|
* modes:
|
||||||
@@ -4127,13 +4235,21 @@ GLFWAPI int glfwGetInputMode(GLFWwindow* window, int mode);
|
|||||||
* GLFW_MOD_CAPS_LOCK bit set when the event was generated with Caps Lock on,
|
* GLFW_MOD_CAPS_LOCK bit set when the event was generated with Caps Lock on,
|
||||||
* and the @ref GLFW_MOD_NUM_LOCK bit when Num Lock was on.
|
* and the @ref GLFW_MOD_NUM_LOCK bit when Num Lock was on.
|
||||||
*
|
*
|
||||||
|
* If the mode is `GLFW_RAW_MOUSE_MOTION`, the value must be either `true`
|
||||||
|
* to enable raw (unscaled and unaccelerated) mouse motion when the cursor is
|
||||||
|
* disabled, or `false` to disable it. If raw motion is not supported,
|
||||||
|
* attempting to set this will emit @ref GLFW_FEATURE_UNAVAILABLE. Call @ref
|
||||||
|
* glfwRawMouseMotionSupported to check for support.
|
||||||
|
*
|
||||||
* @param[in] window The window whose input mode to set.
|
* @param[in] window The window whose input mode to set.
|
||||||
* @param[in] mode One of `GLFW_CURSOR`, `GLFW_STICKY_KEYS`,
|
* @param[in] mode One of `GLFW_CURSOR`, `GLFW_STICKY_KEYS`,
|
||||||
* `GLFW_STICKY_MOUSE_BUTTONS` or `GLFW_LOCK_KEY_MODS`.
|
* `GLFW_STICKY_MOUSE_BUTTONS`, `GLFW_LOCK_KEY_MODS` or
|
||||||
|
* `GLFW_RAW_MOUSE_MOTION`.
|
||||||
* @param[in] value The new value of the specified input mode.
|
* @param[in] value The new value of the specified input mode.
|
||||||
*
|
*
|
||||||
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref
|
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref
|
||||||
* GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR.
|
* GLFW_INVALID_ENUM, @ref GLFW_PLATFORM_ERROR and @ref
|
||||||
|
* GLFW_FEATURE_UNAVAILABLE (see above).
|
||||||
*
|
*
|
||||||
* @thread_safety This function must only be called from the main thread.
|
* @thread_safety This function must only be called from the main thread.
|
||||||
*
|
*
|
||||||
@@ -4145,6 +4261,35 @@ GLFWAPI int glfwGetInputMode(GLFWwindow* window, int mode);
|
|||||||
*/
|
*/
|
||||||
GLFWAPI void glfwSetInputMode(GLFWwindow* window, int mode, int value);
|
GLFWAPI void glfwSetInputMode(GLFWwindow* window, int mode, int value);
|
||||||
|
|
||||||
|
/*! @brief Returns whether raw mouse motion is supported.
|
||||||
|
*
|
||||||
|
* This function returns whether raw mouse motion is supported on the current
|
||||||
|
* system. This status does not change after GLFW has been initialized so you
|
||||||
|
* only need to check this once. If you attempt to enable raw motion on
|
||||||
|
* a system that does not support it, @ref GLFW_PLATFORM_ERROR will be emitted.
|
||||||
|
*
|
||||||
|
* Raw mouse motion is closer to the actual motion of the mouse across
|
||||||
|
* a surface. It is not affected by the scaling and acceleration applied to
|
||||||
|
* the motion of the desktop cursor. That processing is suitable for a cursor
|
||||||
|
* while raw motion is better for controlling for example a 3D camera. Because
|
||||||
|
* of this, raw mouse motion is only provided when the cursor is disabled.
|
||||||
|
*
|
||||||
|
* @return `true` if raw mouse motion is supported on the current machine,
|
||||||
|
* or `false` otherwise.
|
||||||
|
*
|
||||||
|
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
|
||||||
|
*
|
||||||
|
* @thread_safety This function must only be called from the main thread.
|
||||||
|
*
|
||||||
|
* @sa @ref raw_mouse_motion
|
||||||
|
* @sa @ref glfwSetInputMode
|
||||||
|
*
|
||||||
|
* @since Added in version 3.3.
|
||||||
|
*
|
||||||
|
* @ingroup input
|
||||||
|
*/
|
||||||
|
GLFWAPI int glfwRawMouseMotionSupported(void);
|
||||||
|
|
||||||
/*! @brief Returns the layout-specific name of the specified printable key.
|
/*! @brief Returns the layout-specific name of the specified printable key.
|
||||||
*
|
*
|
||||||
* This function returns the name of the specified printable key, encoded as
|
* This function returns the name of the specified printable key, encoded as
|
||||||
|
|||||||
111
glfw/glx_context.c
vendored
111
glfw/glx_context.c
vendored
@@ -47,99 +47,87 @@ static int getGLXFBConfigAttrib(GLXFBConfig fbconfig, int attrib)
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static GLXFBConfig*
|
||||||
|
choose_fb_config(const _GLFWfbconfig* desired, bool trust_window_bit, int *nelements) {
|
||||||
|
int attrib_list[64];
|
||||||
|
int pos = 0;
|
||||||
|
#define ATTR(x, y) { attrib_list[pos++] = x; attrib_list[pos++] = y; }
|
||||||
|
|
||||||
|
ATTR(GLX_DOUBLEBUFFER, desired->doublebuffer ? True : False);
|
||||||
|
if (desired->stereo > 0) ATTR(GLX_STEREO, desired->stereo ? True : False);
|
||||||
|
if (desired->auxBuffers > 0) ATTR(GLX_AUX_BUFFERS, desired->auxBuffers);
|
||||||
|
if (_glfw.glx.ARB_multisample && desired->samples > 0) ATTR(GLX_SAMPLES, desired->samples);
|
||||||
|
if (desired->depthBits != GLFW_DONT_CARE) ATTR(GLX_DEPTH_SIZE, desired->depthBits);
|
||||||
|
if (desired->stencilBits != GLFW_DONT_CARE) ATTR(GLX_STENCIL_SIZE, desired->stencilBits);
|
||||||
|
if (desired->redBits != GLFW_DONT_CARE) ATTR(GLX_RED_SIZE, desired->redBits);
|
||||||
|
if (desired->greenBits != GLFW_DONT_CARE) ATTR(GLX_GREEN_SIZE, desired->greenBits);
|
||||||
|
if (desired->blueBits != GLFW_DONT_CARE) ATTR(GLX_BLUE_SIZE, desired->blueBits);
|
||||||
|
if (desired->alphaBits != GLFW_DONT_CARE) ATTR(GLX_ALPHA_SIZE, desired->alphaBits);
|
||||||
|
if (desired->accumRedBits != GLFW_DONT_CARE) ATTR(GLX_ACCUM_RED_SIZE, desired->accumRedBits);
|
||||||
|
if (desired->accumGreenBits != GLFW_DONT_CARE) ATTR(GLX_ACCUM_GREEN_SIZE, desired->accumGreenBits);
|
||||||
|
if (desired->accumBlueBits != GLFW_DONT_CARE) ATTR(GLX_ACCUM_BLUE_SIZE, desired->accumBlueBits);
|
||||||
|
if (desired->accumAlphaBits != GLFW_DONT_CARE) ATTR(GLX_ACCUM_ALPHA_SIZE, desired->accumAlphaBits);
|
||||||
|
if (!trust_window_bit) ATTR(GLX_DRAWABLE_TYPE, 0);
|
||||||
|
ATTR(None, None);
|
||||||
|
return glXChooseFBConfig(_glfw.x11.display, _glfw.x11.screen, attrib_list, nelements);
|
||||||
|
#undef ATTR
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Return the GLXFBConfig most closely matching the specified hints
|
// Return the GLXFBConfig most closely matching the specified hints
|
||||||
//
|
//
|
||||||
static bool chooseGLXFBConfig(const _GLFWfbconfig* desired,
|
static bool chooseGLXFBConfig(const _GLFWfbconfig* desired,
|
||||||
GLXFBConfig* result)
|
GLXFBConfig* result)
|
||||||
{
|
{
|
||||||
GLXFBConfig* nativeConfigs;
|
GLXFBConfig* nativeConfigs;
|
||||||
_GLFWfbconfig* usableConfigs;
|
int i, nativeCount, ans_idx = 0;
|
||||||
const _GLFWfbconfig* closest;
|
|
||||||
int i, nativeCount, usableCount;
|
|
||||||
const char* vendor;
|
const char* vendor;
|
||||||
bool trustWindowBit = true;
|
bool trustWindowBit = true;
|
||||||
|
static _GLFWfbconfig prev_desired = {0};
|
||||||
|
static GLXFBConfig prev_result = 0;
|
||||||
|
if (prev_result != 0 && memcmp(&prev_desired, desired, sizeof(_GLFWfbconfig)) == 0) {
|
||||||
|
*result = prev_result;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
prev_desired = *desired;
|
||||||
|
|
||||||
// HACK: This is a (hopefully temporary) workaround for Chromium
|
// HACK: This is a (hopefully temporary) workaround for Chromium
|
||||||
// (VirtualBox GL) not setting the window bit on any GLXFBConfigs
|
// (VirtualBox GL) not setting the window bit on any GLXFBConfigs
|
||||||
vendor = glXGetClientString(_glfw.x11.display, GLX_VENDOR);
|
vendor = glXGetClientString(_glfw.x11.display, GLX_VENDOR);
|
||||||
if (vendor && strcmp(vendor, "Chromium") == 0)
|
if (vendor && strcmp(vendor, "Chromium") == 0)
|
||||||
trustWindowBit = false;
|
trustWindowBit = false;
|
||||||
|
nativeConfigs = choose_fb_config(desired, trustWindowBit, &nativeCount);
|
||||||
nativeConfigs =
|
|
||||||
glXGetFBConfigs(_glfw.x11.display, _glfw.x11.screen, &nativeCount);
|
|
||||||
if (!nativeConfigs || !nativeCount)
|
if (!nativeConfigs || !nativeCount)
|
||||||
{
|
{
|
||||||
_glfwInputError(GLFW_API_UNAVAILABLE, "GLX: No GLXFBConfigs returned");
|
_glfwInputError(GLFW_API_UNAVAILABLE, "GLX: No GLXFBConfigs returned");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
usableConfigs = calloc(nativeCount, sizeof(_GLFWfbconfig));
|
|
||||||
usableCount = 0;
|
|
||||||
|
|
||||||
for (i = 0; i < nativeCount; i++)
|
for (i = 0; i < nativeCount; i++)
|
||||||
{
|
{
|
||||||
const GLXFBConfig n = nativeConfigs[i];
|
const GLXFBConfig n = nativeConfigs[i];
|
||||||
_GLFWfbconfig* u = usableConfigs + usableCount;
|
bool transparency_matches = true, srgb_matches = true;
|
||||||
|
if (desired->transparent) {
|
||||||
// Only consider RGBA GLXFBConfigs
|
transparency_matches = false;
|
||||||
if (!(getGLXFBConfigAttrib(n, GLX_RENDER_TYPE) & GLX_RGBA_BIT))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// Only consider window GLXFBConfigs
|
|
||||||
if (!(getGLXFBConfigAttrib(n, GLX_DRAWABLE_TYPE) & GLX_WINDOW_BIT))
|
|
||||||
{
|
|
||||||
if (trustWindowBit)
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (desired->transparent)
|
|
||||||
{
|
|
||||||
XVisualInfo* vi = glXGetVisualFromFBConfig(_glfw.x11.display, n);
|
XVisualInfo* vi = glXGetVisualFromFBConfig(_glfw.x11.display, n);
|
||||||
if (vi)
|
if (vi && _glfwIsVisualTransparentX11(vi->visual)) transparency_matches = true;
|
||||||
{
|
|
||||||
u->transparent = _glfwIsVisualTransparentX11(vi->visual);
|
|
||||||
XFree(vi);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
u->redBits = getGLXFBConfigAttrib(n, GLX_RED_SIZE);
|
if (desired->sRGB && (_glfw.glx.ARB_framebuffer_sRGB || _glfw.glx.EXT_framebuffer_sRGB)) {
|
||||||
u->greenBits = getGLXFBConfigAttrib(n, GLX_GREEN_SIZE);
|
srgb_matches = getGLXFBConfigAttrib(n, GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB) ? true : false;
|
||||||
u->blueBits = getGLXFBConfigAttrib(n, GLX_BLUE_SIZE);
|
}
|
||||||
|
|
||||||
u->alphaBits = getGLXFBConfigAttrib(n, GLX_ALPHA_SIZE);
|
if (transparency_matches && srgb_matches) {
|
||||||
u->depthBits = getGLXFBConfigAttrib(n, GLX_DEPTH_SIZE);
|
ans_idx = i; break;
|
||||||
u->stencilBits = getGLXFBConfigAttrib(n, GLX_STENCIL_SIZE);
|
}
|
||||||
|
|
||||||
u->accumRedBits = getGLXFBConfigAttrib(n, GLX_ACCUM_RED_SIZE);
|
|
||||||
u->accumGreenBits = getGLXFBConfigAttrib(n, GLX_ACCUM_GREEN_SIZE);
|
|
||||||
u->accumBlueBits = getGLXFBConfigAttrib(n, GLX_ACCUM_BLUE_SIZE);
|
|
||||||
u->accumAlphaBits = getGLXFBConfigAttrib(n, GLX_ACCUM_ALPHA_SIZE);
|
|
||||||
|
|
||||||
u->auxBuffers = getGLXFBConfigAttrib(n, GLX_AUX_BUFFERS);
|
|
||||||
|
|
||||||
if (getGLXFBConfigAttrib(n, GLX_STEREO))
|
|
||||||
u->stereo = true;
|
|
||||||
if (getGLXFBConfigAttrib(n, GLX_DOUBLEBUFFER))
|
|
||||||
u->doublebuffer = true;
|
|
||||||
|
|
||||||
if (_glfw.glx.ARB_multisample)
|
|
||||||
u->samples = getGLXFBConfigAttrib(n, GLX_SAMPLES);
|
|
||||||
|
|
||||||
if (_glfw.glx.ARB_framebuffer_sRGB || _glfw.glx.EXT_framebuffer_sRGB)
|
|
||||||
u->sRGB = getGLXFBConfigAttrib(n, GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB);
|
|
||||||
|
|
||||||
u->handle = (uintptr_t) n;
|
|
||||||
usableCount++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
closest = _glfwChooseFBConfig(desired, usableConfigs, usableCount);
|
*result = nativeConfigs[ans_idx];
|
||||||
if (closest)
|
prev_result = nativeConfigs[ans_idx];
|
||||||
*result = (GLXFBConfig) closest->handle;
|
|
||||||
|
|
||||||
XFree(nativeConfigs);
|
XFree(nativeConfigs);
|
||||||
free(usableConfigs);
|
|
||||||
|
|
||||||
return closest != NULL;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the OpenGL context using legacy API
|
// Create the OpenGL context using legacy API
|
||||||
@@ -287,6 +275,7 @@ bool _glfwInitGLX(void)
|
|||||||
|
|
||||||
glfw_dlsym(_glfw.glx.GetFBConfigs, _glfw.glx.handle, "glXGetFBConfigs");
|
glfw_dlsym(_glfw.glx.GetFBConfigs, _glfw.glx.handle, "glXGetFBConfigs");
|
||||||
glfw_dlsym(_glfw.glx.GetFBConfigAttrib, _glfw.glx.handle, "glXGetFBConfigAttrib");
|
glfw_dlsym(_glfw.glx.GetFBConfigAttrib, _glfw.glx.handle, "glXGetFBConfigAttrib");
|
||||||
|
glfw_dlsym(_glfw.glx.ChooseFBConfig, _glfw.glx.handle, "glXChooseFBConfig");
|
||||||
glfw_dlsym(_glfw.glx.GetClientString, _glfw.glx.handle, "glXGetClientString");
|
glfw_dlsym(_glfw.glx.GetClientString, _glfw.glx.handle, "glXGetClientString");
|
||||||
glfw_dlsym(_glfw.glx.QueryExtension, _glfw.glx.handle, "glXQueryExtension");
|
glfw_dlsym(_glfw.glx.QueryExtension, _glfw.glx.handle, "glXQueryExtension");
|
||||||
glfw_dlsym(_glfw.glx.QueryVersion, _glfw.glx.handle, "glXQueryVersion");
|
glfw_dlsym(_glfw.glx.QueryVersion, _glfw.glx.handle, "glXQueryVersion");
|
||||||
|
|||||||
3
glfw/glx_context.h
vendored
3
glfw/glx_context.h
vendored
@@ -73,6 +73,7 @@ typedef struct __GLXcontext* GLXContext;
|
|||||||
typedef void (*__GLXextproc)(void);
|
typedef void (*__GLXextproc)(void);
|
||||||
|
|
||||||
typedef int (*PFNGLXGETFBCONFIGATTRIBPROC)(Display*,GLXFBConfig,int,int*);
|
typedef int (*PFNGLXGETFBCONFIGATTRIBPROC)(Display*,GLXFBConfig,int,int*);
|
||||||
|
typedef GLXFBConfig* (*PFNGLXCHOOSEFBCONFIGPROC)(Display*,int,const int*,int*);
|
||||||
typedef const char* (*PFNGLXGETCLIENTSTRINGPROC)(Display*,int);
|
typedef const char* (*PFNGLXGETCLIENTSTRINGPROC)(Display*,int);
|
||||||
typedef Bool (*PFNGLXQUERYEXTENSIONPROC)(Display*,int*,int*);
|
typedef Bool (*PFNGLXQUERYEXTENSIONPROC)(Display*,int*,int*);
|
||||||
typedef Bool (*PFNGLXQUERYVERSIONPROC)(Display*,int*,int*);
|
typedef Bool (*PFNGLXQUERYVERSIONPROC)(Display*,int*,int*);
|
||||||
@@ -95,6 +96,7 @@ typedef GLXContext (*PFNGLXCREATECONTEXTATTRIBSARBPROC)(Display*,GLXFBConfig,GLX
|
|||||||
// libGL.so function pointer typedefs
|
// libGL.so function pointer typedefs
|
||||||
#define glXGetFBConfigs _glfw.glx.GetFBConfigs
|
#define glXGetFBConfigs _glfw.glx.GetFBConfigs
|
||||||
#define glXGetFBConfigAttrib _glfw.glx.GetFBConfigAttrib
|
#define glXGetFBConfigAttrib _glfw.glx.GetFBConfigAttrib
|
||||||
|
#define glXChooseFBConfig _glfw.glx.ChooseFBConfig
|
||||||
#define glXGetClientString _glfw.glx.GetClientString
|
#define glXGetClientString _glfw.glx.GetClientString
|
||||||
#define glXQueryExtension _glfw.glx.QueryExtension
|
#define glXQueryExtension _glfw.glx.QueryExtension
|
||||||
#define glXQueryVersion _glfw.glx.QueryVersion
|
#define glXQueryVersion _glfw.glx.QueryVersion
|
||||||
@@ -134,6 +136,7 @@ typedef struct _GLFWlibraryGLX
|
|||||||
// GLX 1.3 functions
|
// GLX 1.3 functions
|
||||||
PFNGLXGETFBCONFIGSPROC GetFBConfigs;
|
PFNGLXGETFBCONFIGSPROC GetFBConfigs;
|
||||||
PFNGLXGETFBCONFIGATTRIBPROC GetFBConfigAttrib;
|
PFNGLXGETFBCONFIGATTRIBPROC GetFBConfigAttrib;
|
||||||
|
PFNGLXCHOOSEFBCONFIGPROC ChooseFBConfig;
|
||||||
PFNGLXGETCLIENTSTRINGPROC GetClientString;
|
PFNGLXGETCLIENTSTRINGPROC GetClientString;
|
||||||
PFNGLXQUERYEXTENSIONPROC QueryExtension;
|
PFNGLXQUERYEXTENSIONPROC QueryExtension;
|
||||||
PFNGLXQUERYVERSIONPROC QueryVersion;
|
PFNGLXQUERYVERSIONPROC QueryVersion;
|
||||||
|
|||||||
2
glfw/ibus_glfw.c
vendored
2
glfw/ibus_glfw.c
vendored
@@ -269,7 +269,7 @@ setup_connection(_GLFWIBUSData *ibus) {
|
|||||||
ibus->conn = NULL;
|
ibus->conn = NULL;
|
||||||
}
|
}
|
||||||
debug("Connecting to IBUS daemon @ %s for IME input management\n", ibus->address);
|
debug("Connecting to IBUS daemon @ %s for IME input management\n", ibus->address);
|
||||||
ibus->conn = glfw_dbus_connect_to(ibus->address, "Failed to connect to the IBUS daemon, with error", "ibus", false);
|
ibus->conn = glfw_dbus_connect_to(ibus->address, "Failed to connect to the IBUS daemon, with error", "ibus", true);
|
||||||
if (!ibus->conn) return false;
|
if (!ibus->conn) return false;
|
||||||
free((void*)ibus->input_ctx_path); ibus->input_ctx_path = NULL;
|
free((void*)ibus->input_ctx_path); ibus->input_ctx_path = NULL;
|
||||||
if (!glfw_dbus_call_method_with_reply(
|
if (!glfw_dbus_call_method_with_reply(
|
||||||
|
|||||||
20
glfw/init.c
vendored
20
glfw/init.c
vendored
@@ -53,8 +53,8 @@ static GLFWerrorfun _glfwErrorCallback;
|
|||||||
static _GLFWinitconfig _glfwInitHints =
|
static _GLFWinitconfig _glfwInitHints =
|
||||||
{
|
{
|
||||||
true, // hat buttons
|
true, // hat buttons
|
||||||
|
GLFW_ANGLE_PLATFORM_TYPE_NONE, // ANGLE backend
|
||||||
false, // debug keyboard
|
false, // debug keyboard
|
||||||
true, // enable joystick
|
|
||||||
{
|
{
|
||||||
true, // macOS menu bar
|
true, // macOS menu bar
|
||||||
true // macOS bundle chdir
|
true // macOS bundle chdir
|
||||||
@@ -92,6 +92,7 @@ static void terminate(void)
|
|||||||
_glfw.mappingCount = 0;
|
_glfw.mappingCount = 0;
|
||||||
|
|
||||||
_glfwTerminateVulkan();
|
_glfwTerminateVulkan();
|
||||||
|
_glfwPlatformTerminateJoysticks();
|
||||||
_glfwPlatformTerminate();
|
_glfwPlatformTerminate();
|
||||||
|
|
||||||
_glfw.initialized = false;
|
_glfw.initialized = false;
|
||||||
@@ -168,6 +169,10 @@ void _glfwInputError(int code, const char* format, ...)
|
|||||||
strcpy(description, "The requested format is unavailable");
|
strcpy(description, "The requested format is unavailable");
|
||||||
else if (code == GLFW_NO_WINDOW_CONTEXT)
|
else if (code == GLFW_NO_WINDOW_CONTEXT)
|
||||||
strcpy(description, "The specified window has no context");
|
strcpy(description, "The specified window has no context");
|
||||||
|
else if (code == GLFW_FEATURE_UNAVAILABLE)
|
||||||
|
strcpy(description, "The requested feature cannot be implemented for this platform");
|
||||||
|
else if (code == GLFW_FEATURE_UNIMPLEMENTED)
|
||||||
|
strcpy(description, "The requested feature has not yet been implemented for this platform");
|
||||||
else
|
else
|
||||||
strcpy(description, "ERROR: UNKNOWN GLFW ERROR");
|
strcpy(description, "ERROR: UNKNOWN GLFW ERROR");
|
||||||
}
|
}
|
||||||
@@ -271,12 +276,12 @@ GLFWAPI void glfwInitHint(int hint, int value)
|
|||||||
{
|
{
|
||||||
switch (hint)
|
switch (hint)
|
||||||
{
|
{
|
||||||
case GLFW_ENABLE_JOYSTICKS:
|
|
||||||
_glfwInitHints.enableJoysticks = value;
|
|
||||||
return;
|
|
||||||
case GLFW_JOYSTICK_HAT_BUTTONS:
|
case GLFW_JOYSTICK_HAT_BUTTONS:
|
||||||
_glfwInitHints.hatButtons = value;
|
_glfwInitHints.hatButtons = value;
|
||||||
return;
|
return;
|
||||||
|
case GLFW_ANGLE_PLATFORM_TYPE:
|
||||||
|
_glfwInitHints.angleType = value;
|
||||||
|
return;
|
||||||
case GLFW_DEBUG_KEYBOARD:
|
case GLFW_DEBUG_KEYBOARD:
|
||||||
_glfwInitHints.debugKeyboard = value;
|
_glfwInitHints.debugKeyboard = value;
|
||||||
return;
|
return;
|
||||||
@@ -363,3 +368,10 @@ GLFWAPI void glfwUpdateTimer(unsigned long long timer_id, monotonic_t interval,
|
|||||||
GLFWAPI void glfwRemoveTimer(unsigned long long timer_id) {
|
GLFWAPI void glfwRemoveTimer(unsigned long long timer_id) {
|
||||||
_glfwPlatformRemoveTimer(timer_id);
|
_glfwPlatformRemoveTimer(timer_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GLFWAPI GLFWapplicationclosefun glfwSetApplicationCloseCallback(GLFWapplicationclosefun cbfun)
|
||||||
|
{
|
||||||
|
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||||
|
_GLFW_SWAP_POINTERS(_glfw.callbacks.application_close, cbfun);
|
||||||
|
return cbfun;
|
||||||
|
}
|
||||||
|
|||||||
94
glfw/input.c
vendored
94
glfw/input.c
vendored
@@ -44,6 +44,22 @@
|
|||||||
#define _GLFW_JOYSTICK_BUTTON 2
|
#define _GLFW_JOYSTICK_BUTTON 2
|
||||||
#define _GLFW_JOYSTICK_HATBIT 3
|
#define _GLFW_JOYSTICK_HATBIT 3
|
||||||
|
|
||||||
|
// Initializes the platform joystick API if it has not been already
|
||||||
|
//
|
||||||
|
static bool initJoysticks(void)
|
||||||
|
{
|
||||||
|
if (!_glfw.joysticksInitialized)
|
||||||
|
{
|
||||||
|
if (!_glfwPlatformInitJoysticks())
|
||||||
|
{
|
||||||
|
_glfwPlatformTerminateJoysticks();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return _glfw.joysticksInitialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
// Finds a mapping based on joystick GUID
|
// Finds a mapping based on joystick GUID
|
||||||
//
|
//
|
||||||
static _GLFWmapping* findMapping(const char* guid)
|
static _GLFWmapping* findMapping(const char* guid)
|
||||||
@@ -300,10 +316,10 @@ void _glfwInputKeyboard(_GLFWwindow* window, GLFWkeyevent* ev)
|
|||||||
|
|
||||||
// Notifies shared code of a scroll event
|
// Notifies shared code of a scroll event
|
||||||
//
|
//
|
||||||
void _glfwInputScroll(_GLFWwindow* window, double xoffset, double yoffset, int flags)
|
void _glfwInputScroll(_GLFWwindow* window, double xoffset, double yoffset, int flags, int mods)
|
||||||
{
|
{
|
||||||
if (window->callbacks.scroll)
|
if (window->callbacks.scroll)
|
||||||
window->callbacks.scroll((GLFWwindow*) window, xoffset, yoffset, flags);
|
window->callbacks.scroll((GLFWwindow*) window, xoffset, yoffset, flags, mods);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Notifies shared code of a mouse button click event
|
// Notifies shared code of a mouse button click event
|
||||||
@@ -350,10 +366,11 @@ void _glfwInputCursorEnter(_GLFWwindow* window, bool entered)
|
|||||||
|
|
||||||
// Notifies shared code of files or directories dropped on a window
|
// Notifies shared code of files or directories dropped on a window
|
||||||
//
|
//
|
||||||
void _glfwInputDrop(_GLFWwindow* window, int count, const char** paths)
|
int _glfwInputDrop(_GLFWwindow* window, const char *mime, const char *text, size_t sz)
|
||||||
{
|
{
|
||||||
if (window->callbacks.drop)
|
if (window->callbacks.drop)
|
||||||
window->callbacks.drop((GLFWwindow*) window, count, paths);
|
return window->callbacks.drop((GLFWwindow*) window, mime, text, sz);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Notifies shared code of a joystick connection or disconnection
|
// Notifies shared code of a joystick connection or disconnection
|
||||||
@@ -674,6 +691,8 @@ GLFWAPI int glfwGetInputMode(GLFWwindow* handle, int mode)
|
|||||||
return window->stickyMouseButtons;
|
return window->stickyMouseButtons;
|
||||||
case GLFW_LOCK_KEY_MODS:
|
case GLFW_LOCK_KEY_MODS:
|
||||||
return window->lockKeyMods;
|
return window->lockKeyMods;
|
||||||
|
case GLFW_RAW_MOUSE_MOTION:
|
||||||
|
return window->rawMouseMotion;
|
||||||
}
|
}
|
||||||
|
|
||||||
_glfwInputError(GLFW_INVALID_ENUM, "Invalid input mode 0x%08X", mode);
|
_glfwInputError(GLFW_INVALID_ENUM, "Invalid input mode 0x%08X", mode);
|
||||||
@@ -753,10 +772,32 @@ GLFWAPI void glfwSetInputMode(GLFWwindow* handle, int mode, int value)
|
|||||||
{
|
{
|
||||||
window->lockKeyMods = value ? true : false;
|
window->lockKeyMods = value ? true : false;
|
||||||
}
|
}
|
||||||
|
else if (mode == GLFW_RAW_MOUSE_MOTION)
|
||||||
|
{
|
||||||
|
if (!_glfwPlatformRawMouseMotionSupported())
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"Raw mouse motion is not supported on this system");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
value = value ? true : false;
|
||||||
|
if (window->rawMouseMotion == value)
|
||||||
|
return;
|
||||||
|
|
||||||
|
window->rawMouseMotion = value;
|
||||||
|
_glfwPlatformSetRawMouseMotion(window, value);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
_glfwInputError(GLFW_INVALID_ENUM, "Invalid input mode 0x%08X", mode);
|
_glfwInputError(GLFW_INVALID_ENUM, "Invalid input mode 0x%08X", mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GLFWAPI int glfwRawMouseMotionSupported(void)
|
||||||
|
{
|
||||||
|
_GLFW_REQUIRE_INIT_OR_RETURN(false);
|
||||||
|
return _glfwPlatformRawMouseMotionSupported();
|
||||||
|
}
|
||||||
|
|
||||||
GLFWAPI const char* glfwGetKeyName(int key, int native_key)
|
GLFWAPI const char* glfwGetKeyName(int key, int native_key)
|
||||||
{
|
{
|
||||||
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||||
@@ -1076,6 +1117,9 @@ GLFWAPI int glfwJoystickPresent(int jid)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!initJoysticks())
|
||||||
|
return false;
|
||||||
|
|
||||||
js = _glfw.joysticks + jid;
|
js = _glfw.joysticks + jid;
|
||||||
if (!js->present)
|
if (!js->present)
|
||||||
return false;
|
return false;
|
||||||
@@ -1101,6 +1145,9 @@ GLFWAPI const float* glfwGetJoystickAxes(int jid, int* count)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!initJoysticks())
|
||||||
|
return NULL;
|
||||||
|
|
||||||
js = _glfw.joysticks + jid;
|
js = _glfw.joysticks + jid;
|
||||||
if (!js->present)
|
if (!js->present)
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -1130,6 +1177,9 @@ GLFWAPI const unsigned char* glfwGetJoystickButtons(int jid, int* count)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!initJoysticks())
|
||||||
|
return NULL;
|
||||||
|
|
||||||
js = _glfw.joysticks + jid;
|
js = _glfw.joysticks + jid;
|
||||||
if (!js->present)
|
if (!js->present)
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -1163,6 +1213,9 @@ GLFWAPI const unsigned char* glfwGetJoystickHats(int jid, int* count)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!initJoysticks())
|
||||||
|
return NULL;
|
||||||
|
|
||||||
js = _glfw.joysticks + jid;
|
js = _glfw.joysticks + jid;
|
||||||
if (!js->present)
|
if (!js->present)
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -1189,6 +1242,9 @@ GLFWAPI const char* glfwGetJoystickName(int jid)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!initJoysticks())
|
||||||
|
return NULL;
|
||||||
|
|
||||||
js = _glfw.joysticks + jid;
|
js = _glfw.joysticks + jid;
|
||||||
if (!js->present)
|
if (!js->present)
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -1214,6 +1270,9 @@ GLFWAPI const char* glfwGetJoystickGUID(int jid)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!initJoysticks())
|
||||||
|
return NULL;
|
||||||
|
|
||||||
js = _glfw.joysticks + jid;
|
js = _glfw.joysticks + jid;
|
||||||
if (!js->present)
|
if (!js->present)
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -1259,6 +1318,10 @@ GLFWAPI void* glfwGetJoystickUserPointer(int jid)
|
|||||||
GLFWAPI GLFWjoystickfun glfwSetJoystickCallback(GLFWjoystickfun cbfun)
|
GLFWAPI GLFWjoystickfun glfwSetJoystickCallback(GLFWjoystickfun cbfun)
|
||||||
{
|
{
|
||||||
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||||
|
|
||||||
|
if (!initJoysticks())
|
||||||
|
return NULL;
|
||||||
|
|
||||||
_GLFW_SWAP_POINTERS(_glfw.callbacks.joystick, cbfun);
|
_GLFW_SWAP_POINTERS(_glfw.callbacks.joystick, cbfun);
|
||||||
return cbfun;
|
return cbfun;
|
||||||
}
|
}
|
||||||
@@ -1338,6 +1401,9 @@ GLFWAPI int glfwJoystickIsGamepad(int jid)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!initJoysticks())
|
||||||
|
return false;
|
||||||
|
|
||||||
js = _glfw.joysticks + jid;
|
js = _glfw.joysticks + jid;
|
||||||
if (!js->present)
|
if (!js->present)
|
||||||
return false;
|
return false;
|
||||||
@@ -1363,6 +1429,9 @@ GLFWAPI const char* glfwGetGamepadName(int jid)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!initJoysticks())
|
||||||
|
return NULL;
|
||||||
|
|
||||||
js = _glfw.joysticks + jid;
|
js = _glfw.joysticks + jid;
|
||||||
if (!js->present)
|
if (!js->present)
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -1395,6 +1464,9 @@ GLFWAPI int glfwGetGamepadState(int jid, GLFWgamepadstate* state)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!initJoysticks())
|
||||||
|
return false;
|
||||||
|
|
||||||
js = _glfw.joysticks + jid;
|
js = _glfw.joysticks + jid;
|
||||||
if (!js->present)
|
if (!js->present)
|
||||||
return false;
|
return false;
|
||||||
@@ -1411,8 +1483,18 @@ GLFWAPI int glfwGetGamepadState(int jid, GLFWgamepadstate* state)
|
|||||||
if (e->type == _GLFW_JOYSTICK_AXIS)
|
if (e->type == _GLFW_JOYSTICK_AXIS)
|
||||||
{
|
{
|
||||||
const float value = js->axes[e->index] * e->axisScale + e->axisOffset;
|
const float value = js->axes[e->index] * e->axisScale + e->axisOffset;
|
||||||
if (value > 0.f)
|
// HACK: This should be baked into the value transform
|
||||||
state->buttons[i] = GLFW_PRESS;
|
// TODO: Bake into transform when implementing output modifiers
|
||||||
|
if (e->axisOffset < 0 || (e->axisOffset == 0 && e->axisScale > 0))
|
||||||
|
{
|
||||||
|
if (value >= 0.f)
|
||||||
|
state->buttons[i] = GLFW_PRESS;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (value <= 0.f)
|
||||||
|
state->buttons[i] = GLFW_PRESS;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (e->type == _GLFW_JOYSTICK_HATBIT)
|
else if (e->type == _GLFW_JOYSTICK_HATBIT)
|
||||||
{
|
{
|
||||||
|
|||||||
35
glfw/internal.h
vendored
35
glfw/internal.h
vendored
@@ -198,6 +198,9 @@ typedef void (APIENTRY * PFN_vkVoidFunction)(void);
|
|||||||
#error "No supported window creation API selected"
|
#error "No supported window creation API selected"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "egl_context.h"
|
||||||
|
#include "osmesa_context.h"
|
||||||
|
|
||||||
#define remove_i_from_array(array, i, count) { \
|
#define remove_i_from_array(array, i, count) { \
|
||||||
(count)--; \
|
(count)--; \
|
||||||
if ((i) < (count)) { \
|
if ((i) < (count)) { \
|
||||||
@@ -271,8 +274,8 @@ struct _GLFWerror
|
|||||||
struct _GLFWinitconfig
|
struct _GLFWinitconfig
|
||||||
{
|
{
|
||||||
bool hatButtons;
|
bool hatButtons;
|
||||||
|
int angleType;
|
||||||
bool debugKeyboard;
|
bool debugKeyboard;
|
||||||
bool enableJoysticks;
|
|
||||||
struct {
|
struct {
|
||||||
bool menubar;
|
bool menubar;
|
||||||
bool chdir;
|
bool chdir;
|
||||||
@@ -299,6 +302,7 @@ struct _GLFWwndconfig
|
|||||||
bool maximized;
|
bool maximized;
|
||||||
bool centerCursor;
|
bool centerCursor;
|
||||||
bool focusOnShow;
|
bool focusOnShow;
|
||||||
|
bool mousePassthrough;
|
||||||
bool scaleToMonitor;
|
bool scaleToMonitor;
|
||||||
struct {
|
struct {
|
||||||
bool retina;
|
bool retina;
|
||||||
@@ -392,9 +396,9 @@ struct _GLFWcontext
|
|||||||
// This is defined in the context API's context.h
|
// This is defined in the context API's context.h
|
||||||
_GLFW_PLATFORM_CONTEXT_STATE
|
_GLFW_PLATFORM_CONTEXT_STATE
|
||||||
// This is defined in egl_context.h
|
// This is defined in egl_context.h
|
||||||
_GLFW_EGL_CONTEXT_STATE;
|
_GLFWcontextEGL egl;
|
||||||
// This is defined in osmesa_context.h
|
// This is defined in osmesa_context.h
|
||||||
_GLFW_OSMESA_CONTEXT_STATE;
|
_GLFWcontextOSMesa osmesa;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Window and context structure
|
// Window and context structure
|
||||||
@@ -409,6 +413,7 @@ struct _GLFWwindow
|
|||||||
bool autoIconify;
|
bool autoIconify;
|
||||||
bool floating;
|
bool floating;
|
||||||
bool focusOnShow;
|
bool focusOnShow;
|
||||||
|
bool mousePassthrough;
|
||||||
bool shouldClose;
|
bool shouldClose;
|
||||||
void* userPointer;
|
void* userPointer;
|
||||||
GLFWid id;
|
GLFWid id;
|
||||||
@@ -429,6 +434,7 @@ struct _GLFWwindow
|
|||||||
char keys[GLFW_KEY_LAST + 1];
|
char keys[GLFW_KEY_LAST + 1];
|
||||||
// Virtual cursor position when cursor is disabled
|
// Virtual cursor position when cursor is disabled
|
||||||
double virtualCursorPosX, virtualCursorPosY;
|
double virtualCursorPosX, virtualCursorPosY;
|
||||||
|
bool rawMouseMotion;
|
||||||
|
|
||||||
_GLFWcontext context;
|
_GLFWcontext context;
|
||||||
|
|
||||||
@@ -568,6 +574,7 @@ struct _GLFWlibrary
|
|||||||
_GLFWmonitor** monitors;
|
_GLFWmonitor** monitors;
|
||||||
int monitorCount;
|
int monitorCount;
|
||||||
|
|
||||||
|
bool joysticksInitialized;
|
||||||
_GLFWjoystick joysticks[GLFW_JOYSTICK_LAST + 1];
|
_GLFWjoystick joysticks[GLFW_JOYSTICK_LAST + 1];
|
||||||
_GLFWmapping* mappings;
|
_GLFWmapping* mappings;
|
||||||
int mappingCount;
|
int mappingCount;
|
||||||
@@ -601,8 +608,10 @@ struct _GLFWlibrary
|
|||||||
struct {
|
struct {
|
||||||
GLFWmonitorfun monitor;
|
GLFWmonitorfun monitor;
|
||||||
GLFWjoystickfun joystick;
|
GLFWjoystickfun joystick;
|
||||||
|
GLFWapplicationclosefun application_close;
|
||||||
} callbacks;
|
} callbacks;
|
||||||
|
|
||||||
|
|
||||||
// This is defined in the window API's platform.h
|
// This is defined in the window API's platform.h
|
||||||
_GLFW_PLATFORM_LIBRARY_WINDOW_STATE;
|
_GLFW_PLATFORM_LIBRARY_WINDOW_STATE;
|
||||||
// This is defined in the context API's context.h
|
// This is defined in the context API's context.h
|
||||||
@@ -610,9 +619,9 @@ struct _GLFWlibrary
|
|||||||
// This is defined in the platform's joystick.h
|
// This is defined in the platform's joystick.h
|
||||||
_GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE
|
_GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE
|
||||||
// This is defined in egl_context.h
|
// This is defined in egl_context.h
|
||||||
_GLFW_EGL_LIBRARY_CONTEXT_STATE;
|
_GLFWlibraryEGL egl;
|
||||||
// This is defined in osmesa_context.h
|
// This is defined in osmesa_context.h
|
||||||
_GLFW_OSMESA_LIBRARY_CONTEXT_STATE;
|
_GLFWlibraryOSMesa osmesa;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Global state shared between compilation units of GLFW
|
// Global state shared between compilation units of GLFW
|
||||||
@@ -631,6 +640,8 @@ const char* _glfwPlatformGetVersionString(void);
|
|||||||
void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos);
|
void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos);
|
||||||
void _glfwPlatformSetCursorPos(_GLFWwindow* window, double xpos, double ypos);
|
void _glfwPlatformSetCursorPos(_GLFWwindow* window, double xpos, double ypos);
|
||||||
void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode);
|
void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode);
|
||||||
|
void _glfwPlatformSetRawMouseMotion(_GLFWwindow *window, bool enabled);
|
||||||
|
bool _glfwPlatformRawMouseMotionSupported(void);
|
||||||
int _glfwPlatformCreateCursor(_GLFWcursor* cursor,
|
int _glfwPlatformCreateCursor(_GLFWcursor* cursor,
|
||||||
const GLFWimage* image, int xhot, int yhot, int count);
|
const GLFWimage* image, int xhot, int yhot, int count);
|
||||||
int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, GLFWCursorShape shape);
|
int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, GLFWCursorShape shape);
|
||||||
@@ -657,6 +668,8 @@ void _glfwPlatformSetPrimarySelectionString(const char* string);
|
|||||||
const char* _glfwPlatformGetPrimarySelectionString(void);
|
const char* _glfwPlatformGetPrimarySelectionString(void);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
bool _glfwPlatformInitJoysticks(void);
|
||||||
|
void _glfwPlatformTerminateJoysticks(void);
|
||||||
int _glfwPlatformPollJoystick(_GLFWjoystick* js, int mode);
|
int _glfwPlatformPollJoystick(_GLFWjoystick* js, int mode);
|
||||||
void _glfwPlatformUpdateGamepadGUID(char* guid);
|
void _glfwPlatformUpdateGamepadGUID(char* guid);
|
||||||
|
|
||||||
@@ -708,6 +721,7 @@ float _glfwPlatformGetWindowOpacity(_GLFWwindow* window);
|
|||||||
void _glfwPlatformSetWindowResizable(_GLFWwindow* window, bool enabled);
|
void _glfwPlatformSetWindowResizable(_GLFWwindow* window, bool enabled);
|
||||||
void _glfwPlatformSetWindowDecorated(_GLFWwindow* window, bool enabled);
|
void _glfwPlatformSetWindowDecorated(_GLFWwindow* window, bool enabled);
|
||||||
void _glfwPlatformSetWindowFloating(_GLFWwindow* window, bool enabled);
|
void _glfwPlatformSetWindowFloating(_GLFWwindow* window, bool enabled);
|
||||||
|
void _glfwPlatformSetWindowMousePassthrough(_GLFWwindow* window, bool enabled);
|
||||||
void _glfwPlatformSetWindowOpacity(_GLFWwindow* window, float opacity);
|
void _glfwPlatformSetWindowOpacity(_GLFWwindow* window, float opacity);
|
||||||
void _glfwPlatformUpdateIMEState(_GLFWwindow *w, int which, int a, int b, int c, int d);
|
void _glfwPlatformUpdateIMEState(_GLFWwindow *w, int which, int a, int b, int c, int d);
|
||||||
|
|
||||||
@@ -716,6 +730,10 @@ void _glfwPlatformWaitEvents(void);
|
|||||||
void _glfwPlatformWaitEventsTimeout(monotonic_t timeout);
|
void _glfwPlatformWaitEventsTimeout(monotonic_t timeout);
|
||||||
void _glfwPlatformPostEmptyEvent(void);
|
void _glfwPlatformPostEmptyEvent(void);
|
||||||
|
|
||||||
|
EGLenum _glfwPlatformGetEGLPlatform(EGLint** attribs);
|
||||||
|
EGLNativeDisplayType _glfwPlatformGetEGLNativeDisplay(void);
|
||||||
|
EGLNativeWindowType _glfwPlatformGetEGLNativeWindow(_GLFWwindow* window);
|
||||||
|
|
||||||
void _glfwPlatformGetRequiredInstanceExtensions(char** extensions);
|
void _glfwPlatformGetRequiredInstanceExtensions(char** extensions);
|
||||||
int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance,
|
int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance,
|
||||||
VkPhysicalDevice device,
|
VkPhysicalDevice device,
|
||||||
@@ -755,11 +773,11 @@ void _glfwInputWindowMonitor(_GLFWwindow* window, _GLFWmonitor* monitor);
|
|||||||
|
|
||||||
void _glfwInitializeKeyEvent(GLFWkeyevent *ev, int key, int native_key, int action, int mods);
|
void _glfwInitializeKeyEvent(GLFWkeyevent *ev, int key, int native_key, int action, int mods);
|
||||||
void _glfwInputKeyboard(_GLFWwindow *window, GLFWkeyevent *ev);
|
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, int mods);
|
||||||
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);
|
||||||
void _glfwInputCursorEnter(_GLFWwindow* window, bool entered);
|
void _glfwInputCursorEnter(_GLFWwindow* window, bool entered);
|
||||||
void _glfwInputDrop(_GLFWwindow* window, int count, const char** names);
|
int _glfwInputDrop(_GLFWwindow* window, const char *mime, const char *text, size_t sz);
|
||||||
void _glfwInputJoystick(_GLFWjoystick* js, int event);
|
void _glfwInputJoystick(_GLFWjoystick* js, int event);
|
||||||
void _glfwInputJoystickAxis(_GLFWjoystick* js, int axis, float value);
|
void _glfwInputJoystickAxis(_GLFWjoystick* js, int axis, float value);
|
||||||
void _glfwInputJoystickButton(_GLFWjoystick* js, int button, char value);
|
void _glfwInputJoystickButton(_GLFWjoystick* js, int button, char value);
|
||||||
@@ -789,9 +807,6 @@ void _glfwDebug(const char* format, ...);
|
|||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
bool _glfwStringInExtensionString(const char* string, const char* extensions);
|
bool _glfwStringInExtensionString(const char* string, const char* extensions);
|
||||||
const _GLFWfbconfig* _glfwChooseFBConfig(const _GLFWfbconfig* desired,
|
|
||||||
const _GLFWfbconfig* alternatives,
|
|
||||||
unsigned int count);
|
|
||||||
bool _glfwRefreshContextAttribs(_GLFWwindow* window,
|
bool _glfwRefreshContextAttribs(_GLFWwindow* window,
|
||||||
const _GLFWctxconfig* ctxconfig);
|
const _GLFWctxconfig* ctxconfig);
|
||||||
bool _glfwIsValidContextConfig(const _GLFWctxconfig* ctxconfig);
|
bool _glfwIsValidContextConfig(const _GLFWctxconfig* ctxconfig);
|
||||||
|
|||||||
98
glfw/linux_joystick.c
vendored
98
glfw/linux_joystick.c
vendored
@@ -264,9 +264,50 @@ static int compareJoysticks(const void* fp, const void* sp)
|
|||||||
////// GLFW internal API //////
|
////// GLFW internal API //////
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
// Initialize joystick interface
|
void _glfwDetectJoystickConnectionLinux(void)
|
||||||
//
|
{
|
||||||
bool _glfwInitJoysticksLinux(void)
|
if (_glfw.linjs.inotify <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ssize_t offset = 0;
|
||||||
|
char buffer[16384];
|
||||||
|
const ssize_t size = read(_glfw.linjs.inotify, buffer, sizeof(buffer));
|
||||||
|
|
||||||
|
while (size > offset)
|
||||||
|
{
|
||||||
|
regmatch_t match;
|
||||||
|
const struct inotify_event* e = (struct inotify_event*) (buffer + offset);
|
||||||
|
|
||||||
|
offset += sizeof(struct inotify_event) + e->len;
|
||||||
|
|
||||||
|
if (regexec(&_glfw.linjs.regex, e->name, 1, &match, 0) != 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
char path[PATH_MAX];
|
||||||
|
snprintf(path, sizeof(path), "/dev/input/%s", e->name);
|
||||||
|
|
||||||
|
if (e->mask & (IN_CREATE | IN_ATTRIB))
|
||||||
|
openJoystickDevice(path);
|
||||||
|
else if (e->mask & IN_DELETE)
|
||||||
|
{
|
||||||
|
for (int jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++)
|
||||||
|
{
|
||||||
|
if (strcmp(_glfw.joysticks[jid].linjs.path, path) == 0)
|
||||||
|
{
|
||||||
|
closeJoystick(_glfw.joysticks + jid);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
////// GLFW platform API //////
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
bool _glfwPlatformInitJoysticks(void)
|
||||||
{
|
{
|
||||||
const char* dirname = "/dev/input";
|
const char* dirname = "/dev/input";
|
||||||
|
|
||||||
@@ -320,9 +361,7 @@ bool _glfwInitJoysticksLinux(void)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close all opened joystick handles
|
void _glfwPlatformTerminateJoysticks(void)
|
||||||
//
|
|
||||||
void _glfwTerminateJoysticksLinux(void)
|
|
||||||
{
|
{
|
||||||
int jid;
|
int jid;
|
||||||
|
|
||||||
@@ -333,61 +372,16 @@ void _glfwTerminateJoysticksLinux(void)
|
|||||||
closeJoystick(js);
|
closeJoystick(js);
|
||||||
}
|
}
|
||||||
|
|
||||||
regfree(&_glfw.linjs.regex);
|
|
||||||
|
|
||||||
if (_glfw.linjs.inotify > 0)
|
if (_glfw.linjs.inotify > 0)
|
||||||
{
|
{
|
||||||
if (_glfw.linjs.watch > 0)
|
if (_glfw.linjs.watch > 0)
|
||||||
inotify_rm_watch(_glfw.linjs.inotify, _glfw.linjs.watch);
|
inotify_rm_watch(_glfw.linjs.inotify, _glfw.linjs.watch);
|
||||||
|
|
||||||
close(_glfw.linjs.inotify);
|
close(_glfw.linjs.inotify);
|
||||||
|
regfree(&_glfw.linjs.regex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwDetectJoystickConnectionLinux(void)
|
|
||||||
{
|
|
||||||
|
|
||||||
if (_glfw.linjs.inotify <= 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
ssize_t offset = 0;
|
|
||||||
char buffer[16384];
|
|
||||||
const ssize_t size = read(_glfw.linjs.inotify, buffer, sizeof(buffer));
|
|
||||||
|
|
||||||
while (size > offset)
|
|
||||||
{
|
|
||||||
regmatch_t match;
|
|
||||||
const struct inotify_event* e = (struct inotify_event*) (buffer + offset);
|
|
||||||
|
|
||||||
offset += sizeof(struct inotify_event) + e->len;
|
|
||||||
|
|
||||||
if (regexec(&_glfw.linjs.regex, e->name, 1, &match, 0) != 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
char path[PATH_MAX];
|
|
||||||
snprintf(path, sizeof(path), "/dev/input/%s", e->name);
|
|
||||||
|
|
||||||
if (e->mask & (IN_CREATE | IN_ATTRIB))
|
|
||||||
openJoystickDevice(path);
|
|
||||||
else if (e->mask & IN_DELETE)
|
|
||||||
{
|
|
||||||
for (int jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++)
|
|
||||||
{
|
|
||||||
if (strcmp(_glfw.joysticks[jid].linjs.path, path) == 0)
|
|
||||||
{
|
|
||||||
closeJoystick(_glfw.joysticks + jid);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
|
||||||
////// GLFW platform API //////
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
int _glfwPlatformPollJoystick(_GLFWjoystick* js, int mode UNUSED)
|
int _glfwPlatformPollJoystick(_GLFWjoystick* js, int mode UNUSED)
|
||||||
{
|
{
|
||||||
// Read all queued events (non-blocking)
|
// Read all queued events (non-blocking)
|
||||||
|
|||||||
3
glfw/linux_joystick.h
vendored
3
glfw/linux_joystick.h
vendored
@@ -55,7 +55,4 @@ typedef struct _GLFWlibraryLinux
|
|||||||
bool dropped;
|
bool dropped;
|
||||||
} _GLFWlibraryLinux;
|
} _GLFWlibraryLinux;
|
||||||
|
|
||||||
|
|
||||||
bool _glfwInitJoysticksLinux(void);
|
|
||||||
void _glfwTerminateJoysticksLinux(void);
|
|
||||||
void _glfwDetectJoystickConnectionLinux(void);
|
void _glfwDetectJoystickConnectionLinux(void);
|
||||||
|
|||||||
3
glfw/memfd.h
vendored
3
glfw/memfd.h
vendored
@@ -39,8 +39,7 @@ static inline int memfd_create(const char *name, unsigned int flags) {
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
|
||||||
static inline int
|
static inline int createTmpfileCloexec(char* tmpname)
|
||||||
createTmpfileCloexec(char* tmpname)
|
|
||||||
{
|
{
|
||||||
int fd;
|
int fd;
|
||||||
|
|
||||||
|
|||||||
5
glfw/null_init.c
vendored
5
glfw/null_init.c
vendored
@@ -29,6 +29,8 @@
|
|||||||
|
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
////// GLFW platform API //////
|
////// GLFW platform API //////
|
||||||
@@ -36,11 +38,14 @@
|
|||||||
|
|
||||||
int _glfwPlatformInit(void)
|
int _glfwPlatformInit(void)
|
||||||
{
|
{
|
||||||
|
_glfwPollMonitorsNull();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformTerminate(void)
|
void _glfwPlatformTerminate(void)
|
||||||
{
|
{
|
||||||
|
free(_glfw.null.clipboardString);
|
||||||
_glfwTerminateOSMesa();
|
_glfwTerminateOSMesa();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
9
glfw/null_joystick.c
vendored
9
glfw/null_joystick.c
vendored
@@ -33,6 +33,15 @@
|
|||||||
////// GLFW platform API //////
|
////// GLFW platform API //////
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
bool _glfwPlatformInitJoysticks(void)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwPlatformTerminateJoysticks(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
int _glfwPlatformPollJoystick(_GLFWjoystick* js UNUSED, int mode UNUSED)
|
int _glfwPlatformPollJoystick(_GLFWjoystick* js UNUSED, int mode UNUSED)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
102
glfw/null_monitor.c
vendored
102
glfw/null_monitor.c
vendored
@@ -29,17 +29,53 @@
|
|||||||
|
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
// The the sole (fake) video mode of our (sole) fake monitor
|
||||||
|
//
|
||||||
|
static GLFWvidmode getVideoMode(void)
|
||||||
|
{
|
||||||
|
GLFWvidmode mode;
|
||||||
|
mode.width = 1920;
|
||||||
|
mode.height = 1080;
|
||||||
|
mode.redBits = 8;
|
||||||
|
mode.greenBits = 8;
|
||||||
|
mode.blueBits = 8;
|
||||||
|
mode.refreshRate = 60;
|
||||||
|
return mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
////// GLFW internal API //////
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
void _glfwPollMonitorsNull(void)
|
||||||
|
{
|
||||||
|
const float dpi = 141.f;
|
||||||
|
const GLFWvidmode mode = getVideoMode();
|
||||||
|
_GLFWmonitor* monitor = _glfwAllocMonitor("Null SuperNoop 0",
|
||||||
|
(int) (mode.width * 25.4f / dpi),
|
||||||
|
(int) (mode.height * 25.4f / dpi));
|
||||||
|
_glfwInputMonitor(monitor, GLFW_CONNECTED, _GLFW_INSERT_FIRST);
|
||||||
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
////// GLFW platform API //////
|
////// GLFW platform API //////
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void _glfwPlatformFreeMonitor(_GLFWmonitor* monitor UNUSED)
|
void _glfwPlatformFreeMonitor(_GLFWmonitor* monitor)
|
||||||
{
|
{
|
||||||
|
_glfwFreeGammaArrays(&monitor->null.ramp);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor UNUSED, int* xpos UNUSED, int* ypos UNUSED)
|
void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor UNUSED, int* xpos, int* ypos)
|
||||||
{
|
{
|
||||||
|
if (xpos)
|
||||||
|
*xpos = 0;
|
||||||
|
if (ypos)
|
||||||
|
*ypos = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor UNUSED,
|
void _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor UNUSED,
|
||||||
@@ -52,26 +88,72 @@ void _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor UNUSED,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformGetMonitorWorkarea(_GLFWmonitor* monitor UNUSED,
|
void _glfwPlatformGetMonitorWorkarea(_GLFWmonitor* monitor UNUSED,
|
||||||
int* xpos UNUSED, int* ypos UNUSED,
|
int* xpos, int* ypos,
|
||||||
int* width UNUSED, int* height UNUSED)
|
int* width, int* height)
|
||||||
{
|
{
|
||||||
|
const GLFWvidmode mode = getVideoMode();
|
||||||
|
|
||||||
|
if (xpos)
|
||||||
|
*xpos = 0;
|
||||||
|
if (ypos)
|
||||||
|
*ypos = 10;
|
||||||
|
if (width)
|
||||||
|
*width = mode.width;
|
||||||
|
if (height)
|
||||||
|
*height = mode.height - 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor UNUSED, int* found UNUSED)
|
GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor UNUSED, int* found)
|
||||||
{
|
{
|
||||||
return NULL;
|
GLFWvidmode* mode = calloc(1, sizeof(GLFWvidmode));
|
||||||
|
*mode = getVideoMode();
|
||||||
|
*found = 1;
|
||||||
|
return mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor UNUSED, GLFWvidmode* mode UNUSED)
|
void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor UNUSED, GLFWvidmode* mode)
|
||||||
{
|
{
|
||||||
|
*mode = getVideoMode();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor UNUSED, GLFWgammaramp* ramp UNUSED)
|
bool _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
|
||||||
{
|
{
|
||||||
return false;
|
if (!monitor->null.ramp.size)
|
||||||
|
{
|
||||||
|
_glfwAllocGammaArrays(&monitor->null.ramp, 256);
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < monitor->null.ramp.size; i++)
|
||||||
|
{
|
||||||
|
const float gamma = 2.2f;
|
||||||
|
float value;
|
||||||
|
value = i / (float) (monitor->null.ramp.size - 1);
|
||||||
|
value = powf(value, 1.f / gamma) * 65535.f + 0.5f;
|
||||||
|
value = _glfw_fminf(value, 65535.f);
|
||||||
|
|
||||||
|
monitor->null.ramp.red[i] = (unsigned short) value;
|
||||||
|
monitor->null.ramp.green[i] = (unsigned short) value;
|
||||||
|
monitor->null.ramp.blue[i] = (unsigned short) value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_glfwAllocGammaArrays(ramp, monitor->null.ramp.size);
|
||||||
|
memcpy(ramp->red, monitor->null.ramp.red, sizeof(short) * ramp->size);
|
||||||
|
memcpy(ramp->green, monitor->null.ramp.green, sizeof(short) * ramp->size);
|
||||||
|
memcpy(ramp->blue, monitor->null.ramp.blue, sizeof(short) * ramp->size);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor UNUSED, const GLFWgammaramp* ramp UNUSED)
|
void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp)
|
||||||
{
|
{
|
||||||
|
if (monitor->null.ramp.size != ramp->size)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"Null: Gamma ramp size must match current ramp size");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(monitor->null.ramp.red, ramp->red, sizeof(short) * ramp->size);
|
||||||
|
memcpy(monitor->null.ramp.green, ramp->green, sizeof(short) * ramp->size);
|
||||||
|
memcpy(monitor->null.ramp.blue, ramp->blue, sizeof(short) * ramp->size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
42
glfw/null_platform.h
vendored
42
glfw/null_platform.h
vendored
@@ -27,17 +27,14 @@
|
|||||||
|
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
|
|
||||||
#define _GLFW_PLATFORM_WINDOW_STATE _GLFWwindowNull null
|
#define _GLFW_PLATFORM_WINDOW_STATE _GLFWwindowNull null
|
||||||
|
#define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryNull null
|
||||||
|
#define _GLFW_PLATFORM_MONITOR_STATE _GLFWmonitorNull null
|
||||||
|
|
||||||
#define _GLFW_PLATFORM_CONTEXT_STATE
|
#define _GLFW_PLATFORM_CONTEXT_STATE
|
||||||
#define _GLFW_PLATFORM_MONITOR_STATE
|
|
||||||
#define _GLFW_PLATFORM_CURSOR_STATE
|
#define _GLFW_PLATFORM_CURSOR_STATE
|
||||||
#define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE
|
|
||||||
#define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE
|
#define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE
|
||||||
#define _GLFW_EGL_CONTEXT_STATE
|
|
||||||
#define _GLFW_EGL_LIBRARY_CONTEXT_STATE
|
|
||||||
|
|
||||||
#include "osmesa_context.h"
|
|
||||||
#include "posix_time.h"
|
#include "posix_time.h"
|
||||||
#include "posix_thread.h"
|
#include "posix_thread.h"
|
||||||
#include "null_joystick.h"
|
#include "null_joystick.h"
|
||||||
@@ -56,7 +53,36 @@
|
|||||||
//
|
//
|
||||||
typedef struct _GLFWwindowNull
|
typedef struct _GLFWwindowNull
|
||||||
{
|
{
|
||||||
int width;
|
int xpos;
|
||||||
int height;
|
int ypos;
|
||||||
|
int width;
|
||||||
|
int height;
|
||||||
|
char* title;
|
||||||
|
bool visible;
|
||||||
|
bool iconified;
|
||||||
|
bool maximized;
|
||||||
|
bool resizable;
|
||||||
|
bool decorated;
|
||||||
|
bool floating;
|
||||||
|
bool transparent;
|
||||||
|
float opacity;
|
||||||
} _GLFWwindowNull;
|
} _GLFWwindowNull;
|
||||||
|
|
||||||
|
// Null-specific per-monitor data
|
||||||
|
//
|
||||||
|
typedef struct _GLFWmonitorNull
|
||||||
|
{
|
||||||
|
GLFWgammaramp ramp;
|
||||||
|
} _GLFWmonitorNull;
|
||||||
|
|
||||||
|
// Null-specific global data
|
||||||
|
//
|
||||||
|
typedef struct _GLFWlibraryNull
|
||||||
|
{
|
||||||
|
int xcursor;
|
||||||
|
int ycursor;
|
||||||
|
char* clipboardString;
|
||||||
|
_GLFWwindow* focusedWindow;
|
||||||
|
} _GLFWlibraryNull;
|
||||||
|
|
||||||
|
void _glfwPollMonitorsNull(void);
|
||||||
|
|||||||
509
glfw/null_window.c
vendored
509
glfw/null_window.c
vendored
@@ -30,12 +30,71 @@
|
|||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
#include "../kitty/monotonic.h"
|
#include "../kitty/monotonic.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
static void applySizeLimits(_GLFWwindow* window, int* width, int* height)
|
||||||
|
{
|
||||||
|
if (window->numer != GLFW_DONT_CARE && window->denom != GLFW_DONT_CARE)
|
||||||
|
{
|
||||||
|
const float ratio = (float) window->numer / (float) window->denom;
|
||||||
|
*height = (int) (*width / ratio);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (window->minwidth != GLFW_DONT_CARE && *width < window->minwidth)
|
||||||
|
*width = window->minwidth;
|
||||||
|
else if (window->maxwidth != GLFW_DONT_CARE && *width > window->maxwidth)
|
||||||
|
*width = window->maxwidth;
|
||||||
|
|
||||||
|
if (window->minheight != GLFW_DONT_CARE && *height < window->minheight)
|
||||||
|
*height = window->minheight;
|
||||||
|
else if (window->maxheight != GLFW_DONT_CARE && *height > window->maxheight)
|
||||||
|
*height = window->maxheight;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fitToMonitor(_GLFWwindow* window)
|
||||||
|
{
|
||||||
|
GLFWvidmode mode;
|
||||||
|
_glfwPlatformGetVideoMode(window->monitor, &mode);
|
||||||
|
_glfwPlatformGetMonitorPos(window->monitor,
|
||||||
|
&window->null.xpos,
|
||||||
|
&window->null.ypos);
|
||||||
|
window->null.width = mode.width;
|
||||||
|
window->null.height = mode.height;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void acquireMonitor(_GLFWwindow* window)
|
||||||
|
{
|
||||||
|
_glfwInputMonitorWindow(window->monitor, window);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void releaseMonitor(_GLFWwindow* window)
|
||||||
|
{
|
||||||
|
if (window->monitor->window != window)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_glfwInputMonitorWindow(window->monitor, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
static int createNativeWindow(_GLFWwindow* window,
|
static int createNativeWindow(_GLFWwindow* window,
|
||||||
const _GLFWwndconfig* wndconfig)
|
const _GLFWwndconfig* wndconfig,
|
||||||
|
const _GLFWfbconfig* fbconfig)
|
||||||
{
|
{
|
||||||
window->null.width = wndconfig->width;
|
if (window->monitor)
|
||||||
window->null.height = wndconfig->height;
|
fitToMonitor(window);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
window->null.xpos = 17;
|
||||||
|
window->null.ypos = 17;
|
||||||
|
window->null.width = wndconfig->width;
|
||||||
|
window->null.height = wndconfig->height;
|
||||||
|
}
|
||||||
|
|
||||||
|
window->null.visible = wndconfig->visible;
|
||||||
|
window->null.decorated = wndconfig->decorated;
|
||||||
|
window->null.maximized = wndconfig->maximized;
|
||||||
|
window->null.floating = wndconfig->floating;
|
||||||
|
window->null.transparent = fbconfig->transparent;
|
||||||
|
window->null.opacity = 1.f;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -50,7 +109,7 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window,
|
|||||||
const _GLFWctxconfig* ctxconfig,
|
const _GLFWctxconfig* ctxconfig,
|
||||||
const _GLFWfbconfig* fbconfig)
|
const _GLFWfbconfig* fbconfig)
|
||||||
{
|
{
|
||||||
if (!createNativeWindow(window, wndconfig))
|
if (!createNativeWindow(window, wndconfig, fbconfig))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (ctxconfig->client != GLFW_NO_API)
|
if (ctxconfig->client != GLFW_NO_API)
|
||||||
@@ -70,11 +129,24 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (window->monitor)
|
||||||
|
{
|
||||||
|
_glfwPlatformShowWindow(window);
|
||||||
|
_glfwPlatformFocusWindow(window);
|
||||||
|
acquireMonitor(window);
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformDestroyWindow(_GLFWwindow* window)
|
void _glfwPlatformDestroyWindow(_GLFWwindow* window)
|
||||||
{
|
{
|
||||||
|
if (window->monitor)
|
||||||
|
releaseMonitor(window);
|
||||||
|
|
||||||
|
if (_glfw.null.focusedWindow == window)
|
||||||
|
_glfw.null.focusedWindow = NULL;
|
||||||
|
|
||||||
if (window->context.destroy)
|
if (window->context.destroy)
|
||||||
window->context.destroy(window);
|
window->context.destroy(window);
|
||||||
}
|
}
|
||||||
@@ -88,20 +160,60 @@ void _glfwPlatformSetWindowIcon(_GLFWwindow* window UNUSED, int count UNUSED,
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformSetWindowMonitor(_GLFWwindow* window UNUSED,
|
void _glfwPlatformSetWindowMonitor(_GLFWwindow* window,
|
||||||
_GLFWmonitor* monitor UNUSED,
|
_GLFWmonitor* monitor,
|
||||||
int xpos UNUSED, int ypos UNUSED,
|
int xpos, int ypos,
|
||||||
int width UNUSED, int height UNUSED,
|
int width, int height,
|
||||||
int refreshRate UNUSED)
|
int refreshRate UNUSED)
|
||||||
{
|
{
|
||||||
|
if (window->monitor == monitor)
|
||||||
|
{
|
||||||
|
if (!monitor)
|
||||||
|
{
|
||||||
|
_glfwPlatformSetWindowPos(window, xpos, ypos);
|
||||||
|
_glfwPlatformSetWindowSize(window, width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (window->monitor)
|
||||||
|
releaseMonitor(window);
|
||||||
|
|
||||||
|
_glfwInputWindowMonitor(window, monitor);
|
||||||
|
|
||||||
|
if (window->monitor)
|
||||||
|
{
|
||||||
|
window->null.visible = true;
|
||||||
|
acquireMonitor(window);
|
||||||
|
fitToMonitor(window);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_glfwPlatformSetWindowPos(window, xpos, ypos);
|
||||||
|
_glfwPlatformSetWindowSize(window, width, height);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformGetWindowPos(_GLFWwindow* window UNUSED, int* xpos UNUSED, int* ypos UNUSED)
|
void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos)
|
||||||
{
|
{
|
||||||
|
if (xpos)
|
||||||
|
*xpos = window->null.xpos;
|
||||||
|
if (ypos)
|
||||||
|
*ypos = window->null.ypos;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformSetWindowPos(_GLFWwindow* window UNUSED, int xpos UNUSED, int ypos UNUSED)
|
void _glfwPlatformSetWindowPos(_GLFWwindow* window, int xpos, int ypos)
|
||||||
{
|
{
|
||||||
|
if (window->monitor)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (window->null.xpos != xpos || window->null.ypos != ypos)
|
||||||
|
{
|
||||||
|
window->null.xpos = xpos;
|
||||||
|
window->null.ypos = ypos;
|
||||||
|
_glfwInputWindowPos(window, xpos, ypos);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height)
|
void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height)
|
||||||
@@ -114,18 +226,34 @@ void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height)
|
|||||||
|
|
||||||
void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height)
|
void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height)
|
||||||
{
|
{
|
||||||
window->null.width = width;
|
if (window->monitor)
|
||||||
window->null.height = height;
|
return;
|
||||||
|
|
||||||
|
if (window->null.width != width || window->null.height != height)
|
||||||
|
{
|
||||||
|
window->null.width = width;
|
||||||
|
window->null.height = height;
|
||||||
|
_glfwInputWindowSize(window, width, height);
|
||||||
|
_glfwInputFramebufferSize(window, width, height);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window UNUSED,
|
void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window,
|
||||||
int minwidth UNUSED, int minheight UNUSED,
|
int minwidth UNUSED, int minheight UNUSED,
|
||||||
int maxwidth UNUSED, int maxheight UNUSED)
|
int maxwidth UNUSED, int maxheight UNUSED)
|
||||||
{
|
{
|
||||||
|
int width = window->null.width;
|
||||||
|
int height = window->null.height;
|
||||||
|
applySizeLimits(window, &width, &height);
|
||||||
|
_glfwPlatformSetWindowSize(window, width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window UNUSED, int n UNUSED, int d UNUSED)
|
void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window, int n UNUSED, int d UNUSED)
|
||||||
{
|
{
|
||||||
|
int width = window->null.width;
|
||||||
|
int height = window->null.height;
|
||||||
|
applySizeLimits(window, &width, &height);
|
||||||
|
_glfwPlatformSetWindowSize(window, width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformSetWindowSizeIncrements(_GLFWwindow* window UNUSED, int widthincr UNUSED, int heightincr UNUSED)
|
void _glfwPlatformSetWindowSizeIncrements(_GLFWwindow* window UNUSED, int widthincr UNUSED, int heightincr UNUSED)
|
||||||
@@ -140,10 +268,32 @@ void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* heigh
|
|||||||
*height = window->null.height;
|
*height = window->null.height;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window UNUSED,
|
void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window,
|
||||||
int* left UNUSED, int* top UNUSED,
|
int* left, int* top,
|
||||||
int* right UNUSED, int* bottom UNUSED)
|
int* right, int* bottom)
|
||||||
{
|
{
|
||||||
|
if (window->null.decorated && !window->monitor)
|
||||||
|
{
|
||||||
|
if (left)
|
||||||
|
*left = 1;
|
||||||
|
if (top)
|
||||||
|
*top = 10;
|
||||||
|
if (right)
|
||||||
|
*right = 1;
|
||||||
|
if (bottom)
|
||||||
|
*bottom = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (left)
|
||||||
|
*left = 0;
|
||||||
|
if (top)
|
||||||
|
*top = 0;
|
||||||
|
if (right)
|
||||||
|
*right = 0;
|
||||||
|
if (bottom)
|
||||||
|
*bottom = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformGetWindowContentScale(_GLFWwindow* window UNUSED,
|
void _glfwPlatformGetWindowContentScale(_GLFWwindow* window UNUSED,
|
||||||
@@ -160,59 +310,111 @@ monotonic_t _glfwPlatformGetDoubleClickInterval(_GLFWwindow* window UNUSED)
|
|||||||
return ms_to_monotonic_t(500ll);
|
return ms_to_monotonic_t(500ll);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformIconifyWindow(_GLFWwindow* window UNUSED)
|
void _glfwPlatformIconifyWindow(_GLFWwindow* window)
|
||||||
|
{
|
||||||
|
if (_glfw.null.focusedWindow == window)
|
||||||
|
{
|
||||||
|
_glfw.null.focusedWindow = NULL;
|
||||||
|
_glfwInputWindowFocus(window, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!window->null.iconified)
|
||||||
|
{
|
||||||
|
window->null.iconified = true;
|
||||||
|
_glfwInputWindowIconify(window, true);
|
||||||
|
|
||||||
|
if (window->monitor)
|
||||||
|
releaseMonitor(window);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwPlatformRestoreWindow(_GLFWwindow* window)
|
||||||
|
{
|
||||||
|
if (window->null.iconified)
|
||||||
|
{
|
||||||
|
window->null.iconified = false;
|
||||||
|
_glfwInputWindowIconify(window, false);
|
||||||
|
|
||||||
|
if (window->monitor)
|
||||||
|
acquireMonitor(window);
|
||||||
|
}
|
||||||
|
else if (window->null.maximized)
|
||||||
|
{
|
||||||
|
window->null.maximized = false;
|
||||||
|
_glfwInputWindowMaximize(window, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwPlatformMaximizeWindow(_GLFWwindow* window)
|
||||||
|
{
|
||||||
|
if (!window->null.maximized)
|
||||||
|
{
|
||||||
|
window->null.maximized = true;
|
||||||
|
_glfwInputWindowMaximize(window, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int _glfwPlatformWindowMaximized(_GLFWwindow* window)
|
||||||
|
{
|
||||||
|
return window->null.maximized;
|
||||||
|
}
|
||||||
|
|
||||||
|
int _glfwPlatformWindowHovered(_GLFWwindow* window)
|
||||||
|
{
|
||||||
|
return _glfw.null.xcursor >= window->null.xpos &&
|
||||||
|
_glfw.null.ycursor >= window->null.ypos &&
|
||||||
|
_glfw.null.xcursor <= window->null.xpos + window->null.width - 1 &&
|
||||||
|
_glfw.null.ycursor <= window->null.ypos + window->null.height - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int _glfwPlatformFramebufferTransparent(_GLFWwindow* window)
|
||||||
|
{
|
||||||
|
return window->null.transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwPlatformSetWindowResizable(_GLFWwindow* window, bool enabled)
|
||||||
|
{
|
||||||
|
window->null.resizable = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwPlatformSetWindowDecorated(_GLFWwindow* window, bool enabled)
|
||||||
|
{
|
||||||
|
window->null.decorated = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwPlatformSetWindowFloating(_GLFWwindow* window, bool enabled)
|
||||||
|
{
|
||||||
|
window->null.floating = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwPlatformSetWindowMousePassthrough(_GLFWwindow* window UNUSED, bool enabled UNUSED)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformRestoreWindow(_GLFWwindow* window UNUSED)
|
float _glfwPlatformGetWindowOpacity(_GLFWwindow* window)
|
||||||
|
{
|
||||||
|
return window->null.opacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwPlatformSetWindowOpacity(_GLFWwindow* window, float opacity)
|
||||||
|
{
|
||||||
|
window->null.opacity = opacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwPlatformSetRawMouseMotion(_GLFWwindow *window UNUSED, bool enabled UNUSED)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformMaximizeWindow(_GLFWwindow* window UNUSED)
|
bool _glfwPlatformRawMouseMotionSupported(void)
|
||||||
{
|
{
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int _glfwPlatformWindowMaximized(_GLFWwindow* window UNUSED)
|
void _glfwPlatformShowWindow(_GLFWwindow* window)
|
||||||
{
|
{
|
||||||
return false;
|
window->null.visible = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int _glfwPlatformWindowHovered(_GLFWwindow* window UNUSED)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int _glfwPlatformFramebufferTransparent(_GLFWwindow* window UNUSED)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void _glfwPlatformSetWindowResizable(_GLFWwindow* window UNUSED, bool enabled UNUSED)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void _glfwPlatformSetWindowDecorated(_GLFWwindow* window UNUSED, bool enabled UNUSED)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void _glfwPlatformSetWindowFloating(_GLFWwindow* window UNUSED, bool enabled UNUSED)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
float _glfwPlatformGetWindowOpacity(_GLFWwindow* window UNUSED)
|
|
||||||
{
|
|
||||||
return 1.f;
|
|
||||||
}
|
|
||||||
|
|
||||||
void _glfwPlatformSetWindowOpacity(_GLFWwindow* window UNUSED, float opacity UNUSED)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void _glfwPlatformShowWindow(_GLFWwindow* window UNUSED)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void _glfwPlatformRequestWindowAttention(_GLFWwindow* window UNUSED)
|
void _glfwPlatformRequestWindowAttention(_GLFWwindow* window UNUSED)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -222,21 +424,41 @@ int _glfwPlatformWindowBell(_GLFWwindow* window UNUSED)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformUnhideWindow(_GLFWwindow* window UNUSED)
|
void _glfwPlatformHideWindow(_GLFWwindow* window)
|
||||||
{
|
{
|
||||||
|
if (_glfw.null.focusedWindow == window)
|
||||||
|
{
|
||||||
|
_glfw.null.focusedWindow = NULL;
|
||||||
|
_glfwInputWindowFocus(window, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
window->null.visible = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformHideWindow(_GLFWwindow* window UNUSED)
|
void _glfwPlatformFocusWindow(_GLFWwindow* window)
|
||||||
{
|
{
|
||||||
|
if (_glfw.null.focusedWindow == window)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!window->null.visible)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_GLFWwindow* previous = _glfw.null.focusedWindow;
|
||||||
|
_glfw.null.focusedWindow = window;
|
||||||
|
|
||||||
|
if (previous)
|
||||||
|
{
|
||||||
|
_glfwInputWindowFocus(previous, false);
|
||||||
|
if (previous->monitor && previous->autoIconify)
|
||||||
|
_glfwPlatformIconifyWindow(previous);
|
||||||
|
}
|
||||||
|
|
||||||
|
_glfwInputWindowFocus(window, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformFocusWindow(_GLFWwindow* window UNUSED)
|
int _glfwPlatformWindowFocused(_GLFWwindow* window)
|
||||||
{
|
{
|
||||||
}
|
return _glfw.null.focusedWindow == window;
|
||||||
|
|
||||||
int _glfwPlatformWindowFocused(_GLFWwindow* window UNUSED)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int _glfwPlatformWindowOccluded(_GLFWwindow* window UNUSED)
|
int _glfwPlatformWindowOccluded(_GLFWwindow* window UNUSED)
|
||||||
@@ -244,14 +466,14 @@ int _glfwPlatformWindowOccluded(_GLFWwindow* window UNUSED)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int _glfwPlatformWindowIconified(_GLFWwindow* window UNUSED)
|
int _glfwPlatformWindowIconified(_GLFWwindow* window)
|
||||||
{
|
{
|
||||||
return false;
|
return window->null.iconified;
|
||||||
}
|
}
|
||||||
|
|
||||||
int _glfwPlatformWindowVisible(_GLFWwindow* window UNUSED)
|
int _glfwPlatformWindowVisible(_GLFWwindow* window)
|
||||||
{
|
{
|
||||||
return false;
|
return window->null.visible;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformPollEvents(void)
|
void _glfwPlatformPollEvents(void)
|
||||||
@@ -270,12 +492,18 @@ void _glfwPlatformPostEmptyEvent(void)
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformGetCursorPos(_GLFWwindow* window UNUSED, double* xpos UNUSED, double* ypos UNUSED)
|
void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos)
|
||||||
{
|
{
|
||||||
|
if (xpos)
|
||||||
|
*xpos = _glfw.null.xcursor - window->null.xpos;
|
||||||
|
if (ypos)
|
||||||
|
*ypos = _glfw.null.ycursor - window->null.ypos;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformSetCursorPos(_GLFWwindow* window UNUSED, double x UNUSED, double y UNUSED)
|
void _glfwPlatformSetCursorPos(_GLFWwindow* window, double x, double y)
|
||||||
{
|
{
|
||||||
|
_glfw.null.xcursor = window->null.xpos + (int) x;
|
||||||
|
_glfw.null.ycursor = window->null.ypos + (int) y;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformSetCursorMode(_GLFWwindow* window UNUSED, int mode UNUSED)
|
void _glfwPlatformSetCursorMode(_GLFWwindow* window UNUSED, int mode UNUSED)
|
||||||
@@ -302,23 +530,142 @@ void _glfwPlatformSetCursor(_GLFWwindow* window UNUSED, _GLFWcursor* cursor UNUS
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformSetClipboardString(const char* string UNUSED)
|
void _glfwPlatformSetClipboardString(const char* string)
|
||||||
{
|
{
|
||||||
|
char* copy = _glfw_strdup(string);
|
||||||
|
free(_glfw.null.clipboardString);
|
||||||
|
_glfw.null.clipboardString = copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* _glfwPlatformGetClipboardString(void)
|
const char* _glfwPlatformGetClipboardString(void)
|
||||||
{
|
{
|
||||||
|
return _glfw.null.clipboardString;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* _glfwPlatformGetNativeKeyName(int native_key)
|
||||||
|
{
|
||||||
|
switch (scancode)
|
||||||
|
{
|
||||||
|
case GLFW_KEY_APOSTROPHE:
|
||||||
|
return "'";
|
||||||
|
case GLFW_KEY_COMMA:
|
||||||
|
return ",";
|
||||||
|
case GLFW_KEY_MINUS:
|
||||||
|
case GLFW_KEY_KP_SUBTRACT:
|
||||||
|
return "-";
|
||||||
|
case GLFW_KEY_PERIOD:
|
||||||
|
case GLFW_KEY_KP_DECIMAL:
|
||||||
|
return ".";
|
||||||
|
case GLFW_KEY_SLASH:
|
||||||
|
case GLFW_KEY_KP_DIVIDE:
|
||||||
|
return "/";
|
||||||
|
case GLFW_KEY_SEMICOLON:
|
||||||
|
return ";";
|
||||||
|
case GLFW_KEY_EQUAL:
|
||||||
|
case GLFW_KEY_KP_EQUAL:
|
||||||
|
return "=";
|
||||||
|
case GLFW_KEY_LEFT_BRACKET:
|
||||||
|
return "[";
|
||||||
|
case GLFW_KEY_RIGHT_BRACKET:
|
||||||
|
return "]";
|
||||||
|
case GLFW_KEY_KP_MULTIPLY:
|
||||||
|
return "*";
|
||||||
|
case GLFW_KEY_KP_ADD:
|
||||||
|
return "+";
|
||||||
|
case GLFW_KEY_BACKSLASH:
|
||||||
|
case GLFW_KEY_WORLD_1:
|
||||||
|
case GLFW_KEY_WORLD_2:
|
||||||
|
return "\\";
|
||||||
|
case GLFW_KEY_0:
|
||||||
|
case GLFW_KEY_KP_0:
|
||||||
|
return "0";
|
||||||
|
case GLFW_KEY_1:
|
||||||
|
case GLFW_KEY_KP_1:
|
||||||
|
return "1";
|
||||||
|
case GLFW_KEY_2:
|
||||||
|
case GLFW_KEY_KP_2:
|
||||||
|
return "2";
|
||||||
|
case GLFW_KEY_3:
|
||||||
|
case GLFW_KEY_KP_3:
|
||||||
|
return "3";
|
||||||
|
case GLFW_KEY_4:
|
||||||
|
case GLFW_KEY_KP_4:
|
||||||
|
return "4";
|
||||||
|
case GLFW_KEY_5:
|
||||||
|
case GLFW_KEY_KP_5:
|
||||||
|
return "5";
|
||||||
|
case GLFW_KEY_6:
|
||||||
|
case GLFW_KEY_KP_6:
|
||||||
|
return "6";
|
||||||
|
case GLFW_KEY_7:
|
||||||
|
case GLFW_KEY_KP_7:
|
||||||
|
return "7";
|
||||||
|
case GLFW_KEY_8:
|
||||||
|
case GLFW_KEY_KP_8:
|
||||||
|
return "8";
|
||||||
|
case GLFW_KEY_9:
|
||||||
|
case GLFW_KEY_KP_9:
|
||||||
|
return "9";
|
||||||
|
case GLFW_KEY_A:
|
||||||
|
return "a";
|
||||||
|
case GLFW_KEY_B:
|
||||||
|
return "b";
|
||||||
|
case GLFW_KEY_C:
|
||||||
|
return "c";
|
||||||
|
case GLFW_KEY_D:
|
||||||
|
return "d";
|
||||||
|
case GLFW_KEY_E:
|
||||||
|
return "e";
|
||||||
|
case GLFW_KEY_F:
|
||||||
|
return "f";
|
||||||
|
case GLFW_KEY_G:
|
||||||
|
return "g";
|
||||||
|
case GLFW_KEY_H:
|
||||||
|
return "h";
|
||||||
|
case GLFW_KEY_I:
|
||||||
|
return "i";
|
||||||
|
case GLFW_KEY_J:
|
||||||
|
return "j";
|
||||||
|
case GLFW_KEY_K:
|
||||||
|
return "k";
|
||||||
|
case GLFW_KEY_L:
|
||||||
|
return "l";
|
||||||
|
case GLFW_KEY_M:
|
||||||
|
return "m";
|
||||||
|
case GLFW_KEY_N:
|
||||||
|
return "n";
|
||||||
|
case GLFW_KEY_O:
|
||||||
|
return "o";
|
||||||
|
case GLFW_KEY_P:
|
||||||
|
return "p";
|
||||||
|
case GLFW_KEY_Q:
|
||||||
|
return "q";
|
||||||
|
case GLFW_KEY_R:
|
||||||
|
return "r";
|
||||||
|
case GLFW_KEY_S:
|
||||||
|
return "s";
|
||||||
|
case GLFW_KEY_T:
|
||||||
|
return "t";
|
||||||
|
case GLFW_KEY_U:
|
||||||
|
return "u";
|
||||||
|
case GLFW_KEY_V:
|
||||||
|
return "v";
|
||||||
|
case GLFW_KEY_W:
|
||||||
|
return "w";
|
||||||
|
case GLFW_KEY_X:
|
||||||
|
return "x";
|
||||||
|
case GLFW_KEY_Y:
|
||||||
|
return "y";
|
||||||
|
case GLFW_KEY_Z:
|
||||||
|
return "z";
|
||||||
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* _glfwPlatformGetNativeKeyName(int native_key UNUSED)
|
int _glfwPlatformGetNativeKeyForKey(int key)
|
||||||
{
|
{
|
||||||
return "";
|
return key;
|
||||||
}
|
|
||||||
|
|
||||||
int _glfwPlatformGetNativeKeyForKey(int key UNUSED)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformGetRequiredInstanceExtensions(char** extensions UNUSED)
|
void _glfwPlatformGetRequiredInstanceExtensions(char** extensions UNUSED)
|
||||||
@@ -338,6 +685,6 @@ VkResult _glfwPlatformCreateWindowSurface(VkInstance instance UNUSED,
|
|||||||
VkSurfaceKHR* surface UNUSED)
|
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_EXTENSION_NOT_PRESENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
4
glfw/osmesa_context.h
vendored
4
glfw/osmesa_context.h
vendored
@@ -54,10 +54,6 @@ typedef GLFWglproc (GLAPIENTRY * PFN_OSMesaGetProcAddress)(const char*);
|
|||||||
#define OSMesaGetDepthBuffer _glfw.osmesa.GetDepthBuffer
|
#define OSMesaGetDepthBuffer _glfw.osmesa.GetDepthBuffer
|
||||||
#define OSMesaGetProcAddress _glfw.osmesa.GetProcAddress
|
#define OSMesaGetProcAddress _glfw.osmesa.GetProcAddress
|
||||||
|
|
||||||
#define _GLFW_OSMESA_CONTEXT_STATE _GLFWcontextOSMesa osmesa
|
|
||||||
#define _GLFW_OSMESA_LIBRARY_CONTEXT_STATE _GLFWlibraryOSMesa osmesa
|
|
||||||
|
|
||||||
|
|
||||||
// OSMesa-specific per-context data
|
// OSMesa-specific per-context data
|
||||||
//
|
//
|
||||||
typedef struct _GLFWcontextOSMesa
|
typedef struct _GLFWcontextOSMesa
|
||||||
|
|||||||
@@ -54,6 +54,7 @@
|
|||||||
"headers": [
|
"headers": [
|
||||||
"wl_platform.h",
|
"wl_platform.h",
|
||||||
"posix_thread.h",
|
"posix_thread.h",
|
||||||
|
"wl_cursors.h",
|
||||||
"xkb_glfw.h",
|
"xkb_glfw.h",
|
||||||
"dbus_glfw.h",
|
"dbus_glfw.h",
|
||||||
"ibus_glfw.h",
|
"ibus_glfw.h",
|
||||||
@@ -78,6 +79,7 @@
|
|||||||
"wl_init.c",
|
"wl_init.c",
|
||||||
"wl_monitor.c",
|
"wl_monitor.c",
|
||||||
"wl_window.c",
|
"wl_window.c",
|
||||||
|
"wl_cursors.c",
|
||||||
"posix_thread.c",
|
"posix_thread.c",
|
||||||
"xkb_glfw.c",
|
"xkb_glfw.c",
|
||||||
"dbus_glfw.c",
|
"dbus_glfw.c",
|
||||||
|
|||||||
35
glfw/window.c
vendored
35
glfw/window.c
vendored
@@ -240,13 +240,14 @@ GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height,
|
|||||||
window->videoMode.blueBits = fbconfig.blueBits;
|
window->videoMode.blueBits = fbconfig.blueBits;
|
||||||
window->videoMode.refreshRate = _glfw.hints.refreshRate;
|
window->videoMode.refreshRate = _glfw.hints.refreshRate;
|
||||||
|
|
||||||
window->monitor = (_GLFWmonitor*) monitor;
|
window->monitor = (_GLFWmonitor*) monitor;
|
||||||
window->resizable = wndconfig.resizable;
|
window->resizable = wndconfig.resizable;
|
||||||
window->decorated = wndconfig.decorated;
|
window->decorated = wndconfig.decorated;
|
||||||
window->autoIconify = wndconfig.autoIconify;
|
window->autoIconify = wndconfig.autoIconify;
|
||||||
window->floating = wndconfig.floating;
|
window->floating = wndconfig.floating;
|
||||||
window->focusOnShow = wndconfig.focusOnShow;
|
window->focusOnShow = wndconfig.focusOnShow;
|
||||||
window->cursorMode = GLFW_CURSOR_NORMAL;
|
window->mousePassthrough = wndconfig.mousePassthrough;
|
||||||
|
window->cursorMode = GLFW_CURSOR_NORMAL;
|
||||||
|
|
||||||
window->minwidth = GLFW_DONT_CARE;
|
window->minwidth = GLFW_DONT_CARE;
|
||||||
window->minheight = GLFW_DONT_CARE;
|
window->minheight = GLFW_DONT_CARE;
|
||||||
@@ -273,6 +274,9 @@ GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (wndconfig.mousePassthrough)
|
||||||
|
_glfwPlatformSetWindowMousePassthrough(window, true);
|
||||||
|
|
||||||
if (window->monitor)
|
if (window->monitor)
|
||||||
{
|
{
|
||||||
if (wndconfig.centerCursor)
|
if (wndconfig.centerCursor)
|
||||||
@@ -422,6 +426,9 @@ GLFWAPI void glfwWindowHint(int hint, int value)
|
|||||||
case GLFW_FOCUS_ON_SHOW:
|
case GLFW_FOCUS_ON_SHOW:
|
||||||
_glfw.hints.window.focusOnShow = value ? true : false;
|
_glfw.hints.window.focusOnShow = value ? true : false;
|
||||||
return;
|
return;
|
||||||
|
case GLFW_MOUSE_PASSTHROUGH:
|
||||||
|
_glfw.hints.window.mousePassthrough = value ? true : false;
|
||||||
|
return;
|
||||||
case GLFW_CLIENT_API:
|
case GLFW_CLIENT_API:
|
||||||
_glfw.hints.context.client = value;
|
_glfw.hints.context.client = value;
|
||||||
return;
|
return;
|
||||||
@@ -440,7 +447,7 @@ GLFWAPI void glfwWindowHint(int hint, int value)
|
|||||||
case GLFW_OPENGL_FORWARD_COMPAT:
|
case GLFW_OPENGL_FORWARD_COMPAT:
|
||||||
_glfw.hints.context.forward = value ? true : false;
|
_glfw.hints.context.forward = value ? true : false;
|
||||||
return;
|
return;
|
||||||
case GLFW_OPENGL_DEBUG_CONTEXT:
|
case GLFW_CONTEXT_DEBUG:
|
||||||
_glfw.hints.context.debug = value ? true : false;
|
_glfw.hints.context.debug = value ? true : false;
|
||||||
return;
|
return;
|
||||||
case GLFW_CONTEXT_NO_ERROR:
|
case GLFW_CONTEXT_NO_ERROR:
|
||||||
@@ -905,6 +912,8 @@ GLFWAPI int glfwGetWindowAttrib(GLFWwindow* handle, int attrib)
|
|||||||
return _glfwPlatformWindowHovered(window);
|
return _glfwPlatformWindowHovered(window);
|
||||||
case GLFW_FOCUS_ON_SHOW:
|
case GLFW_FOCUS_ON_SHOW:
|
||||||
return window->focusOnShow;
|
return window->focusOnShow;
|
||||||
|
case GLFW_MOUSE_PASSTHROUGH:
|
||||||
|
return window->mousePassthrough;
|
||||||
case GLFW_TRANSPARENT_FRAMEBUFFER:
|
case GLFW_TRANSPARENT_FRAMEBUFFER:
|
||||||
return _glfwPlatformFramebufferTransparent(window);
|
return _glfwPlatformFramebufferTransparent(window);
|
||||||
case GLFW_OCCLUDED:
|
case GLFW_OCCLUDED:
|
||||||
@@ -931,7 +940,7 @@ GLFWAPI int glfwGetWindowAttrib(GLFWwindow* handle, int attrib)
|
|||||||
return window->context.robustness;
|
return window->context.robustness;
|
||||||
case GLFW_OPENGL_FORWARD_COMPAT:
|
case GLFW_OPENGL_FORWARD_COMPAT:
|
||||||
return window->context.forward;
|
return window->context.forward;
|
||||||
case GLFW_OPENGL_DEBUG_CONTEXT:
|
case GLFW_CONTEXT_DEBUG:
|
||||||
return window->context.debug;
|
return window->context.debug;
|
||||||
case GLFW_OPENGL_PROFILE:
|
case GLFW_OPENGL_PROFILE:
|
||||||
return window->context.profile;
|
return window->context.profile;
|
||||||
@@ -985,6 +994,14 @@ GLFWAPI void glfwSetWindowAttrib(GLFWwindow* handle, int attrib, int value)
|
|||||||
}
|
}
|
||||||
else if (attrib == GLFW_FOCUS_ON_SHOW)
|
else if (attrib == GLFW_FOCUS_ON_SHOW)
|
||||||
window->focusOnShow = value;
|
window->focusOnShow = value;
|
||||||
|
else if (attrib == GLFW_MOUSE_PASSTHROUGH)
|
||||||
|
{
|
||||||
|
if (window->mousePassthrough == value)
|
||||||
|
return;
|
||||||
|
|
||||||
|
window->mousePassthrough = value;
|
||||||
|
_glfwPlatformSetWindowMousePassthrough(window, value);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
_glfwInputError(GLFW_INVALID_ENUM, "Invalid window attribute 0x%08X", attrib);
|
_glfwInputError(GLFW_INVALID_ENUM, "Invalid window attribute 0x%08X", attrib);
|
||||||
}
|
}
|
||||||
|
|||||||
65
glfw/wl_cursors.c
vendored
Normal file
65
glfw/wl_cursors.c
vendored
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
// Future devs supporting whatever Wayland protocol stabilizes for cursor selection: see _themeAdd.
|
||||||
|
|
||||||
|
#include "internal.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
static int
|
||||||
|
pixels_from_scale(int scale) {
|
||||||
|
static bool queried_env = false;
|
||||||
|
static int factor = 32;
|
||||||
|
if (!queried_env) {
|
||||||
|
const char *env = getenv("XCURSOR_SIZE");
|
||||||
|
if (env) {
|
||||||
|
const int retval = atoi(env);
|
||||||
|
if (retval > 0 && retval < 2048) factor = retval;
|
||||||
|
}
|
||||||
|
queried_env = true;
|
||||||
|
}
|
||||||
|
return factor * scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct wl_cursor_theme*
|
||||||
|
glfw_wlc_theme_for_scale(int scale) {
|
||||||
|
GLFWWLCursorThemes *t = &_glfw.wl.cursor_themes;
|
||||||
|
for (size_t i = 0; i < t->count; i++) {
|
||||||
|
if (t->themes[i].scale == scale) return t->themes[i].theme;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (t->count >= t->capacity) {
|
||||||
|
t->themes = realloc(t->themes, sizeof(GLFWWLCursorTheme) * (t->count + 16));
|
||||||
|
if (!t->themes) {
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR, "Wayland: Out of memory allocating space for cursor themes");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
t->capacity = t->count + 16;
|
||||||
|
}
|
||||||
|
struct wl_cursor_theme *ans = wl_cursor_theme_load(getenv("XCURSOR_THEME"), pixels_from_scale(scale), _glfw.wl.shm);
|
||||||
|
if (!ans) {
|
||||||
|
_glfwInputError(
|
||||||
|
GLFW_PLATFORM_ERROR, "Wayland: wl_cursor_theme_load failed at scale: %d pixels: %d",
|
||||||
|
scale, pixels_from_scale(scale)
|
||||||
|
);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
GLFWWLCursorTheme *theme = t->themes + t->count++;
|
||||||
|
theme->scale = scale;
|
||||||
|
theme->theme = ans;
|
||||||
|
return ans;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
glfw_wlc_destroy(void) {
|
||||||
|
GLFWWLCursorThemes *t = &_glfw.wl.cursor_themes;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < t->count; i++) {
|
||||||
|
wl_cursor_theme_destroy(t->themes[i].theme);
|
||||||
|
}
|
||||||
|
free(t->themes);
|
||||||
|
t->themes = NULL; t->capacity = 0; t->count = 0;
|
||||||
|
}
|
||||||
18
glfw/wl_cursors.h
vendored
Normal file
18
glfw/wl_cursors.h
vendored
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
// Declarations for a HiDPI-aware cursor theme manager.
|
||||||
|
|
||||||
|
#include <wayland-cursor.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
struct wl_cursor_theme *theme;
|
||||||
|
int scale;
|
||||||
|
} GLFWWLCursorTheme;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
GLFWWLCursorTheme *themes;
|
||||||
|
size_t count, capacity;
|
||||||
|
} GLFWWLCursorThemes;
|
||||||
|
|
||||||
|
|
||||||
|
struct wl_cursor_theme* glfw_wlc_theme_for_scale(int scale);
|
||||||
|
void glfw_wlc_destroy(void);
|
||||||
89
glfw/wl_init.c
vendored
89
glfw/wl_init.c
vendored
@@ -113,7 +113,7 @@ static void pointerHandleEnter(void* data UNUSED,
|
|||||||
}
|
}
|
||||||
|
|
||||||
window->wl.decorations.focus = focus;
|
window->wl.decorations.focus = focus;
|
||||||
_glfw.wl.pointerSerial = serial;
|
_glfw.wl.serial = serial;
|
||||||
_glfw.wl.pointerFocus = window;
|
_glfw.wl.pointerFocus = window;
|
||||||
|
|
||||||
window->wl.hovered = true;
|
window->wl.hovered = true;
|
||||||
@@ -134,20 +134,23 @@ static void pointerHandleLeave(void* data UNUSED,
|
|||||||
|
|
||||||
window->wl.hovered = false;
|
window->wl.hovered = false;
|
||||||
|
|
||||||
_glfw.wl.pointerSerial = serial;
|
_glfw.wl.serial = serial;
|
||||||
_glfw.wl.pointerFocus = NULL;
|
_glfw.wl.pointerFocus = NULL;
|
||||||
_glfwInputCursorEnter(window, false);
|
_glfwInputCursorEnter(window, false);
|
||||||
_glfw.wl.cursorPreviousShape = GLFW_INVALID_CURSOR;
|
_glfw.wl.cursorPreviousShape = GLFW_INVALID_CURSOR;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void setCursor(GLFWCursorShape shape)
|
static void setCursor(GLFWCursorShape shape, _GLFWwindow* window)
|
||||||
{
|
{
|
||||||
struct wl_buffer* buffer;
|
struct wl_buffer* buffer;
|
||||||
struct wl_cursor* cursor;
|
struct wl_cursor* cursor;
|
||||||
struct wl_cursor_image* image;
|
struct wl_cursor_image* image;
|
||||||
struct wl_surface* surface = _glfw.wl.cursorSurface;
|
struct wl_surface* surface = _glfw.wl.cursorSurface;
|
||||||
|
const int scale = window->wl.scale;
|
||||||
|
|
||||||
cursor = _glfwLoadCursor(shape);
|
struct wl_cursor_theme *theme = glfw_wlc_theme_for_scale(scale);
|
||||||
|
if (!theme) return;
|
||||||
|
cursor = _glfwLoadCursor(shape, theme);
|
||||||
if (!cursor) return;
|
if (!cursor) return;
|
||||||
// TODO: handle animated cursors too.
|
// TODO: handle animated cursors too.
|
||||||
image = cursor->images[0];
|
image = cursor->images[0];
|
||||||
@@ -158,10 +161,11 @@ static void setCursor(GLFWCursorShape shape)
|
|||||||
buffer = wl_cursor_image_get_buffer(image);
|
buffer = wl_cursor_image_get_buffer(image);
|
||||||
if (!buffer)
|
if (!buffer)
|
||||||
return;
|
return;
|
||||||
wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.pointerSerial,
|
wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.serial,
|
||||||
surface,
|
surface,
|
||||||
image->hotspot_x,
|
image->hotspot_x / scale,
|
||||||
image->hotspot_y);
|
image->hotspot_y / scale);
|
||||||
|
wl_surface_set_buffer_scale(surface, scale);
|
||||||
wl_surface_attach(surface, buffer, 0, 0);
|
wl_surface_attach(surface, buffer, 0, 0);
|
||||||
wl_surface_damage(surface, 0, 0,
|
wl_surface_damage(surface, 0, 0,
|
||||||
image->width, image->height);
|
image->width, image->height);
|
||||||
@@ -225,7 +229,7 @@ static void pointerHandleMotion(void* data UNUSED,
|
|||||||
assert(0);
|
assert(0);
|
||||||
}
|
}
|
||||||
if (_glfw.wl.cursorPreviousShape != cursorShape)
|
if (_glfw.wl.cursorPreviousShape != cursorShape)
|
||||||
setCursor(cursorShape);
|
setCursor(cursorShape, window);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pointerHandleButton(void* data UNUSED,
|
static void pointerHandleButton(void* data UNUSED,
|
||||||
@@ -301,7 +305,7 @@ static void pointerHandleButton(void* data UNUSED,
|
|||||||
if (window->wl.decorations.focus != mainWindow)
|
if (window->wl.decorations.focus != mainWindow)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_glfw.wl.pointerSerial = serial;
|
_glfw.wl.serial = serial;
|
||||||
|
|
||||||
/* Makes left, right and middle 0, 1 and 2. Overall order follows evdev
|
/* Makes left, right and middle 0, 1 and 2. Overall order follows evdev
|
||||||
* codes. */
|
* codes. */
|
||||||
@@ -330,11 +334,11 @@ static void pointerHandleAxis(void* data UNUSED,
|
|||||||
axis == WL_POINTER_AXIS_VERTICAL_SCROLL);
|
axis == WL_POINTER_AXIS_VERTICAL_SCROLL);
|
||||||
|
|
||||||
if (axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL)
|
if (axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL)
|
||||||
x = wl_fixed_to_double(value) * -1;
|
x = -wl_fixed_to_double(value);
|
||||||
else if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL)
|
else if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL)
|
||||||
y = wl_fixed_to_double(value) * -1;
|
y = -wl_fixed_to_double(value);
|
||||||
|
|
||||||
_glfwInputScroll(window, x, y, 1);
|
_glfwInputScroll(window, x, y, 1, _glfw.wl.xkb.states.modifiers);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct wl_pointer_listener pointerListener = {
|
static const struct wl_pointer_listener pointerListener = {
|
||||||
@@ -372,7 +376,7 @@ static void keyboardHandleKeymap(void* data UNUSED,
|
|||||||
|
|
||||||
static void keyboardHandleEnter(void* data UNUSED,
|
static void keyboardHandleEnter(void* data UNUSED,
|
||||||
struct wl_keyboard* keyboard UNUSED,
|
struct wl_keyboard* keyboard UNUSED,
|
||||||
uint32_t serial UNUSED,
|
uint32_t serial,
|
||||||
struct wl_surface* surface,
|
struct wl_surface* surface,
|
||||||
struct wl_array* keys)
|
struct wl_array* keys)
|
||||||
{
|
{
|
||||||
@@ -388,6 +392,7 @@ static void keyboardHandleEnter(void* data UNUSED,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_glfw.wl.serial = serial;
|
||||||
_glfw.wl.keyboardFocus = window;
|
_glfw.wl.keyboardFocus = window;
|
||||||
_glfwInputWindowFocus(window, true);
|
_glfwInputWindowFocus(window, true);
|
||||||
uint32_t* key;
|
uint32_t* key;
|
||||||
@@ -403,7 +408,7 @@ static void keyboardHandleEnter(void* data UNUSED,
|
|||||||
|
|
||||||
static void keyboardHandleLeave(void* data UNUSED,
|
static void keyboardHandleLeave(void* data UNUSED,
|
||||||
struct wl_keyboard* keyboard UNUSED,
|
struct wl_keyboard* keyboard UNUSED,
|
||||||
uint32_t serial UNUSED,
|
uint32_t serial,
|
||||||
struct wl_surface* surface UNUSED)
|
struct wl_surface* surface UNUSED)
|
||||||
{
|
{
|
||||||
_GLFWwindow* window = _glfw.wl.keyboardFocus;
|
_GLFWwindow* window = _glfw.wl.keyboardFocus;
|
||||||
@@ -411,6 +416,7 @@ static void keyboardHandleLeave(void* data UNUSED,
|
|||||||
if (!window)
|
if (!window)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
_glfw.wl.serial = serial;
|
||||||
_glfw.wl.keyboardFocus = NULL;
|
_glfw.wl.keyboardFocus = NULL;
|
||||||
_glfwInputWindowFocus(window, false);
|
_glfwInputWindowFocus(window, false);
|
||||||
toggleTimer(&_glfw.wl.eventLoopData, _glfw.wl.keyRepeatInfo.keyRepeatTimer, 0);
|
toggleTimer(&_glfw.wl.eventLoopData, _glfw.wl.keyRepeatInfo.keyRepeatTimer, 0);
|
||||||
@@ -427,7 +433,7 @@ dispatchPendingKeyRepeats(id_type timer_id UNUSED, void *data UNUSED) {
|
|||||||
|
|
||||||
static void keyboardHandleKey(void* data UNUSED,
|
static void keyboardHandleKey(void* data UNUSED,
|
||||||
struct wl_keyboard* keyboard UNUSED,
|
struct wl_keyboard* keyboard UNUSED,
|
||||||
uint32_t serial UNUSED,
|
uint32_t serial,
|
||||||
uint32_t time UNUSED,
|
uint32_t time UNUSED,
|
||||||
uint32_t key,
|
uint32_t key,
|
||||||
uint32_t state)
|
uint32_t state)
|
||||||
@@ -436,6 +442,8 @@ static void keyboardHandleKey(void* data UNUSED,
|
|||||||
if (!window)
|
if (!window)
|
||||||
return;
|
return;
|
||||||
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.wl.serial = serial;
|
||||||
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;
|
_glfw.wl.keyRepeatInfo.key = 0;
|
||||||
@@ -454,12 +462,13 @@ static void keyboardHandleKey(void* data UNUSED,
|
|||||||
|
|
||||||
static void keyboardHandleModifiers(void* data UNUSED,
|
static void keyboardHandleModifiers(void* data UNUSED,
|
||||||
struct wl_keyboard* keyboard UNUSED,
|
struct wl_keyboard* keyboard UNUSED,
|
||||||
uint32_t serial UNUSED,
|
uint32_t serial,
|
||||||
uint32_t modsDepressed,
|
uint32_t modsDepressed,
|
||||||
uint32_t modsLatched,
|
uint32_t modsLatched,
|
||||||
uint32_t modsLocked,
|
uint32_t modsLocked,
|
||||||
uint32_t group)
|
uint32_t group)
|
||||||
{
|
{
|
||||||
|
_glfw.wl.serial = serial;
|
||||||
glfw_xkb_update_modifiers(&_glfw.wl.xkb, modsDepressed, modsLatched, modsLocked, 0, 0, group);
|
glfw_xkb_update_modifiers(&_glfw.wl.xkb, modsDepressed, modsLatched, modsLocked, 0, 0, group);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -708,6 +717,9 @@ glfwWaylandCheckForServerSideDecorations(void) {
|
|||||||
|
|
||||||
int _glfwPlatformInit(void)
|
int _glfwPlatformInit(void)
|
||||||
{
|
{
|
||||||
|
int i;
|
||||||
|
_GLFWmonitor* monitor;
|
||||||
|
|
||||||
_glfw.wl.cursor.handle = _glfw_dlopen("libwayland-cursor.so.0");
|
_glfw.wl.cursor.handle = _glfw_dlopen("libwayland-cursor.so.0");
|
||||||
if (!_glfw.wl.cursor.handle)
|
if (!_glfw.wl.cursor.handle)
|
||||||
{
|
{
|
||||||
@@ -759,12 +771,16 @@ int _glfwPlatformInit(void)
|
|||||||
// Sync so we got all initial output events
|
// Sync so we got all initial output events
|
||||||
wl_display_roundtrip(_glfw.wl.display);
|
wl_display_roundtrip(_glfw.wl.display);
|
||||||
|
|
||||||
#ifdef __linux__
|
for (i = 0; i < _glfw.monitorCount; ++i)
|
||||||
if (_glfw.hints.init.enableJoysticks) {
|
{
|
||||||
if (!_glfwInitJoysticksLinux())
|
monitor = _glfw.monitors[i];
|
||||||
return false;
|
if (monitor->widthMM <= 0 || monitor->heightMM <= 0)
|
||||||
|
{
|
||||||
|
// If Wayland does not provide a physical size, assume the default 96 DPI
|
||||||
|
monitor->widthMM = (int) (monitor->modes[monitor->wl.currentMode].width * 25.4f / 96.f);
|
||||||
|
monitor->heightMM = (int) (monitor->modes[monitor->wl.currentMode].height * 25.4f / 96.f);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
if (!_glfw.wl.wmBase)
|
if (!_glfw.wl.wmBase)
|
||||||
{
|
{
|
||||||
@@ -775,35 +791,21 @@ int _glfwPlatformInit(void)
|
|||||||
|
|
||||||
if (_glfw.wl.shm)
|
if (_glfw.wl.shm)
|
||||||
{
|
{
|
||||||
const char *cursorTheme = getenv("XCURSOR_THEME"), *cursorSizeStr = getenv("XCURSOR_SIZE");
|
|
||||||
char *cursorSizeEnd;
|
|
||||||
int cursorSize = 32;
|
|
||||||
if (cursorSizeStr)
|
|
||||||
{
|
|
||||||
errno = 0;
|
|
||||||
long cursorSizeLong = strtol(cursorSizeStr, &cursorSizeEnd, 10);
|
|
||||||
if (!*cursorSizeEnd && !errno && cursorSizeLong > 0 && cursorSizeLong <= INT_MAX)
|
|
||||||
cursorSize = (int)cursorSizeLong;
|
|
||||||
}
|
|
||||||
_glfw.wl.cursorTheme = wl_cursor_theme_load(cursorTheme, cursorSize, _glfw.wl.shm);
|
|
||||||
if (!_glfw.wl.cursorTheme)
|
|
||||||
{
|
|
||||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
|
||||||
"Wayland: Unable to load default cursor theme");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
_glfw.wl.cursorSurface =
|
_glfw.wl.cursorSurface =
|
||||||
wl_compositor_create_surface(_glfw.wl.compositor);
|
wl_compositor_create_surface(_glfw.wl.compositor);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"Wayland: Failed to find Wayland SHM");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformTerminate(void)
|
void _glfwPlatformTerminate(void)
|
||||||
{
|
{
|
||||||
#ifdef __linux__
|
|
||||||
_glfwTerminateJoysticksLinux();
|
|
||||||
#endif
|
|
||||||
_glfwTerminateEGL();
|
_glfwTerminateEGL();
|
||||||
if (_glfw.wl.egl.handle)
|
if (_glfw.wl.egl.handle)
|
||||||
{
|
{
|
||||||
@@ -814,8 +816,7 @@ void _glfwPlatformTerminate(void)
|
|||||||
glfw_xkb_release(&_glfw.wl.xkb);
|
glfw_xkb_release(&_glfw.wl.xkb);
|
||||||
glfw_dbus_terminate(&_glfw.wl.dbus);
|
glfw_dbus_terminate(&_glfw.wl.dbus);
|
||||||
|
|
||||||
if (_glfw.wl.cursorTheme)
|
glfw_wlc_destroy();
|
||||||
wl_cursor_theme_destroy(_glfw.wl.cursorTheme);
|
|
||||||
if (_glfw.wl.cursor.handle)
|
if (_glfw.wl.cursor.handle)
|
||||||
{
|
{
|
||||||
_glfw_dlclose(_glfw.wl.cursor.handle);
|
_glfw_dlclose(_glfw.wl.cursor.handle);
|
||||||
@@ -852,7 +853,7 @@ void _glfwPlatformTerminate(void)
|
|||||||
wl_data_source_destroy(_glfw.wl.dataSourceForClipboard);
|
wl_data_source_destroy(_glfw.wl.dataSourceForClipboard);
|
||||||
for (size_t doi=0; doi < arraysz(_glfw.wl.dataOffers); doi++) {
|
for (size_t doi=0; doi < arraysz(_glfw.wl.dataOffers); doi++) {
|
||||||
if (_glfw.wl.dataOffers[doi].id) {
|
if (_glfw.wl.dataOffers[doi].id) {
|
||||||
wl_data_offer_destroy(_glfw.wl.dataOffers[doi].id);
|
destroy_data_offer(&_glfw.wl.dataOffers[doi]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (_glfw.wl.dataDevice)
|
if (_glfw.wl.dataDevice)
|
||||||
|
|||||||
4
glfw/wl_monitor.c
vendored
4
glfw/wl_monitor.c
vendored
@@ -202,7 +202,7 @@ void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode)
|
|||||||
|
|
||||||
bool _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor UNUSED, GLFWgammaramp* ramp UNUSED)
|
bool _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor UNUSED, GLFWgammaramp* ramp UNUSED)
|
||||||
{
|
{
|
||||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
_glfwInputError(GLFW_FEATURE_UNAVAILABLE,
|
||||||
"Wayland: Gamma ramp access is not available");
|
"Wayland: Gamma ramp access is not available");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -210,7 +210,7 @@ bool _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor UNUSED, GLFWgammaramp* ramp
|
|||||||
void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor UNUSED,
|
void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor UNUSED,
|
||||||
const GLFWgammaramp* ramp UNUSED)
|
const GLFWgammaramp* ramp UNUSED)
|
||||||
{
|
{
|
||||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
_glfwInputError(GLFW_FEATURE_UNAVAILABLE,
|
||||||
"Wayland: Gamma ramp access is not available");
|
"Wayland: Gamma ramp access is not available");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
59
glfw/wl_platform.h
vendored
59
glfw/wl_platform.h
vendored
@@ -50,8 +50,7 @@ typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR
|
|||||||
#endif
|
#endif
|
||||||
#include "backend_utils.h"
|
#include "backend_utils.h"
|
||||||
#include "xkb_glfw.h"
|
#include "xkb_glfw.h"
|
||||||
#include "egl_context.h"
|
#include "wl_cursors.h"
|
||||||
#include "osmesa_context.h"
|
|
||||||
|
|
||||||
#include "wayland-xdg-shell-client-protocol.h"
|
#include "wayland-xdg-shell-client-protocol.h"
|
||||||
#include "wayland-viewporter-client-protocol.h"
|
#include "wayland-viewporter-client-protocol.h"
|
||||||
@@ -65,9 +64,6 @@ typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR
|
|||||||
#define _glfw_dlclose(handle) dlclose(handle)
|
#define _glfw_dlclose(handle) dlclose(handle)
|
||||||
#define _glfw_dlsym(handle, name) dlsym(handle, name)
|
#define _glfw_dlsym(handle, name) dlsym(handle, name)
|
||||||
|
|
||||||
#define _GLFW_EGL_NATIVE_WINDOW ((EGLNativeWindowType) window->wl.native)
|
|
||||||
#define _GLFW_EGL_NATIVE_DISPLAY ((EGLNativeDisplayType) _glfw.wl.display)
|
|
||||||
|
|
||||||
#define _GLFW_PLATFORM_WINDOW_STATE _GLFWwindowWayland wl
|
#define _GLFW_PLATFORM_WINDOW_STATE _GLFWwindowWayland wl
|
||||||
#define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryWayland wl
|
#define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryWayland wl
|
||||||
#define _GLFW_PLATFORM_MONITOR_STATE _GLFWmonitorWayland wl
|
#define _GLFW_PLATFORM_MONITOR_STATE _GLFWmonitorWayland wl
|
||||||
@@ -76,18 +72,6 @@ typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR
|
|||||||
#define _GLFW_PLATFORM_CONTEXT_STATE
|
#define _GLFW_PLATFORM_CONTEXT_STATE
|
||||||
#define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE
|
#define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE
|
||||||
|
|
||||||
struct wl_cursor_image {
|
|
||||||
uint32_t width;
|
|
||||||
uint32_t height;
|
|
||||||
uint32_t hotspot_x;
|
|
||||||
uint32_t hotspot_y;
|
|
||||||
uint32_t delay;
|
|
||||||
};
|
|
||||||
struct wl_cursor {
|
|
||||||
unsigned int image_count;
|
|
||||||
struct wl_cursor_image** images;
|
|
||||||
char* name;
|
|
||||||
};
|
|
||||||
typedef struct wl_cursor_theme* (* PFN_wl_cursor_theme_load)(const char*, int, struct wl_shm*);
|
typedef struct wl_cursor_theme* (* PFN_wl_cursor_theme_load)(const char*, int, struct wl_shm*);
|
||||||
typedef void (* PFN_wl_cursor_theme_destroy)(struct wl_cursor_theme*);
|
typedef void (* PFN_wl_cursor_theme_destroy)(struct wl_cursor_theme*);
|
||||||
typedef struct wl_cursor* (* PFN_wl_cursor_theme_get_cursor)(struct wl_cursor_theme*, const char*);
|
typedef struct wl_cursor* (* PFN_wl_cursor_theme_get_cursor)(struct wl_cursor_theme*, const char*);
|
||||||
@@ -195,28 +179,19 @@ typedef enum _GLFWWaylandOfferType
|
|||||||
|
|
||||||
typedef struct _GLFWWaylandDataOffer
|
typedef struct _GLFWWaylandDataOffer
|
||||||
{
|
{
|
||||||
struct wl_data_offer *id;
|
void *id;
|
||||||
const char *mime;
|
|
||||||
_GLFWWaylandOfferType offer_type;
|
_GLFWWaylandOfferType offer_type;
|
||||||
size_t idx;
|
size_t idx;
|
||||||
int is_self_offer;
|
bool is_self_offer;
|
||||||
int has_uri_list;
|
bool is_primary;
|
||||||
|
const char *plain_text_mime, *mime_for_drop;
|
||||||
uint32_t source_actions;
|
uint32_t source_actions;
|
||||||
uint32_t dnd_action;
|
uint32_t dnd_action;
|
||||||
struct wl_surface *surface;
|
struct wl_surface *surface;
|
||||||
|
const char **mimes;
|
||||||
|
size_t mimes_capacity, mimes_count;
|
||||||
} _GLFWWaylandDataOffer;
|
} _GLFWWaylandDataOffer;
|
||||||
|
|
||||||
typedef struct _GLFWWaylandPrimaryOffer
|
|
||||||
{
|
|
||||||
struct zwp_primary_selection_offer_v1 *id;
|
|
||||||
const char *mime;
|
|
||||||
_GLFWWaylandOfferType offer_type;
|
|
||||||
size_t idx;
|
|
||||||
int is_self_offer;
|
|
||||||
int has_uri_list;
|
|
||||||
struct wl_surface *surface;
|
|
||||||
} _GLFWWaylandPrimaryOffer;
|
|
||||||
|
|
||||||
// Wayland-specific global data
|
// Wayland-specific global data
|
||||||
//
|
//
|
||||||
typedef struct _GLFWlibraryWayland
|
typedef struct _GLFWlibraryWayland
|
||||||
@@ -229,14 +204,14 @@ typedef struct _GLFWlibraryWayland
|
|||||||
struct wl_seat* seat;
|
struct wl_seat* seat;
|
||||||
struct wl_pointer* pointer;
|
struct wl_pointer* pointer;
|
||||||
struct wl_keyboard* keyboard;
|
struct wl_keyboard* keyboard;
|
||||||
|
struct wl_data_device_manager* dataDeviceManager;
|
||||||
|
struct wl_data_device* dataDevice;
|
||||||
struct xdg_wm_base* wmBase;
|
struct xdg_wm_base* wmBase;
|
||||||
struct zxdg_decoration_manager_v1* decorationManager;
|
struct zxdg_decoration_manager_v1* decorationManager;
|
||||||
struct wp_viewporter* viewporter;
|
struct wp_viewporter* viewporter;
|
||||||
struct zwp_relative_pointer_manager_v1* relativePointerManager;
|
struct zwp_relative_pointer_manager_v1* relativePointerManager;
|
||||||
struct zwp_pointer_constraints_v1* pointerConstraints;
|
struct zwp_pointer_constraints_v1* pointerConstraints;
|
||||||
struct zwp_idle_inhibit_manager_v1* idleInhibitManager;
|
struct zwp_idle_inhibit_manager_v1* idleInhibitManager;
|
||||||
struct wl_data_device_manager* dataDeviceManager;
|
|
||||||
struct wl_data_device* dataDevice;
|
|
||||||
struct wl_data_source* dataSourceForClipboard;
|
struct wl_data_source* dataSourceForClipboard;
|
||||||
struct zwp_primary_selection_device_manager_v1* primarySelectionDeviceManager;
|
struct zwp_primary_selection_device_manager_v1* primarySelectionDeviceManager;
|
||||||
struct zwp_primary_selection_device_v1* primarySelectionDevice;
|
struct zwp_primary_selection_device_v1* primarySelectionDevice;
|
||||||
@@ -245,13 +220,13 @@ typedef struct _GLFWlibraryWayland
|
|||||||
int compositorVersion;
|
int compositorVersion;
|
||||||
int seatVersion;
|
int seatVersion;
|
||||||
|
|
||||||
struct wl_cursor_theme* cursorTheme;
|
|
||||||
struct wl_surface* cursorSurface;
|
struct wl_surface* cursorSurface;
|
||||||
GLFWCursorShape cursorPreviousShape;
|
GLFWCursorShape cursorPreviousShape;
|
||||||
uint32_t pointerSerial;
|
uint32_t serial;
|
||||||
|
|
||||||
int32_t keyboardRepeatRate;
|
int32_t keyboardRepeatRate;
|
||||||
monotonic_t keyboardRepeatDelay;
|
monotonic_t keyboardRepeatDelay;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
uint32_t key;
|
uint32_t key;
|
||||||
id_type keyRepeatTimer;
|
id_type keyRepeatTimer;
|
||||||
@@ -287,8 +262,7 @@ typedef struct _GLFWlibraryWayland
|
|||||||
size_t dataOffersCounter;
|
size_t dataOffersCounter;
|
||||||
_GLFWWaylandDataOffer dataOffers[8];
|
_GLFWWaylandDataOffer dataOffers[8];
|
||||||
char* primarySelectionString;
|
char* primarySelectionString;
|
||||||
size_t primarySelectionOffersCounter;
|
GLFWWLCursorThemes cursor_themes;
|
||||||
_GLFWWaylandPrimaryOffer primarySelectionOffers[8];
|
|
||||||
} _GLFWlibraryWayland;
|
} _GLFWlibraryWayland;
|
||||||
|
|
||||||
// Wayland-specific per-monitor data
|
// Wayland-specific per-monitor data
|
||||||
@@ -313,7 +287,11 @@ typedef struct _GLFWcursorWayland
|
|||||||
struct wl_buffer* buffer;
|
struct wl_buffer* buffer;
|
||||||
int width, height;
|
int width, height;
|
||||||
int xhot, yhot;
|
int xhot, yhot;
|
||||||
int currentImage;
|
unsigned int currentImage;
|
||||||
|
/** The scale of the cursor, or 0 if the cursor should be loaded late, or -1 if the cursor variable itself is unused. */
|
||||||
|
int scale;
|
||||||
|
/** Cursor shape stored to allow late cursor loading in setCursorImage. */
|
||||||
|
GLFWCursorShape shape;
|
||||||
} _GLFWcursorWayland;
|
} _GLFWcursorWayland;
|
||||||
|
|
||||||
|
|
||||||
@@ -321,4 +299,5 @@ void _glfwAddOutputWayland(uint32_t name, uint32_t version);
|
|||||||
void _glfwSetupWaylandDataDevice(void);
|
void _glfwSetupWaylandDataDevice(void);
|
||||||
void _glfwSetupWaylandPrimarySelectionDevice(void);
|
void _glfwSetupWaylandPrimarySelectionDevice(void);
|
||||||
void animateCursorImage(id_type timer_id, void *data);
|
void animateCursorImage(id_type timer_id, void *data);
|
||||||
struct wl_cursor* _glfwLoadCursor(GLFWCursorShape);
|
struct wl_cursor* _glfwLoadCursor(GLFWCursorShape, struct wl_cursor_theme*);
|
||||||
|
void destroy_data_offer(_GLFWWaylandDataOffer*);
|
||||||
|
|||||||
528
glfw/wl_window.c
vendored
528
glfw/wl_window.c
vendored
@@ -42,7 +42,65 @@
|
|||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
|
|
||||||
|
|
||||||
#define URI_LIST_MIME "text/uri-list"
|
static void setCursorImage(_GLFWwindow* window)
|
||||||
|
{
|
||||||
|
_GLFWcursorWayland defaultCursor = {.shape = GLFW_ARROW_CURSOR};
|
||||||
|
_GLFWcursorWayland* cursorWayland = window->cursor ? &window->cursor->wl : &defaultCursor;
|
||||||
|
struct wl_cursor_image* image = NULL;
|
||||||
|
struct wl_buffer* buffer = NULL;
|
||||||
|
struct wl_surface* surface = _glfw.wl.cursorSurface;
|
||||||
|
const int scale = window->wl.scale;
|
||||||
|
|
||||||
|
if (cursorWayland->scale < 0) {
|
||||||
|
buffer = cursorWayland->buffer;
|
||||||
|
toggleTimer(&_glfw.wl.eventLoopData, _glfw.wl.cursorAnimationTimer, 0);
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
if (cursorWayland->scale != scale) {
|
||||||
|
struct wl_cursor *newCursor = NULL;
|
||||||
|
struct wl_cursor_theme *theme = glfw_wlc_theme_for_scale(scale);
|
||||||
|
if (theme) newCursor = _glfwLoadCursor(cursorWayland->shape, theme);
|
||||||
|
if (newCursor != NULL) {
|
||||||
|
cursorWayland->cursor = newCursor;
|
||||||
|
cursorWayland->scale = scale;
|
||||||
|
cursorWayland->currentImage = 0;
|
||||||
|
} else {
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR, "Wayland: late cursor load failed; proceeding with existing cursor");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!cursorWayland->cursor || !cursorWayland->cursor->image_count)
|
||||||
|
return;
|
||||||
|
if (cursorWayland->currentImage >= cursorWayland->cursor->image_count) cursorWayland->currentImage = 0;
|
||||||
|
image = cursorWayland->cursor->images[cursorWayland->currentImage];
|
||||||
|
if (!image) image = cursorWayland->cursor->images[0];
|
||||||
|
if (!image) return;
|
||||||
|
buffer = wl_cursor_image_get_buffer(image);
|
||||||
|
if (image->delay && window->cursor) {
|
||||||
|
changeTimerInterval(&_glfw.wl.eventLoopData, _glfw.wl.cursorAnimationTimer, ms_to_monotonic_t(image->delay));
|
||||||
|
toggleTimer(&_glfw.wl.eventLoopData, _glfw.wl.cursorAnimationTimer, 1);
|
||||||
|
} else {
|
||||||
|
toggleTimer(&_glfw.wl.eventLoopData, _glfw.wl.cursorAnimationTimer, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!buffer)
|
||||||
|
return;
|
||||||
|
|
||||||
|
cursorWayland->width = image->width;
|
||||||
|
cursorWayland->height = image->height;
|
||||||
|
cursorWayland->xhot = image->hotspot_x;
|
||||||
|
cursorWayland->yhot = image->hotspot_y;
|
||||||
|
}
|
||||||
|
|
||||||
|
wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.serial,
|
||||||
|
surface,
|
||||||
|
cursorWayland->xhot / scale,
|
||||||
|
cursorWayland->yhot / scale);
|
||||||
|
wl_surface_set_buffer_scale(surface, scale);
|
||||||
|
wl_surface_attach(surface, buffer, 0, 0);
|
||||||
|
wl_surface_damage(surface, 0, 0,
|
||||||
|
cursorWayland->width, cursorWayland->height);
|
||||||
|
wl_surface_commit(surface);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static bool checkScaleChange(_GLFWwindow* window)
|
static bool checkScaleChange(_GLFWwindow* window)
|
||||||
@@ -73,6 +131,7 @@ static bool checkScaleChange(_GLFWwindow* window)
|
|||||||
{
|
{
|
||||||
window->wl.scale = scale;
|
window->wl.scale = scale;
|
||||||
wl_surface_set_buffer_scale(window->wl.surface, scale);
|
wl_surface_set_buffer_scale(window->wl.surface, scale);
|
||||||
|
setCursorImage(window);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (window->wl.monitorsCount > 0 && !window->wl.initial_scale_notified) {
|
if (window->wl.monitorsCount > 0 && !window->wl.initial_scale_notified) {
|
||||||
@@ -187,8 +246,7 @@ static void dispatchChangesAfterConfigure(_GLFWwindow *window, int32_t width, in
|
|||||||
* 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.
|
||||||
*/
|
*/
|
||||||
static int
|
static int createAnonymousFile(off_t size)
|
||||||
createAnonymousFile(off_t size)
|
|
||||||
{
|
{
|
||||||
int ret, fd = -1, shm_anon = 0;
|
int ret, fd = -1, shm_anon = 0;
|
||||||
#ifdef HAS_MEMFD_CREATE
|
#ifdef HAS_MEMFD_CREATE
|
||||||
@@ -355,10 +413,10 @@ static void createDecorations(_GLFWwindow* window)
|
|||||||
|
|
||||||
static void destroyDecoration(_GLFWdecorationWayland* decoration)
|
static void destroyDecoration(_GLFWdecorationWayland* decoration)
|
||||||
{
|
{
|
||||||
if (decoration->surface)
|
|
||||||
wl_surface_destroy(decoration->surface);
|
|
||||||
if (decoration->subsurface)
|
if (decoration->subsurface)
|
||||||
wl_subsurface_destroy(decoration->subsurface);
|
wl_subsurface_destroy(decoration->subsurface);
|
||||||
|
if (decoration->surface)
|
||||||
|
wl_surface_destroy(decoration->surface);
|
||||||
if (decoration->viewport)
|
if (decoration->viewport)
|
||||||
wp_viewport_destroy(decoration->viewport);
|
wp_viewport_destroy(decoration->viewport);
|
||||||
decoration->surface = NULL;
|
decoration->surface = NULL;
|
||||||
@@ -379,7 +437,9 @@ static void xdgDecorationHandleConfigure(void* data,
|
|||||||
uint32_t mode)
|
uint32_t mode)
|
||||||
{
|
{
|
||||||
_GLFWwindow* window = data;
|
_GLFWwindow* window = data;
|
||||||
|
|
||||||
window->wl.decorations.serverSide = (mode == ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE);
|
window->wl.decorations.serverSide = (mode == ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE);
|
||||||
|
|
||||||
if (!window->wl.decorations.serverSide)
|
if (!window->wl.decorations.serverSide)
|
||||||
createDecorations(window);
|
createDecorations(window);
|
||||||
}
|
}
|
||||||
@@ -388,9 +448,9 @@ static const struct zxdg_toplevel_decoration_v1_listener xdgDecorationListener =
|
|||||||
xdgDecorationHandleConfigure,
|
xdgDecorationHandleConfigure,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void handleEnter(void *data,
|
static void surfaceHandleEnter(void *data,
|
||||||
struct wl_surface *surface UNUSED,
|
struct wl_surface *surface UNUSED,
|
||||||
struct wl_output *output)
|
struct wl_output *output)
|
||||||
{
|
{
|
||||||
_GLFWwindow* window = data;
|
_GLFWwindow* window = data;
|
||||||
_GLFWmonitor* monitor = wl_output_get_user_data(output);
|
_GLFWmonitor* monitor = wl_output_get_user_data(output);
|
||||||
@@ -411,9 +471,9 @@ static void handleEnter(void *data,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handleLeave(void *data,
|
static void surfaceHandleLeave(void *data,
|
||||||
struct wl_surface *surface UNUSED,
|
struct wl_surface *surface UNUSED,
|
||||||
struct wl_output *output)
|
struct wl_output *output)
|
||||||
{
|
{
|
||||||
_GLFWwindow* window = data;
|
_GLFWwindow* window = data;
|
||||||
_GLFWmonitor* monitor = wl_output_get_user_data(output);
|
_GLFWmonitor* monitor = wl_output_get_user_data(output);
|
||||||
@@ -436,8 +496,8 @@ static void handleLeave(void *data,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static const struct wl_surface_listener surfaceListener = {
|
static const struct wl_surface_listener surfaceListener = {
|
||||||
handleEnter,
|
surfaceHandleEnter,
|
||||||
handleLeave
|
surfaceHandleLeave
|
||||||
};
|
};
|
||||||
|
|
||||||
static void setIdleInhibitor(_GLFWwindow* window, bool enable)
|
static void setIdleInhibitor(_GLFWwindow* window, bool enable)
|
||||||
@@ -487,8 +547,7 @@ static bool createSurface(_GLFWwindow* window,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void setFullscreen(_GLFWwindow* window, _GLFWmonitor* monitor, bool on)
|
||||||
setFullscreen(_GLFWwindow* window, _GLFWmonitor* monitor, bool on)
|
|
||||||
{
|
{
|
||||||
if (window->wl.xdg.toplevel)
|
if (window->wl.xdg.toplevel)
|
||||||
{
|
{
|
||||||
@@ -679,56 +738,15 @@ static bool createXdgSurface(_GLFWwindow* window)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void incrementCursorImage(_GLFWwindow* window)
|
||||||
setCursorImage(_GLFWcursorWayland* cursorWayland)
|
|
||||||
{
|
{
|
||||||
struct wl_cursor_image* image;
|
if (window && window->wl.decorations.focus == mainWindow && window->cursorMode != GLFW_CURSOR_HIDDEN) {
|
||||||
struct wl_buffer* buffer;
|
|
||||||
struct wl_surface* surface = _glfw.wl.cursorSurface;
|
|
||||||
|
|
||||||
if (!cursorWayland->cursor) {
|
|
||||||
buffer = cursorWayland->buffer;
|
|
||||||
toggleTimer(&_glfw.wl.eventLoopData, _glfw.wl.cursorAnimationTimer, 0);
|
|
||||||
} else
|
|
||||||
{
|
|
||||||
image = cursorWayland->cursor->images[cursorWayland->currentImage];
|
|
||||||
buffer = wl_cursor_image_get_buffer(image);
|
|
||||||
if (image->delay) {
|
|
||||||
changeTimerInterval(&_glfw.wl.eventLoopData, _glfw.wl.cursorAnimationTimer, ms_to_monotonic_t(image->delay));
|
|
||||||
toggleTimer(&_glfw.wl.eventLoopData, _glfw.wl.cursorAnimationTimer, 1);
|
|
||||||
} else {
|
|
||||||
toggleTimer(&_glfw.wl.eventLoopData, _glfw.wl.cursorAnimationTimer, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!buffer)
|
|
||||||
return;
|
|
||||||
|
|
||||||
cursorWayland->width = image->width;
|
|
||||||
cursorWayland->height = image->height;
|
|
||||||
cursorWayland->xhot = image->hotspot_x;
|
|
||||||
cursorWayland->yhot = image->hotspot_y;
|
|
||||||
}
|
|
||||||
|
|
||||||
wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.pointerSerial,
|
|
||||||
surface,
|
|
||||||
cursorWayland->xhot,
|
|
||||||
cursorWayland->yhot);
|
|
||||||
wl_surface_attach(surface, buffer, 0, 0);
|
|
||||||
wl_surface_damage(surface, 0, 0,
|
|
||||||
cursorWayland->width, cursorWayland->height);
|
|
||||||
wl_surface_commit(surface);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
incrementCursorImage(_GLFWwindow* window)
|
|
||||||
{
|
|
||||||
if (window && window->wl.decorations.focus == mainWindow) {
|
|
||||||
_GLFWcursor* cursor = window->wl.currentCursor;
|
_GLFWcursor* cursor = window->wl.currentCursor;
|
||||||
if (cursor && cursor->wl.cursor)
|
if (cursor && cursor->wl.cursor)
|
||||||
{
|
{
|
||||||
cursor->wl.currentImage += 1;
|
cursor->wl.currentImage += 1;
|
||||||
cursor->wl.currentImage %= cursor->wl.cursor->image_count;
|
cursor->wl.currentImage %= cursor->wl.cursor->image_count;
|
||||||
setCursorImage(&cursor->wl);
|
setCursorImage(window);
|
||||||
toggleTimer(&_glfw.wl.eventLoopData, _glfw.wl.cursorAnimationTimer, cursor->wl.cursor->image_count > 1);
|
toggleTimer(&_glfw.wl.eventLoopData, _glfw.wl.cursorAnimationTimer, cursor->wl.cursor->image_count > 1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -743,12 +761,19 @@ animateCursorImage(id_type timer_id UNUSED, void *data UNUSED) {
|
|||||||
|
|
||||||
static void
|
static void
|
||||||
abortOnFatalError(int last_error) {
|
abortOnFatalError(int last_error) {
|
||||||
_glfwInputError(GLFW_PLATFORM_ERROR, "Wayland: fatal display error: %s", strerror(last_error));
|
static bool abort_called = false;
|
||||||
_GLFWwindow* window = _glfw.windowListHead;
|
if (!abort_called) {
|
||||||
while (window)
|
abort_called = true;
|
||||||
{
|
_glfwInputError(GLFW_PLATFORM_ERROR, "Wayland: fatal display error: %s", strerror(last_error));
|
||||||
_glfwInputWindowCloseRequest(window);
|
if (_glfw.callbacks.application_close) _glfw.callbacks.application_close(1);
|
||||||
window = window->next;
|
else {
|
||||||
|
_GLFWwindow* window = _glfw.windowListHead;
|
||||||
|
while (window)
|
||||||
|
{
|
||||||
|
_glfwInputWindowCloseRequest(window);
|
||||||
|
window = window->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// ensure the tick callback is called
|
// ensure the tick callback is called
|
||||||
_glfw.wl.eventLoopData.wakeup_data_read = true;
|
_glfw.wl.eventLoopData.wakeup_data_read = true;
|
||||||
@@ -761,8 +786,7 @@ wayland_read_events(int poll_result, int events, void *data UNUSED) {
|
|||||||
else wl_display_cancel_read(_glfw.wl.display);
|
else wl_display_cancel_read(_glfw.wl.display);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void handleEvents(monotonic_t timeout)
|
||||||
handleEvents(monotonic_t timeout)
|
|
||||||
{
|
{
|
||||||
struct wl_display* display = _glfw.wl.display;
|
struct wl_display* display = _glfw.wl.display;
|
||||||
errno = 0;
|
errno = 0;
|
||||||
@@ -804,24 +828,25 @@ handleEvents(monotonic_t timeout)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static struct wl_cursor*
|
static struct wl_cursor*
|
||||||
try_cursor_names(int arg_count, ...) {
|
try_cursor_names(struct wl_cursor_theme* theme, int arg_count, ...) {
|
||||||
struct wl_cursor* ans = NULL;
|
struct wl_cursor* ans = NULL;
|
||||||
va_list ap;
|
va_list ap;
|
||||||
va_start(ap, arg_count);
|
va_start(ap, arg_count);
|
||||||
for (int i = 0; i < arg_count && !ans; i++) {
|
for (int i = 0; i < arg_count && !ans; i++) {
|
||||||
const char *name = va_arg(ap, const char *);
|
const char *name = va_arg(ap, const char *);
|
||||||
ans = wl_cursor_theme_get_cursor(_glfw.wl.cursorTheme, name);
|
ans = wl_cursor_theme_get_cursor(theme, name);
|
||||||
}
|
}
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
return ans;
|
return ans;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct wl_cursor* _glfwLoadCursor(GLFWCursorShape shape)
|
struct wl_cursor* _glfwLoadCursor(GLFWCursorShape shape, struct wl_cursor_theme* theme)
|
||||||
{
|
{
|
||||||
static bool warnings[GLFW_INVALID_CURSOR] = {0};
|
static bool warnings[GLFW_INVALID_CURSOR] = {0};
|
||||||
|
if (!theme) return NULL;
|
||||||
#define NUMARGS(...) (sizeof((const char*[]){__VA_ARGS__})/sizeof(const char*))
|
#define NUMARGS(...) (sizeof((const char*[]){__VA_ARGS__})/sizeof(const char*))
|
||||||
#define C(name, ...) case name: { \
|
#define C(name, ...) case name: { \
|
||||||
ans = try_cursor_names(NUMARGS(__VA_ARGS__), __VA_ARGS__); \
|
ans = try_cursor_names(theme, NUMARGS(__VA_ARGS__), __VA_ARGS__); \
|
||||||
if (!ans && !warnings[name]) {\
|
if (!ans && !warnings[name]) {\
|
||||||
_glfwInputError(GLFW_PLATFORM_ERROR, "Wayland: Could not find standard cursor: %s", #name); \
|
_glfwInputError(GLFW_PLATFORM_ERROR, "Wayland: Could not find standard cursor: %s", #name); \
|
||||||
warnings[name] = true; \
|
warnings[name] = true; \
|
||||||
@@ -831,7 +856,7 @@ struct wl_cursor* _glfwLoadCursor(GLFWCursorShape shape)
|
|||||||
struct wl_cursor* ans = NULL;
|
struct wl_cursor* ans = NULL;
|
||||||
switch (shape)
|
switch (shape)
|
||||||
{
|
{
|
||||||
C(GLFW_ARROW_CURSOR, "arrow", "left_ptr", "default")
|
C(GLFW_ARROW_CURSOR, "left_ptr", "arrow", "default")
|
||||||
C(GLFW_IBEAM_CURSOR, "xterm", "ibeam", "text")
|
C(GLFW_IBEAM_CURSOR, "xterm", "ibeam", "text")
|
||||||
C(GLFW_CROSSHAIR_CURSOR, "crosshair", "cross")
|
C(GLFW_CROSSHAIR_CURSOR, "crosshair", "cross")
|
||||||
C(GLFW_HAND_CURSOR, "hand2", "grab", "grabbing", "closedhand")
|
C(GLFW_HAND_CURSOR, "hand2", "grab", "grabbing", "closedhand")
|
||||||
@@ -901,6 +926,7 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window,
|
|||||||
}
|
}
|
||||||
|
|
||||||
window->wl.currentCursor = NULL;
|
window->wl.currentCursor = NULL;
|
||||||
|
// Don't set window->wl.cursorTheme to NULL here.
|
||||||
|
|
||||||
window->wl.monitors = calloc(1, sizeof(_GLFWmonitor*));
|
window->wl.monitors = calloc(1, sizeof(_GLFWmonitor*));
|
||||||
window->wl.monitorsCount = 0;
|
window->wl.monitorsCount = 0;
|
||||||
@@ -957,12 +983,10 @@ void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title)
|
|||||||
{
|
{
|
||||||
if (window->wl.title)
|
if (window->wl.title)
|
||||||
free(window->wl.title);
|
free(window->wl.title);
|
||||||
window->wl.title = _glfw_strdup(title);
|
|
||||||
// Wayland cannot handle requests larger than ~8200 bytes. Sending
|
// Wayland cannot handle requests larger than ~8200 bytes. Sending
|
||||||
// on causes an abort(). Since titles this large are meaningless anyway
|
// one causes an abort(). Since titles this large are meaningless anyway
|
||||||
// ensure they do not happen. One should really truncate ensuring valid UTF-8
|
// ensure they do not happen.
|
||||||
// but I cant be bothered.
|
window->wl.title = utf_8_strndup(title, 2048);
|
||||||
if (title && strnlen(title, 2048) >= 2048) window->wl.title[2048] = 0;
|
|
||||||
if (window->wl.xdg.toplevel)
|
if (window->wl.xdg.toplevel)
|
||||||
xdg_toplevel_set_title(window->wl.xdg.toplevel, window->wl.title);
|
xdg_toplevel_set_title(window->wl.xdg.toplevel, window->wl.title);
|
||||||
}
|
}
|
||||||
@@ -970,8 +994,8 @@ void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title)
|
|||||||
void _glfwPlatformSetWindowIcon(_GLFWwindow* window UNUSED,
|
void _glfwPlatformSetWindowIcon(_GLFWwindow* window UNUSED,
|
||||||
int count UNUSED, const GLFWimage* images UNUSED)
|
int count UNUSED, const GLFWimage* images UNUSED)
|
||||||
{
|
{
|
||||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
_glfwInputError(GLFW_FEATURE_UNAVAILABLE,
|
||||||
"Wayland: Setting window icon not supported");
|
"Wayland: The platform does not support setting the window icon");
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformGetWindowPos(_GLFWwindow* window UNUSED, int* xpos UNUSED, int* ypos UNUSED)
|
void _glfwPlatformGetWindowPos(_GLFWwindow* window UNUSED, int* xpos UNUSED, int* ypos UNUSED)
|
||||||
@@ -979,16 +1003,16 @@ void _glfwPlatformGetWindowPos(_GLFWwindow* window UNUSED, int* xpos UNUSED, int
|
|||||||
// A Wayland client is not aware of its position, so just warn and leave it
|
// A Wayland client is not aware of its position, so just warn and leave it
|
||||||
// as (0, 0)
|
// as (0, 0)
|
||||||
|
|
||||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
_glfwInputError(GLFW_FEATURE_UNAVAILABLE,
|
||||||
"Wayland: Window position retrieval not supported");
|
"Wayland: The platform does not provide the window position");
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformSetWindowPos(_GLFWwindow* window UNUSED, int xpos UNUSED, int ypos UNUSED)
|
void _glfwPlatformSetWindowPos(_GLFWwindow* window UNUSED, int xpos UNUSED, int ypos UNUSED)
|
||||||
{
|
{
|
||||||
// A Wayland client can not set its position, so just warn
|
// A Wayland client can not set its position, so just warn
|
||||||
|
|
||||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
_glfwInputError(GLFW_FEATURE_UNAVAILABLE,
|
||||||
"Wayland: Window position setting not supported");
|
"Wayland: The platform does not support setting the window position");
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height)
|
void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height)
|
||||||
@@ -1029,6 +1053,8 @@ void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window UNUSED,
|
|||||||
{
|
{
|
||||||
// TODO: find out how to trigger a resize.
|
// TODO: find out how to trigger a resize.
|
||||||
// The actual limits are checked in the xdg_toplevel::configure handler.
|
// The actual limits are checked in the xdg_toplevel::configure handler.
|
||||||
|
_glfwInputError(GLFW_FEATURE_UNIMPLEMENTED,
|
||||||
|
"Wayland: Window aspect ratio not yet implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformSetWindowSizeIncrements(_GLFWwindow* window UNUSED,
|
void _glfwPlatformSetWindowSizeIncrements(_GLFWwindow* window UNUSED,
|
||||||
@@ -1042,8 +1068,10 @@ void _glfwPlatformGetFramebufferSize(_GLFWwindow* window,
|
|||||||
int* width, int* height)
|
int* width, int* height)
|
||||||
{
|
{
|
||||||
_glfwPlatformGetWindowSize(window, width, height);
|
_glfwPlatformGetWindowSize(window, width, height);
|
||||||
*width *= window->wl.scale;
|
if (width)
|
||||||
*height *= window->wl.scale;
|
*width *= window->wl.scale;
|
||||||
|
if (height)
|
||||||
|
*height *= window->wl.scale;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window,
|
void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window,
|
||||||
@@ -1133,7 +1161,7 @@ void _glfwPlatformRequestWindowAttention(_GLFWwindow* window UNUSED)
|
|||||||
// TODO
|
// TODO
|
||||||
static bool notified = false;
|
static bool notified = false;
|
||||||
if (!notified) {
|
if (!notified) {
|
||||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
_glfwInputError(GLFW_FEATURE_UNIMPLEMENTED,
|
||||||
"Wayland: Window attention request not implemented yet");
|
"Wayland: Window attention request not implemented yet");
|
||||||
notified = true;
|
notified = true;
|
||||||
}
|
}
|
||||||
@@ -1154,8 +1182,8 @@ int _glfwPlatformWindowBell(_GLFWwindow* window UNUSED)
|
|||||||
|
|
||||||
void _glfwPlatformFocusWindow(_GLFWwindow* window UNUSED)
|
void _glfwPlatformFocusWindow(_GLFWwindow* window UNUSED)
|
||||||
{
|
{
|
||||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
_glfwInputError(GLFW_FEATURE_UNAVAILABLE,
|
||||||
"Wayland: Focusing a window requires user interaction");
|
"Wayland: The platform does not support setting the input focus");
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformSetWindowMonitor(_GLFWwindow* window,
|
void _glfwPlatformSetWindowMonitor(_GLFWwindow* window,
|
||||||
@@ -1208,7 +1236,7 @@ int _glfwPlatformFramebufferTransparent(_GLFWwindow* window)
|
|||||||
void _glfwPlatformSetWindowResizable(_GLFWwindow* window UNUSED, bool enabled UNUSED)
|
void _glfwPlatformSetWindowResizable(_GLFWwindow* window UNUSED, bool enabled UNUSED)
|
||||||
{
|
{
|
||||||
// TODO
|
// TODO
|
||||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
_glfwInputError(GLFW_FEATURE_UNIMPLEMENTED,
|
||||||
"Wayland: Window attribute setting not implemented yet");
|
"Wayland: Window attribute setting not implemented yet");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1226,10 +1254,23 @@ void _glfwPlatformSetWindowDecorated(_GLFWwindow* window, bool enabled)
|
|||||||
void _glfwPlatformSetWindowFloating(_GLFWwindow* window UNUSED, bool enabled UNUSED)
|
void _glfwPlatformSetWindowFloating(_GLFWwindow* window UNUSED, bool enabled UNUSED)
|
||||||
{
|
{
|
||||||
// TODO
|
// TODO
|
||||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
_glfwInputError(GLFW_FEATURE_UNIMPLEMENTED,
|
||||||
"Wayland: Window attribute setting not implemented yet");
|
"Wayland: Window attribute setting not implemented yet");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _glfwPlatformSetWindowMousePassthrough(_GLFWwindow* window, bool enabled)
|
||||||
|
{
|
||||||
|
if (enabled)
|
||||||
|
{
|
||||||
|
struct wl_region* region = wl_compositor_create_region(_glfw.wl.compositor);
|
||||||
|
wl_surface_set_input_region(window->wl.surface, region);
|
||||||
|
wl_region_destroy(region);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
wl_surface_set_input_region(window->wl.surface, 0);
|
||||||
|
wl_surface_commit(window->wl.surface);
|
||||||
|
}
|
||||||
|
|
||||||
float _glfwPlatformGetWindowOpacity(_GLFWwindow* window UNUSED)
|
float _glfwPlatformGetWindowOpacity(_GLFWwindow* window UNUSED)
|
||||||
{
|
{
|
||||||
return 1.f;
|
return 1.f;
|
||||||
@@ -1237,6 +1278,18 @@ float _glfwPlatformGetWindowOpacity(_GLFWwindow* window UNUSED)
|
|||||||
|
|
||||||
void _glfwPlatformSetWindowOpacity(_GLFWwindow* window UNUSED, float opacity UNUSED)
|
void _glfwPlatformSetWindowOpacity(_GLFWwindow* window UNUSED, float opacity UNUSED)
|
||||||
{
|
{
|
||||||
|
_glfwInputError(GLFW_FEATURE_UNAVAILABLE,
|
||||||
|
"Wayland: The platform does not support setting the window opacity");
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwPlatformSetRawMouseMotion(_GLFWwindow *window UNUSED, bool enabled UNUSED)
|
||||||
|
{
|
||||||
|
// This is handled in relativePointerHandleRelativeMotion
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _glfwPlatformRawMouseMotionSupported(void)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformPollEvents(void)
|
void _glfwPlatformPollEvents(void)
|
||||||
@@ -1305,21 +1358,24 @@ int _glfwPlatformCreateCursor(_GLFWcursor* cursor,
|
|||||||
cursor->wl.buffer = createShmBuffer(image);
|
cursor->wl.buffer = createShmBuffer(image);
|
||||||
if (!cursor->wl.buffer)
|
if (!cursor->wl.buffer)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
cursor->wl.width = image->width;
|
cursor->wl.width = image->width;
|
||||||
cursor->wl.height = image->height;
|
cursor->wl.height = image->height;
|
||||||
cursor->wl.xhot = xhot;
|
cursor->wl.xhot = xhot;
|
||||||
cursor->wl.yhot = yhot;
|
cursor->wl.yhot = yhot;
|
||||||
|
cursor->wl.scale = -1;
|
||||||
|
cursor->wl.shape = GLFW_INVALID_CURSOR;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, GLFWCursorShape shape)
|
int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, GLFWCursorShape shape)
|
||||||
{
|
{
|
||||||
struct wl_cursor* standardCursor;
|
// Don't actually load the cursor at this point,
|
||||||
|
// because there's not enough info to be properly HiDPI aware.
|
||||||
standardCursor = _glfwLoadCursor(shape);
|
cursor->wl.cursor = NULL;
|
||||||
if (!standardCursor) return false;
|
|
||||||
cursor->wl.cursor = standardCursor;
|
|
||||||
cursor->wl.currentImage = 0;
|
cursor->wl.currentImage = 0;
|
||||||
|
cursor->wl.scale = 0;
|
||||||
|
cursor->wl.shape = shape;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1333,31 +1389,42 @@ void _glfwPlatformDestroyCursor(_GLFWcursor* cursor)
|
|||||||
wl_buffer_destroy(cursor->wl.buffer);
|
wl_buffer_destroy(cursor->wl.buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handleRelativeMotion(void* data,
|
static void relativePointerHandleRelativeMotion(void* data,
|
||||||
struct zwp_relative_pointer_v1* pointer UNUSED,
|
struct zwp_relative_pointer_v1* pointer UNUSED,
|
||||||
uint32_t timeHi UNUSED,
|
uint32_t timeHi UNUSED,
|
||||||
uint32_t timeLo UNUSED,
|
uint32_t timeLo UNUSED,
|
||||||
wl_fixed_t dx UNUSED,
|
wl_fixed_t dx,
|
||||||
wl_fixed_t dy UNUSED,
|
wl_fixed_t dy,
|
||||||
wl_fixed_t dxUnaccel,
|
wl_fixed_t dxUnaccel,
|
||||||
wl_fixed_t dyUnaccel)
|
wl_fixed_t dyUnaccel)
|
||||||
{
|
{
|
||||||
_GLFWwindow* window = data;
|
_GLFWwindow* window = data;
|
||||||
|
double xpos = window->virtualCursorPosX;
|
||||||
|
double ypos = window->virtualCursorPosY;
|
||||||
|
|
||||||
if (window->cursorMode != GLFW_CURSOR_DISABLED)
|
if (window->cursorMode != GLFW_CURSOR_DISABLED)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_glfwInputCursorPos(window,
|
if (window->rawMouseMotion)
|
||||||
window->virtualCursorPosX + wl_fixed_to_double(dxUnaccel),
|
{
|
||||||
window->virtualCursorPosY + wl_fixed_to_double(dyUnaccel));
|
xpos += wl_fixed_to_double(dxUnaccel);
|
||||||
|
ypos += wl_fixed_to_double(dyUnaccel);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
xpos += wl_fixed_to_double(dx);
|
||||||
|
ypos += wl_fixed_to_double(dy);
|
||||||
|
}
|
||||||
|
|
||||||
|
_glfwInputCursorPos(window, xpos, ypos);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct zwp_relative_pointer_v1_listener relativePointerListener = {
|
static const struct zwp_relative_pointer_v1_listener relativePointerListener = {
|
||||||
handleRelativeMotion
|
relativePointerHandleRelativeMotion
|
||||||
};
|
};
|
||||||
|
|
||||||
static void handleLocked(void* data UNUSED,
|
static void lockedPointerHandleLocked(void* data UNUSED,
|
||||||
struct zwp_locked_pointer_v1* lockedPointer UNUSED)
|
struct zwp_locked_pointer_v1* lockedPointer UNUSED)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1377,14 +1444,14 @@ static void unlockPointer(_GLFWwindow* window)
|
|||||||
|
|
||||||
static void lockPointer(_GLFWwindow* window UNUSED);
|
static void lockPointer(_GLFWwindow* window UNUSED);
|
||||||
|
|
||||||
static void handleUnlocked(void* data UNUSED,
|
static void lockedPointerHandleUnlocked(void* data UNUSED,
|
||||||
struct zwp_locked_pointer_v1* lockedPointer UNUSED)
|
struct zwp_locked_pointer_v1* lockedPointer UNUSED)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct zwp_locked_pointer_v1_listener lockedPointerListener = {
|
static const struct zwp_locked_pointer_v1_listener lockedPointerListener = {
|
||||||
handleLocked,
|
lockedPointerHandleLocked,
|
||||||
handleUnlocked
|
lockedPointerHandleUnlocked
|
||||||
};
|
};
|
||||||
|
|
||||||
static void lockPointer(_GLFWwindow* window)
|
static void lockPointer(_GLFWwindow* window)
|
||||||
@@ -1421,7 +1488,7 @@ static void lockPointer(_GLFWwindow* window)
|
|||||||
window->wl.pointerLock.relativePointer = relativePointer;
|
window->wl.pointerLock.relativePointer = relativePointer;
|
||||||
window->wl.pointerLock.lockedPointer = lockedPointer;
|
window->wl.pointerLock.lockedPointer = lockedPointer;
|
||||||
|
|
||||||
wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.pointerSerial,
|
wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.serial,
|
||||||
NULL, 0, 0);
|
NULL, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1432,8 +1499,6 @@ static bool isPointerLocked(_GLFWwindow* window)
|
|||||||
|
|
||||||
void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor)
|
void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor)
|
||||||
{
|
{
|
||||||
struct wl_cursor* defaultCursor;
|
|
||||||
|
|
||||||
if (!_glfw.wl.pointer)
|
if (!_glfw.wl.pointer)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -1450,21 +1515,7 @@ void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor)
|
|||||||
|
|
||||||
if (window->cursorMode == GLFW_CURSOR_NORMAL)
|
if (window->cursorMode == GLFW_CURSOR_NORMAL)
|
||||||
{
|
{
|
||||||
if (cursor)
|
setCursorImage(window);
|
||||||
setCursorImage(&cursor->wl);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
defaultCursor = _glfwLoadCursor(GLFW_ARROW_CURSOR);
|
|
||||||
if (!defaultCursor) return;
|
|
||||||
_GLFWcursorWayland cursorWayland = {
|
|
||||||
defaultCursor,
|
|
||||||
NULL,
|
|
||||||
0, 0,
|
|
||||||
0, 0,
|
|
||||||
0
|
|
||||||
};
|
|
||||||
setCursorImage(&cursorWayland);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (window->cursorMode == GLFW_CURSOR_DISABLED)
|
else if (window->cursorMode == GLFW_CURSOR_DISABLED)
|
||||||
{
|
{
|
||||||
@@ -1473,8 +1524,7 @@ void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor)
|
|||||||
}
|
}
|
||||||
else if (window->cursorMode == GLFW_CURSOR_HIDDEN)
|
else if (window->cursorMode == GLFW_CURSOR_HIDDEN)
|
||||||
{
|
{
|
||||||
wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.pointerSerial,
|
wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.serial, NULL, 0, 0);
|
||||||
NULL, 0, 0);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1509,10 +1559,11 @@ static void _glfwSendPrimarySelectionText(void *data UNUSED, struct zwp_primary_
|
|||||||
send_text(_glfw.wl.primarySelectionString, fd);
|
send_text(_glfw.wl.primarySelectionString, fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
static char* read_offer_string(int data_pipe) {
|
static char* read_offer_string(int data_pipe, size_t *data_sz) {
|
||||||
wl_display_flush(_glfw.wl.display);
|
wl_display_flush(_glfw.wl.display);
|
||||||
size_t sz = 0, capacity = 0;
|
size_t capacity = 0;
|
||||||
char *buf = NULL;
|
char *buf = NULL;
|
||||||
|
*data_sz = 0;
|
||||||
struct pollfd fds;
|
struct pollfd fds;
|
||||||
fds.fd = data_pipe;
|
fds.fd = data_pipe;
|
||||||
fds.events = POLLIN;
|
fds.events = POLLIN;
|
||||||
@@ -1533,20 +1584,20 @@ static char* read_offer_string(int data_pipe) {
|
|||||||
if (!ret) {
|
if (!ret) {
|
||||||
bail("Wayland: Failed to read clipboard data from pipe (timed out)");
|
bail("Wayland: Failed to read clipboard data from pipe (timed out)");
|
||||||
}
|
}
|
||||||
if (capacity <= sz || capacity - sz <= 64) {
|
if (capacity <= *data_sz || capacity - *data_sz <= 64) {
|
||||||
capacity += 4096;
|
capacity += 4096;
|
||||||
buf = realloc(buf, capacity);
|
buf = realloc(buf, capacity);
|
||||||
if (!buf) {
|
if (!buf) {
|
||||||
bail("Wayland: Failed to allocate memory to read clipboard data");
|
bail("Wayland: Failed to allocate memory to read clipboard data");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ret = read(data_pipe, buf + sz, capacity - sz - 1);
|
ret = read(data_pipe, buf + *data_sz, capacity - *data_sz - 1);
|
||||||
if (ret == -1) {
|
if (ret == -1) {
|
||||||
if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK) continue;
|
if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK) continue;
|
||||||
bail("Wayland: Failed to read clipboard data from pipe with error: %s", strerror(errno));
|
bail("Wayland: Failed to read clipboard data from pipe with error: %s", strerror(errno));
|
||||||
}
|
}
|
||||||
if (ret == 0) { close(data_pipe); buf[sz] = 0; return buf; }
|
if (ret == 0) { close(data_pipe); buf[*data_sz] = 0; return buf; }
|
||||||
sz += ret;
|
*data_sz += ret;
|
||||||
start = glfwGetTime();
|
start = glfwGetTime();
|
||||||
}
|
}
|
||||||
bail("Wayland: Failed to read clipboard data from pipe (timed out)");
|
bail("Wayland: Failed to read clipboard data from pipe (timed out)");
|
||||||
@@ -1559,15 +1610,16 @@ static char* read_primary_selection_offer(struct zwp_primary_selection_offer_v1
|
|||||||
if (pipe2(pipefd, O_CLOEXEC) != 0) return NULL;
|
if (pipe2(pipefd, O_CLOEXEC) != 0) return NULL;
|
||||||
zwp_primary_selection_offer_v1_receive(primary_selection_offer, mime, pipefd[1]);
|
zwp_primary_selection_offer_v1_receive(primary_selection_offer, mime, pipefd[1]);
|
||||||
close(pipefd[1]);
|
close(pipefd[1]);
|
||||||
return read_offer_string(pipefd[0]);
|
size_t sz = 0;
|
||||||
|
return read_offer_string(pipefd[0], &sz);
|
||||||
}
|
}
|
||||||
|
|
||||||
static char* read_data_offer(struct wl_data_offer *data_offer, const char *mime) {
|
static char* read_data_offer(struct wl_data_offer *data_offer, const char *mime, size_t *sz) {
|
||||||
int pipefd[2];
|
int pipefd[2];
|
||||||
if (pipe2(pipefd, O_CLOEXEC) != 0) return NULL;
|
if (pipe2(pipefd, O_CLOEXEC) != 0) return NULL;
|
||||||
wl_data_offer_receive(data_offer, mime, pipefd[1]);
|
wl_data_offer_receive(data_offer, mime, pipefd[1]);
|
||||||
close(pipefd[1]);
|
close(pipefd[1]);
|
||||||
return read_offer_string(pipefd[0]);
|
return read_offer_string(pipefd[0], sz);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void data_source_canceled(void *data UNUSED, struct wl_data_source *wl_data_source) {
|
static void data_source_canceled(void *data UNUSED, struct wl_data_source *wl_data_source) {
|
||||||
@@ -1596,20 +1648,23 @@ static const struct zwp_primary_selection_source_v1_listener primary_selection_s
|
|||||||
.cancelled = primary_selection_source_canceled,
|
.cancelled = primary_selection_source_canceled,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void
|
||||||
|
destroy_data_offer(_GLFWWaylandDataOffer *offer) {
|
||||||
|
if (offer->id) {
|
||||||
|
if (offer->is_primary) zwp_primary_selection_offer_v1_destroy(offer->id);
|
||||||
|
else wl_data_offer_destroy(offer->id);
|
||||||
|
}
|
||||||
|
if (offer->mimes) {
|
||||||
|
for (size_t i = 0; i < offer->mimes_count; i++) free((char*)offer->mimes[i]);
|
||||||
|
free(offer->mimes);
|
||||||
|
}
|
||||||
|
memset(offer, 0, sizeof(_GLFWWaylandDataOffer));
|
||||||
|
}
|
||||||
|
|
||||||
static void prune_unclaimed_data_offers(void) {
|
static void prune_unclaimed_data_offers(void) {
|
||||||
for (size_t i = 0; i < arraysz(_glfw.wl.dataOffers); i++) {
|
for (size_t i = 0; i < arraysz(_glfw.wl.dataOffers); i++) {
|
||||||
if (_glfw.wl.dataOffers[i].id && !_glfw.wl.dataOffers[i].offer_type) {
|
if (_glfw.wl.dataOffers[i].id && !_glfw.wl.dataOffers[i].offer_type) {
|
||||||
wl_data_offer_destroy(_glfw.wl.dataOffers[i].id);
|
destroy_data_offer(&_glfw.wl.dataOffers[i]);
|
||||||
memset(_glfw.wl.dataOffers + i, 0, sizeof(_glfw.wl.dataOffers[0]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void prune_unclaimed_primary_selection_offers(void) {
|
|
||||||
for (size_t i = 0; i < arraysz(_glfw.wl.primarySelectionOffers); i++) {
|
|
||||||
if (_glfw.wl.primarySelectionOffers[i].id && !_glfw.wl.dataOffers[i].offer_type) {
|
|
||||||
zwp_primary_selection_offer_v1_destroy(_glfw.wl.primarySelectionOffers[i].id);
|
|
||||||
memset(_glfw.wl.primarySelectionOffers + i, 0, sizeof(_glfw.wl.primarySelectionOffers[0]));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1628,25 +1683,32 @@ static void mark_selection_offer(void *data UNUSED, struct wl_data_device *data_
|
|||||||
|
|
||||||
static void mark_primary_selection_offer(void *data UNUSED, struct zwp_primary_selection_device_v1* primary_selection_device UNUSED,
|
static void mark_primary_selection_offer(void *data UNUSED, struct zwp_primary_selection_device_v1* primary_selection_device UNUSED,
|
||||||
struct zwp_primary_selection_offer_v1 *primary_selection_offer) {
|
struct zwp_primary_selection_offer_v1 *primary_selection_offer) {
|
||||||
for (size_t i = 0; i < arraysz(_glfw.wl.primarySelectionOffers); i++) {
|
for (size_t i = 0; i < arraysz(_glfw.wl.dataOffers); i++) {
|
||||||
if (_glfw.wl.primarySelectionOffers[i].id == primary_selection_offer) {
|
if (_glfw.wl.dataOffers[i].id == primary_selection_offer) {
|
||||||
_glfw.wl.primarySelectionOffers[i].offer_type = PRIMARY_SELECTION;
|
_glfw.wl.dataOffers[i].offer_type = PRIMARY_SELECTION;
|
||||||
} else if (_glfw.wl.primarySelectionOffers[i].offer_type == PRIMARY_SELECTION) {
|
} else if (_glfw.wl.dataOffers[i].offer_type == PRIMARY_SELECTION) {
|
||||||
_glfw.wl.primarySelectionOffers[i].offer_type = EXPIRED; // previous selection offer
|
_glfw.wl.dataOffers[i].offer_type = EXPIRED; // previous selection offer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
prune_unclaimed_primary_selection_offers();
|
prune_unclaimed_data_offers();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void set_offer_mimetype(struct _GLFWWaylandDataOffer* offer, const char* mime) {
|
static void
|
||||||
if (strcmp(mime, "text/plain;charset=utf-8") == 0)
|
set_offer_mimetype(_GLFWWaylandDataOffer* offer, const char* mime) {
|
||||||
offer->mime = "text/plain;charset=utf-8";
|
if (strcmp(mime, "text/plain;charset=utf-8") == 0) {
|
||||||
else if (!offer->mime && strcmp(mime, "text/plain") == 0)
|
offer->plain_text_mime = "text/plain;charset=utf-8";
|
||||||
offer->mime = "text/plain";
|
} else if (!offer->plain_text_mime && strcmp(mime, "text/plain")) {
|
||||||
else if (strcmp(mime, clipboard_mime()) == 0)
|
offer->plain_text_mime = "text/plain";
|
||||||
offer->is_self_offer = 1;
|
}
|
||||||
else if (strcmp(mime, URI_LIST_MIME) == 0)
|
if (strcmp(mime, clipboard_mime()) == 0) {
|
||||||
offer->has_uri_list = 1;
|
offer->is_self_offer = true;
|
||||||
|
}
|
||||||
|
if (!offer->mimes || offer->mimes_count >= offer->mimes_capacity - 1) {
|
||||||
|
offer->mimes = realloc(offer->mimes, sizeof(char*) * (offer->mimes_capacity + 64));
|
||||||
|
if (offer->mimes) offer->mimes_capacity += 64;
|
||||||
|
else return;
|
||||||
|
}
|
||||||
|
offer->mimes[offer->mimes_count++] = _glfw_strdup(mime);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handle_offer_mimetype(void *data UNUSED, struct wl_data_offer* id, const char *mime) {
|
static void handle_offer_mimetype(void *data UNUSED, struct wl_data_offer* id, const char *mime) {
|
||||||
@@ -1659,9 +1721,9 @@ static void handle_offer_mimetype(void *data UNUSED, struct wl_data_offer* id, c
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void handle_primary_selection_offer_mimetype(void *data UNUSED, struct zwp_primary_selection_offer_v1* id, const char *mime) {
|
static void handle_primary_selection_offer_mimetype(void *data UNUSED, struct zwp_primary_selection_offer_v1* id, const char *mime) {
|
||||||
for (size_t i = 0; i < arraysz(_glfw.wl.primarySelectionOffers); i++) {
|
for (size_t i = 0; i < arraysz(_glfw.wl.dataOffers); i++) {
|
||||||
if (_glfw.wl.primarySelectionOffers[i].id == id) {
|
if (_glfw.wl.dataOffers[i].id == id) {
|
||||||
set_offer_mimetype((struct _GLFWWaylandDataOffer*)&_glfw.wl.primarySelectionOffers[i], mime);
|
set_offer_mimetype((_GLFWWaylandDataOffer*)&_glfw.wl.dataOffers[i], mime);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1696,7 +1758,8 @@ static const struct zwp_primary_selection_offer_v1_listener primary_selection_of
|
|||||||
.offer = handle_primary_selection_offer_mimetype,
|
.offer = handle_primary_selection_offer_mimetype,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void handle_data_offer(void *data UNUSED, struct wl_data_device *wl_data_device UNUSED, struct wl_data_offer *id) {
|
static size_t
|
||||||
|
handle_data_offer_generic(void *id, bool is_primary) {
|
||||||
size_t smallest_idx = SIZE_MAX, pos = 0;
|
size_t smallest_idx = SIZE_MAX, pos = 0;
|
||||||
for (size_t i = 0; i < arraysz(_glfw.wl.dataOffers); i++) {
|
for (size_t i = 0; i < arraysz(_glfw.wl.dataOffers); i++) {
|
||||||
if (_glfw.wl.dataOffers[i].idx && _glfw.wl.dataOffers[i].idx < smallest_idx) {
|
if (_glfw.wl.dataOffers[i].idx && _glfw.wl.dataOffers[i].idx < smallest_idx) {
|
||||||
@@ -1704,47 +1767,48 @@ static void handle_data_offer(void *data UNUSED, struct wl_data_device *wl_data_
|
|||||||
pos = i;
|
pos = i;
|
||||||
}
|
}
|
||||||
if (_glfw.wl.dataOffers[i].id == NULL) {
|
if (_glfw.wl.dataOffers[i].id == NULL) {
|
||||||
_glfw.wl.dataOffers[i].id = id;
|
pos = i;
|
||||||
_glfw.wl.dataOffers[i].idx = ++_glfw.wl.dataOffersCounter;
|
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (_glfw.wl.dataOffers[pos].id) wl_data_offer_destroy(_glfw.wl.dataOffers[pos].id);
|
if (_glfw.wl.dataOffers[pos].id) destroy_data_offer(&_glfw.wl.dataOffers[pos]);
|
||||||
memset(_glfw.wl.dataOffers + pos, 0, sizeof(_glfw.wl.dataOffers[0]));
|
|
||||||
_glfw.wl.dataOffers[pos].id = id;
|
|
||||||
_glfw.wl.dataOffers[pos].idx = ++_glfw.wl.dataOffersCounter;
|
|
||||||
end:
|
end:
|
||||||
|
_glfw.wl.dataOffers[pos].id = id;
|
||||||
|
_glfw.wl.dataOffers[pos].is_primary = is_primary;
|
||||||
|
_glfw.wl.dataOffers[pos].idx = ++_glfw.wl.dataOffersCounter;
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_data_offer(void *data UNUSED, struct wl_data_device *wl_data_device UNUSED, struct wl_data_offer *id) {
|
||||||
|
handle_data_offer_generic(id, false);
|
||||||
wl_data_offer_add_listener(id, &data_offer_listener, NULL);
|
wl_data_offer_add_listener(id, &data_offer_listener, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handle_primary_selection_offer(void *data UNUSED, struct zwp_primary_selection_device_v1 *zwp_primary_selection_device_v1 UNUSED, struct zwp_primary_selection_offer_v1 *id) {
|
static void handle_primary_selection_offer(void *data UNUSED, struct zwp_primary_selection_device_v1 *zwp_primary_selection_device_v1 UNUSED, struct zwp_primary_selection_offer_v1 *id) {
|
||||||
size_t smallest_idx = SIZE_MAX, pos = 0;
|
handle_data_offer_generic(id, true);
|
||||||
for (size_t i = 0; i < arraysz(_glfw.wl.primarySelectionOffers); i++) {
|
|
||||||
if (_glfw.wl.primarySelectionOffers[i].idx && _glfw.wl.primarySelectionOffers[i].idx < smallest_idx) {
|
|
||||||
smallest_idx = _glfw.wl.primarySelectionOffers[i].idx;
|
|
||||||
pos = i;
|
|
||||||
}
|
|
||||||
if (_glfw.wl.primarySelectionOffers[i].id == NULL) {
|
|
||||||
_glfw.wl.primarySelectionOffers[i].id = id;
|
|
||||||
_glfw.wl.primarySelectionOffers[i].idx = ++_glfw.wl.primarySelectionOffersCounter;
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (_glfw.wl.primarySelectionOffers[pos].id) zwp_primary_selection_offer_v1_destroy(_glfw.wl.primarySelectionOffers[pos].id);
|
|
||||||
memset(_glfw.wl.primarySelectionOffers + pos, 0, sizeof(_glfw.wl.primarySelectionOffers[0]));
|
|
||||||
_glfw.wl.primarySelectionOffers[pos].id = id;
|
|
||||||
_glfw.wl.primarySelectionOffers[pos].idx = ++_glfw.wl.primarySelectionOffersCounter;
|
|
||||||
end:
|
|
||||||
zwp_primary_selection_offer_v1_add_listener(id, &primary_selection_offer_listener, NULL);
|
zwp_primary_selection_offer_v1_add_listener(id, &primary_selection_offer_listener, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void drag_enter(void *data UNUSED, struct wl_data_device *wl_data_device UNUSED, uint32_t serial, struct wl_surface *surface, wl_fixed_t x UNUSED, wl_fixed_t y UNUSED, struct wl_data_offer *id) {
|
static void drag_enter(void *data UNUSED, struct wl_data_device *wl_data_device UNUSED, uint32_t serial, struct wl_surface *surface, wl_fixed_t x UNUSED, wl_fixed_t y UNUSED, struct wl_data_offer *id) {
|
||||||
for (size_t i = 0; i < arraysz(_glfw.wl.dataOffers); i++) {
|
for (size_t i = 0; i < arraysz(_glfw.wl.dataOffers); i++) {
|
||||||
if (_glfw.wl.dataOffers[i].id == id) {
|
_GLFWWaylandDataOffer *d = _glfw.wl.dataOffers + i;
|
||||||
_glfw.wl.dataOffers[i].offer_type = DRAG_AND_DROP;
|
if (d->id == id) {
|
||||||
_glfw.wl.dataOffers[i].surface = surface;
|
d->offer_type = DRAG_AND_DROP;
|
||||||
const char *mime = _glfw.wl.dataOffers[i].has_uri_list ? URI_LIST_MIME : NULL;
|
d->surface = surface;
|
||||||
wl_data_offer_accept(id, serial, mime);
|
_GLFWwindow* window = _glfw.windowListHead;
|
||||||
|
int format_priority = 0;
|
||||||
|
while (window)
|
||||||
|
{
|
||||||
|
if (window->wl.surface == surface) {
|
||||||
|
for (size_t x = 0; x < d->mimes_count; x++) {
|
||||||
|
int prio = _glfwInputDrop(window, d->mimes[x], NULL, 0);
|
||||||
|
if (prio > format_priority) d->mime_for_drop = d->mimes[x];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
window = window->next;
|
||||||
|
}
|
||||||
|
wl_data_offer_accept(id, serial, d->mime_for_drop);
|
||||||
} else if (_glfw.wl.dataOffers[i].offer_type == DRAG_AND_DROP) {
|
} else if (_glfw.wl.dataOffers[i].offer_type == DRAG_AND_DROP) {
|
||||||
_glfw.wl.dataOffers[i].offer_type = EXPIRED; // previous drag offer
|
_glfw.wl.dataOffers[i].offer_type = EXPIRED; // previous drag offer
|
||||||
}
|
}
|
||||||
@@ -1755,39 +1819,34 @@ static void drag_enter(void *data UNUSED, struct wl_data_device *wl_data_device
|
|||||||
static void drag_leave(void *data UNUSED, struct wl_data_device *wl_data_device UNUSED) {
|
static void drag_leave(void *data UNUSED, struct wl_data_device *wl_data_device UNUSED) {
|
||||||
for (size_t i = 0; i < arraysz(_glfw.wl.dataOffers); i++) {
|
for (size_t i = 0; i < arraysz(_glfw.wl.dataOffers); i++) {
|
||||||
if (_glfw.wl.dataOffers[i].offer_type == DRAG_AND_DROP) {
|
if (_glfw.wl.dataOffers[i].offer_type == DRAG_AND_DROP) {
|
||||||
wl_data_offer_destroy(_glfw.wl.dataOffers[i].id);
|
destroy_data_offer(&_glfw.wl.dataOffers[i]);
|
||||||
memset(_glfw.wl.dataOffers + i, 0, sizeof(_glfw.wl.dataOffers[0]));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void drop(void *data, struct wl_data_device *wl_data_device UNUSED) {
|
static void drop(void *data UNUSED, struct wl_data_device *wl_data_device UNUSED) {
|
||||||
for (size_t i = 0; i < arraysz(_glfw.wl.dataOffers); i++) {
|
for (size_t i = 0; i < arraysz(_glfw.wl.dataOffers); i++) {
|
||||||
if (_glfw.wl.dataOffers[i].offer_type == DRAG_AND_DROP) {
|
if (_glfw.wl.dataOffers[i].offer_type == DRAG_AND_DROP && _glfw.wl.dataOffers[i].mime_for_drop) {
|
||||||
char *uri_list = read_data_offer(_glfw.wl.dataOffers[i].id, URI_LIST_MIME);
|
size_t sz = 0;
|
||||||
if (uri_list) {
|
char *data = read_data_offer(_glfw.wl.dataOffers[i].id, _glfw.wl.dataOffers[i].mime_for_drop, &sz);
|
||||||
wl_data_offer_finish(_glfw.wl.dataOffers[i].id);
|
if (data) {
|
||||||
int count;
|
// We dont do finish as this requires version 3 for wl_data_device_manager
|
||||||
char** paths = parseUriList(data, &count);
|
// which then requires more work with calling set_actions for drag and drop to function
|
||||||
|
// wl_data_offer_finish(_glfw.wl.dataOffers[i].id);
|
||||||
|
|
||||||
_GLFWwindow* window = _glfw.windowListHead;
|
_GLFWwindow* window = _glfw.windowListHead;
|
||||||
while (window)
|
while (window)
|
||||||
{
|
{
|
||||||
if (window->wl.surface == _glfw.wl.dataOffers[i].surface) {
|
if (window->wl.surface == _glfw.wl.dataOffers[i].surface) {
|
||||||
_glfwInputDrop(window, count, (const char**) paths);
|
_glfwInputDrop(window, _glfw.wl.dataOffers[i].mime_for_drop, data, sz);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
window = window->next;
|
window = window->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
free(data);
|
||||||
for (int k = 0; k < count; k++)
|
|
||||||
free(paths[k]);
|
|
||||||
free(paths);
|
|
||||||
free(uri_list);
|
|
||||||
}
|
}
|
||||||
wl_data_offer_destroy(_glfw.wl.dataOffers[i].id);
|
destroy_data_offer(&_glfw.wl.dataOffers[i]);
|
||||||
memset(_glfw.wl.dataOffers + i, 0, sizeof(_glfw.wl.dataOffers[0]));
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1892,10 +1951,12 @@ void _glfwPlatformSetClipboardString(const char* string)
|
|||||||
const char* _glfwPlatformGetClipboardString(void)
|
const char* _glfwPlatformGetClipboardString(void)
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < arraysz(_glfw.wl.dataOffers); i++) {
|
for (size_t i = 0; i < arraysz(_glfw.wl.dataOffers); i++) {
|
||||||
if (_glfw.wl.dataOffers[i].id && _glfw.wl.dataOffers[i].mime && _glfw.wl.dataOffers[i].offer_type == CLIPBOARD) {
|
_GLFWWaylandDataOffer *d = _glfw.wl.dataOffers + i;
|
||||||
if (_glfw.wl.dataOffers[i].is_self_offer) return _glfw.wl.clipboardString;
|
if (d->id && d->offer_type == CLIPBOARD && d->plain_text_mime) {
|
||||||
|
if (d->is_self_offer) return _glfw.wl.clipboardString;
|
||||||
free(_glfw.wl.pasteString);
|
free(_glfw.wl.pasteString);
|
||||||
_glfw.wl.pasteString = read_data_offer(_glfw.wl.dataOffers[i].id, _glfw.wl.dataOffers[i].mime);
|
size_t sz = 0;
|
||||||
|
_glfw.wl.pasteString = read_data_offer(d->id, d->plain_text_mime, &sz);
|
||||||
return _glfw.wl.pasteString;
|
return _glfw.wl.pasteString;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1942,19 +2003,38 @@ const char* _glfwPlatformGetPrimarySelectionString(void)
|
|||||||
{
|
{
|
||||||
if (_glfw.wl.dataSourceForPrimarySelection != NULL) return _glfw.wl.primarySelectionString;
|
if (_glfw.wl.dataSourceForPrimarySelection != NULL) return _glfw.wl.primarySelectionString;
|
||||||
|
|
||||||
for (size_t i = 0; i < arraysz(_glfw.wl.primarySelectionOffers); i++) {
|
for (size_t i = 0; i < arraysz(_glfw.wl.dataOffers); i++) {
|
||||||
if (_glfw.wl.primarySelectionOffers[i].id && _glfw.wl.primarySelectionOffers[i].mime && _glfw.wl.primarySelectionOffers[i].offer_type == PRIMARY_SELECTION) {
|
_GLFWWaylandDataOffer *d = _glfw.wl.dataOffers + i;
|
||||||
if (_glfw.wl.primarySelectionOffers[i].is_self_offer) {
|
if (d->id && d->is_primary && d->offer_type == PRIMARY_SELECTION && d->plain_text_mime) {
|
||||||
|
if (d->is_self_offer) {
|
||||||
return _glfw.wl.primarySelectionString;
|
return _glfw.wl.primarySelectionString;
|
||||||
}
|
}
|
||||||
free(_glfw.wl.pasteString);
|
free(_glfw.wl.pasteString);
|
||||||
_glfw.wl.pasteString = read_primary_selection_offer(_glfw.wl.primarySelectionOffers[i].id, _glfw.wl.primarySelectionOffers[i].mime);
|
_glfw.wl.pasteString = read_primary_selection_offer(d->id, d->plain_text_mime);
|
||||||
return _glfw.wl.pasteString;
|
return _glfw.wl.pasteString;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EGLenum _glfwPlatformGetEGLPlatform(EGLint** attribs UNUSED)
|
||||||
|
{
|
||||||
|
if (_glfw.egl.EXT_platform_base && _glfw.egl.EXT_platform_wayland)
|
||||||
|
return EGL_PLATFORM_WAYLAND_EXT;
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
EGLNativeDisplayType _glfwPlatformGetEGLNativeDisplay(void)
|
||||||
|
{
|
||||||
|
return _glfw.wl.display;
|
||||||
|
}
|
||||||
|
|
||||||
|
EGLNativeWindowType _glfwPlatformGetEGLNativeWindow(_GLFWwindow* window)
|
||||||
|
{
|
||||||
|
return window->wl.native;
|
||||||
|
}
|
||||||
|
|
||||||
void _glfwPlatformGetRequiredInstanceExtensions(char** extensions)
|
void _glfwPlatformGetRequiredInstanceExtensions(char** extensions)
|
||||||
{
|
{
|
||||||
if (!_glfw.vk.KHR_surface || !_glfw.vk.KHR_wayland_surface)
|
if (!_glfw.vk.KHR_surface || !_glfw.vk.KHR_wayland_surface)
|
||||||
|
|||||||
93
glfw/x11_init.c
vendored
93
glfw/x11_init.c
vendored
@@ -42,11 +42,11 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
|
||||||
// Check whether the specified atom is supported
|
// Return the atom ID only if it is listed in the specified array
|
||||||
//
|
//
|
||||||
static Atom getSupportedAtom(Atom* supportedAtoms,
|
static Atom getAtomIfSupported(Atom* supportedAtoms,
|
||||||
unsigned long atomCount,
|
unsigned long atomCount,
|
||||||
const char* atomName)
|
const char* atomName)
|
||||||
{
|
{
|
||||||
const Atom atom = XInternAtom(_glfw.x11.display, atomName, False);
|
const Atom atom = XInternAtom(_glfw.x11.display, atomName, False);
|
||||||
|
|
||||||
@@ -64,9 +64,8 @@ static Atom getSupportedAtom(Atom* supportedAtoms,
|
|||||||
static void detectEWMH(void)
|
static void detectEWMH(void)
|
||||||
{
|
{
|
||||||
// First we read the _NET_SUPPORTING_WM_CHECK property on the root window
|
// First we read the _NET_SUPPORTING_WM_CHECK property on the root window
|
||||||
Window* windowFromRoot = NULL;
|
|
||||||
|
|
||||||
// Then we look for the _NET_SUPPORTING_WM_CHECK property of the root window
|
Window* windowFromRoot = NULL;
|
||||||
if (!_glfwGetWindowPropertyX11(_glfw.x11.root,
|
if (!_glfwGetWindowPropertyX11(_glfw.x11.root,
|
||||||
_glfw.x11.NET_SUPPORTING_WM_CHECK,
|
_glfw.x11.NET_SUPPORTING_WM_CHECK,
|
||||||
XA_WINDOW,
|
XA_WINDOW,
|
||||||
@@ -93,6 +92,7 @@ static void detectEWMH(void)
|
|||||||
_glfwReleaseErrorHandlerX11();
|
_glfwReleaseErrorHandlerX11();
|
||||||
|
|
||||||
// If the property exists, it should contain the XID of the window
|
// If the property exists, it should contain the XID of the window
|
||||||
|
|
||||||
if (*windowFromRoot != *windowFromChild)
|
if (*windowFromRoot != *windowFromChild)
|
||||||
{
|
{
|
||||||
XFree(windowFromRoot);
|
XFree(windowFromRoot);
|
||||||
@@ -103,49 +103,50 @@ static void detectEWMH(void)
|
|||||||
XFree(windowFromRoot);
|
XFree(windowFromRoot);
|
||||||
XFree(windowFromChild);
|
XFree(windowFromChild);
|
||||||
|
|
||||||
// We are now fairly sure that an EWMH-compliant window manager is running
|
// We are now fairly sure that an EWMH-compliant WM is currently running
|
||||||
// We can now start querying the WM about what features it supports by
|
// We can now start querying the WM about what features it supports by
|
||||||
// looking in the _NET_SUPPORTED property on the root window
|
// looking in the _NET_SUPPORTED property on the root window
|
||||||
// It should contain a list of supported EWMH protocol and state atoms
|
// It should contain a list of supported EWMH protocol and state atoms
|
||||||
|
|
||||||
Atom* supportedAtoms = NULL;
|
Atom* supportedAtoms = NULL;
|
||||||
const unsigned long atomCount = _glfwGetWindowPropertyX11(_glfw.x11.root,
|
const unsigned long atomCount =
|
||||||
_glfw.x11.NET_SUPPORTED,
|
_glfwGetWindowPropertyX11(_glfw.x11.root,
|
||||||
XA_ATOM,
|
_glfw.x11.NET_SUPPORTED,
|
||||||
(unsigned char**) &supportedAtoms);
|
XA_ATOM,
|
||||||
|
(unsigned char**) &supportedAtoms);
|
||||||
if (!supportedAtoms)
|
if (!supportedAtoms)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// See which of the atoms we support that are supported by the WM
|
// See which of the atoms we support that are supported by the WM
|
||||||
|
|
||||||
_glfw.x11.NET_WM_STATE =
|
_glfw.x11.NET_WM_STATE =
|
||||||
getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE");
|
getAtomIfSupported(supportedAtoms, atomCount, "_NET_WM_STATE");
|
||||||
_glfw.x11.NET_WM_STATE_ABOVE =
|
_glfw.x11.NET_WM_STATE_ABOVE =
|
||||||
getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE_ABOVE");
|
getAtomIfSupported(supportedAtoms, atomCount, "_NET_WM_STATE_ABOVE");
|
||||||
_glfw.x11.NET_WM_STATE_FULLSCREEN =
|
_glfw.x11.NET_WM_STATE_FULLSCREEN =
|
||||||
getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE_FULLSCREEN");
|
getAtomIfSupported(supportedAtoms, atomCount, "_NET_WM_STATE_FULLSCREEN");
|
||||||
_glfw.x11.NET_WM_STATE_MAXIMIZED_VERT =
|
_glfw.x11.NET_WM_STATE_MAXIMIZED_VERT =
|
||||||
getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE_MAXIMIZED_VERT");
|
getAtomIfSupported(supportedAtoms, atomCount, "_NET_WM_STATE_MAXIMIZED_VERT");
|
||||||
_glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ =
|
_glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ =
|
||||||
getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE_MAXIMIZED_HORZ");
|
getAtomIfSupported(supportedAtoms, atomCount, "_NET_WM_STATE_MAXIMIZED_HORZ");
|
||||||
_glfw.x11.NET_WM_STATE_DEMANDS_ATTENTION =
|
_glfw.x11.NET_WM_STATE_DEMANDS_ATTENTION =
|
||||||
getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE_DEMANDS_ATTENTION");
|
getAtomIfSupported(supportedAtoms, atomCount, "_NET_WM_STATE_DEMANDS_ATTENTION");
|
||||||
_glfw.x11.NET_WM_FULLSCREEN_MONITORS =
|
_glfw.x11.NET_WM_FULLSCREEN_MONITORS =
|
||||||
getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_FULLSCREEN_MONITORS");
|
getAtomIfSupported(supportedAtoms, atomCount, "_NET_WM_FULLSCREEN_MONITORS");
|
||||||
_glfw.x11.NET_WM_WINDOW_TYPE =
|
_glfw.x11.NET_WM_WINDOW_TYPE =
|
||||||
getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_WINDOW_TYPE");
|
getAtomIfSupported(supportedAtoms, atomCount, "_NET_WM_WINDOW_TYPE");
|
||||||
_glfw.x11.NET_WM_WINDOW_TYPE_NORMAL =
|
_glfw.x11.NET_WM_WINDOW_TYPE_NORMAL =
|
||||||
getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_WINDOW_TYPE_NORMAL");
|
getAtomIfSupported(supportedAtoms, atomCount, "_NET_WM_WINDOW_TYPE_NORMAL");
|
||||||
_glfw.x11.NET_WORKAREA =
|
_glfw.x11.NET_WORKAREA =
|
||||||
getSupportedAtom(supportedAtoms, atomCount, "_NET_WORKAREA");
|
getAtomIfSupported(supportedAtoms, atomCount, "_NET_WORKAREA");
|
||||||
_glfw.x11.NET_CURRENT_DESKTOP =
|
_glfw.x11.NET_CURRENT_DESKTOP =
|
||||||
getSupportedAtom(supportedAtoms, atomCount, "_NET_CURRENT_DESKTOP");
|
getAtomIfSupported(supportedAtoms, atomCount, "_NET_CURRENT_DESKTOP");
|
||||||
_glfw.x11.NET_ACTIVE_WINDOW =
|
_glfw.x11.NET_ACTIVE_WINDOW =
|
||||||
getSupportedAtom(supportedAtoms, atomCount, "_NET_ACTIVE_WINDOW");
|
getAtomIfSupported(supportedAtoms, atomCount, "_NET_ACTIVE_WINDOW");
|
||||||
_glfw.x11.NET_FRAME_EXTENTS =
|
_glfw.x11.NET_FRAME_EXTENTS =
|
||||||
getSupportedAtom(supportedAtoms, atomCount, "_NET_FRAME_EXTENTS");
|
getAtomIfSupported(supportedAtoms, atomCount, "_NET_FRAME_EXTENTS");
|
||||||
_glfw.x11.NET_REQUEST_FRAME_EXTENTS =
|
_glfw.x11.NET_REQUEST_FRAME_EXTENTS =
|
||||||
getSupportedAtom(supportedAtoms, atomCount, "_NET_REQUEST_FRAME_EXTENTS");
|
getAtomIfSupported(supportedAtoms, atomCount, "_NET_REQUEST_FRAME_EXTENTS");
|
||||||
|
|
||||||
XFree(supportedAtoms);
|
XFree(supportedAtoms);
|
||||||
}
|
}
|
||||||
@@ -326,6 +327,30 @@ static bool initExtensions(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(__CYGWIN__)
|
||||||
|
_glfw.x11.xshape.handle = _glfw_dlopen("libXext-6.so");
|
||||||
|
#else
|
||||||
|
_glfw.x11.xshape.handle = _glfw_dlopen("libXext.so.6");
|
||||||
|
#endif
|
||||||
|
if (_glfw.x11.xshape.handle)
|
||||||
|
{
|
||||||
|
glfw_dlsym(_glfw.x11.xshape.QueryExtension, _glfw.x11.xshape.handle, "XShapeQueryExtension");
|
||||||
|
glfw_dlsym(_glfw.x11.xshape.ShapeCombineRegion, _glfw.x11.xshape.handle, "XShapeCombineRegion");
|
||||||
|
glfw_dlsym(_glfw.x11.xshape.QueryVersion, _glfw.x11.xshape.handle, "XShapeQueryVersion");
|
||||||
|
|
||||||
|
if (XShapeQueryExtension(_glfw.x11.display,
|
||||||
|
&_glfw.x11.xshape.errorBase,
|
||||||
|
&_glfw.x11.xshape.eventBase))
|
||||||
|
{
|
||||||
|
if (XShapeQueryVersion(_glfw.x11.display,
|
||||||
|
&_glfw.x11.xshape.major,
|
||||||
|
&_glfw.x11.xshape.minor))
|
||||||
|
{
|
||||||
|
_glfw.x11.xshape.available = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_glfw.x11.xkb.major = 1;
|
_glfw.x11.xkb.major = 1;
|
||||||
_glfw.x11.xkb.minor = 0;
|
_glfw.x11.xkb.minor = 0;
|
||||||
_glfw.x11.xkb.available = XkbQueryExtension(_glfw.x11.display,
|
_glfw.x11.xkb.available = XkbQueryExtension(_glfw.x11.display,
|
||||||
@@ -384,7 +409,6 @@ static bool initExtensions(void)
|
|||||||
_glfw.x11.XdndFinished = XInternAtom(_glfw.x11.display, "XdndFinished", False);
|
_glfw.x11.XdndFinished = XInternAtom(_glfw.x11.display, "XdndFinished", False);
|
||||||
_glfw.x11.XdndSelection = XInternAtom(_glfw.x11.display, "XdndSelection", False);
|
_glfw.x11.XdndSelection = XInternAtom(_glfw.x11.display, "XdndSelection", False);
|
||||||
_glfw.x11.XdndTypeList = XInternAtom(_glfw.x11.display, "XdndTypeList", False);
|
_glfw.x11.XdndTypeList = XInternAtom(_glfw.x11.display, "XdndTypeList", False);
|
||||||
_glfw.x11.text_uri_list = XInternAtom(_glfw.x11.display, "text/uri-list", False);
|
|
||||||
|
|
||||||
// ICCCM, EWMH and Motif window property atoms
|
// ICCCM, EWMH and Motif window property atoms
|
||||||
// These can be set safely even without WM support
|
// These can be set safely even without WM support
|
||||||
@@ -503,8 +527,11 @@ static Window createHelperWindow(void)
|
|||||||
|
|
||||||
// X error handler
|
// X error handler
|
||||||
//
|
//
|
||||||
static int errorHandler(Display *display UNUSED, XErrorEvent* event)
|
static int errorHandler(Display *display, XErrorEvent* event)
|
||||||
{
|
{
|
||||||
|
if (_glfw.x11.display != display)
|
||||||
|
return 0;
|
||||||
|
|
||||||
_glfw.x11.errorCode = event->error_code;
|
_glfw.x11.errorCode = event->error_code;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -626,15 +653,6 @@ int _glfwPlatformInit(void)
|
|||||||
_glfw.x11.helperWindowHandle = createHelperWindow();
|
_glfw.x11.helperWindowHandle = createHelperWindow();
|
||||||
_glfw.x11.hiddenCursorHandle = createHiddenCursor();
|
_glfw.x11.hiddenCursorHandle = createHiddenCursor();
|
||||||
|
|
||||||
#if defined(__linux__)
|
|
||||||
if (_glfw.hints.init.enableJoysticks) {
|
|
||||||
if (!_glfwInitJoysticksLinux())
|
|
||||||
return false;
|
|
||||||
if (_glfw.linjs.inotify > 0)
|
|
||||||
addWatch(&_glfw.x11.eventLoopData, "joystick", _glfw.linjs.inotify, POLLIN, 1, NULL, NULL);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
_glfwPollMonitorsX11();
|
_glfwPollMonitorsX11();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -713,9 +731,6 @@ void _glfwPlatformTerminate(void)
|
|||||||
_glfwTerminateEGL();
|
_glfwTerminateEGL();
|
||||||
_glfwTerminateGLX();
|
_glfwTerminateGLX();
|
||||||
|
|
||||||
#if defined(__linux__)
|
|
||||||
_glfwTerminateJoysticksLinux();
|
|
||||||
#endif
|
|
||||||
finalizePollData(&_glfw.x11.eventLoopData);
|
finalizePollData(&_glfw.x11.eventLoopData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
29
glfw/x11_monitor.c
vendored
29
glfw/x11_monitor.c
vendored
@@ -169,7 +169,7 @@ void _glfwPollMonitorsX11(void)
|
|||||||
if (widthMM <= 0 || heightMM <= 0)
|
if (widthMM <= 0 || heightMM <= 0)
|
||||||
{
|
{
|
||||||
// HACK: If RandR does not provide a physical size, assume the
|
// HACK: If RandR does not provide a physical size, assume the
|
||||||
// X11 default 96 DPI and calcuate from the CRTC viewport
|
// X11 default 96 DPI and calculate from the CRTC viewport
|
||||||
// NOTE: These members are affected by rotation, unlike the mode
|
// NOTE: These members are affected by rotation, unlike the mode
|
||||||
// info and output info members
|
// info and output info members
|
||||||
widthMM = (int) (ci->width * 25.4f / 96.f);
|
widthMM = (int) (ci->width * 25.4f / 96.f);
|
||||||
@@ -241,7 +241,8 @@ void _glfwSetVideoModeX11(_GLFWmonitor* monitor, const GLFWvidmode* desired)
|
|||||||
if (_glfwCompareVideoModes(¤t, best) == 0)
|
if (_glfwCompareVideoModes(¤t, best) == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
XRRScreenResources* sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root);
|
XRRScreenResources* sr =
|
||||||
|
XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root);
|
||||||
XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc);
|
XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc);
|
||||||
XRROutputInfo* oi = XRRGetOutputInfo(_glfw.x11.display, sr, monitor->x11.output);
|
XRROutputInfo* oi = XRRGetOutputInfo(_glfw.x11.display, sr, monitor->x11.output);
|
||||||
|
|
||||||
@@ -289,7 +290,8 @@ void _glfwRestoreVideoModeX11(_GLFWmonitor* monitor)
|
|||||||
if (monitor->x11.oldMode == None)
|
if (monitor->x11.oldMode == None)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
XRRScreenResources* sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root);
|
XRRScreenResources* sr =
|
||||||
|
XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root);
|
||||||
XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc);
|
XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc);
|
||||||
|
|
||||||
XRRSetCrtcConfig(_glfw.x11.display,
|
XRRSetCrtcConfig(_glfw.x11.display,
|
||||||
@@ -321,9 +323,10 @@ void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos)
|
|||||||
{
|
{
|
||||||
if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken)
|
if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken)
|
||||||
{
|
{
|
||||||
|
XRRScreenResources* sr =
|
||||||
XRRScreenResources* sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root);
|
XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root);
|
||||||
XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc);
|
XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc);
|
||||||
|
|
||||||
if (ci)
|
if (ci)
|
||||||
{
|
{
|
||||||
if (xpos)
|
if (xpos)
|
||||||
@@ -333,6 +336,7 @@ void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos)
|
|||||||
|
|
||||||
XRRFreeCrtcInfo(ci);
|
XRRFreeCrtcInfo(ci);
|
||||||
}
|
}
|
||||||
|
|
||||||
XRRFreeScreenResources(sr);
|
XRRFreeScreenResources(sr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -352,8 +356,8 @@ void _glfwPlatformGetMonitorWorkarea(_GLFWmonitor* monitor, int* xpos, int* ypos
|
|||||||
|
|
||||||
if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken)
|
if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken)
|
||||||
{
|
{
|
||||||
|
XRRScreenResources* sr =
|
||||||
XRRScreenResources* sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root);
|
XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root);
|
||||||
XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc);
|
XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc);
|
||||||
|
|
||||||
areaX = ci->x;
|
areaX = ci->x;
|
||||||
@@ -446,7 +450,8 @@ GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count)
|
|||||||
|
|
||||||
if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken)
|
if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken)
|
||||||
{
|
{
|
||||||
XRRScreenResources* sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root);
|
XRRScreenResources* sr =
|
||||||
|
XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root);
|
||||||
XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc);
|
XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc);
|
||||||
XRROutputInfo* oi = XRRGetOutputInfo(_glfw.x11.display, sr, monitor->x11.output);
|
XRROutputInfo* oi = XRRGetOutputInfo(_glfw.x11.display, sr, monitor->x11.output);
|
||||||
|
|
||||||
@@ -493,17 +498,19 @@ void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode)
|
|||||||
{
|
{
|
||||||
if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken)
|
if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken)
|
||||||
{
|
{
|
||||||
|
XRRScreenResources* sr =
|
||||||
XRRScreenResources* sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root);
|
XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root);
|
||||||
XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc);
|
XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc);
|
||||||
|
|
||||||
if (ci) {
|
if (ci)
|
||||||
|
{
|
||||||
const XRRModeInfo* mi = getModeInfo(sr, ci->mode);
|
const XRRModeInfo* mi = getModeInfo(sr, ci->mode);
|
||||||
if (mi) // mi can be NULL if the monitor has been disconnected
|
if (mi) // mi can be NULL if the monitor has been disconnected
|
||||||
*mode = vidmodeFromModeInfo(mi, ci);
|
*mode = vidmodeFromModeInfo(mi, ci);
|
||||||
|
|
||||||
XRRFreeCrtcInfo(ci);
|
XRRFreeCrtcInfo(ci);
|
||||||
}
|
}
|
||||||
|
|
||||||
XRRFreeScreenResources(sr);
|
XRRFreeScreenResources(sr);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
35
glfw/x11_platform.h
vendored
35
glfw/x11_platform.h
vendored
@@ -51,6 +51,9 @@
|
|||||||
// The XInput extension provides raw mouse motion input
|
// The XInput extension provides raw mouse motion input
|
||||||
#include <X11/extensions/XInput2.h>
|
#include <X11/extensions/XInput2.h>
|
||||||
|
|
||||||
|
// The Shape extension provides custom window shapes
|
||||||
|
#include <X11/extensions/shape.h>
|
||||||
|
|
||||||
// The libxkb library is used for improved keyboard support
|
// The libxkb library is used for improved keyboard support
|
||||||
#include "xkb_glfw.h"
|
#include "xkb_glfw.h"
|
||||||
#include "backend_utils.h"
|
#include "backend_utils.h"
|
||||||
@@ -125,6 +128,16 @@ typedef XRenderPictFormat* (* PFN_XRenderFindVisualFormat)(Display*,Visual const
|
|||||||
#define XRenderQueryVersion _glfw.x11.xrender.QueryVersion
|
#define XRenderQueryVersion _glfw.x11.xrender.QueryVersion
|
||||||
#define XRenderFindVisualFormat _glfw.x11.xrender.FindVisualFormat
|
#define XRenderFindVisualFormat _glfw.x11.xrender.FindVisualFormat
|
||||||
|
|
||||||
|
typedef Bool (* PFN_XShapeQueryExtension)(Display*,int*,int*);
|
||||||
|
typedef Status (* PFN_XShapeQueryVersion)(Display*dpy,int*,int*);
|
||||||
|
typedef void (* PFN_XShapeCombineRegion)(Display*,Window,int,int,int,Region,int);
|
||||||
|
typedef void (* PFN_XShapeCombineMask)(Display*,Window,int,int,int,Pixmap,int);
|
||||||
|
|
||||||
|
#define XShapeQueryExtension _glfw.x11.xshape.QueryExtension
|
||||||
|
#define XShapeQueryVersion _glfw.x11.xshape.QueryVersion
|
||||||
|
#define XShapeCombineRegion _glfw.x11.xshape.ShapeCombineRegion
|
||||||
|
#define XShapeCombineMask _glfw.x11.xshape.ShapeCombineMask
|
||||||
|
|
||||||
typedef VkFlags VkXlibSurfaceCreateFlagsKHR;
|
typedef VkFlags VkXlibSurfaceCreateFlagsKHR;
|
||||||
typedef VkFlags VkXcbSurfaceCreateFlagsKHR;
|
typedef VkFlags VkXcbSurfaceCreateFlagsKHR;
|
||||||
|
|
||||||
@@ -153,8 +166,6 @@ typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR)(Vk
|
|||||||
|
|
||||||
#include "posix_thread.h"
|
#include "posix_thread.h"
|
||||||
#include "glx_context.h"
|
#include "glx_context.h"
|
||||||
#include "egl_context.h"
|
|
||||||
#include "osmesa_context.h"
|
|
||||||
#if defined(__linux__)
|
#if defined(__linux__)
|
||||||
#include "linux_joystick.h"
|
#include "linux_joystick.h"
|
||||||
#else
|
#else
|
||||||
@@ -165,9 +176,6 @@ typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR)(Vk
|
|||||||
#define _glfw_dlclose(handle) dlclose(handle)
|
#define _glfw_dlclose(handle) dlclose(handle)
|
||||||
#define _glfw_dlsym(handle, name) dlsym(handle, name)
|
#define _glfw_dlsym(handle, name) dlsym(handle, name)
|
||||||
|
|
||||||
#define _GLFW_EGL_NATIVE_WINDOW ((EGLNativeWindowType) window->x11.handle)
|
|
||||||
#define _GLFW_EGL_NATIVE_DISPLAY ((EGLNativeDisplayType) _glfw.x11.display)
|
|
||||||
|
|
||||||
#define _GLFW_PLATFORM_WINDOW_STATE _GLFWwindowX11 x11
|
#define _GLFW_PLATFORM_WINDOW_STATE _GLFWwindowX11 x11
|
||||||
#define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryX11 x11
|
#define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryX11 x11
|
||||||
#define _GLFW_PLATFORM_MONITOR_STATE _GLFWmonitorX11 x11
|
#define _GLFW_PLATFORM_MONITOR_STATE _GLFWmonitorX11 x11
|
||||||
@@ -266,7 +274,6 @@ typedef struct _GLFWlibraryX11
|
|||||||
Atom XdndFinished;
|
Atom XdndFinished;
|
||||||
Atom XdndSelection;
|
Atom XdndSelection;
|
||||||
Atom XdndTypeList;
|
Atom XdndTypeList;
|
||||||
Atom text_uri_list;
|
|
||||||
|
|
||||||
// Selection (clipboard) atoms
|
// Selection (clipboard) atoms
|
||||||
Atom TARGETS;
|
Atom TARGETS;
|
||||||
@@ -327,7 +334,8 @@ typedef struct _GLFWlibraryX11
|
|||||||
struct {
|
struct {
|
||||||
int version;
|
int version;
|
||||||
Window source;
|
Window source;
|
||||||
Atom format;
|
char format[128];
|
||||||
|
int format_priority;
|
||||||
} xdnd;
|
} xdnd;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
@@ -382,6 +390,19 @@ typedef struct _GLFWlibraryX11
|
|||||||
PFN_XRenderFindVisualFormat FindVisualFormat;
|
PFN_XRenderFindVisualFormat FindVisualFormat;
|
||||||
} xrender;
|
} xrender;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
bool available;
|
||||||
|
void* handle;
|
||||||
|
int major;
|
||||||
|
int minor;
|
||||||
|
int eventBase;
|
||||||
|
int errorBase;
|
||||||
|
PFN_XShapeQueryExtension QueryExtension;
|
||||||
|
PFN_XShapeCombineRegion ShapeCombineRegion;
|
||||||
|
PFN_XShapeQueryVersion QueryVersion;
|
||||||
|
PFN_XShapeCombineMask ShapeCombineMask;
|
||||||
|
} xshape;
|
||||||
|
|
||||||
EventLoopData eventLoopData;
|
EventLoopData eventLoopData;
|
||||||
|
|
||||||
} _GLFWlibraryX11;
|
} _GLFWlibraryX11;
|
||||||
|
|||||||
295
glfw/x11_window.c
vendored
295
glfw/x11_window.c
vendored
@@ -422,14 +422,18 @@ static char* convertLatin1toUTF8(const char* source)
|
|||||||
size_t size = 1;
|
size_t size = 1;
|
||||||
const char* sp;
|
const char* sp;
|
||||||
|
|
||||||
for (sp = source; *sp; sp++)
|
if (source) {
|
||||||
size += (*sp & 0x80) ? 2 : 1;
|
for (sp = source; *sp; sp++)
|
||||||
|
size += (*sp & 0x80) ? 2 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
char* target = calloc(size, 1);
|
char* target = calloc(size, 1);
|
||||||
char* tp = target;
|
char* tp = target;
|
||||||
|
|
||||||
for (sp = source; *sp; sp++)
|
if (source) {
|
||||||
tp += encodeUTF8(tp, *sp);
|
for (sp = source; *sp; sp++)
|
||||||
|
tp += encodeUTF8(tp, *sp);
|
||||||
|
}
|
||||||
|
|
||||||
return target;
|
return target;
|
||||||
}
|
}
|
||||||
@@ -455,22 +459,41 @@ static void updateCursorImage(_GLFWwindow* window)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Enable XI2 raw mouse motion events
|
||||||
|
//
|
||||||
|
static void enableRawMouseMotion(_GLFWwindow* window UNUSED)
|
||||||
|
{
|
||||||
|
XIEventMask em;
|
||||||
|
unsigned char mask[XIMaskLen(XI_RawMotion)] = { 0 };
|
||||||
|
|
||||||
|
em.deviceid = XIAllMasterDevices;
|
||||||
|
em.mask_len = sizeof(mask);
|
||||||
|
em.mask = mask;
|
||||||
|
XISetMask(mask, XI_RawMotion);
|
||||||
|
|
||||||
|
XISelectEvents(_glfw.x11.display, _glfw.x11.root, &em, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disable XI2 raw mouse motion events
|
||||||
|
//
|
||||||
|
static void disableRawMouseMotion(_GLFWwindow* window UNUSED)
|
||||||
|
{
|
||||||
|
XIEventMask em;
|
||||||
|
unsigned char mask[] = { 0 };
|
||||||
|
|
||||||
|
em.deviceid = XIAllMasterDevices;
|
||||||
|
em.mask_len = sizeof(mask);
|
||||||
|
em.mask = mask;
|
||||||
|
|
||||||
|
XISelectEvents(_glfw.x11.display, _glfw.x11.root, &em, 1);
|
||||||
|
}
|
||||||
|
|
||||||
// Apply disabled cursor mode to a focused window
|
// Apply disabled cursor mode to a focused window
|
||||||
//
|
//
|
||||||
static void disableCursor(_GLFWwindow* window)
|
static void disableCursor(_GLFWwindow* window)
|
||||||
{
|
{
|
||||||
if (_glfw.x11.xi.available)
|
if (window->rawMouseMotion)
|
||||||
{
|
enableRawMouseMotion(window);
|
||||||
XIEventMask em;
|
|
||||||
unsigned char mask[XIMaskLen(XI_RawMotion)] = { 0 };
|
|
||||||
|
|
||||||
em.deviceid = XIAllMasterDevices;
|
|
||||||
em.mask_len = sizeof(mask);
|
|
||||||
em.mask = mask;
|
|
||||||
XISetMask(mask, XI_RawMotion);
|
|
||||||
|
|
||||||
XISelectEvents(_glfw.x11.display, _glfw.x11.root, &em, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
_glfw.x11.disabledCursorWindow = window;
|
_glfw.x11.disabledCursorWindow = window;
|
||||||
_glfwPlatformGetCursorPos(window,
|
_glfwPlatformGetCursorPos(window,
|
||||||
@@ -490,17 +513,8 @@ static void disableCursor(_GLFWwindow* window)
|
|||||||
//
|
//
|
||||||
static void enableCursor(_GLFWwindow* window)
|
static void enableCursor(_GLFWwindow* window)
|
||||||
{
|
{
|
||||||
if (_glfw.x11.xi.available)
|
if (window->rawMouseMotion)
|
||||||
{
|
disableRawMouseMotion(window);
|
||||||
XIEventMask em;
|
|
||||||
unsigned char mask[] = { 0 };
|
|
||||||
|
|
||||||
em.deviceid = XIAllMasterDevices;
|
|
||||||
em.mask_len = sizeof(mask);
|
|
||||||
em.mask = mask;
|
|
||||||
|
|
||||||
XISelectEvents(_glfw.x11.display, _glfw.x11.root, &em, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
_glfw.x11.disabledCursorWindow = NULL;
|
_glfw.x11.disabledCursorWindow = NULL;
|
||||||
XUngrabPointer(_glfw.x11.display, CurrentTime);
|
XUngrabPointer(_glfw.x11.display, CurrentTime);
|
||||||
@@ -761,7 +775,7 @@ static Atom writeTargetToProperty(const XSelectionRequestEvent* request)
|
|||||||
|
|
||||||
if (j < formatCount)
|
if (j < formatCount)
|
||||||
{
|
{
|
||||||
XChangeProperty(_glfw.x11.display,
|
if (selectionString) XChangeProperty(_glfw.x11.display,
|
||||||
request->requestor,
|
request->requestor,
|
||||||
targets[i + 1],
|
targets[i + 1],
|
||||||
targets[i],
|
targets[i],
|
||||||
@@ -813,7 +827,7 @@ static Atom writeTargetToProperty(const XSelectionRequestEvent* request)
|
|||||||
{
|
{
|
||||||
// The requested target is one we support
|
// The requested target is one we support
|
||||||
|
|
||||||
XChangeProperty(_glfw.x11.display,
|
if (selectionString) XChangeProperty(_glfw.x11.display,
|
||||||
request->requestor,
|
request->requestor,
|
||||||
request->property,
|
request->property,
|
||||||
request->target,
|
request->target,
|
||||||
@@ -944,8 +958,10 @@ static const char* getSelectionString(Atom selection)
|
|||||||
(XPointer) ¬ification))
|
(XPointer) ¬ification))
|
||||||
{
|
{
|
||||||
monotonic_t time = glfwGetTime();
|
monotonic_t time = glfwGetTime();
|
||||||
if (time - start > s_to_monotonic_t(2ll))
|
if (time - start > s_to_monotonic_t(2ll)) {
|
||||||
|
free(string);
|
||||||
return "";
|
return "";
|
||||||
|
}
|
||||||
waitForX11Event(s_to_monotonic_t(2ll) - (time - start));
|
waitForX11Event(s_to_monotonic_t(2ll) - (time - start));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1075,6 +1091,21 @@ static void onConfigChange(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
get_atom_names(Atom *atoms, int count, char **atom_names) {
|
||||||
|
_glfwGrabErrorHandlerX11();
|
||||||
|
XGetAtomNames(_glfw.x11.display, atoms, count, atom_names);
|
||||||
|
_glfwReleaseErrorHandlerX11();
|
||||||
|
if (_glfw.x11.errorCode != Success) {
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
_glfwGrabErrorHandlerX11();
|
||||||
|
atom_names[i] = XGetAtomName(_glfw.x11.display, atoms[i]);
|
||||||
|
_glfwReleaseErrorHandlerX11();
|
||||||
|
if (_glfw.x11.errorCode != Success) atom_names[i] = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Process the specified X event
|
// Process the specified X event
|
||||||
//
|
//
|
||||||
static void processEvent(XEvent *event)
|
static void processEvent(XEvent *event)
|
||||||
@@ -1107,6 +1138,7 @@ static void processEvent(XEvent *event)
|
|||||||
_GLFWwindow* window = _glfw.x11.disabledCursorWindow;
|
_GLFWwindow* window = _glfw.x11.disabledCursorWindow;
|
||||||
|
|
||||||
if (window &&
|
if (window &&
|
||||||
|
window->rawMouseMotion &&
|
||||||
event->xcookie.extension == _glfw.x11.xi.majorOpcode &&
|
event->xcookie.extension == _glfw.x11.xi.majorOpcode &&
|
||||||
XGetEventData(_glfw.x11.display, &event->xcookie) &&
|
XGetEventData(_glfw.x11.display, &event->xcookie) &&
|
||||||
event->xcookie.evtype == XI_RawMotion)
|
event->xcookie.evtype == XI_RawMotion)
|
||||||
@@ -1150,12 +1182,26 @@ static void processEvent(XEvent *event)
|
|||||||
else if (event->type == _glfw.x11.xkb.eventBase)
|
else if (event->type == _glfw.x11.xkb.eventBase)
|
||||||
{
|
{
|
||||||
XkbEvent *kb_event = (XkbEvent*)event;
|
XkbEvent *kb_event = (XkbEvent*)event;
|
||||||
|
if (kb_event->any.device != (unsigned int)_glfw.x11.xkb.keyboard_device_id) return;
|
||||||
switch(kb_event->any.xkb_type) {
|
switch(kb_event->any.xkb_type) {
|
||||||
case XkbNewKeyboardNotify:
|
case XkbNewKeyboardNotify: {
|
||||||
if(!glfw_xkb_update_x11_keyboard_id(&_glfw.x11.xkb)) return;
|
XkbNewKeyboardNotifyEvent *newkb_event = (XkbNewKeyboardNotifyEvent*)kb_event;
|
||||||
/* fallthrough */
|
if (_glfw.hints.init.debugKeyboard) printf(
|
||||||
|
"Got XkbNewKeyboardNotify event with changes: key codes: %d geometry: %d device id: %d\n",
|
||||||
|
!!(newkb_event->changed & XkbNKN_KeycodesMask), !!(newkb_event->changed & XkbNKN_GeometryMask),
|
||||||
|
!!(newkb_event->changed & XkbNKN_DeviceIDMask));
|
||||||
|
if (newkb_event->changed & XkbNKN_DeviceIDMask) {
|
||||||
|
keymap_dirty = true;
|
||||||
|
if (!glfw_xkb_update_x11_keyboard_id(&_glfw.x11.xkb)) return;
|
||||||
|
}
|
||||||
|
if (newkb_event->changed & XkbNKN_KeycodesMask) {
|
||||||
|
keymap_dirty = true;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
case XkbMapNotify:
|
case XkbMapNotify:
|
||||||
{
|
{
|
||||||
|
if (_glfw.hints.init.debugKeyboard) printf("Got XkbMapNotify event, keymaps will be reloaded\n");
|
||||||
keymap_dirty = true;
|
keymap_dirty = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1250,13 +1296,13 @@ static void processEvent(XEvent *event)
|
|||||||
|
|
||||||
// Modern X provides scroll events as mouse button presses
|
// Modern X provides scroll events as mouse button presses
|
||||||
else if (event->xbutton.button == Button4)
|
else if (event->xbutton.button == Button4)
|
||||||
_glfwInputScroll(window, 0.0, 1.0, 0);
|
_glfwInputScroll(window, 0.0, 1.0, 0, mods);
|
||||||
else if (event->xbutton.button == Button5)
|
else if (event->xbutton.button == Button5)
|
||||||
_glfwInputScroll(window, 0.0, -1.0, 0);
|
_glfwInputScroll(window, 0.0, -1.0, 0, mods);
|
||||||
else if (event->xbutton.button == Button6)
|
else if (event->xbutton.button == Button6)
|
||||||
_glfwInputScroll(window, 1.0, 0.0, 0);
|
_glfwInputScroll(window, 1.0, 0.0, 0, mods);
|
||||||
else if (event->xbutton.button == Button7)
|
else if (event->xbutton.button == Button7)
|
||||||
_glfwInputScroll(window, -1.0, 0.0, 0);
|
_glfwInputScroll(window, -1.0, 0.0, 0, mods);
|
||||||
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -1348,7 +1394,7 @@ static void processEvent(XEvent *event)
|
|||||||
{
|
{
|
||||||
if (_glfw.x11.disabledCursorWindow != window)
|
if (_glfw.x11.disabledCursorWindow != window)
|
||||||
return;
|
return;
|
||||||
if (_glfw.x11.xi.available)
|
if (window->rawMouseMotion)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const int dx = x - window->x11.lastCursorPosX;
|
const int dx = x - window->x11.lastCursorPosX;
|
||||||
@@ -1393,12 +1439,18 @@ static void processEvent(XEvent *event)
|
|||||||
if (!event->xany.send_event && window->x11.parent != _glfw.x11.root)
|
if (!event->xany.send_event && window->x11.parent != _glfw.x11.root)
|
||||||
{
|
{
|
||||||
Window dummy;
|
Window dummy;
|
||||||
|
_glfwGrabErrorHandlerX11();
|
||||||
XTranslateCoordinates(_glfw.x11.display,
|
XTranslateCoordinates(_glfw.x11.display,
|
||||||
window->x11.parent,
|
window->x11.parent,
|
||||||
_glfw.x11.root,
|
_glfw.x11.root,
|
||||||
xpos, ypos,
|
xpos, ypos,
|
||||||
&xpos, &ypos,
|
&xpos, &ypos,
|
||||||
&dummy);
|
&dummy);
|
||||||
|
_glfwReleaseErrorHandlerX11();
|
||||||
|
if (_glfw.x11.errorCode != Success) {
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR, "X11: Failed to translate ConfigureNotiy co-ords for reparented window");
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (xpos != window->x11.xpos || ypos != window->x11.ypos)
|
if (xpos != window->x11.xpos || ypos != window->x11.ypos)
|
||||||
@@ -1454,7 +1506,8 @@ static void processEvent(XEvent *event)
|
|||||||
|
|
||||||
_glfw.x11.xdnd.source = event->xclient.data.l[0];
|
_glfw.x11.xdnd.source = event->xclient.data.l[0];
|
||||||
_glfw.x11.xdnd.version = event->xclient.data.l[1] >> 24;
|
_glfw.x11.xdnd.version = event->xclient.data.l[1] >> 24;
|
||||||
_glfw.x11.xdnd.format = None;
|
memset(_glfw.x11.xdnd.format, 0, sizeof(_glfw.x11.xdnd.format));
|
||||||
|
_glfw.x11.xdnd.format_priority = 0;
|
||||||
|
|
||||||
if (_glfw.x11.xdnd.version > _GLFW_XDND_VERSION)
|
if (_glfw.x11.xdnd.version > _GLFW_XDND_VERSION)
|
||||||
return;
|
return;
|
||||||
@@ -1471,14 +1524,22 @@ static void processEvent(XEvent *event)
|
|||||||
count = 3;
|
count = 3;
|
||||||
formats = (Atom*) event->xclient.data.l + 2;
|
formats = (Atom*) event->xclient.data.l + 2;
|
||||||
}
|
}
|
||||||
|
char **atom_names = calloc(count, sizeof(char*));
|
||||||
|
if (atom_names) {
|
||||||
|
get_atom_names(formats, count, atom_names);
|
||||||
|
|
||||||
for (i = 0; i < count; i++)
|
for (i = 0; i < count; i++)
|
||||||
{
|
|
||||||
if (formats[i] == _glfw.x11.text_uri_list)
|
|
||||||
{
|
{
|
||||||
_glfw.x11.xdnd.format = _glfw.x11.text_uri_list;
|
if (atom_names[i]) {
|
||||||
break;
|
int prio = _glfwInputDrop(window, atom_names[i], NULL, 0);
|
||||||
|
if (prio > _glfw.x11.xdnd.format_priority) {
|
||||||
|
_glfw.x11.xdnd.format_priority = prio;
|
||||||
|
strncpy(_glfw.x11.xdnd.format, atom_names[i], arraysz(_glfw.x11.xdnd.format) - 1);
|
||||||
|
}
|
||||||
|
XFree(atom_names[i]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
free(atom_names);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (list && formats)
|
if (list && formats)
|
||||||
@@ -1492,7 +1553,7 @@ static void processEvent(XEvent *event)
|
|||||||
if (_glfw.x11.xdnd.version > _GLFW_XDND_VERSION)
|
if (_glfw.x11.xdnd.version > _GLFW_XDND_VERSION)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (_glfw.x11.xdnd.format)
|
if (_glfw.x11.xdnd.format_priority > 0)
|
||||||
{
|
{
|
||||||
if (_glfw.x11.xdnd.version >= 1)
|
if (_glfw.x11.xdnd.version >= 1)
|
||||||
time = event->xclient.data.l[2];
|
time = event->xclient.data.l[2];
|
||||||
@@ -1500,7 +1561,7 @@ static void processEvent(XEvent *event)
|
|||||||
// Request the chosen format from the source window
|
// Request the chosen format from the source window
|
||||||
XConvertSelection(_glfw.x11.display,
|
XConvertSelection(_glfw.x11.display,
|
||||||
_glfw.x11.XdndSelection,
|
_glfw.x11.XdndSelection,
|
||||||
_glfw.x11.xdnd.format,
|
XInternAtom(_glfw.x11.display, _glfw.x11.xdnd.format, 0),
|
||||||
_glfw.x11.XdndSelection,
|
_glfw.x11.XdndSelection,
|
||||||
window->x11.handle,
|
window->x11.handle,
|
||||||
time);
|
time);
|
||||||
@@ -1526,17 +1587,21 @@ static void processEvent(XEvent *event)
|
|||||||
const int xabs = (event->xclient.data.l[2] >> 16) & 0xffff;
|
const int xabs = (event->xclient.data.l[2] >> 16) & 0xffff;
|
||||||
const int yabs = (event->xclient.data.l[2]) & 0xffff;
|
const int yabs = (event->xclient.data.l[2]) & 0xffff;
|
||||||
Window dummy;
|
Window dummy;
|
||||||
int xpos, ypos;
|
int xpos = 0, ypos = 0;
|
||||||
|
|
||||||
if (_glfw.x11.xdnd.version > _GLFW_XDND_VERSION)
|
if (_glfw.x11.xdnd.version > _GLFW_XDND_VERSION)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
_glfwGrabErrorHandlerX11();
|
||||||
XTranslateCoordinates(_glfw.x11.display,
|
XTranslateCoordinates(_glfw.x11.display,
|
||||||
_glfw.x11.root,
|
_glfw.x11.root,
|
||||||
window->x11.handle,
|
window->x11.handle,
|
||||||
xabs, yabs,
|
xabs, yabs,
|
||||||
&xpos, &ypos,
|
&xpos, &ypos,
|
||||||
&dummy);
|
&dummy);
|
||||||
|
_glfwReleaseErrorHandlerX11();
|
||||||
|
if (_glfw.x11.errorCode != Success)
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR, "X11: Failed to get DND event position");
|
||||||
|
|
||||||
_glfwInputCursorPos(window, xpos, ypos);
|
_glfwInputCursorPos(window, xpos, ypos);
|
||||||
|
|
||||||
@@ -1548,7 +1613,7 @@ static void processEvent(XEvent *event)
|
|||||||
reply.xclient.data.l[2] = 0; // Specify an empty rectangle
|
reply.xclient.data.l[2] = 0; // Specify an empty rectangle
|
||||||
reply.xclient.data.l[3] = 0;
|
reply.xclient.data.l[3] = 0;
|
||||||
|
|
||||||
if (_glfw.x11.xdnd.format)
|
if (_glfw.x11.xdnd.format_priority > 0)
|
||||||
{
|
{
|
||||||
// Reply that we are ready to copy the dragged data
|
// Reply that we are ready to copy the dragged data
|
||||||
reply.xclient.data.l[1] = 1; // Accept with no rectangle
|
reply.xclient.data.l[1] = 1; // Accept with no rectangle
|
||||||
@@ -1578,14 +1643,7 @@ static void processEvent(XEvent *event)
|
|||||||
|
|
||||||
if (result)
|
if (result)
|
||||||
{
|
{
|
||||||
int i, count;
|
_glfwInputDrop(window, _glfw.x11.xdnd.format, data, result);
|
||||||
char** paths = parseUriList(data, &count);
|
|
||||||
|
|
||||||
_glfwInputDrop(window, count, (const char**) paths);
|
|
||||||
|
|
||||||
for (i = 0; i < count; i++)
|
|
||||||
free(paths[i]);
|
|
||||||
free(paths);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data)
|
if (data)
|
||||||
@@ -1798,7 +1856,7 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window,
|
|||||||
const _GLFWctxconfig* ctxconfig,
|
const _GLFWctxconfig* ctxconfig,
|
||||||
const _GLFWfbconfig* fbconfig)
|
const _GLFWfbconfig* fbconfig)
|
||||||
{
|
{
|
||||||
Visual* visual;
|
Visual* visual = NULL;
|
||||||
int depth;
|
int depth;
|
||||||
|
|
||||||
if (ctxconfig->client != GLFW_NO_API)
|
if (ctxconfig->client != GLFW_NO_API)
|
||||||
@@ -1824,8 +1882,7 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctxconfig->client == GLFW_NO_API ||
|
if (!visual)
|
||||||
ctxconfig->source == GLFW_OSMESA_CONTEXT_API)
|
|
||||||
{
|
{
|
||||||
visual = DefaultVisual(_glfw.x11.display, _glfw.x11.screen);
|
visual = DefaultVisual(_glfw.x11.display, _glfw.x11.screen);
|
||||||
depth = DefaultDepth(_glfw.x11.display, _glfw.x11.screen);
|
depth = DefaultDepth(_glfw.x11.display, _glfw.x11.screen);
|
||||||
@@ -1971,10 +2028,14 @@ void _glfwPlatformSetWindowIcon(_GLFWwindow* window,
|
|||||||
void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos)
|
void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos)
|
||||||
{
|
{
|
||||||
Window dummy;
|
Window dummy;
|
||||||
int x, y;
|
int x = 0, y = 0;
|
||||||
|
|
||||||
|
_glfwGrabErrorHandlerX11();
|
||||||
XTranslateCoordinates(_glfw.x11.display, window->x11.handle, _glfw.x11.root,
|
XTranslateCoordinates(_glfw.x11.display, window->x11.handle, _glfw.x11.root,
|
||||||
0, 0, &x, &y, &dummy);
|
0, 0, &x, &y, &dummy);
|
||||||
|
_glfwReleaseErrorHandlerX11();
|
||||||
|
if (_glfw.x11.errorCode != Success)
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR, "X11: Failed to get window position");
|
||||||
|
|
||||||
if (xpos)
|
if (xpos)
|
||||||
*xpos = x;
|
*xpos = x;
|
||||||
@@ -2373,6 +2434,7 @@ int _glfwPlatformWindowMaximized(_GLFWwindow* window)
|
|||||||
{
|
{
|
||||||
return maximized;
|
return maximized;
|
||||||
}
|
}
|
||||||
|
|
||||||
const unsigned long count =
|
const unsigned long count =
|
||||||
_glfwGetWindowPropertyX11(window->x11.handle,
|
_glfwGetWindowPropertyX11(window->x11.handle,
|
||||||
_glfw.x11.NET_WM_STATE,
|
_glfw.x11.NET_WM_STATE,
|
||||||
@@ -2404,13 +2466,19 @@ int _glfwPlatformWindowHovered(_GLFWwindow* window)
|
|||||||
int rootX, rootY, childX, childY;
|
int rootX, rootY, childX, childY;
|
||||||
unsigned int mask;
|
unsigned int mask;
|
||||||
|
|
||||||
if (!XQueryPointer(_glfw.x11.display, w,
|
_glfwGrabErrorHandlerX11();
|
||||||
&root, &w, &rootX, &rootY, &childX, &childY, &mask))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (w == window->x11.handle)
|
const Bool result = XQueryPointer(_glfw.x11.display, w,
|
||||||
|
&root, &w, &rootX, &rootY,
|
||||||
|
&childX, &childY, &mask);
|
||||||
|
|
||||||
|
_glfwReleaseErrorHandlerX11();
|
||||||
|
|
||||||
|
if (_glfw.x11.errorCode == BadWindow)
|
||||||
|
w = _glfw.x11.root;
|
||||||
|
else if (!result)
|
||||||
|
return false;
|
||||||
|
else if (w == window->x11.handle)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2524,6 +2592,25 @@ void _glfwPlatformSetWindowFloating(_GLFWwindow* window, bool enabled)
|
|||||||
XFlush(_glfw.x11.display);
|
XFlush(_glfw.x11.display);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _glfwPlatformSetWindowMousePassthrough(_GLFWwindow* window, bool enabled)
|
||||||
|
{
|
||||||
|
if (!_glfw.x11.xshape.available)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (enabled)
|
||||||
|
{
|
||||||
|
Region region = XCreateRegion();
|
||||||
|
XShapeCombineRegion(_glfw.x11.display, window->x11.handle,
|
||||||
|
ShapeInput, 0, 0, region, ShapeSet);
|
||||||
|
XDestroyRegion(region);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
XShapeCombineMask(_glfw.x11.display, window->x11.handle,
|
||||||
|
ShapeInput, 0, 0, None, ShapeSet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
float _glfwPlatformGetWindowOpacity(_GLFWwindow* window)
|
float _glfwPlatformGetWindowOpacity(_GLFWwindow* window)
|
||||||
{
|
{
|
||||||
float opacity = 1.f;
|
float opacity = 1.f;
|
||||||
@@ -2572,7 +2659,8 @@ _glfwDispatchX11Events(void) {
|
|||||||
unsigned dispatched = 0;
|
unsigned dispatched = 0;
|
||||||
|
|
||||||
#if defined(__linux__)
|
#if defined(__linux__)
|
||||||
if (_glfw.hints.init.enableJoysticks) _glfwDetectJoystickConnectionLinux();
|
if (_glfw.joysticksInitialized)
|
||||||
|
_glfwDetectJoystickConnectionLinux();
|
||||||
#endif
|
#endif
|
||||||
dispatched += dispatch_x11_queued_events(XEventsQueued(_glfw.x11.display, QueuedAfterFlush));
|
dispatched += dispatch_x11_queued_events(XEventsQueued(_glfw.x11.display, QueuedAfterFlush));
|
||||||
|
|
||||||
@@ -2599,6 +2687,25 @@ _glfwDispatchX11Events(void) {
|
|||||||
return dispatched;
|
return dispatched;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _glfwPlatformSetRawMouseMotion(_GLFWwindow *window, bool enabled)
|
||||||
|
{
|
||||||
|
if (!_glfw.x11.xi.available)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (_glfw.x11.disabledCursorWindow != window)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (enabled)
|
||||||
|
enableRawMouseMotion(window);
|
||||||
|
else
|
||||||
|
disableRawMouseMotion(window);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _glfwPlatformRawMouseMotionSupported(void)
|
||||||
|
{
|
||||||
|
return _glfw.x11.xi.available;
|
||||||
|
}
|
||||||
|
|
||||||
void _glfwPlatformPollEvents(void)
|
void _glfwPlatformPollEvents(void)
|
||||||
{
|
{
|
||||||
_glfwDispatchX11Events();
|
_glfwDispatchX11Events();
|
||||||
@@ -2692,7 +2799,7 @@ int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, GLFWCursorShape shape
|
|||||||
int native = 0;
|
int native = 0;
|
||||||
#define C(name, val) case name: native = val; break;
|
#define C(name, val) case name: native = val; break;
|
||||||
switch(shape) {
|
switch(shape) {
|
||||||
C(GLFW_ARROW_CURSOR, XC_arrow);
|
C(GLFW_ARROW_CURSOR, XC_left_ptr);
|
||||||
C(GLFW_IBEAM_CURSOR, XC_xterm);
|
C(GLFW_IBEAM_CURSOR, XC_xterm);
|
||||||
C(GLFW_CROSSHAIR_CURSOR, XC_crosshair);
|
C(GLFW_CROSSHAIR_CURSOR, XC_crosshair);
|
||||||
C(GLFW_HAND_CURSOR, XC_hand2);
|
C(GLFW_HAND_CURSOR, XC_hand2);
|
||||||
@@ -2735,8 +2842,9 @@ void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor UNUSED)
|
|||||||
|
|
||||||
void _glfwPlatformSetClipboardString(const char* string)
|
void _glfwPlatformSetClipboardString(const char* string)
|
||||||
{
|
{
|
||||||
|
char* copy = _glfw_strdup(string);
|
||||||
free(_glfw.x11.clipboardString);
|
free(_glfw.x11.clipboardString);
|
||||||
_glfw.x11.clipboardString = _glfw_strdup(string);
|
_glfw.x11.clipboardString = copy;
|
||||||
|
|
||||||
XSetSelectionOwner(_glfw.x11.display,
|
XSetSelectionOwner(_glfw.x11.display,
|
||||||
_glfw.x11.CLIPBOARD,
|
_glfw.x11.CLIPBOARD,
|
||||||
@@ -2779,6 +2887,55 @@ const char* _glfwPlatformGetPrimarySelectionString(void)
|
|||||||
return getSelectionString(_glfw.x11.PRIMARY);
|
return getSelectionString(_glfw.x11.PRIMARY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EGLenum _glfwPlatformGetEGLPlatform(EGLint** attribs)
|
||||||
|
{
|
||||||
|
if (_glfw.egl.ANGLE_platform_angle)
|
||||||
|
{
|
||||||
|
int type = 0;
|
||||||
|
|
||||||
|
if (_glfw.egl.ANGLE_platform_angle_opengl)
|
||||||
|
{
|
||||||
|
if (_glfw.hints.init.angleType == GLFW_ANGLE_PLATFORM_TYPE_OPENGL)
|
||||||
|
type = EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_glfw.egl.ANGLE_platform_angle_vulkan)
|
||||||
|
{
|
||||||
|
if (_glfw.hints.init.angleType == GLFW_ANGLE_PLATFORM_TYPE_VULKAN)
|
||||||
|
type = EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type)
|
||||||
|
{
|
||||||
|
*attribs = calloc(5, sizeof(EGLint));
|
||||||
|
(*attribs)[0] = EGL_PLATFORM_ANGLE_TYPE_ANGLE;
|
||||||
|
(*attribs)[1] = type;
|
||||||
|
(*attribs)[2] = EGL_PLATFORM_ANGLE_NATIVE_PLATFORM_TYPE_ANGLE;
|
||||||
|
(*attribs)[3] = EGL_PLATFORM_X11_EXT;
|
||||||
|
(*attribs)[4] = EGL_NONE;
|
||||||
|
return EGL_PLATFORM_ANGLE_ANGLE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_glfw.egl.EXT_platform_base && _glfw.egl.EXT_platform_x11)
|
||||||
|
return EGL_PLATFORM_X11_EXT;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
EGLNativeDisplayType _glfwPlatformGetEGLNativeDisplay(void)
|
||||||
|
{
|
||||||
|
return _glfw.x11.display;
|
||||||
|
}
|
||||||
|
|
||||||
|
EGLNativeWindowType _glfwPlatformGetEGLNativeWindow(_GLFWwindow* window)
|
||||||
|
{
|
||||||
|
if (_glfw.egl.platform)
|
||||||
|
return &window->x11.handle;
|
||||||
|
else
|
||||||
|
return (EGLNativeWindowType) window->x11.handle;
|
||||||
|
}
|
||||||
|
|
||||||
void _glfwPlatformGetRequiredInstanceExtensions(char** extensions)
|
void _glfwPlatformGetRequiredInstanceExtensions(char** extensions)
|
||||||
{
|
{
|
||||||
if (!_glfw.vk.KHR_surface)
|
if (!_glfw.vk.KHR_surface)
|
||||||
|
|||||||
59
glfw/xkb_glfw.c
vendored
59
glfw/xkb_glfw.c
vendored
@@ -371,9 +371,31 @@ load_compose_tables(_GLFWXKBData *xkb) {
|
|||||||
xkb_compose_table_unref(compose_table);
|
xkb_compose_table_unref(compose_table);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline xkb_mod_mask_t
|
||||||
|
active_unknown_modifiers(_GLFWXKBData *xkb, struct xkb_state *state) {
|
||||||
|
size_t i = 0;
|
||||||
|
xkb_mod_mask_t ans = 0;
|
||||||
|
while (xkb->unknownModifiers[i] != XKB_MOD_INVALID) {
|
||||||
|
if (xkb_state_mod_index_is_active(state, xkb->unknownModifiers[i], XKB_STATE_MODS_EFFECTIVE)) ans |= (1 << xkb->unknownModifiers[i]);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
return ans;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
update_modifiers(_GLFWXKBData *xkb) {
|
||||||
|
XKBStateGroup *group = &xkb->states;
|
||||||
|
#define S(attr, name) if (xkb_state_mod_index_is_active(group->state, xkb->attr##Idx, XKB_STATE_MODS_EFFECTIVE)) group->modifiers |= GLFW_MOD_##name
|
||||||
|
S(control, CONTROL); S(alt, ALT); S(shift, SHIFT); S(super, SUPER); S(capsLock, CAPS_LOCK); S(numLock, NUM_LOCK);
|
||||||
|
#undef S
|
||||||
|
xkb->states.activeUnknownModifiers = active_unknown_modifiers(xkb, xkb->states.state);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
glfw_xkb_compile_keymap(_GLFWXKBData *xkb, const char *map_str) {
|
glfw_xkb_compile_keymap(_GLFWXKBData *xkb, const char *map_str) {
|
||||||
const char *err;
|
const char *err;
|
||||||
|
debug("Loading new XKB keymaps\n");
|
||||||
release_keyboard_data(xkb);
|
release_keyboard_data(xkb);
|
||||||
err = load_keymaps(xkb, map_str);
|
err = load_keymaps(xkb, map_str);
|
||||||
if (err) {
|
if (err) {
|
||||||
@@ -396,36 +418,17 @@ glfw_xkb_compile_keymap(_GLFWXKBData *xkb, const char *map_str) {
|
|||||||
S(capsLock, XKB_MOD_NAME_CAPS);
|
S(capsLock, XKB_MOD_NAME_CAPS);
|
||||||
S(numLock, XKB_MOD_NAME_NUM);
|
S(numLock, XKB_MOD_NAME_NUM);
|
||||||
#undef S
|
#undef S
|
||||||
size_t capacity = sizeof(xkb->unknownModifiers)/sizeof(xkb->unknownModifiers[0]), j = 0;
|
size_t capacity = arraysz(xkb->unknownModifiers), j = 0;
|
||||||
for (xkb_mod_index_t i = 0; i < capacity; i++) xkb->unknownModifiers[i] = XKB_MOD_INVALID;
|
for (xkb_mod_index_t i = 0; i < capacity; i++) xkb->unknownModifiers[i] = XKB_MOD_INVALID;
|
||||||
for (xkb_mod_index_t i = 0; i < xkb_keymap_num_mods(xkb->keymap) && j < capacity - 1; i++) {
|
for (xkb_mod_index_t i = 0; i < xkb_keymap_num_mods(xkb->keymap) && j < capacity - 1; i++) {
|
||||||
if (i != xkb->controlIdx && i != xkb->altIdx && i != xkb->shiftIdx && i != xkb->superIdx && i != xkb->capsLockIdx && i != xkb->numLockIdx) xkb->unknownModifiers[j++] = i;
|
if (i != xkb->controlIdx && i != xkb->altIdx && i != xkb->shiftIdx && i != xkb->superIdx && i != xkb->capsLockIdx && i != xkb->numLockIdx) xkb->unknownModifiers[j++] = i;
|
||||||
}
|
}
|
||||||
xkb->states.modifiers = 0;
|
xkb->states.modifiers = 0;
|
||||||
xkb->states.activeUnknownModifiers = 0;
|
xkb->states.activeUnknownModifiers = 0;
|
||||||
|
update_modifiers(xkb);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline xkb_mod_mask_t
|
|
||||||
active_unknown_modifiers(_GLFWXKBData *xkb, struct xkb_state *state) {
|
|
||||||
size_t i = 0;
|
|
||||||
xkb_mod_mask_t ans = 0;
|
|
||||||
while (xkb->unknownModifiers[i] != XKB_MOD_INVALID) {
|
|
||||||
if (xkb_state_mod_index_is_active(state, xkb->unknownModifiers[i], XKB_STATE_MODS_EFFECTIVE)) ans |= (1 << xkb->unknownModifiers[i]);
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
return ans;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
update_modifiers(_GLFWXKBData *xkb, XKBStateGroup *group) {
|
|
||||||
#define S(attr, name) if (xkb_state_mod_index_is_active(group->state, xkb->attr##Idx, XKB_STATE_MODS_EFFECTIVE)) group->modifiers |= GLFW_MOD_##name
|
|
||||||
S(control, CONTROL); S(alt, ALT); S(shift, SHIFT); S(super, SUPER); S(capsLock, CAPS_LOCK); S(numLock, NUM_LOCK);
|
|
||||||
#undef S
|
|
||||||
xkb->states.activeUnknownModifiers = active_unknown_modifiers(xkb, xkb->states.state);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
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) {
|
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) {
|
||||||
if (!xkb->keymap) return;
|
if (!xkb->keymap) return;
|
||||||
@@ -434,7 +437,7 @@ glfw_xkb_update_modifiers(_GLFWXKBData *xkb, xkb_mod_mask_t depressed, xkb_mod_m
|
|||||||
// We have to update the groups in clean_state, as they change for
|
// We have to update the groups in clean_state, as they change for
|
||||||
// different keyboard layouts, see https://github.com/kovidgoyal/kitty/issues/488
|
// different keyboard layouts, see https://github.com/kovidgoyal/kitty/issues/488
|
||||||
xkb_state_update_mask(xkb->states.clean_state, 0, 0, 0, base_group, latched_group, locked_group);
|
xkb_state_update_mask(xkb->states.clean_state, 0, 0, 0, base_group, latched_group, locked_group);
|
||||||
update_modifiers(xkb, &xkb->states);
|
update_modifiers(xkb);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
@@ -503,14 +506,19 @@ static inline const char*
|
|||||||
format_xkb_mods(_GLFWXKBData *xkb, const char* name, xkb_mod_mask_t mods) {
|
format_xkb_mods(_GLFWXKBData *xkb, const char* name, xkb_mod_mask_t mods) {
|
||||||
static char buf[512];
|
static char buf[512];
|
||||||
char *p = buf, *s;
|
char *p = buf, *s;
|
||||||
#define pr(x) p += snprintf(p, sizeof(buf) - (p - buf) - 1, "%s", x)
|
#define pr(x) { \
|
||||||
|
int num_needed = -1; \
|
||||||
|
ssize_t space_left = sizeof(buf) - (p - buf) - 1; \
|
||||||
|
if (space_left > 0) num_needed = snprintf(p, space_left, "%s", x); \
|
||||||
|
if (num_needed > 0) p += num_needed; \
|
||||||
|
}
|
||||||
pr(name); pr(": ");
|
pr(name); pr(": ");
|
||||||
s = p;
|
s = p;
|
||||||
for (xkb_mod_index_t i = 0; i < xkb_keymap_num_mods(xkb->keymap); i++) {
|
for (xkb_mod_index_t i = 0; i < xkb_keymap_num_mods(xkb->keymap); i++) {
|
||||||
xkb_mod_mask_t m = 1 << i;
|
xkb_mod_mask_t m = 1 << i;
|
||||||
if (m & mods) { pr(xkb_keymap_mod_get_name(xkb->keymap, i)); pr("+"); }
|
if (m & mods) { pr(xkb_keymap_mod_get_name(xkb->keymap, i)); pr("+"); }
|
||||||
}
|
}
|
||||||
if (p == s) pr("none");
|
if (p == s) { pr("none"); }
|
||||||
else p--;
|
else p--;
|
||||||
pr(" ");
|
pr(" ");
|
||||||
#undef pr
|
#undef pr
|
||||||
@@ -620,6 +628,9 @@ glfw_xkb_handle_key_event(_GLFWwindow *window, _GLFWXKBData *xkb, xkb_keycode_t
|
|||||||
}
|
}
|
||||||
if (key_text[0]) { debug("%s: %s ", text_type, key_text); }
|
if (key_text[0]) { debug("%s: %s ", text_type, key_text); }
|
||||||
}
|
}
|
||||||
|
if (xkb_sym == XKB_KEY_ISO_First_Group || xkb_sym == XKB_KEY_ISO_Last_Group || xkb_sym == XKB_KEY_ISO_Next_Group || xkb_sym == XKB_KEY_ISO_Prev_Group || xkb_sym == XKB_KEY_Mode_switch) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
int glfw_sym = glfw_key_for_sym(xkb_sym);
|
int glfw_sym = glfw_key_for_sym(xkb_sym);
|
||||||
bool is_fallback = false;
|
bool is_fallback = false;
|
||||||
if (glfw_sym == GLFW_KEY_UNKNOWN && !key_text[0]) {
|
if (glfw_sym == GLFW_KEY_UNKNOWN && !key_text[0]) {
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
See https://sw.kovidgoyal.net/kitty/graphics-protocol.html
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
See https://sw.kovidgoyal.net/kitty/key-encoding.html
|
|
||||||
@@ -3,28 +3,37 @@
|
|||||||
# License: GPL v3 Copyright: 2018, Kovid Goyal <kovid at kovidgoyal.net>
|
# License: GPL v3 Copyright: 2018, Kovid Goyal <kovid at kovidgoyal.net>
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
import sys
|
||||||
from contextlib import suppress
|
from contextlib import suppress
|
||||||
|
from typing import TYPE_CHECKING, List, Optional, Tuple
|
||||||
|
|
||||||
from kitty.cli import parse_args
|
from kitty.cli import parse_args
|
||||||
|
from kitty.cli_stub import AskCLIOptions
|
||||||
from kitty.constants import cache_dir
|
from kitty.constants import cache_dir
|
||||||
|
from kitty.typing import BossType
|
||||||
|
|
||||||
|
from ..tui.handler import result_handler
|
||||||
from ..tui.operations import alternate_screen, styled
|
from ..tui.operations import alternate_screen, styled
|
||||||
|
from ..tui.utils import get_key_press
|
||||||
|
|
||||||
readline = None
|
if TYPE_CHECKING:
|
||||||
|
import readline
|
||||||
|
else:
|
||||||
|
readline = None
|
||||||
|
|
||||||
|
|
||||||
def get_history_items():
|
def get_history_items() -> List[str]:
|
||||||
return list(map(readline.get_history_item, range(1, readline.get_current_history_length() + 1)))
|
return list(map(readline.get_history_item, range(1, readline.get_current_history_length() + 1)))
|
||||||
|
|
||||||
|
|
||||||
def sort_key(item):
|
def sort_key(item: str) -> Tuple[int, str]:
|
||||||
return len(item), item.lower()
|
return len(item), item.lower()
|
||||||
|
|
||||||
|
|
||||||
class HistoryCompleter:
|
class HistoryCompleter:
|
||||||
|
|
||||||
def __init__(self, name=None):
|
def __init__(self, name: Optional[str] = None):
|
||||||
self.matches = []
|
self.matches: List[str] = []
|
||||||
self.history_path = None
|
self.history_path = None
|
||||||
if name:
|
if name:
|
||||||
ddir = os.path.join(cache_dir(), 'ask')
|
ddir = os.path.join(cache_dir(), 'ask')
|
||||||
@@ -32,7 +41,7 @@ class HistoryCompleter:
|
|||||||
os.makedirs(ddir)
|
os.makedirs(ddir)
|
||||||
self.history_path = os.path.join(ddir, name)
|
self.history_path = os.path.join(ddir, name)
|
||||||
|
|
||||||
def complete(self, text, state):
|
def complete(self, text: str, state: int) -> Optional[str]:
|
||||||
response = None
|
response = None
|
||||||
if state == 0:
|
if state == 0:
|
||||||
history_values = get_history_items()
|
history_values = get_history_items()
|
||||||
@@ -47,22 +56,22 @@ class HistoryCompleter:
|
|||||||
response = None
|
response = None
|
||||||
return response
|
return response
|
||||||
|
|
||||||
def __enter__(self):
|
def __enter__(self) -> 'HistoryCompleter':
|
||||||
if self.history_path:
|
if self.history_path:
|
||||||
with suppress(Exception):
|
with suppress(Exception):
|
||||||
readline.read_history_file(self.history_path)
|
readline.read_history_file(self.history_path)
|
||||||
readline.set_completer(self.complete)
|
readline.set_completer(self.complete)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def __exit__(self, *a):
|
def __exit__(self, *a: object) -> None:
|
||||||
if self.history_path:
|
if self.history_path:
|
||||||
readline.write_history_file(self.history_path)
|
readline.write_history_file(self.history_path)
|
||||||
|
|
||||||
|
|
||||||
def option_text():
|
def option_text() -> str:
|
||||||
return '''\
|
return '''\
|
||||||
--type -t
|
--type -t
|
||||||
choices=line
|
choices=line,yesno,choices
|
||||||
default=line
|
default=line
|
||||||
Type of input. Defaults to asking for a line of text.
|
Type of input. Defaults to asking for a line of text.
|
||||||
|
|
||||||
@@ -75,47 +84,103 @@ message is shown.
|
|||||||
--name -n
|
--name -n
|
||||||
The name for this question. Used to store history of previous answers which can
|
The name for this question. Used to store history of previous answers which can
|
||||||
be used for completions and via the browse history readline bindings.
|
be used for completions and via the browse history readline bindings.
|
||||||
|
|
||||||
|
|
||||||
|
--choice -c
|
||||||
|
type=list
|
||||||
|
dest=choices
|
||||||
|
A choice for the choices type. Every choice has the syntax: letter:text Where
|
||||||
|
letter is the accelerator key and text is the corresponding text. There can be
|
||||||
|
an optional color specification after the letter to indicate what color it should
|
||||||
|
be.
|
||||||
|
For example: y:Yes and n;red:No
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
|
||||||
def main(args):
|
try:
|
||||||
|
from typing import TypedDict
|
||||||
|
except ImportError:
|
||||||
|
TypedDict = dict
|
||||||
|
|
||||||
|
|
||||||
|
class Response(TypedDict):
|
||||||
|
items: List[str]
|
||||||
|
response: Optional[str]
|
||||||
|
|
||||||
|
|
||||||
|
def choice(cli_opts: AskCLIOptions, items: List[str]) -> Response:
|
||||||
|
with alternate_screen():
|
||||||
|
if cli_opts.message:
|
||||||
|
print(styled(cli_opts.message, bold=True))
|
||||||
|
print()
|
||||||
|
allowed = ''
|
||||||
|
for choice in cli_opts.choices:
|
||||||
|
color = 'green'
|
||||||
|
letter, text = choice.split(':', maxsplit=1)
|
||||||
|
if ';' in letter:
|
||||||
|
letter, color = letter.split(';', maxsplit=1)
|
||||||
|
letter = letter.lower()
|
||||||
|
idx = text.lower().index(letter)
|
||||||
|
allowed += letter
|
||||||
|
print(text[:idx], styled(text[idx], fg=color), text[idx + 1:], sep='', end=' ')
|
||||||
|
print()
|
||||||
|
response = get_key_press(allowed, '')
|
||||||
|
return {'items': items, 'response': response}
|
||||||
|
|
||||||
|
|
||||||
|
def yesno(cli_opts: AskCLIOptions, items: List[str]) -> Response:
|
||||||
|
with alternate_screen():
|
||||||
|
if cli_opts.message:
|
||||||
|
print(styled(cli_opts.message, bold=True))
|
||||||
|
print()
|
||||||
|
print(' ', styled('Y', fg='green') + 'es', ' ', styled('N', fg='red') + 'o')
|
||||||
|
response = get_key_press('yn', 'n')
|
||||||
|
return {'items': items, 'response': response}
|
||||||
|
|
||||||
|
|
||||||
|
def main(args: List[str]) -> Response:
|
||||||
# For some reason importing readline in a key handler in the main kitty process
|
# For some reason importing readline in a key handler in the main kitty process
|
||||||
# causes a crash of the python interpreter, probably because of some global
|
# causes a crash of the python interpreter, probably because of some global
|
||||||
# lock
|
# lock
|
||||||
global readline
|
global readline
|
||||||
import readline as rl
|
|
||||||
readline = rl
|
|
||||||
from kitty.shell import init_readline
|
|
||||||
msg = 'Ask the user for input'
|
msg = 'Ask the user for input'
|
||||||
try:
|
try:
|
||||||
args, items = parse_args(args[1:], option_text, '', msg, 'kitty ask')
|
cli_opts, items = parse_args(args[1:], option_text, '', msg, 'kitty ask', result_class=AskCLIOptions)
|
||||||
except SystemExit as e:
|
except SystemExit as e:
|
||||||
if e.code != 0:
|
if e.code != 0:
|
||||||
print(e.args[0])
|
print(e.args[0])
|
||||||
input('Press enter to quit...')
|
input('Press enter to quit...')
|
||||||
raise SystemExit(e.code)
|
raise SystemExit(e.code)
|
||||||
|
|
||||||
init_readline(readline)
|
if cli_opts.type == 'yesno':
|
||||||
ans = {'items': items}
|
return yesno(cli_opts, items)
|
||||||
|
if cli_opts.type == 'choices':
|
||||||
|
return choice(cli_opts, items)
|
||||||
|
|
||||||
with alternate_screen(), HistoryCompleter(args.name):
|
import readline as rl
|
||||||
if args.message:
|
readline = rl
|
||||||
print(styled(args.message, bold=True))
|
from kitty.shell import init_readline
|
||||||
|
init_readline(readline)
|
||||||
|
response = None
|
||||||
|
|
||||||
|
with alternate_screen(), HistoryCompleter(cli_opts.name):
|
||||||
|
if cli_opts.message:
|
||||||
|
print(styled(cli_opts.message, bold=True))
|
||||||
|
|
||||||
prompt = '> '
|
prompt = '> '
|
||||||
with suppress(KeyboardInterrupt, EOFError):
|
with suppress(KeyboardInterrupt, EOFError):
|
||||||
ans['response'] = input(prompt)
|
response = input(prompt)
|
||||||
return ans
|
return {'items': items, 'response': response}
|
||||||
|
|
||||||
|
|
||||||
def handle_result(args, data, target_window_id, boss):
|
@result_handler()
|
||||||
if 'response' in data:
|
def handle_result(args: List[str], data: Response, target_window_id: int, boss: BossType) -> None:
|
||||||
|
if data['response'] is not None:
|
||||||
func, *args = data['items']
|
func, *args = data['items']
|
||||||
getattr(boss, func)(data['response'], *args)
|
getattr(boss, func)(data['response'], *args)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
import sys
|
|
||||||
ans = main(sys.argv)
|
ans = main(sys.argv)
|
||||||
if ans:
|
if ans:
|
||||||
print(ans)
|
print(ans)
|
||||||
|
|||||||
@@ -111,7 +111,7 @@ end:
|
|||||||
if (job_data[i] && job_data[i]->started) wait_for_thread(threads, i);
|
if (job_data[i] && job_data[i]->started) wait_for_thread(threads, i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (i = 0; i < num_threads; i++) job_data[i] = free_job(job_data[i]);
|
if (job_data) { for (i = 0; i < num_threads; i++) job_data[i] = free_job(job_data[i]); }
|
||||||
free(job_data);
|
free(job_data);
|
||||||
free_threads(threads);
|
free_threads(threads);
|
||||||
return ret;
|
return ret;
|
||||||
@@ -130,7 +130,7 @@ run_search(Options *opts, GlobalData *global, const char * const *lines, const s
|
|||||||
ALLOC_VEC(text_t, chars, 8192 * 20);
|
ALLOC_VEC(text_t, chars, 8192 * 20);
|
||||||
if (chars.data == NULL) return 1;
|
if (chars.data == NULL) return 1;
|
||||||
ALLOC_VEC(Candidate, candidates, 8192);
|
ALLOC_VEC(Candidate, candidates, 8192);
|
||||||
if (candidates.data == NULL) { FREE_VEC(chars) return 1; }
|
if (candidates.data == NULL) { FREE_VEC(chars); return 1; }
|
||||||
|
|
||||||
for (size_t i = 0; i < num_lines; i++) {
|
for (size_t i = 0; i < num_lines; i++) {
|
||||||
sz = sizes[i];
|
sz = sizes[i];
|
||||||
|
|||||||
@@ -3,39 +3,40 @@
|
|||||||
# License: GPL v3 Copyright: 2018, Kovid Goyal <kovid at kovidgoyal.net>
|
# License: GPL v3 Copyright: 2018, Kovid Goyal <kovid at kovidgoyal.net>
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
from typing import Iterable, List, Union
|
||||||
|
|
||||||
|
from kitty.key_encoding import KeyEvent
|
||||||
|
|
||||||
|
from . import subseq_matcher
|
||||||
from ..tui.handler import Handler
|
from ..tui.handler import Handler
|
||||||
from ..tui.loop import Loop
|
from ..tui.loop import Loop
|
||||||
|
|
||||||
from . import subseq_matcher
|
|
||||||
|
|
||||||
|
|
||||||
def match(
|
def match(
|
||||||
input_data,
|
input_data: Union[str, bytes, Iterable[Union[str, bytes]]],
|
||||||
query,
|
query: str,
|
||||||
threads=0,
|
threads: int = 0,
|
||||||
positions=False,
|
positions: bool = False,
|
||||||
level1='/',
|
level1: str = '/',
|
||||||
level2='-_0123456789',
|
level2: str = '-_0123456789',
|
||||||
level3='.',
|
level3: str = '.',
|
||||||
limit=0,
|
limit: int = 0,
|
||||||
mark_before='',
|
mark_before: str = '',
|
||||||
mark_after='',
|
mark_after: str = '',
|
||||||
delimiter='\n'
|
delimiter: str = '\n'
|
||||||
):
|
) -> List[str]:
|
||||||
if isinstance(input_data, str):
|
if isinstance(input_data, str):
|
||||||
input_data = input_data.encode('utf-8')
|
idata = [x.encode('utf-8') for x in input_data.split(delimiter)]
|
||||||
if isinstance(input_data, bytes):
|
elif isinstance(input_data, bytes):
|
||||||
input_data = input_data.split(delimiter.encode('utf-8'))
|
idata = input_data.split(delimiter.encode('utf-8'))
|
||||||
else:
|
else:
|
||||||
input_data = [x.encode('utf-8') if isinstance(x, str) else x for x in input_data]
|
idata = [x.encode('utf-8') if isinstance(x, str) else x for x in input_data]
|
||||||
query = query.lower()
|
query = query.lower()
|
||||||
level1 = level1.lower()
|
level1 = level1.lower()
|
||||||
level2 = level2.lower()
|
level2 = level2.lower()
|
||||||
level3 = level3.lower()
|
level3 = level3.lower()
|
||||||
data = subseq_matcher.match(
|
data = subseq_matcher.match(
|
||||||
input_data, (level1, level2, level3), query,
|
idata, (level1, level2, level3), query,
|
||||||
positions, limit, threads,
|
positions, limit, threads,
|
||||||
mark_before, mark_after, delimiter)
|
mark_before, mark_after, delimiter)
|
||||||
if data is None:
|
if data is None:
|
||||||
@@ -45,23 +46,23 @@ def match(
|
|||||||
|
|
||||||
class ChooseHandler(Handler):
|
class ChooseHandler(Handler):
|
||||||
|
|
||||||
def initialize(self):
|
def initialize(self) -> None:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def on_text(self, text, in_bracketed_paste=False):
|
def on_text(self, text: str, in_bracketed_paste: bool = False) -> None:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def on_key(self, key_event):
|
def on_key(self, key_event: KeyEvent) -> None:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def on_interrupt(self):
|
def on_interrupt(self) -> None:
|
||||||
self.quit_loop(1)
|
self.quit_loop(1)
|
||||||
|
|
||||||
def on_eot(self):
|
def on_eot(self) -> None:
|
||||||
self.quit_loop(1)
|
self.quit_loop(1)
|
||||||
|
|
||||||
|
|
||||||
def main(args):
|
def main(args: List[str]) -> None:
|
||||||
loop = Loop()
|
loop = Loop()
|
||||||
handler = ChooseHandler()
|
handler = ChooseHandler()
|
||||||
loop.loop(handler)
|
loop.loop(handler)
|
||||||
|
|||||||
9
kittens/choose/subseq_matcher.pyi
Normal file
9
kittens/choose/subseq_matcher.pyi
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
from typing import List, Optional, Tuple
|
||||||
|
|
||||||
|
|
||||||
|
def match(
|
||||||
|
lines: List[bytes], levels: Tuple[str, str, str], needle: str,
|
||||||
|
output_positions: bool, limit: int, num_threads: int, mark_before: str,
|
||||||
|
mark_after: str, delimiter: str
|
||||||
|
) -> Optional[str]:
|
||||||
|
pass
|
||||||
@@ -28,8 +28,9 @@
|
|||||||
#define ENSURE_SPACE(TYPE, vec, amt) \
|
#define ENSURE_SPACE(TYPE, vec, amt) \
|
||||||
if (vec.size + amt >= vec.capacity) { \
|
if (vec.size + amt >= vec.capacity) { \
|
||||||
vec.capacity = MAX(vec.capacity * 2, vec.size + amt); \
|
vec.capacity = MAX(vec.capacity * 2, vec.size + amt); \
|
||||||
vec.data = (TYPE*)realloc(vec.data, sizeof(TYPE) * vec.capacity); \
|
void *temp = realloc(vec.data, sizeof(TYPE) * vec.capacity); \
|
||||||
if (vec.data == NULL) { REPORT_OOM; ret = 1; break; } \
|
if (temp == NULL) { REPORT_OOM; ret = 1; free(vec.data); vec.data = NULL; vec.size = 0; vec.capacity = 0; break; } \
|
||||||
|
else vec.data = temp; \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define NEXT(vec) (vec.data[vec.size])
|
#define NEXT(vec) (vec.data[vec.size])
|
||||||
|
|||||||
@@ -4,8 +4,10 @@
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
from typing import List, NoReturn, Optional
|
||||||
|
|
||||||
from kitty.cli import parse_args
|
from kitty.cli import parse_args
|
||||||
|
from kitty.cli_stub import ClipboardCLIOptions
|
||||||
|
|
||||||
from ..tui.handler import Handler
|
from ..tui.handler import Handler
|
||||||
from ..tui.loop import Loop
|
from ..tui.loop import Loop
|
||||||
@@ -13,12 +15,12 @@ from ..tui.loop import Loop
|
|||||||
|
|
||||||
class Clipboard(Handler):
|
class Clipboard(Handler):
|
||||||
|
|
||||||
def __init__(self, data_to_send, args):
|
def __init__(self, data_to_send: Optional[bytes], args: ClipboardCLIOptions):
|
||||||
self.args = args
|
self.args = args
|
||||||
self.clipboard_contents = None
|
self.clipboard_contents: Optional[str] = None
|
||||||
self.data_to_send = data_to_send
|
self.data_to_send = data_to_send
|
||||||
|
|
||||||
def initialize(self):
|
def initialize(self) -> None:
|
||||||
if self.data_to_send is not None:
|
if self.data_to_send is not None:
|
||||||
self.cmd.write_to_clipboard(self.data_to_send, self.args.use_primary)
|
self.cmd.write_to_clipboard(self.data_to_send, self.args.use_primary)
|
||||||
if not self.args.get_clipboard:
|
if not self.args.get_clipboard:
|
||||||
@@ -32,17 +34,17 @@ class Clipboard(Handler):
|
|||||||
return
|
return
|
||||||
self.cmd.request_from_clipboard(self.args.use_primary)
|
self.cmd.request_from_clipboard(self.args.use_primary)
|
||||||
|
|
||||||
def on_clipboard_response(self, text, from_primary=False):
|
def on_clipboard_response(self, text: str, from_primary: bool = False) -> None:
|
||||||
self.clipboard_contents = text
|
self.clipboard_contents = text
|
||||||
self.quit_loop(0)
|
self.quit_loop(0)
|
||||||
|
|
||||||
def on_capability_response(self, name, val):
|
def on_capability_response(self, name: str, val: str) -> None:
|
||||||
self.quit_loop(0)
|
self.quit_loop(0)
|
||||||
|
|
||||||
def on_interrupt(self):
|
def on_interrupt(self) -> None:
|
||||||
self.quit_loop(1)
|
self.quit_loop(1)
|
||||||
|
|
||||||
def on_eot(self):
|
def on_eot(self) -> None:
|
||||||
self.quit_loop(1)
|
self.quit_loop(1)
|
||||||
|
|
||||||
|
|
||||||
@@ -80,16 +82,16 @@ To set the clipboard text, pipe in the new text on stdin. Use the
|
|||||||
usage = ''
|
usage = ''
|
||||||
|
|
||||||
|
|
||||||
def main(args):
|
def main(args: List[str]) -> NoReturn:
|
||||||
args, items = parse_args(args[1:], OPTIONS, usage, help_text, 'kitty +kitten clipboard')
|
cli_opts, items = parse_args(args[1:], OPTIONS, usage, help_text, 'kitty +kitten clipboard', result_class=ClipboardCLIOptions)
|
||||||
if items:
|
if items:
|
||||||
raise SystemExit('Unrecognized extra command line arguments')
|
raise SystemExit('Unrecognized extra command line arguments')
|
||||||
data = None
|
data: Optional[bytes] = None
|
||||||
if not sys.stdin.isatty():
|
if not sys.stdin.isatty():
|
||||||
data = sys.stdin.buffer.read()
|
data = sys.stdin.buffer.read()
|
||||||
sys.stdin = open(os.ctermid(), 'r')
|
sys.stdin = open(os.ctermid(), 'r')
|
||||||
loop = Loop()
|
loop = Loop()
|
||||||
handler = Clipboard(data, args)
|
handler = Clipboard(data, cli_opts)
|
||||||
loop.loop(handler)
|
loop.loop(handler)
|
||||||
if loop.return_code == 0 and handler.clipboard_contents:
|
if loop.return_code == 0 and handler.clipboard_contents:
|
||||||
sys.stdout.write(handler.clipboard_contents)
|
sys.stdout.write(handler.clipboard_contents)
|
||||||
@@ -100,6 +102,7 @@ def main(args):
|
|||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
main(sys.argv)
|
main(sys.argv)
|
||||||
elif __name__ == '__doc__':
|
elif __name__ == '__doc__':
|
||||||
sys.cli_docs['usage'] = usage
|
cd = sys.cli_docs # type: ignore
|
||||||
sys.cli_docs['options'] = OPTIONS
|
cd['usage'] = usage
|
||||||
sys.cli_docs['help_text'] = help_text
|
cd['options'] = OPTIONS
|
||||||
|
cd['help_text'] = help_text
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
class GlobalData:
|
||||||
|
|
||||||
|
def __init__(self) -> None:
|
||||||
|
self.title = ''
|
||||||
|
self.cmd = ''
|
||||||
|
|
||||||
|
|
||||||
|
global_data = GlobalData
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user