Compare commits
2374 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 | ||
|
|
644ee646a2 | ||
|
|
8f1ec053ef | ||
|
|
2e3037ce3a | ||
|
|
109a856b91 | ||
|
|
eaec854bfb | ||
|
|
2c6cc6f047 | ||
|
|
f32ae10339 | ||
|
|
c46317f96f | ||
|
|
a67e4e550e | ||
|
|
65a7b19f40 | ||
|
|
1b5daf930a | ||
|
|
748ca81d4b | ||
|
|
0ea7d24ba4 | ||
|
|
6c9861cb76 | ||
|
|
a1125b5cc8 | ||
|
|
b4e189d2bf | ||
|
|
dbc763fca0 | ||
|
|
4c03ffeae2 | ||
|
|
2719ac7d01 | ||
|
|
219b81b5ee | ||
|
|
8e1443360f | ||
|
|
d55242aa82 | ||
|
|
ba531969ec | ||
|
|
c12e7587cb | ||
|
|
3aac0860a2 | ||
|
|
e4fd12001c | ||
|
|
3581ffe04b | ||
|
|
f6901e4a3d | ||
|
|
5a2cc4578e | ||
|
|
6b5acc4d3d | ||
|
|
43326c9bd0 | ||
|
|
96f3253e6d | ||
|
|
f5090c951a | ||
|
|
edacdc5e25 | ||
|
|
c67661af61 | ||
|
|
5e60329adf | ||
|
|
6b4f8408de | ||
|
|
ea1ef709c6 | ||
|
|
bbf247c5c0 | ||
|
|
8243fd505f | ||
|
|
ed9f9db1b0 | ||
|
|
74bed658e1 | ||
|
|
2f7bdc274d | ||
|
|
1347ff27d9 | ||
|
|
5bf4d520f5 | ||
|
|
cf8d665eb7 | ||
|
|
b2eee6df5c | ||
|
|
e8121b39ec | ||
|
|
5359abab76 | ||
|
|
01644ac3f0 | ||
|
|
8fbf552494 | ||
|
|
9c3390c5e6 | ||
|
|
24d45b99e3 | ||
|
|
936f2186cc | ||
|
|
c68b302fa2 | ||
|
|
ca7cab1a2d | ||
|
|
083b294659 | ||
|
|
bc24716476 | ||
|
|
4acab65016 | ||
|
|
f6b03f106c | ||
|
|
8f9bbeabd7 | ||
|
|
ac72ac7af2 | ||
|
|
68e00bc8e1 | ||
|
|
922d6b3b32 | ||
|
|
4dde98305e | ||
|
|
3593189a75 | ||
|
|
4f135be86c | ||
|
|
605b32f78a | ||
|
|
476a8b1429 | ||
|
|
da9165aebf | ||
|
|
455a1e9532 | ||
|
|
f12031e284 | ||
|
|
df551bc992 | ||
|
|
35fb702833 | ||
|
|
072cd29e3c | ||
|
|
624dd78460 | ||
|
|
51c4737a29 | ||
|
|
d63ea11cac | ||
|
|
3d307794be | ||
|
|
d32a05925f | ||
|
|
04006ea81e | ||
|
|
1723616968 | ||
|
|
23bc2171c9 | ||
|
|
0b3602f764 | ||
|
|
0e448347cd | ||
|
|
e0c66ea5ba | ||
|
|
268de9a9d5 | ||
|
|
74eb523178 | ||
|
|
8c540d5a46 | ||
|
|
2045055ae3 | ||
|
|
d8ed135b46 | ||
|
|
3a4ba7e834 | ||
|
|
fab57fbdf1 | ||
|
|
76a93b6cd6 | ||
|
|
f44c3a4606 | ||
|
|
714bee7f45 | ||
|
|
91673642b3 | ||
|
|
fee08d746c | ||
|
|
527ff0238a | ||
|
|
789d649b5c | ||
|
|
8020657d8c | ||
|
|
a15d3ff12d | ||
|
|
fbce95aeda | ||
|
|
9bc1b5a2d9 | ||
|
|
6a8b7bf92f | ||
|
|
48728bdfdc | ||
|
|
b6416cf8a9 | ||
|
|
053de5763a | ||
|
|
fdb915d0c8 | ||
|
|
c2769c9aed | ||
|
|
57deb19d0b | ||
|
|
321771b150 | ||
|
|
61dd2011f5 | ||
|
|
8a5f189213 | ||
|
|
14560b008a | ||
|
|
db85e07d41 | ||
|
|
07c838fe24 | ||
|
|
1583b1b0c6 | ||
|
|
d250555cd0 | ||
|
|
dbd0dab154 | ||
|
|
b479ea410d | ||
|
|
1db613e95b | ||
|
|
70071fe1f6 | ||
|
|
58688dda38 | ||
|
|
756d65c41e | ||
|
|
b9a08eacb0 | ||
|
|
b653711446 | ||
|
|
e725c647ef | ||
|
|
003f77b257 | ||
|
|
10b578e6d2 | ||
|
|
151c6c2c70 | ||
|
|
53e6de9bd9 | ||
|
|
66a455a079 | ||
|
|
f8855410e0 | ||
|
|
93e8074325 | ||
|
|
296f512bfb | ||
|
|
c8f20d0edf | ||
|
|
286f3630d7 | ||
|
|
38423505b1 | ||
|
|
9a3c621eb6 | ||
|
|
bcf847fe98 | ||
|
|
ee7a5eef99 | ||
|
|
7bed66a458 | ||
|
|
b26229c44e | ||
|
|
c497c0f96a | ||
|
|
6df64613f2 | ||
|
|
46dd648380 | ||
|
|
4cd5de78c7 | ||
|
|
32fa46d6eb | ||
|
|
902c2f6c88 | ||
|
|
2a5196873a | ||
|
|
d2067141d3 | ||
|
|
b5229ec73c | ||
|
|
3a2a16f54c | ||
|
|
b2d428618c | ||
|
|
97af84a063 | ||
|
|
18faee6250 | ||
|
|
fd90a3ddc3 | ||
|
|
a08931d84d | ||
|
|
2f0b6e24c9 | ||
|
|
33c5fc0fb6 | ||
|
|
71adb2dcf8 | ||
|
|
1ae324691d | ||
|
|
689d059517 | ||
|
|
18f0ab9e02 | ||
|
|
088ab5f137 | ||
|
|
3dd83975ba | ||
|
|
a796a6cbef | ||
|
|
4766d7de82 | ||
|
|
4a3686c16c | ||
|
|
b49105495c | ||
|
|
ca2eda2c5b | ||
|
|
4fc7c4aafc | ||
|
|
0981828493 | ||
|
|
6bc4f18a59 | ||
|
|
79532a315c | ||
|
|
7472a992ed | ||
|
|
e40616a0db | ||
|
|
dd8b97a86c | ||
|
|
5eff3897de | ||
|
|
530cf2eb14 | ||
|
|
2baa34beb8 | ||
|
|
87e2f7f86d | ||
|
|
e142083d53 | ||
|
|
2e850a0d0d | ||
|
|
aec9c31bca | ||
|
|
598a147500 | ||
|
|
ba201c4c92 | ||
|
|
5bc7cfaa43 | ||
|
|
2804e1ff81 | ||
|
|
ae27d36902 | ||
|
|
08182fbe4d | ||
|
|
778474f436 | ||
|
|
c6698ce305 | ||
|
|
21bc215313 | ||
|
|
88a9cc42d2 | ||
|
|
28f33a67cf | ||
|
|
6742fabfba | ||
|
|
b3806f4533 | ||
|
|
6d5fb4ccc6 | ||
|
|
2487f18f24 | ||
|
|
f59afff1d1 | ||
|
|
b92f95b092 | ||
|
|
d68ae01448 | ||
|
|
87eda834d3 | ||
|
|
c28ff5259a | ||
|
|
4619259e26 | ||
|
|
7bf0afa621 | ||
|
|
e3e02c7271 | ||
|
|
24e17cb7d8 | ||
|
|
769998adca | ||
|
|
9b5d88e92d | ||
|
|
6d7bebee3a | ||
|
|
1c38654321 | ||
|
|
da7a78691f | ||
|
|
1eaf7083ef | ||
|
|
79a6fcdc5c | ||
|
|
90bcbbf426 | ||
|
|
41049e2a40 | ||
|
|
c9b8510e9c | ||
|
|
d854fc1cd0 | ||
|
|
5f7bcae072 | ||
|
|
652eec3033 | ||
|
|
a9928ec98a | ||
|
|
e1dfb608ca | ||
|
|
2cee3a8809 | ||
|
|
804f72b31a | ||
|
|
e106dcc83b | ||
|
|
9347be639b | ||
|
|
ffc0c42a63 | ||
|
|
f5e855b3ad | ||
|
|
9af4dc4bff | ||
|
|
6f6180c34a | ||
|
|
6ddd751713 | ||
|
|
2c72b06012 | ||
|
|
88854c1aa4 | ||
|
|
5ad704469f | ||
|
|
c140e17a6f | ||
|
|
4fc733a9c8 | ||
|
|
c5c59e4c55 | ||
|
|
e0edef6719 | ||
|
|
0f46ce49e2 | ||
|
|
f9fd39b8c1 | ||
|
|
bd75157428 | ||
|
|
f987f3ba77 | ||
|
|
1c16806efd | ||
|
|
29155fef23 | ||
|
|
c05cbed5b2 | ||
|
|
4f85d4db71 | ||
|
|
468468ab9f | ||
|
|
1b4a6da577 | ||
|
|
aed7a197c7 | ||
|
|
c257b7ecfd | ||
|
|
d6072f6218 | ||
|
|
4ea72a2892 | ||
|
|
89b07a1c6b | ||
|
|
db0cd61807 | ||
|
|
6feb906953 | ||
|
|
7cbf8c63bc | ||
|
|
fae51d4e00 | ||
|
|
c510584afd | ||
|
|
738878c2ff | ||
|
|
d5682fe49a | ||
|
|
d8dd22048a | ||
|
|
737d8b96b6 | ||
|
|
c8627c9713 | ||
|
|
65fa7da24a | ||
|
|
c4c6ef799f | ||
|
|
0d18b91895 | ||
|
|
42089aaadc | ||
|
|
432d0f3318 | ||
|
|
4ade6587e8 | ||
|
|
1724f11429 | ||
|
|
75d66d1048 | ||
|
|
feccef67b9 | ||
|
|
a7d30a199d | ||
|
|
37bbfb11d3 | ||
|
|
79c80b4043 | ||
|
|
18a1402ae2 | ||
|
|
5d639b91b0 | ||
|
|
080c09d22e | ||
|
|
00c2670039 | ||
|
|
f113184165 | ||
|
|
d69f8af107 | ||
|
|
ad2bd1bf63 | ||
|
|
059786ab66 | ||
|
|
72dfa5e5e6 | ||
|
|
d84da6b7b8 | ||
|
|
6aa82d82ad | ||
|
|
a649eb2a48 | ||
|
|
83932c8099 | ||
|
|
95e36cece1 | ||
|
|
7075a7f1c0 | ||
|
|
3093610d26 | ||
|
|
86eed7f895 | ||
|
|
5dc14c5861 | ||
|
|
cab87f6fb2 | ||
|
|
fb3acd1f4a | ||
|
|
b247cef85c | ||
|
|
70445f33e9 | ||
|
|
cadb4f1389 | ||
|
|
bf75a4de61 | ||
|
|
400ab584ac | ||
|
|
9edad62144 | ||
|
|
e94205098f | ||
|
|
35ab7eb472 | ||
|
|
18619b14ac | ||
|
|
97e0b9b65a | ||
|
|
5175d9f4a6 | ||
|
|
a5aed0f4ab | ||
|
|
14d693a8ff | ||
|
|
645963cc24 | ||
|
|
20751c2807 | ||
|
|
dda886b97c | ||
|
|
b796ceecdd | ||
|
|
4def89ebb5 | ||
|
|
bd1c1839dd | ||
|
|
8739f698f9 | ||
|
|
b8c8482f20 | ||
|
|
4348ca8cc5 | ||
|
|
d1aa59080f | ||
|
|
bf0ffa80be | ||
|
|
2a89a0c87e | ||
|
|
de84489a20 | ||
|
|
40901778ad | ||
|
|
c1febea659 | ||
|
|
b42f4ac288 | ||
|
|
fae57a5868 | ||
|
|
7a02d09508 | ||
|
|
8ec6fe960d | ||
|
|
61a77e19ef | ||
|
|
82e88b54c7 | ||
|
|
ab8975f4da | ||
|
|
5e7fd21c8d | ||
|
|
30cd9b2ae4 | ||
|
|
4f7d12f3fd | ||
|
|
62da158823 | ||
|
|
2d19b87208 | ||
|
|
54ca775006 | ||
|
|
a64a0d64cb | ||
|
|
6634dc81fe | ||
|
|
a2d5eef398 | ||
|
|
8184ba246a | ||
|
|
54ad1d103a | ||
|
|
d92f8a90ef | ||
|
|
d33c287344 | ||
|
|
782eebf976 | ||
|
|
0fbf75b95a | ||
|
|
5781facf4b | ||
|
|
b710ffc403 | ||
|
|
7d8edccb04 | ||
|
|
3750d70173 | ||
|
|
025e0bb546 | ||
|
|
033367de91 | ||
|
|
f93b605b75 | ||
|
|
7b4141b0c8 | ||
|
|
90acef72dc | ||
|
|
43f200be77 | ||
|
|
2fbb167803 | ||
|
|
2b396262f0 | ||
|
|
74deca52b9 | ||
|
|
058d956464 | ||
|
|
0f38dc1bd1 | ||
|
|
576b03c047 | ||
|
|
59cb1ad1e0 | ||
|
|
f77acdce14 | ||
|
|
43a98a1df1 | ||
|
|
d1cf771c14 | ||
|
|
10e5fcc375 | ||
|
|
2112932d04 | ||
|
|
be505ce6e0 | ||
|
|
4d6472128c | ||
|
|
26b7b1ec63 | ||
|
|
9a8f0a9b5a | ||
|
|
16dbbf3a1e | ||
|
|
8492d0a264 | ||
|
|
d8f8f1f590 | ||
|
|
b762e81da0 | ||
|
|
8b3b68ea69 | ||
|
|
28525766a5 | ||
|
|
d8fc23c38f | ||
|
|
8cae70fa36 | ||
|
|
7f2b98fad7 | ||
|
|
2b6dde2ac5 | ||
|
|
0c254fa7c7 | ||
|
|
fe7375becc | ||
|
|
b6ee88056e | ||
|
|
96f691ad64 | ||
|
|
8cf3380a77 | ||
|
|
e8d7e3e98b | ||
|
|
8af0a8476f | ||
|
|
2de4248f76 | ||
|
|
8c73ab6afb | ||
|
|
ee9bd77dc4 | ||
|
|
81f31ca215 | ||
|
|
51eff372f8 | ||
|
|
087376b44d | ||
|
|
e49047ef7d | ||
|
|
c117f36009 | ||
|
|
5ec83ee759 | ||
|
|
410165c14d | ||
|
|
973ef9fcda | ||
|
|
396bfb8540 | ||
|
|
aaf597bffd | ||
|
|
63c4f64bf5 | ||
|
|
5745dc34f7 | ||
|
|
114b8cff93 | ||
|
|
261571bb69 | ||
|
|
497e2c9163 | ||
|
|
ac01ffaa54 | ||
|
|
eb9fe06d10 | ||
|
|
506f2f7db7 | ||
|
|
f476c56f91 | ||
|
|
474688888d | ||
|
|
7ddbb613fe | ||
|
|
adc1c06089 | ||
|
|
1f8631cc99 | ||
|
|
f9e4e71285 | ||
|
|
5529194c8d | ||
|
|
5b008163af | ||
|
|
802da7087c | ||
|
|
53ab7617ca | ||
|
|
4369255a25 | ||
|
|
b709ee6842 | ||
|
|
4a8f9efe79 | ||
|
|
19d36fbe69 | ||
|
|
d37e73db54 | ||
|
|
a8f6615380 | ||
|
|
97fe38fbbc | ||
|
|
3378175450 | ||
|
|
9f60d2aea3 | ||
|
|
46d49e18c0 | ||
|
|
43fc335be2 | ||
|
|
f68339c571 | ||
|
|
0d68b7078c | ||
|
|
2e71dde780 | ||
|
|
51ddd584d6 | ||
|
|
4b090259cd | ||
|
|
f3b9ff5f9f | ||
|
|
4ec1a8d9c3 | ||
|
|
350cfeb7ef | ||
|
|
97d379b13e | ||
|
|
2154d555e5 | ||
|
|
1389c36657 | ||
|
|
bd1e7d6942 | ||
|
|
aadab38487 | ||
|
|
91299a279b | ||
|
|
53275c9137 | ||
|
|
fb1c318a09 | ||
|
|
2a07b3f46a | ||
|
|
ffc4e99717 | ||
|
|
fe807dd66f | ||
|
|
40ce5db812 | ||
|
|
649a9f4a6f | ||
|
|
e17ce875be | ||
|
|
415701c58a | ||
|
|
f16f80b459 | ||
|
|
628e6cc87f | ||
|
|
8f9a225c3a | ||
|
|
7b41bc95e1 | ||
|
|
2d06ee5822 | ||
|
|
40b4fb966f | ||
|
|
be696a9d76 | ||
|
|
1ffe9bef35 | ||
|
|
ed70d95c44 | ||
|
|
49bf876f73 | ||
|
|
e512b4d3e3 | ||
|
|
e78b6c7c7c | ||
|
|
a7403c0005 | ||
|
|
5bed0dddaa | ||
|
|
bc302dad23 | ||
|
|
41b0f8852f | ||
|
|
2fadd3e7ba | ||
|
|
dcfd2b8d60 | ||
|
|
7fe63a7aad | ||
|
|
67f2ec2421 | ||
|
|
8e7a23a7b9 | ||
|
|
8e96a27d51 | ||
|
|
b337d4d9d5 | ||
|
|
d9404c0362 | ||
|
|
e4ba5f449f | ||
|
|
17fd749e8d | ||
|
|
f3be5b5e57 | ||
|
|
e619eb9cbb | ||
|
|
a65ee155c5 | ||
|
|
4037480d2b | ||
|
|
97e6978ed8 | ||
|
|
f05eefcc20 | ||
|
|
3f926dfd8b | ||
|
|
59f64c5e33 | ||
|
|
87059a2004 | ||
|
|
7c52dd2bd8 | ||
|
|
70c2765a6e | ||
|
|
3618f4d642 | ||
|
|
698569536d | ||
|
|
c398d3d16e | ||
|
|
9dbc54aad6 | ||
|
|
931cb223cd | ||
|
|
336ee53fea | ||
|
|
34350af61c | ||
|
|
72f7cb3b7d | ||
|
|
481047a446 | ||
|
|
3bf1d73b07 | ||
|
|
b3b830bb5f | ||
|
|
def0c55df3 | ||
|
|
b995e00850 | ||
|
|
32dfc94909 | ||
|
|
20f7118432 | ||
|
|
37e6c3f0cb | ||
|
|
0459dda5c2 | ||
|
|
a10c816c05 | ||
|
|
c0c7cfacc2 | ||
|
|
8cdb6647ed | ||
|
|
b68e3c85b9 | ||
|
|
ef25d5bbd5 | ||
|
|
278bf6e897 | ||
|
|
90a985b73a | ||
|
|
b016353809 | ||
|
|
bc222af2e2 | ||
|
|
44599c9460 | ||
|
|
902fc22670 | ||
|
|
d84e22fbf1 | ||
|
|
6cc720a350 | ||
|
|
c905978874 | ||
|
|
bfe595a8e8 | ||
|
|
94d56d1a9e | ||
|
|
bd3f0b5363 | ||
|
|
6fae3545c7 | ||
|
|
297963f6ab | ||
|
|
a0ceba407e | ||
|
|
35fa91fba2 | ||
|
|
a5d6cd169e | ||
|
|
06c2263657 | ||
|
|
472c6f6b8d | ||
|
|
afcaca85da | ||
|
|
2575349ec2 | ||
|
|
77054f688d | ||
|
|
c5cb24378f | ||
|
|
d66123dd14 | ||
|
|
4ef8f11f9e | ||
|
|
599be7ddc9 | ||
|
|
685497fc8c | ||
|
|
57542fc204 | ||
|
|
8d9323aec6 | ||
|
|
4984a25b19 | ||
|
|
3bdcb29e01 | ||
|
|
b9ab8e6348 | ||
|
|
4a851701e9 | ||
|
|
eafd8af937 | ||
|
|
28bb123be8 | ||
|
|
8e1ed2f8c3 | ||
|
|
4a0fcb3cff | ||
|
|
b5c2163238 | ||
|
|
d0ecdfb330 | ||
|
|
bdf7d98a36 | ||
|
|
e4b0980d15 | ||
|
|
d99c57aeae | ||
|
|
5f855ce547 | ||
|
|
68f3b6fbeb | ||
|
|
dc6d14943e | ||
|
|
05f7334db9 | ||
|
|
cd707e9335 | ||
|
|
505ed5e43b | ||
|
|
9dc8bf5f62 | ||
|
|
f8098662b6 | ||
|
|
de7a0e86c4 | ||
|
|
ca55438fda | ||
|
|
a4b60e7eef | ||
|
|
5d22e07738 | ||
|
|
bdade7e151 | ||
|
|
6958ded4c4 | ||
|
|
cc06104be6 | ||
|
|
059c34c345 | ||
|
|
9cbb726566 | ||
|
|
e8b4356a88 | ||
|
|
634138cd3b | ||
|
|
3f6b07de81 | ||
|
|
d218900b57 | ||
|
|
cab949a939 | ||
|
|
e350822f5e | ||
|
|
3d6fe93297 | ||
|
|
3a5baf2722 | ||
|
|
cdb472cb56 | ||
|
|
e634350e77 | ||
|
|
464a6c1441 | ||
|
|
d3750b2244 | ||
|
|
b8d2b76ee4 | ||
|
|
14fb7c3201 | ||
|
|
922bc62e0e | ||
|
|
00cae4ccd1 | ||
|
|
61df266df7 | ||
|
|
17751666f2 | ||
|
|
961b2c9b65 | ||
|
|
eaf6f06047 | ||
|
|
d0ac218c05 | ||
|
|
1a01bc15d8 | ||
|
|
cdbe2f13ca | ||
|
|
4f5264277e | ||
|
|
bed3adcc95 | ||
|
|
0c5d59bcf6 | ||
|
|
ff20acd8b8 | ||
|
|
d1cffcde68 | ||
|
|
546dd9b225 | ||
|
|
2a666620c8 | ||
|
|
db50985040 | ||
|
|
8c6d593c41 | ||
|
|
40086c8d1c | ||
|
|
38f73b9f5e | ||
|
|
49429b5f49 | ||
|
|
d9f90ef077 | ||
|
|
6a126fa18e | ||
|
|
14d703f5cc | ||
|
|
9850025f3a | ||
|
|
8daab0ba41 | ||
|
|
88f25ccc76 | ||
|
|
50e7351c73 | ||
|
|
51453a54e4 | ||
|
|
c02ba03f39 | ||
|
|
78dec3d698 | ||
|
|
1590c59131 | ||
|
|
b26f79998a | ||
|
|
489f3e6c9d | ||
|
|
5fef4726a7 | ||
|
|
51fdb8200a | ||
|
|
fb0d98ead1 | ||
|
|
4096caba64 | ||
|
|
38f77144fa | ||
|
|
b8041ce17f | ||
|
|
00575733c8 | ||
|
|
621c92780c | ||
|
|
37f03af4b7 | ||
|
|
bdc4558a43 | ||
|
|
46d483e8b2 | ||
|
|
5143b62a07 | ||
|
|
87ed774cb4 | ||
|
|
4e427d05b7 | ||
|
|
195d987331 | ||
|
|
9b58317fb1 | ||
|
|
1cb15dedac | ||
|
|
5521d6b623 | ||
|
|
f5cf6c1dcb | ||
|
|
89307727e7 | ||
|
|
c30c21b250 | ||
|
|
b6fb087d7e | ||
|
|
97c2b7c1fe | ||
|
|
81506640c8 | ||
|
|
8244f7cd58 | ||
|
|
63573d6e26 | ||
|
|
9368f7f670 | ||
|
|
b7a11035d5 | ||
|
|
2e1b5e2fa7 | ||
|
|
8e5cbafe63 | ||
|
|
eb006a6688 | ||
|
|
40b9049deb | ||
|
|
64ffca2d0a | ||
|
|
1f4b6d4e9a | ||
|
|
eb30ba7722 | ||
|
|
3e0f4d36bc | ||
|
|
1fb118edee | ||
|
|
ca39634880 | ||
|
|
f8418d68a6 | ||
|
|
c0000fb24e | ||
|
|
c169f7ae83 | ||
|
|
7ab5244bf5 | ||
|
|
7e36489034 | ||
|
|
d259b12ae7 | ||
|
|
8f8138d9bd | ||
|
|
a8668f5fbf | ||
|
|
e00e6bd1c2 | ||
|
|
0fc6c47556 | ||
|
|
d530dccb96 | ||
|
|
37bf0e81d2 | ||
|
|
f872f955b0 | ||
|
|
003cd0a203 | ||
|
|
e7173f8145 | ||
|
|
93af102bec | ||
|
|
67f23664c9 | ||
|
|
39f6071c68 | ||
|
|
edc8878632 | ||
|
|
93b62c4dfd | ||
|
|
c3e210c80f | ||
|
|
9a5cc8f650 | ||
|
|
5e7fbfefe9 | ||
|
|
29ad6fba22 | ||
|
|
c848c3ee0d | ||
|
|
547132131a | ||
|
|
40186fb54b | ||
|
|
5dc4e79c8d | ||
|
|
556992a117 | ||
|
|
a41ef8d513 | ||
|
|
6d96a89328 | ||
|
|
0fb1481038 | ||
|
|
4b77530c65 | ||
|
|
cdb493cf50 | ||
|
|
c9a574a764 | ||
|
|
bdb633a882 | ||
|
|
37aee7133d | ||
|
|
2cfd55f3ce | ||
|
|
2e8188e89d | ||
|
|
1e172caea3 | ||
|
|
6866cd0fb8 | ||
|
|
2719926870 | ||
|
|
406891abcc | ||
|
|
4be6e9009a | ||
|
|
6a31909557 | ||
|
|
f49f0d19f9 | ||
|
|
a2407f94e4 | ||
|
|
62a0be4a11 | ||
|
|
b9029f6c67 | ||
|
|
92496f42c9 | ||
|
|
841c907efc | ||
|
|
9bc288cd8e | ||
|
|
2ef0391b08 | ||
|
|
6db768d1a3 | ||
|
|
9b080950a9 | ||
|
|
3cd1fef4cb | ||
|
|
a491a801bf | ||
|
|
41ebb72276 | ||
|
|
e4c0e9073e | ||
|
|
efad733cc5 | ||
|
|
1fcd6e1811 | ||
|
|
75d697fa97 | ||
|
|
cde69670ba | ||
|
|
0be6c9cb97 | ||
|
|
8c9d2d3ca2 | ||
|
|
c84e73d8e6 | ||
|
|
3fb00f6c70 | ||
|
|
86305fdeb3 | ||
|
|
710e146d22 | ||
|
|
d5abc84bea | ||
|
|
6f8214c15c | ||
|
|
a56475e32f | ||
|
|
9dadd91887 | ||
|
|
df5a73bb35 | ||
|
|
a50bf59a2c | ||
|
|
241354ae52 | ||
|
|
c863116011 | ||
|
|
5cbd591a1e | ||
|
|
6bb78c9499 | ||
|
|
893f406a99 | ||
|
|
f722b898b0 | ||
|
|
18335b3eac | ||
|
|
4708b592e2 | ||
|
|
7598a2965c | ||
|
|
1b59761a19 | ||
|
|
7fd1053e0f | ||
|
|
e178e7f6a5 | ||
|
|
d0bf21ab16 | ||
|
|
c826965833 | ||
|
|
a76db39c19 | ||
|
|
323a538bdd | ||
|
|
2435feca3b | ||
|
|
29d059680c | ||
|
|
aaaf7f9d8b | ||
|
|
bc90ce569a | ||
|
|
27f9f1756b | ||
|
|
9135387cfa | ||
|
|
af3504e05c | ||
|
|
9c9eac9d46 | ||
|
|
f28383206a | ||
|
|
ba1c093d18 | ||
|
|
3ea3a85694 | ||
|
|
0e1a423889 | ||
|
|
3ce68ed53f | ||
|
|
90c10da398 | ||
|
|
630bf28c22 | ||
|
|
ff89c1d8e4 | ||
|
|
96703c23c8 | ||
|
|
2b78f5adad | ||
|
|
ab7df777eb | ||
|
|
adbc694ff8 | ||
|
|
7709cdb12b | ||
|
|
f6051f73f5 | ||
|
|
d5c2a21cdf | ||
|
|
8ffc841a3a | ||
|
|
6c478977bb | ||
|
|
07beb53b37 | ||
|
|
59df1a8647 | ||
|
|
fb98aa650d | ||
|
|
9981b5a9c6 | ||
|
|
603533e632 | ||
|
|
38bc90f724 | ||
|
|
721beb9202 | ||
|
|
2e99259589 | ||
|
|
83e6b75872 | ||
|
|
cf70946f50 | ||
|
|
f1c36aba83 | ||
|
|
2973cf15a4 | ||
|
|
55969bc3c5 | ||
|
|
a8504c971a | ||
|
|
1644de2083 | ||
|
|
dd1fb85f60 | ||
|
|
b945b19865 | ||
|
|
91bf9f2ec8 | ||
|
|
f151f4c165 | ||
|
|
95b9b2d373 | ||
|
|
8be698681c | ||
|
|
da3e1a3730 | ||
|
|
29f637c19a | ||
|
|
3d01565ba7 | ||
|
|
962291cc8e | ||
|
|
a662dace9c | ||
|
|
d34e0b325e | ||
|
|
4c242ec528 | ||
|
|
658be9405f | ||
|
|
15e8f6ad8a | ||
|
|
a5aca35f1c | ||
|
|
ae9df1ffac | ||
|
|
8bf2e098f5 | ||
|
|
7091d554b5 | ||
|
|
bada795320 | ||
|
|
7d385849fb | ||
|
|
78775b7f6b | ||
|
|
8d21a5b6b3 | ||
|
|
9da095ca50 | ||
|
|
0fafc07db0 | ||
|
|
65b95999c1 | ||
|
|
056012871f | ||
|
|
c7b377080c | ||
|
|
47acc9ff2f | ||
|
|
fe62700825 | ||
|
|
6bcab56988 | ||
|
|
fbc4d3e1be | ||
|
|
c89d1643f4 | ||
|
|
e2226a1509 | ||
|
|
656916e0fa | ||
|
|
4a55eb9e7f | ||
|
|
9c8cf04a80 | ||
|
|
e846bc9308 | ||
|
|
3c7a71772c | ||
|
|
857a53e80f | ||
|
|
84fcabe5cf | ||
|
|
9dc410c9fd | ||
|
|
8ebad06e7e | ||
|
|
5db1a07f81 | ||
|
|
48e5c8edb3 | ||
|
|
eefc21920e | ||
|
|
d7dd9c295b | ||
|
|
4faf71bd03 | ||
|
|
2751dbdb94 | ||
|
|
fe329cb4ab | ||
|
|
741e719ff8 | ||
|
|
866bb32046 | ||
|
|
7f01e758b3 | ||
|
|
03003d270e | ||
|
|
3d313016ba | ||
|
|
1292c752a8 | ||
|
|
4783947135 | ||
|
|
c9045788f5 | ||
|
|
4eed8463b3 | ||
|
|
303711ab8d | ||
|
|
98d7fc9f39 | ||
|
|
c0a96f2087 | ||
|
|
c509ecca52 | ||
|
|
e5d8eb7845 | ||
|
|
277f43aed6 | ||
|
|
f1494b64e5 | ||
|
|
6b9c71ec62 | ||
|
|
d12a4b0a1a | ||
|
|
a75d075dd1 | ||
|
|
8f8a37bf94 | ||
|
|
03f692fed8 | ||
|
|
614416d4b0 | ||
|
|
feb851716e | ||
|
|
2b095f720e | ||
|
|
d6e750727f | ||
|
|
961ff8633d | ||
|
|
8406d4a8f1 | ||
|
|
e25b64ae15 | ||
|
|
59205a4caf | ||
|
|
5001797179 | ||
|
|
b24dd69067 | ||
|
|
4f163338dd | ||
|
|
1e8f1f8cc6 | ||
|
|
5c3e2e6877 | ||
|
|
ff52ff7865 | ||
|
|
f6f55aaa9a | ||
|
|
6f1aecab99 | ||
|
|
f33205a490 | ||
|
|
2920638a3d | ||
|
|
1ae32b5742 | ||
|
|
4e9dabfb25 | ||
|
|
ca2c419c9b | ||
|
|
020c1311ca | ||
|
|
8193b2a44b | ||
|
|
324a000777 | ||
|
|
951b1c1e83 | ||
|
|
8e57fd93c6 | ||
|
|
d262f43b5b | ||
|
|
73224e7d95 | ||
|
|
19463c81a3 | ||
|
|
6f2bb31068 | ||
|
|
abf9c4117d | ||
|
|
39f50830d7 | ||
|
|
c2fd7005cb | ||
|
|
52f2ed33f5 | ||
|
|
a51239c6ae | ||
|
|
e6217e1428 | ||
|
|
f61dfb0828 | ||
|
|
00fe963e7c | ||
|
|
009ea1c8cd | ||
|
|
72069015b9 | ||
|
|
6c0c67dd7b | ||
|
|
3c090519a0 | ||
|
|
5da70929f6 | ||
|
|
5b66d6209f | ||
|
|
9f7f353485 | ||
|
|
05f01525c3 | ||
|
|
3aa016940c | ||
|
|
a792c94ccf | ||
|
|
249e59b310 | ||
|
|
3b43b76222 | ||
|
|
398f5cfbdc | ||
|
|
bc47be64b0 | ||
|
|
59c6fb9ce7 | ||
|
|
8b99d0a432 | ||
|
|
639b18c7e8 | ||
|
|
701942f6ef | ||
|
|
9d8e6a2b30 | ||
|
|
581deb6073 | ||
|
|
9849a69afd | ||
|
|
5f33d907aa | ||
|
|
0919eda640 | ||
|
|
5952a140e0 | ||
|
|
6d92996661 | ||
|
|
04e4b0c469 | ||
|
|
20f4a9a942 | ||
|
|
5552679c11 | ||
|
|
1369a36178 | ||
|
|
529337e00a | ||
|
|
fe882dad15 | ||
|
|
4fff84b4b9 | ||
|
|
3e964163c0 | ||
|
|
10a987b908 | ||
|
|
03e417e1be | ||
|
|
c95d3b19b3 | ||
|
|
1fa9b8f102 | ||
|
|
c27cf31a7c | ||
|
|
ad672fc9d6 | ||
|
|
a0f298ddb0 | ||
|
|
9b740849ed | ||
|
|
a3f9835b7b | ||
|
|
f4294b83fb | ||
|
|
4fa4a20b22 | ||
|
|
af2c9a49b1 | ||
|
|
bdeec61266 | ||
|
|
268e5cef3b | ||
|
|
b37f4333e2 | ||
|
|
f0c663d42d | ||
|
|
e36e44ab3a | ||
|
|
2dceec444f | ||
|
|
eaba3cff0b | ||
|
|
ec31a348cf | ||
|
|
d6a6e26500 | ||
|
|
cab1ba4e50 | ||
|
|
a2f589be00 | ||
|
|
7622cbaed5 | ||
|
|
53df123c0d | ||
|
|
c660840c19 | ||
|
|
c6d3ede57e | ||
|
|
6037167336 | ||
|
|
0804447881 | ||
|
|
83482873dc | ||
|
|
5e351e4d65 | ||
|
|
408cd9cf9b | ||
|
|
8b47e63136 | ||
|
|
379ec88776 | ||
|
|
a320e8bc25 | ||
|
|
1c4f5b471d | ||
|
|
d5846282a9 | ||
|
|
8b56f1ced6 | ||
|
|
0987a536b1 | ||
|
|
099510f4d1 | ||
|
|
35c6014025 | ||
|
|
895ac26d43 | ||
|
|
da999f730b | ||
|
|
47969e9f18 | ||
|
|
b6267d4a8c | ||
|
|
2df97e309b | ||
|
|
078b23e6aa | ||
|
|
d8eeed2296 | ||
|
|
e5afc5297a | ||
|
|
465ed48e73 | ||
|
|
f8b311b289 | ||
|
|
934336e642 | ||
|
|
6f5ff05c56 | ||
|
|
2376b7c255 | ||
|
|
ef86f8a20c | ||
|
|
b3f1acd400 | ||
|
|
5c4462281e | ||
|
|
91d94f262c | ||
|
|
2651acce91 | ||
|
|
25cfcdba76 | ||
|
|
6f5004fc13 | ||
|
|
df9c1aea64 | ||
|
|
a309069b6b | ||
|
|
beb90f2c55 | ||
|
|
0e0aba7a5e | ||
|
|
6e9b41314e | ||
|
|
dbeac923ed | ||
|
|
5953c2097d | ||
|
|
8969206450 | ||
|
|
41318d763b | ||
|
|
8251b906b6 | ||
|
|
790d630d17 | ||
|
|
c9644039b1 | ||
|
|
34de072a10 | ||
|
|
f6d7b3aa04 | ||
|
|
5c31c2b98e | ||
|
|
2cc779b667 | ||
|
|
7f4294f68c | ||
|
|
fd2515da5c | ||
|
|
db1f53fc29 | ||
|
|
96f5c66755 | ||
|
|
4baf7b5bba | ||
|
|
58bb5a7d1f | ||
|
|
c63dd76814 | ||
|
|
8d3e6b4796 | ||
|
|
b10312e249 | ||
|
|
6f3a9d6d29 | ||
|
|
c4e89d9d0c | ||
|
|
00a2126152 | ||
|
|
e7099cc771 | ||
|
|
b6724ed177 | ||
|
|
fcedc9f5c3 | ||
|
|
cb095be0cc | ||
|
|
ecf2c86787 | ||
|
|
971c28ce97 | ||
|
|
482129ff35 | ||
|
|
65c75859bc | ||
|
|
fcb26e5dc7 | ||
|
|
0dc6ac26c3 | ||
|
|
48303bac75 | ||
|
|
5ab8a665be | ||
|
|
733158a2de | ||
|
|
a2e47d2d0e | ||
|
|
bfb97a6e6f | ||
|
|
fc1a8351b0 | ||
|
|
be7a4a5868 | ||
|
|
493892a4df | ||
|
|
106dc2b03b | ||
|
|
d5490475f1 | ||
|
|
999a6a288c | ||
|
|
7d9d096fbf | ||
|
|
c129dd9331 | ||
|
|
5c75ac0a96 | ||
|
|
bafedf8376 | ||
|
|
136f15e647 | ||
|
|
e9e4ac13ee | ||
|
|
e24c758341 | ||
|
|
4b65b4ac2b | ||
|
|
d8d7765a82 | ||
|
|
b98bc1c787 | ||
|
|
4b08ce2a09 | ||
|
|
ed62e72a98 | ||
|
|
a28710c1fc | ||
|
|
764a058cf6 | ||
|
|
a538663679 | ||
|
|
8920d64f7d | ||
|
|
a051cb9ee3 | ||
|
|
56864cdfb7 | ||
|
|
428c600788 | ||
|
|
748f1a90b9 | ||
|
|
d3cee832ce | ||
|
|
8129246a10 | ||
|
|
a2789650e5 | ||
|
|
af376cf27e | ||
|
|
6c8ccbd73a | ||
|
|
626ac0d5b8 | ||
|
|
2550bc910d | ||
|
|
0a153e2524 | ||
|
|
facd353228 | ||
|
|
5b7eac280c | ||
|
|
7ab63525c7 | ||
|
|
a1c49a0f7f | ||
|
|
4c4c6ab0e6 | ||
|
|
2e0d39b512 | ||
|
|
0899019518 | ||
|
|
db16996181 | ||
|
|
aa2b21456f | ||
|
|
7e8e1e9e89 | ||
|
|
01e9702958 | ||
|
|
6d970c1175 | ||
|
|
16c0871e22 | ||
|
|
fd7ddc2905 | ||
|
|
c181919a57 | ||
|
|
5955b44c74 | ||
|
|
8b5f02bb0b | ||
|
|
f2a1ff2584 | ||
|
|
11522ccc92 | ||
|
|
bb97c589c1 | ||
|
|
4a5a9b2888 | ||
|
|
b1bd581065 | ||
|
|
3bd1ca0ac3 | ||
|
|
bbeb08ba08 | ||
|
|
66dbdf4b40 | ||
|
|
f0a2c34eca | ||
|
|
9f35b9281b | ||
|
|
7624578c21 | ||
|
|
d4b477ad78 | ||
|
|
e6d5eea7eb | ||
|
|
bef9490fa8 | ||
|
|
d593ccba2f | ||
|
|
1902d8bb19 | ||
|
|
f10c65f1bf | ||
|
|
da507dfd19 | ||
|
|
13254ac4d5 | ||
|
|
fc9ffb3115 | ||
|
|
f64ffcac48 | ||
|
|
f2a6cb3dbb | ||
|
|
4767d2b8d6 | ||
|
|
1ceb8b1b0b | ||
|
|
719a9a5b64 | ||
|
|
5adf7c2a3a | ||
|
|
1c9d6bf9e6 | ||
|
|
f85dfe91a9 | ||
|
|
749fb84053 | ||
|
|
e33af8b2f8 | ||
|
|
61a9f7baae | ||
|
|
4d4b690a99 | ||
|
|
d4c2293d56 | ||
|
|
3b34cec64c | ||
|
|
a1e9b854e3 | ||
|
|
01ed1e1604 | ||
|
|
b7b1a1f1c6 | ||
|
|
c9446727d3 | ||
|
|
cff79bc9d4 | ||
|
|
72ccf87d19 | ||
|
|
2387c71b3c | ||
|
|
47a2120023 | ||
|
|
b777353766 | ||
|
|
5d4491667b | ||
|
|
9fbd14f815 | ||
|
|
f38b27e923 | ||
|
|
cb8116e2af | ||
|
|
2066dd0077 | ||
|
|
37afd7aaa7 | ||
|
|
8df9ccc72c | ||
|
|
862075bd65 | ||
|
|
27ffed5a1a | ||
|
|
bf2c50b58b | ||
|
|
34c35ff4ca | ||
|
|
174a45b4bd | ||
|
|
e44b331cc3 | ||
|
|
aed504efdc | ||
|
|
ca38568187 | ||
|
|
a653c17e8a | ||
|
|
6bbd33eca4 | ||
|
|
494235750e | ||
|
|
076c81c4ee | ||
|
|
abd4de7311 | ||
|
|
4629ef627f | ||
|
|
b1c2e90a05 | ||
|
|
c19cbaad24 | ||
|
|
1a3fdac4e4 | ||
|
|
d343981faa | ||
|
|
51c0c51884 | ||
|
|
cb2d162bec | ||
|
|
6507fd1ac2 | ||
|
|
442f2adf23 | ||
|
|
702613915b | ||
|
|
8ebc9553c3 | ||
|
|
ae8076e411 | ||
|
|
f3974671f6 | ||
|
|
dcb2d95f9a | ||
|
|
c8bb7aae40 | ||
|
|
4711e10df2 | ||
|
|
28f1b8a7a0 | ||
|
|
104e213934 | ||
|
|
fe3a432845 | ||
|
|
423f8e59cc | ||
|
|
1c468b2931 | ||
|
|
85faad5ec7 | ||
|
|
869152750c | ||
|
|
7fd4ec50c9 | ||
|
|
8de4dd334b | ||
|
|
c5cc208397 | ||
|
|
718e6fa93d | ||
|
|
0833697c49 | ||
|
|
112ae0edab | ||
|
|
502c31b408 | ||
|
|
062563a562 | ||
|
|
c385532b10 | ||
|
|
81f4b4cece | ||
|
|
23482e3cf4 | ||
|
|
b49b34c4c1 | ||
|
|
b40ca5800d | ||
|
|
3b25081353 | ||
|
|
5726466db3 | ||
|
|
27acd4c7d4 | ||
|
|
f98d780f3e | ||
|
|
8177cfac2a | ||
|
|
fb4123a6f2 | ||
|
|
191913b7eb | ||
|
|
3a3f745d31 | ||
|
|
eebe12a972 | ||
|
|
274dd2f3fe | ||
|
|
fb5dbc811b | ||
|
|
c31c32f921 | ||
|
|
22b756753a | ||
|
|
cb7eb48768 | ||
|
|
22ed014123 | ||
|
|
419b078104 | ||
|
|
b51584525a | ||
|
|
728dbbfff0 | ||
|
|
7485269c37 | ||
|
|
cffaa54a78 | ||
|
|
1f597fd2b3 | ||
|
|
48d792bc19 | ||
|
|
5da123c632 | ||
|
|
27887ada45 | ||
|
|
4c9a6ed56c | ||
|
|
1bf2864638 | ||
|
|
c8bd61b345 | ||
|
|
7ee04b37ac | ||
|
|
5957befaad | ||
|
|
17a16ccd21 | ||
|
|
1de940d7b4 | ||
|
|
9a2ff9e419 | ||
|
|
84caf787aa | ||
|
|
e9d0d40809 | ||
|
|
0e2a5c63c6 | ||
|
|
9916802a69 | ||
|
|
bfac482940 | ||
|
|
8778cf63c4 | ||
|
|
d5d1e6c11e | ||
|
|
8e6780e761 | ||
|
|
ddb961f9af | ||
|
|
670de085a3 | ||
|
|
4c49573465 | ||
|
|
13d478ffca | ||
|
|
1cc95a605c | ||
|
|
e19f180c71 | ||
|
|
d3ad15dc51 | ||
|
|
3aaa69b36c | ||
|
|
41906cf7db | ||
|
|
f3696da0ff | ||
|
|
fab723b9bc | ||
|
|
d3a3a89098 | ||
|
|
68313e99a7 | ||
|
|
9b73d25151 | ||
|
|
440db8f4bd | ||
|
|
6690c4f916 | ||
|
|
6d3ad7d903 | ||
|
|
0d60b88f1d | ||
|
|
aa82d8fddd | ||
|
|
10f5461cd8 | ||
|
|
c7a0626c69 | ||
|
|
6a9a7dee55 | ||
|
|
8952afd6cc | ||
|
|
526c526bf3 | ||
|
|
12e269e791 | ||
|
|
c2f6450af3 | ||
|
|
c8dfe955d7 | ||
|
|
71091e73a4 | ||
|
|
25d1b2328f | ||
|
|
4085fe2e8e | ||
|
|
74445674f2 | ||
|
|
c343bdd120 | ||
|
|
5ff4a6f4d8 | ||
|
|
5172597d96 | ||
|
|
a09fb7b20d | ||
|
|
af9e633d56 | ||
|
|
df62478418 | ||
|
|
c623cd5d01 | ||
|
|
3126f31cbf | ||
|
|
c33c88b2c6 | ||
|
|
36d5afef9f | ||
|
|
c8ed52f600 | ||
|
|
8d7e083e64 | ||
|
|
2144f43142 | ||
|
|
66d2930b7e | ||
|
|
4dcaec0997 | ||
|
|
33da5ca869 | ||
|
|
4c1a69a98c | ||
|
|
d613962f5b | ||
|
|
8f7cef1232 | ||
|
|
7a91ba3699 | ||
|
|
14018a5e54 | ||
|
|
81a03fcea8 | ||
|
|
48962a58ae | ||
|
|
8c9c777ad3 | ||
|
|
dc6e276e39 | ||
|
|
8182fcecd2 | ||
|
|
4d082dbf80 | ||
|
|
5b5c49d317 | ||
|
|
51b5510669 | ||
|
|
7a4b438dc6 | ||
|
|
1a29de5ac9 | ||
|
|
ed8edf3e4c | ||
|
|
9fcde9d81d | ||
|
|
81ffa7e948 | ||
|
|
93d2d30867 | ||
|
|
42e05c5ad2 | ||
|
|
d37e815f13 | ||
|
|
a1f454937c | ||
|
|
b041dcc8ce | ||
|
|
22c65c5d03 | ||
|
|
60b64dadfe | ||
|
|
edb25314c5 | ||
|
|
19bce0c23c | ||
|
|
8ceb941051 | ||
|
|
8b28cbb30c | ||
|
|
de130787f6 | ||
|
|
6e94dae9cd | ||
|
|
d2431783f1 | ||
|
|
5787b472c0 | ||
|
|
6bdfc0387b | ||
|
|
7ba98344b6 | ||
|
|
c887df6ab4 | ||
|
|
a8ad4461a1 | ||
|
|
32a0e28686 | ||
|
|
df13f0ce5a | ||
|
|
972f0c0e2b | ||
|
|
c7a3a4d421 |
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
|
||||
7
.gitattributes
vendored
7
.gitattributes
vendored
@@ -3,11 +3,14 @@ kitty/emoji.h linguist-generated=true
|
||||
kitty/keys.h linguist-generated=true
|
||||
kitty/charsets.c linguist-generated=true
|
||||
kitty/key_encoding.py linguist-generated=true
|
||||
kitty/unicode-data.c
|
||||
kitty/unicode-data.c linguist-generated=true
|
||||
kitty/rgb.py linguist-generated=true
|
||||
kitty/gl-wrapper.* linguist-generated=true
|
||||
kitty/khrplatform.h linguist-generated=true
|
||||
kitty/glfw-wrapper.* linguist-generated=true
|
||||
kitty/parse-graphics-command.h linguist-generated=true
|
||||
glfw/*.c linguist-vendored=true
|
||||
glfw/*.h linguist-vendored=true
|
||||
kittens/unicode_input/names.h linguist-generated=true
|
||||
|
||||
*.py text diff=python
|
||||
*.m text diff=objc
|
||||
|
||||
3
.github/FUNDING.yml
vendored
Normal file
3
.github/FUNDING.yml
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
patreon: kovidgoyal
|
||||
liberapay: kovidgoyal
|
||||
custom: https://sw.kovidgoyal.net/kitty/support.html
|
||||
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
|
||||
32
.gitignore
vendored
32
.gitignore
vendored
@@ -1,19 +1,21 @@
|
||||
*.so
|
||||
*.pyc
|
||||
*.pyo
|
||||
tags
|
||||
build
|
||||
linux-package
|
||||
kitty.app
|
||||
logo/*.iconset
|
||||
compile_commands.json
|
||||
glad/out
|
||||
asan-launcher
|
||||
asan-launcher.dSYM
|
||||
kitty-profile
|
||||
dev
|
||||
__pycache__
|
||||
glfw/wayland-*-client-protocol.[ch]
|
||||
docs/_build
|
||||
docs/generated
|
||||
*_stub.pyi
|
||||
/.dmypy.json
|
||||
/tags
|
||||
/build/
|
||||
/linux-package/
|
||||
/kitty.app/
|
||||
/compile_commands.json
|
||||
/link_commands.json
|
||||
/glad/out/
|
||||
/kitty/launcher/
|
||||
/*.dSYM/
|
||||
__pycache__/
|
||||
/glfw/wayland-*-client-protocol.[ch]
|
||||
/docs/_build/
|
||||
/docs/generated/
|
||||
/.mypy_cache
|
||||
.DS_Store
|
||||
bypy/b
|
||||
|
||||
172
.travis.yml
172
.travis.yml
@@ -1,172 +0,0 @@
|
||||
git:
|
||||
depth: false
|
||||
matrix:
|
||||
fast_finish: true
|
||||
include:
|
||||
- os: linux
|
||||
dist: xenial
|
||||
group: beta
|
||||
language: python
|
||||
sudo: false
|
||||
env: USE_BUNDLE=1 SW=$HOME/sw PKG_CONFIG_PATH=$SW/lib/pkgconfig LD_LIBRARY_PATH=$SW/lib PYTHON=$SW/bin/python3
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- libgl1-mesa-dev
|
||||
- libxi-dev
|
||||
- libxrandr-dev
|
||||
- libxinerama-dev
|
||||
- libxcursor-dev
|
||||
- libxcb-xkb-dev
|
||||
- libdbus-1-dev
|
||||
|
||||
- os: linux
|
||||
dist: xenial
|
||||
group: beta
|
||||
sudo: false
|
||||
env:
|
||||
- CC=gcc CFLAGS=-funsigned-char SANITIZE_ARG=--sanitize
|
||||
language: python
|
||||
python: "3.5"
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- libgl1-mesa-dev
|
||||
- libfontconfig1-dev
|
||||
- libharfbuzz-dev
|
||||
- libxi-dev
|
||||
- libxrandr-dev
|
||||
- libxinerama-dev
|
||||
- libxcursor-dev
|
||||
- libxcb-xkb-dev
|
||||
- libpng-dev
|
||||
- libdbus-1-dev
|
||||
- python3-pil
|
||||
|
||||
- os: linux
|
||||
dist: xenial
|
||||
group: beta
|
||||
sudo: false
|
||||
env:
|
||||
- CC=clang SANITIZE_ARG=--sanitize
|
||||
language: python
|
||||
python: "3.5"
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- libgl1-mesa-dev
|
||||
- libfontconfig1-dev
|
||||
- libharfbuzz-dev
|
||||
- libxi-dev
|
||||
- libxrandr-dev
|
||||
- libxinerama-dev
|
||||
- libxcursor-dev
|
||||
- libxcb-xkb-dev
|
||||
- libpng-dev
|
||||
- libdbus-1-dev
|
||||
- python3-pil
|
||||
|
||||
- os: linux
|
||||
dist: xenial
|
||||
group: beta
|
||||
sudo: false
|
||||
env:
|
||||
- RUN_FLAKE=1 BUILD_PKG=linux-package
|
||||
language: python
|
||||
python: "3.6"
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- libgl1-mesa-dev
|
||||
- libfontconfig1-dev
|
||||
- libharfbuzz-dev
|
||||
- libxi-dev
|
||||
- libxrandr-dev
|
||||
- libxinerama-dev
|
||||
- libxcursor-dev
|
||||
- libxcb-xkb-dev
|
||||
- libpng-dev
|
||||
- libdbus-1-dev
|
||||
- python3-pil
|
||||
- clang
|
||||
- os: osx
|
||||
language: generic
|
||||
env: SWBASE=/Users/Shared/buildbot/sw SW=$SWBASE/sw PATH=$SW/bin:$PATH
|
||||
|
||||
- os: osx
|
||||
language: generic
|
||||
addons:
|
||||
homebrew:
|
||||
update: true
|
||||
brewfile: true
|
||||
env: USE_BREW=1 BUILD_PKG=osx-bundle
|
||||
|
||||
env:
|
||||
global:
|
||||
- PYTHON=python3
|
||||
- PKG_CONFIG_PATH=$HOME/harfbuzz/lib/pkgconfig:$PKG_CONFIG_PATH
|
||||
- LD_LIBRARY_PATH=$HOME/harfbuzz/lib:$LD_LIBRARY_PATH
|
||||
- ASAN_OPTIONS=leak_check_at_exit=0
|
||||
|
||||
install: |
|
||||
set -e
|
||||
if [[ "$RUN_FLAKE" == "1" ]]; then pip install flake8; fi
|
||||
if [[ "$TRAVIS_OS_NAME" == 'osx' ]]; then
|
||||
if [[ "$USE_BREW" == "1" ]]; then
|
||||
logo/make.py
|
||||
else
|
||||
mkdir -p $SW;
|
||||
curl https://download.calibre-ebook.com/travis/kitty/osx.tar.xz | tar xJ -C $SW;
|
||||
fi
|
||||
else
|
||||
if [[ "$USE_BUNDLE" == "1" ]]; then
|
||||
mkdir -p $SW;
|
||||
curl https://download.calibre-ebook.com/travis/kitty/linux-64.tar.xz | tar xJ -C $SW;
|
||||
find $SW -type f -name '*.pc' -exec sed -i "s,/sw/sw,$SW,g" {} \;;
|
||||
find $SW -type f -name '_sysconfig*.py' -exec sed -i "s,/sw/sw,$SW,g" {} \;;
|
||||
else
|
||||
pushd /tmp
|
||||
wget --no-check-certificate http://xkbcommon.org/download/libxkbcommon-0.6.1.tar.xz
|
||||
tar xf libxkbcommon-0.6.1.tar.xz
|
||||
cd libxkbcommon-0.6.1
|
||||
./configure --prefix=$HOME/harfbuzz --disable-dependency-tracking --disable-static
|
||||
make -j2
|
||||
make install
|
||||
wget https://github.com/behdad/harfbuzz/releases/download/1.6.3/harfbuzz-1.6.3.tar.bz2
|
||||
tar xf harfbuzz-1.6.3.tar.bz2
|
||||
cd harfbuzz-1.6.3
|
||||
./configure --prefix=$HOME/harfbuzz --disable-dependency-tracking --disable-static --with-glib=no --with-gobject=no --with-cairo=no --with-fontconfig=no --with-icu=no --with-directwrite=no --with-freetype=yes
|
||||
make -j2
|
||||
make install
|
||||
cd ..
|
||||
popd
|
||||
fi
|
||||
if [[ "$BUILD_PKG" == "linux-package" ]]; then
|
||||
pip install sphinx
|
||||
fi
|
||||
fi
|
||||
pkg-config --cflags harfbuzz
|
||||
if [[ "$TRAVIS_OS_NAME" != 'osx' ]]; then
|
||||
PLIB=$(ldd `which python` | grep libpython | cut -d ' ' -f 3)
|
||||
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:`dirname $PLIB`
|
||||
fi
|
||||
set +e
|
||||
|
||||
before_script:
|
||||
- echo LD_LIBRARY_PATH=$LD_LIBRARY_PATH PKG_CONFIG_PATH=$PKG_CONFIG_PATH
|
||||
- $PYTHON setup.py build --debug --verbose $SANITIZE_ARG;
|
||||
|
||||
script: |
|
||||
set -e
|
||||
|
||||
if grep -Inr '\s$' kitty kitty_tests kittens docs *.py *.asciidoc *.rst .gitattributes .gitignore; then echo Trailing whitespace found, aborting.; exit 1; fi
|
||||
|
||||
if [[ -z "$SANITIZE_ARG" ]]; then $PYTHON test.py; else ./asan-launcher test.py; fi
|
||||
|
||||
if [[ "$RUN_FLAKE" == "1" ]]; then flake8 --count .; fi
|
||||
|
||||
if [[ "$BUILD_PKG" == "linux-package" ]]; then make FAIL_WARN=-W man && make FAIL_WARN=-W html; fi
|
||||
|
||||
if [[ ! -z "$BUILD_PKG" ]]; then $PYTHON setup.py $BUILD_PKG; fi
|
||||
|
||||
set +e
|
||||
11
Brewfile
11
Brewfile
@@ -1,5 +1,6 @@
|
||||
brew 'imagemagick'
|
||||
brew 'optipng'
|
||||
brew 'librsvg'
|
||||
brew 'harfbuzz'
|
||||
brew 'python'
|
||||
pkg-config
|
||||
zlib
|
||||
python
|
||||
imagemagick
|
||||
harfbuzz
|
||||
sphinx-doc
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
### Reporting bugs
|
||||
|
||||
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
|
||||
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>
|
||||
|
||||
8
LICENSE
8
LICENSE
@@ -1,7 +1,7 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
@@ -645,7 +645,7 @@ the "copyright" line and a pointer to where the full notice is found.
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
@@ -664,11 +664,11 @@ might be different; for a GUI interface, you would use an "about box".
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
<https://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
||||
<https://www.gnu.org/philosophy/why-not-lgpl.html>.
|
||||
|
||||
14
Makefile
14
Makefile
@@ -1,8 +1,8 @@
|
||||
ifdef V
|
||||
VVAL=--verbose
|
||||
VVAL=--verbose
|
||||
endif
|
||||
ifdef VERBOSE
|
||||
VVAL=--verbose
|
||||
VVAL=--verbose
|
||||
endif
|
||||
|
||||
all:
|
||||
@@ -18,6 +18,9 @@ clean:
|
||||
debug:
|
||||
python3 setup.py build $(VVAL) --debug
|
||||
|
||||
debug-event-loop:
|
||||
python3 setup.py build $(VVAL) --debug --extra-logging=event-loop
|
||||
|
||||
# Build with the ASAN and UBSAN sanitizers
|
||||
asan:
|
||||
python3 setup.py build $(VVAL) --debug --sanitize
|
||||
@@ -25,12 +28,7 @@ asan:
|
||||
profile:
|
||||
python3 setup.py build $(VVAL) --profile
|
||||
|
||||
logo/kitty.iconset/icon_256x256.png: logo/kitty.svg logo/make.py
|
||||
logo/make.py
|
||||
|
||||
rendered_logo: logo/kitty.iconset/icon_256x256.png
|
||||
|
||||
app: rendered_logo
|
||||
app:
|
||||
python3 setup.py kitty.app $(VVAL)
|
||||
|
||||
man:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
= kitty - the fast, featureful, GPU based, terminal emulator
|
||||
|
||||
See https://sw.kovidgoyal.net/kitty
|
||||
See https://sw.kovidgoyal.net/kitty/
|
||||
|
||||
image::https://travis-ci.org/kovidgoyal/kitty.svg?branch=master[Build status, link=https://travis-ci.org/kovidgoyal/kitty]
|
||||
image:https://github.com/kovidgoyal/kitty/workflows/CI/badge.svg["Build status", link="https://github.com/kovidgoyal/kitty/actions?query=workflow%3ACI"]
|
||||
|
||||
64
__main__.py
64
__main__.py
@@ -1,57 +1,59 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/env python3
|
||||
# vim:fileencoding=utf-8
|
||||
# License: GPL v3 Copyright: 2015, Kovid Goyal <kovid at kovidgoyal.net>
|
||||
|
||||
import sys
|
||||
import os
|
||||
from typing import List
|
||||
|
||||
|
||||
def icat(args):
|
||||
from kittens.runner import run_kitten
|
||||
def icat(args: List[str]) -> None:
|
||||
from kittens.runner import run_kitten as rk
|
||||
sys.argv = args
|
||||
run_kitten('icat')
|
||||
rk('icat')
|
||||
|
||||
|
||||
def list_fonts(args):
|
||||
from kitty.fonts.list import main
|
||||
main(args)
|
||||
def list_fonts(args: List[str]) -> None:
|
||||
from kitty.fonts.list import main as list_main
|
||||
list_main(args)
|
||||
|
||||
|
||||
def remote_control(args):
|
||||
from kitty.remote_control import main
|
||||
main(args)
|
||||
def remote_control(args: List[str]) -> None:
|
||||
from kitty.remote_control import main as rc_main
|
||||
rc_main(args)
|
||||
|
||||
|
||||
def runpy(args):
|
||||
def runpy(args: List[str]) -> None:
|
||||
sys.argv = ['kitty'] + args[2:]
|
||||
exec(args[1])
|
||||
|
||||
|
||||
def hold(args):
|
||||
def hold(args: List[str]) -> None:
|
||||
import subprocess
|
||||
ret = subprocess.Popen(args[1:]).wait()
|
||||
sys.stdin.read()
|
||||
raise SystemExit(ret)
|
||||
|
||||
|
||||
def complete(args):
|
||||
from kitty.complete import main
|
||||
main(args[1:], entry_points, namespaced_entry_points)
|
||||
def complete(args: List[str]) -> None:
|
||||
from kitty.complete import main as complete_main
|
||||
complete_main(args[1:], entry_points, namespaced_entry_points)
|
||||
|
||||
|
||||
def launch(args):
|
||||
def launch(args: List[str]) -> None:
|
||||
import runpy
|
||||
sys.argv = args[1:]
|
||||
exe = args[1]
|
||||
if exe.startswith(':'):
|
||||
import shutil
|
||||
exe = shutil.which(exe[1:])
|
||||
if not exe:
|
||||
q = shutil.which(exe[1:])
|
||||
if not q:
|
||||
raise SystemExit('{} not found in PATH'.format(args[1][1:]))
|
||||
exe = q
|
||||
runpy.run_path(exe, run_name='__main__')
|
||||
|
||||
|
||||
def run_kitten(args):
|
||||
def run_kitten(args: List[str]) -> None:
|
||||
try:
|
||||
kitten = args[1]
|
||||
except IndexError:
|
||||
@@ -59,11 +61,16 @@ def run_kitten(args):
|
||||
list_kittens()
|
||||
raise SystemExit(1)
|
||||
sys.argv = args[1:]
|
||||
from kittens.runner import run_kitten
|
||||
run_kitten(kitten)
|
||||
from kittens.runner import run_kitten as rk
|
||||
rk(kitten)
|
||||
|
||||
|
||||
def namespaced(args):
|
||||
def 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(args[1:])
|
||||
|
||||
@@ -75,6 +82,7 @@ entry_points = {
|
||||
'runpy': runpy,
|
||||
'launch': launch,
|
||||
'kitten': run_kitten,
|
||||
'edit-config': edit_config_file,
|
||||
|
||||
'@': remote_control,
|
||||
'+': namespaced,
|
||||
@@ -84,19 +92,21 @@ namespaced_entry_points['hold'] = hold
|
||||
namespaced_entry_points['complete'] = complete
|
||||
|
||||
|
||||
def setup_openssl_environment():
|
||||
def setup_openssl_environment() -> None:
|
||||
# Workaround for Linux distros that have still failed to get their heads
|
||||
# out of their asses and implement a common location for SSL certificates.
|
||||
# It's not that hard people, there exists a wonderful tool called the symlink
|
||||
# See http://www.mobileread.com/forums/showthread.php?t=256095
|
||||
# See https://www.mobileread.com/forums/showthread.php?t=256095
|
||||
if 'SSL_CERT_FILE' not in os.environ and 'SSL_CERT_DIR' not in os.environ:
|
||||
if os.access('/etc/pki/tls/certs/ca-bundle.crt', os.R_OK):
|
||||
os.environ['SSL_CERT_FILE'] = '/etc/pki/tls/certs/ca-bundle.crt'
|
||||
setattr(sys, 'kitty_ssl_env_var', 'SSL_CERT_FILE')
|
||||
elif os.path.isdir('/etc/ssl/certs'):
|
||||
os.environ['SSL_CERT_DIR'] = '/etc/ssl/certs'
|
||||
setattr(sys, 'kitty_ssl_env_var', 'SSL_CERT_DIR')
|
||||
|
||||
|
||||
def main():
|
||||
def main() -> None:
|
||||
if getattr(sys, 'frozen', False) and 'darwin' not in sys.platform.lower():
|
||||
setup_openssl_environment()
|
||||
first_arg = '' if len(sys.argv) < 2 else sys.argv[1]
|
||||
@@ -107,8 +117,8 @@ def main():
|
||||
elif first_arg.startswith('+'):
|
||||
namespaced(['+', first_arg[1:]] + sys.argv[2:])
|
||||
else:
|
||||
from kitty.main import main
|
||||
main()
|
||||
from kitty.main import main as kitty_main
|
||||
kitty_main()
|
||||
else:
|
||||
func(sys.argv[1:])
|
||||
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
/*
|
||||
* linux-launcher.c
|
||||
* Copyright (C) 2017 Kovid Goyal <kovid at kovidgoyal.net>
|
||||
*
|
||||
* Distributed under terms of the GPL3 license.
|
||||
*/
|
||||
|
||||
#include <Python.h>
|
||||
|
||||
#define MAX_ARGC 1024
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
wchar_t *argvw[MAX_ARGC + 1] = {0};
|
||||
argvw[0] = L"kitty";
|
||||
for (int i = 1; i < argc; i++) argvw[i] = Py_DecodeLocale(argv[i], NULL);
|
||||
int ret = Py_Main(argc, argvw);
|
||||
for (int i = 1; i < argc; i++) PyMem_RawFree(argvw[i]);
|
||||
return ret;
|
||||
}
|
||||
@@ -1,24 +1,48 @@
|
||||
#!/usr/bin/env python3
|
||||
# vim:fileencoding=utf-8
|
||||
# License: GPL v3 Copyright: 2019, Kovid Goyal <kovid at kovidgoyal.net>
|
||||
|
||||
import glob
|
||||
import os
|
||||
import sys
|
||||
import re
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
|
||||
base = os.path.dirname(os.path.abspath(__file__))
|
||||
os.chdir(base)
|
||||
sys.path.insert(0, base)
|
||||
|
||||
from kitty.terminfo import generate_terminfo # noqa
|
||||
def compile_terminfo(base):
|
||||
with tempfile.TemporaryDirectory() as tdir:
|
||||
proc = subprocess.run(['tic', '-x', '-o' + tdir, 'terminfo/kitty.terminfo'], check=True, stderr=subprocess.PIPE)
|
||||
regex = '^"terminfo/kitty.terminfo", line [0-9]+, col [0-9]+, terminal \'xterm-kitty\': older tic versions may treat the description field as an alias$'
|
||||
for error in proc.stderr.decode('utf-8').splitlines():
|
||||
if not re.match(regex, error):
|
||||
print(error, file=sys.stderr)
|
||||
tfiles = glob.glob(os.path.join(tdir, '*', 'xterm-kitty'))
|
||||
if not tfiles:
|
||||
raise SystemExit('tic failed to output the compiled kitty terminfo file')
|
||||
|
||||
with open('terminfo/kitty.terminfo', 'w') as f:
|
||||
f.write(generate_terminfo())
|
||||
tfile = tfiles[0]
|
||||
directory, xterm_kitty = os.path.split(tfile)
|
||||
_, directory = os.path.split(directory)
|
||||
odir = os.path.join(base, directory)
|
||||
os.makedirs(odir, exist_ok=True)
|
||||
ofile = os.path.join(odir, xterm_kitty)
|
||||
shutil.move(tfile, ofile)
|
||||
|
||||
os.environ['TERMINFO'] = os.path.join(base, 'terminfo')
|
||||
subprocess.check_call(['tic', '-x', 'terminfo/kitty.terminfo'])
|
||||
# On OS X tic puts the compiled database into a different directory
|
||||
try:
|
||||
os.mkdir('terminfo/78')
|
||||
except FileExistsError:
|
||||
pass
|
||||
shutil.copy2('terminfo/x/xterm-kitty', 'terminfo/78')
|
||||
|
||||
def generate_terminfo():
|
||||
base = os.path.dirname(os.path.abspath(__file__))
|
||||
os.chdir(base)
|
||||
sys.path.insert(0, base)
|
||||
|
||||
from kitty.terminfo import generate_terminfo
|
||||
|
||||
with open('terminfo/kitty.terminfo', 'w') as f:
|
||||
f.write(generate_terminfo())
|
||||
|
||||
compile_terminfo(os.path.join(base, 'terminfo'))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
generate_terminfo()
|
||||
|
||||
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}"]
|
||||
}
|
||||
}
|
||||
|
||||
]
|
||||
@@ -1,2 +1,27 @@
|
||||
#!/bin/bash
|
||||
cloc --exclude-list-file <(echo -e 'kitty/wcwidth-std.h\nkitty/glfw.c\nkitty/keys.h\nkitty/charsets.c\nkitty/unicode-data.c\nkitty/key_encoding.py\nkitty/rgb.py\nkitty/gl.h\nkitty/gl-wrapper.h\nkitty/gl-wrapper.c\nkitty/khrplatform.h\nkitty/glfw-wrapper.h\nkitty/glfw-wrapper.c\nkitty/emoji.h\nkittens/unicode_input/names.h') kitty kittens
|
||||
#!/usr/bin/env python
|
||||
|
||||
import subprocess
|
||||
|
||||
files_to_exclude = '''\
|
||||
kitty/wcwidth-std.h
|
||||
kitty/glfw.c
|
||||
kitty/keys.h
|
||||
kitty/charsets.c
|
||||
kitty/unicode-data.c
|
||||
kitty/key_encoding.py
|
||||
kitty/rgb.py
|
||||
kitty/gl.h
|
||||
kitty/gl-wrapper.h
|
||||
kitty/gl-wrapper.c
|
||||
kitty/glfw-wrapper.h
|
||||
kitty/glfw-wrapper.c
|
||||
kitty/emoji.h
|
||||
kittens/unicode_input/names.h
|
||||
kitty/parse-graphics-command.h
|
||||
'''
|
||||
|
||||
p = subprocess.Popen([
|
||||
'cloc', '--exclude-list-file', '/dev/stdin', 'kitty', 'kittens'
|
||||
], stdin=subprocess.PIPE)
|
||||
p.communicate(files_to_exclude.encode('utf-8'))
|
||||
raise SystemExit(p.wait())
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
#
|
||||
|
||||
# You can set these variables from the command line.
|
||||
SPHINXOPTS = -T $(FAIL_WARN)
|
||||
SPHINXBUILD = python3 .. +launch :sphinx-build
|
||||
SPHINXOPTS = -j auto -T $(FAIL_WARN)
|
||||
SPHINXBUILD = sphinx-build
|
||||
SPHINXPROJ = kitty
|
||||
SOURCEDIR = .
|
||||
BUILDDIR = _build
|
||||
|
||||
2
docs/_static/custom.css
vendored
2
docs/_static/custom.css
vendored
@@ -78,6 +78,8 @@ body div.document {
|
||||
div.sphinxsidebar {
|
||||
font-size: inherit;
|
||||
line-height: inherit;
|
||||
max-height: 100%;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
#sidebartoc li {
|
||||
|
||||
9
docs/_templates/layout.html
vendored
9
docs/_templates/layout.html
vendored
@@ -1,13 +1,6 @@
|
||||
{% extends "!layout.html" %}
|
||||
|
||||
{%- block extrahead %}
|
||||
<!-- Google Analytics -->
|
||||
<script>
|
||||
window.ga=window.ga||function(){(ga.q=ga.q||[]).push(arguments)};ga.l=+new Date;
|
||||
ga('create', 'UA-20736318-2', 'auto');
|
||||
ga('send', 'pageview');
|
||||
</script>
|
||||
<script async="async" src='https://www.google-analytics.com/analytics.js'></script>
|
||||
<!-- End Google Analytics -->
|
||||
<!-- kitty analytics placeholder -->
|
||||
{{ super() }}
|
||||
{% endblock %}
|
||||
|
||||
@@ -46,7 +46,7 @@ particular desktop, but it should work for most major desktop environments.
|
||||
# Place the kitty.desktop file somewhere it can be found by the OS
|
||||
cp ~/.local/kitty.app/share/applications/kitty.desktop ~/.local/share/applications
|
||||
# Update the path to the kitty icon in the kitty.desktop file
|
||||
sed -i "s/Icon\=kitty/Icon\=\/home\/$USER\/.local\/kitty.app\/share\/icons\/hicolor\/256x256\/apps\/kitty.png/g" ~/.local/share/applications/kitty.desktop
|
||||
sed -i "s|Icon=kitty|Icon=/home/$USER/.local/kitty.app/share/icons/hicolor/256x256/apps/kitty.png|g" ~/.local/share/applications/kitty.desktop
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
Building kitty from source
|
||||
==============================
|
||||
|
||||
.. image:: https://travis-ci.org/kovidgoyal/kitty.svg?branch=master
|
||||
.. image:: https://github.com/kovidgoyal/kitty/workflows/CI/badge.svg
|
||||
:alt: Build status
|
||||
:target: https://travis-ci.org/kovidgoyal/kitty
|
||||
:target: https://github.com/kovidgoyal/kitty/actions?query=workflow%3ACI
|
||||
|
||||
|
||||
|kitty| is designed to run from source, for easy hackability. Make sure
|
||||
@@ -18,8 +18,10 @@ Run-time dependencies:
|
||||
* harfbuzz >= 1.5.0
|
||||
* zlib
|
||||
* libpng
|
||||
* liblcms2
|
||||
* freetype (not needed on macOS)
|
||||
* fontconfig (not needed on macOS)
|
||||
* libcanberra (not needed on macOS)
|
||||
* ImageMagick (optional, needed to use the ``kitty icat`` tool to display images in the terminal)
|
||||
* pygments (optional, need for syntax highlighting in ``kitty +kitten diff``)
|
||||
|
||||
@@ -28,7 +30,7 @@ Build-time dependencies:
|
||||
* gcc or clang
|
||||
* pkg-config
|
||||
* For building on Linux in addition to the above dependencies you might also need to install the ``-dev`` packages for:
|
||||
``libdbus-1-dev``, ``libxcursor-dev``, ``libxrandr-dev``, ``libxi-dev``, ``libxinerama-dev``, ``libgl1-mesa-dev``, ``libxkbcommon-x11-dev``, ``libfontconfig-dev`` and ``libpython-dev``.
|
||||
``libdbus-1-dev``, ``libxcursor-dev``, ``libxrandr-dev``, ``libxi-dev``, ``libxinerama-dev``, ``libgl1-mesa-dev``, ``libxkbcommon-x11-dev``, ``libfontconfig-dev``, and ``libpython-dev``,
|
||||
if they are not already installed by your distro.
|
||||
|
||||
Install and run from source
|
||||
@@ -44,25 +46,17 @@ Now build the native code parts of |kitty| with the following command::
|
||||
|
||||
You can run |kitty|, as::
|
||||
|
||||
python3 .
|
||||
./kitty/launcher/kitty
|
||||
|
||||
If that works, you can create a script to launch |kitty|:
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
#!/usr/bin/env python3
|
||||
import runpy
|
||||
runpy.run_path('/path/to/kitty/dir', run_name='__main__')
|
||||
|
||||
And place it in :file:`~/bin` or :file:`/usr/bin` so that you can run |kitty| using
|
||||
If that works, you can create a symlink to the launcher in :file:`~/bin` or
|
||||
some other directory on your PATH so that you can run |kitty| using
|
||||
just ``kitty``.
|
||||
|
||||
|
||||
Building kitty.app on macOS from source
|
||||
-------------------------------------------
|
||||
|
||||
Install `imagemagick`, `optipng` and `librsvg` using `brew` or similar (needed
|
||||
for the logo generation step). And run::
|
||||
Run::
|
||||
|
||||
make app
|
||||
|
||||
@@ -70,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
|
||||
you might have to rebuild the app.
|
||||
|
||||
Note that the released :file:`kitty.dmg` includes all dependencies, unlike the
|
||||
:file:`kitty.app` built above and is built automatically by using the :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::
|
||||
The released :file:`kitty.dmg` includes all dependencies, unlike the
|
||||
:file:`kitty.app` built above and is built automatically by using the
|
||||
: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
|
||||
@@ -107,7 +123,13 @@ without needing to install all of |kitty|.
|
||||
development package of :file:`ncurses`. Also, if you are building from
|
||||
a git checkout instead of the released source code tarball, you will
|
||||
need :file:`sphinx-build` from the `Sphinx documentation generator
|
||||
<http://www.sphinx-doc.org/>`_.
|
||||
<https://www.sphinx-doc.org/>`_.
|
||||
|
||||
This applies to creating packages for |kitty| for macOS package managers such as
|
||||
brew or MacPorts as well.
|
||||
|
||||
|
||||
.. note::
|
||||
|kitty| has its own update check mechanism, if you would like to turn
|
||||
it off for your package, use
|
||||
``python3 setup.py linux-package --update-check-interval=0``
|
||||
|
||||
@@ -2,6 +2,956 @@ Changelog
|
||||
==============
|
||||
|
||||
|kitty| is a feature full, cross-platform, *fast*, GPU based terminal emulator.
|
||||
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]
|
||||
--------------------
|
||||
|
||||
- A new :doc:`marks` feature that allows highlighting and scrolling to arbitrary
|
||||
text in the terminal window.
|
||||
|
||||
- hints kitten: Allow pressing :sc:`goto_file_line` to quickly open
|
||||
the selected file at the selected line in vim or a configurable editor (:iss:`2268`)
|
||||
|
||||
- Allow having more than one full height window in the :code:`tall` layout
|
||||
(:iss:`2276`)
|
||||
|
||||
- Allow choosing OpenType features for individual fonts via the
|
||||
:opt:`font_features` option. (:pull:`2248`)
|
||||
|
||||
- Wayland: Fix a freeze in rare circumstances when having multiple OS Windows
|
||||
(:iss:`2307` and :iss:`1722`)
|
||||
|
||||
- Wayland: Fix window titles being set to very long strings on the order of 8KB
|
||||
causing a crash (:iss:`1526`)
|
||||
|
||||
- Add an option :opt:`force_ltr` to turn off the display of text in RTL scripts
|
||||
in right-to-left order (:pull:`2293`)
|
||||
|
||||
- Allow opening new tabs/windows before the current tab/window as well as after
|
||||
it with the :option:`launch --location` option.
|
||||
|
||||
- Add a :opt:`resize_in_steps` option that can be used to resize the OS window
|
||||
in steps as large as character cells (:pull:`2131`)
|
||||
|
||||
- When triple-click+dragging to select multiple lines, extend the selection
|
||||
of the first line to match the rest on the left (:pull:`2284`)
|
||||
|
||||
- macOS: Add a :code:`titlebar-only` setting to
|
||||
:opt:`hide_window_decorations` to only hide the title bar (:pull:`2286`)
|
||||
|
||||
- Fix a segfault when using :option:`kitty --debug-config` with maps (:iss:`2270`)
|
||||
|
||||
- ``goto_tab`` now maps numbers larger than the last tab to the last tab
|
||||
(:iss:`2291`)
|
||||
|
||||
- Fix URL detection not working for urls of the form scheme:///url
|
||||
(:iss:`2292`)
|
||||
|
||||
- When windows are semi-transparent and all contain graphics, correctly render
|
||||
them. (:iss:`2310`)
|
||||
|
||||
0.15.1 [2019-12-21]
|
||||
--------------------
|
||||
|
||||
- Fix a crash/incorrect rendering when detaching a window in some circumstances
|
||||
(:iss:`2173`)
|
||||
|
||||
- hints kitten: Add an option :option:`kitty +kitten hints --ascending` to
|
||||
control if the hints numbers increase or decrease from top to bottom
|
||||
|
||||
- Fix :opt:`background_opacity` incorrectly applying to selected text and
|
||||
reverse video text (:iss:`2177`)
|
||||
|
||||
- Add a new option :opt:`tab_bar_background` to specify a different color
|
||||
for the tab bar (:iss:`2198`)
|
||||
|
||||
- Add a new option :opt:`active_tab_title_template` to specify a different
|
||||
template for active tab titles (:iss:`2198`)
|
||||
|
||||
- Fix lines at the edge of the window at certain windows sizes when drawing
|
||||
images on a transparent window (:iss:`2079`)
|
||||
|
||||
- Fix window not being rendered for the first time until some input has been
|
||||
received from child process (:iss:`2216`)
|
||||
|
||||
|
||||
0.15.0 [2019-11-27]
|
||||
--------------------
|
||||
|
||||
- Add a new action :ref:`detach_window <detach_window>` that can be used to move the current
|
||||
window into a different tab (:iss:`1310`)
|
||||
|
||||
- Add a new action :doc:`launch <launch>` that unifies launching of processes
|
||||
in new kitty windows/tabs.
|
||||
|
||||
- Add a new style ``powerline`` for tab bar rendering, see :opt:`tab_bar_style` (:pull:`2021`)
|
||||
|
||||
- Allow changing colors by mapping a keyboard shortcut to read a kitty config
|
||||
file with color definitions. See the :doc:`FAQ <faq>` for details
|
||||
(:iss:`2083`)
|
||||
|
||||
- hints kitten: Allow completely customizing the matching and actions performed
|
||||
by the kitten using your own script (:iss:`2124`)
|
||||
|
||||
- Wayland: Fix key repeat not being stopped when focus leaves window. This is
|
||||
expected behavior on Wayland, apparently (:iss:`2014`)
|
||||
|
||||
- When drawing unicode symbols that are followed by spaces, use multiple cells
|
||||
to avoid resized or cut-off glyphs (:iss:`1452`)
|
||||
|
||||
- diff kitten: Allow diffing remote files easily via ssh (:iss:`727`)
|
||||
|
||||
- unicode input kitten: Add an option :option:`kitty +kitten unicode_input
|
||||
--emoji-variation` to control the presentation variant of selected emojis
|
||||
(:iss:`2139`)
|
||||
|
||||
- Add specialised rendering for a few more box powerline and unicode symbols
|
||||
(:pull:`2074` and :pull:`2021`)
|
||||
|
||||
- Add a new socket only mode for :opt:`allow_remote_control`. This makes
|
||||
it possible for programs running on the local machine to control kitty
|
||||
but not programs running over ssh.
|
||||
|
||||
- hints kitten: Allow using named groups in the regular expression. The named
|
||||
groups are passed to the invoked program for further processing.
|
||||
|
||||
- Fix a regression in 0.14.5 that caused rendering of private use glyphs
|
||||
with and without spaces to be identical (:iss:`2117`)
|
||||
|
||||
- Wayland: Fix incorrect scale used when first creating an OS window
|
||||
(:iss:`2133`)
|
||||
|
||||
- macOS: Disable mouse hiding by default as getting it to work robustly
|
||||
on Cocoa is too much effort (:iss:`2158`)
|
||||
|
||||
|
||||
0.14.6 [2019-09-25]
|
||||
---------------------
|
||||
|
||||
- macOS: Fix a regression in the previous release that caused a crash when
|
||||
pressing a unprintable key, such as the POWER key (:iss:`1997`)
|
||||
|
||||
- Fix a regression in the previous release that caused kitty to not always
|
||||
respond to DPI changes (:pull:`1999`)
|
||||
|
||||
|
||||
0.14.5 [2019-09-23]
|
||||
---------------------
|
||||
|
||||
- Implement a hack to (mostly) preserve tabs when cat-ting a file with them and then
|
||||
copying the text or passing screen contents to another program (:iss:`1829`)
|
||||
|
||||
- When all visible windows have the same background color, use that as the
|
||||
color for the global padding, instead of the configured background color
|
||||
(:iss:`1957`)
|
||||
|
||||
- When resetting the terminal, also reset parser state, this allows easy
|
||||
recovery from incomplete escape codes (:iss:`1961`)
|
||||
|
||||
- Allow mapping keys commonly found on European keyboards (:pull:`1928`)
|
||||
|
||||
- Fix incorrect rendering of some symbols when followed by a space while using
|
||||
the PowerLine font which does not have a space glyph (:iss:`1225`)
|
||||
|
||||
- Linux: Allow using fonts with spacing=90 in addition to fonts with
|
||||
spacing=100 (:iss:`1968`)
|
||||
|
||||
- Use selection foreground color for underlines as well (:iss:`1982`)
|
||||
|
||||
0.14.4 [2019-08-31]
|
||||
---------------------
|
||||
|
||||
- hints kitten: Add a :option:`kitty +kitten hints --alphabet` option to
|
||||
control what alphabets are used for hints (:iss:`1879`)
|
||||
|
||||
- hints kitten: Allow specifying :option:`kitty +kitten hints --program`
|
||||
multiple times to run multiple programs (:iss:`1879`)
|
||||
|
||||
- Add a :opt:`kitten_alias` option that can be used to alias kitten invocation
|
||||
for brevity and to change kitten option defaults globally (:iss:`1879`)
|
||||
|
||||
- macOS: Add an option :opt:`macos_show_window_title_in` to control
|
||||
showing the window title in the menubar/titlebar (:pull:`1837`)
|
||||
|
||||
- macOS: Allow drag and drop of text from other applications into kitty
|
||||
(:pull:`1921`)
|
||||
|
||||
- When running kittens, use the colorscheme of the current window
|
||||
rather than the configured colorscheme (:iss:`1906`)
|
||||
|
||||
- Don't fail to start if running the shell to read the EDITOR env var fails
|
||||
(:iss:`1869`)
|
||||
|
||||
- Disable the ``liga`` and ``dlig`` OpenType features for broken fonts
|
||||
such as Nimbus Mono.
|
||||
|
||||
- Fix a regression that broke setting background_opacity via remote control
|
||||
(:iss:`1895`)
|
||||
|
||||
- Fix piping PNG images into the icat kitten not working (:iss:`1920`)
|
||||
|
||||
- When the OS returns a fallback font that does not actually contain glyphs
|
||||
for the text, do not exhaust the list of fallback fonts (:iss:`1918`)
|
||||
|
||||
- Fix formatting attributes not reset across line boundaries when passing
|
||||
buffer as ANSI (:iss:`1924`)
|
||||
|
||||
|
||||
0.14.3 [2019-07-29]
|
||||
---------------------
|
||||
|
||||
- Remote control: Add a command `kitty @ scroll-window` to scroll windows
|
||||
|
||||
- Allow passing a ``!neighbor`` argument to the new_window mapping to open a
|
||||
new window next to the active window (:iss:`1746`)
|
||||
|
||||
- Document the kitty remote control protocol (:iss:`1646`)
|
||||
|
||||
- Add a new option :opt:`pointer_shape_when_grabbed` that allows you to control
|
||||
the mouse pointer shape when the terminal programs grabs the pointer
|
||||
(:iss:`1808`)
|
||||
|
||||
- Add an option :opt:`terminal_select_modifiers` to control which modifiers
|
||||
are used to override mouse selection even when a terminal application has
|
||||
grabbed the mouse (:iss:`1774`)
|
||||
|
||||
- When piping data to a child in the pipe command do it in a thread so as not
|
||||
to block the UI (:iss:`1708`)
|
||||
|
||||
- unicode_input kitten: Fix a regression that broke using indices to select
|
||||
recently used symbols.
|
||||
|
||||
- Fix a regression that caused closing an overlay window to focus
|
||||
the previously focused window rather than the underlying window (:iss:`1720`)
|
||||
|
||||
- macOS: Reduce energy consumption when idle by shutting down Apple's display
|
||||
link thread after 30 second of inactivity (:iss:`1763`)
|
||||
|
||||
- Linux: Fix incorrect scaling for fallback fonts when the font has an
|
||||
underscore that renders out of bounds (:iss:`1713`)
|
||||
|
||||
- macOS: Fix finding fallback font for private use unicode symbols not working
|
||||
reliably (:iss:`1650`)
|
||||
|
||||
- Fix an out of bounds read causing a crash when selecting text with the mouse
|
||||
in the alternate screen mode (:iss:`1578`)
|
||||
|
||||
- Linux: Use the system "bell" sound for the terminal bell. Adds libcanberra
|
||||
as a new dependency to play the system sound.
|
||||
|
||||
- macOS: Fix a rare deadlock causing kitty to hang (:iss:`1779`)
|
||||
|
||||
- Linux: Fix a regression in 0.14.0 that caused the event loop to tick
|
||||
continuously, wasting CPU even when idle (:iss:`1782`)
|
||||
|
||||
- ssh kitten: Make argument parsing more like ssh (:iss:`1787`)
|
||||
|
||||
- When using :opt:`strip_trailing_spaces` do not remove empty lines
|
||||
(:iss:`1802`)
|
||||
|
||||
- Fix a crash when displaying very large number of images (:iss:`1825`)
|
||||
|
||||
|
||||
0.14.2 [2019-06-09]
|
||||
---------------------
|
||||
|
||||
- Add an option :opt:`placement_strategy` to control how the cell area is
|
||||
aligned inside the window when the window size is not an exact multiple
|
||||
of the cell size (:pull:`1670`)
|
||||
|
||||
- hints kitten: Add a :option:`kitty +kitten hints --multiple-joiner` option to
|
||||
control how multiple selections are serialized when copying to clipboard
|
||||
or inserting into the terminal. You can have them on separate lines,
|
||||
separated by arbitrary characters, or even serialized as JSON (:iss:`1665`)
|
||||
|
||||
- macOS: Fix a regression in the previous release that broke using
|
||||
:kbd:`ctrl+shift+tab` (:iss:`1671`)
|
||||
|
||||
- panel kitten: Fix the contents of the panel kitten not being positioned
|
||||
correctly on the vertical axis
|
||||
|
||||
- icat kitten: Fix a regression that broke passing directories to icat
|
||||
(:iss:`1683`)
|
||||
|
||||
- clipboard kitten: Add a :option:`kitty +kitten clipboard --wait-for-completion`
|
||||
option to have the kitten wait till copying to clipboard is complete
|
||||
(:iss:`1693`)
|
||||
|
||||
- Allow using the :doc:`pipe <pipe>` command to send screen and scrollback
|
||||
contents directly to the clipboard (:iss:`1693`)
|
||||
|
||||
- Linux: Disable the Wayland backend on GNOME by default as GNOME has no
|
||||
support for server side decorations. Can be controlled by
|
||||
:opt:`linux_display_server`.
|
||||
|
||||
- Add an option to control the default :opt:`update_check_interval` when
|
||||
building kitty packages
|
||||
|
||||
- Wayland: Fix resizing the window on a compositor that does not provide
|
||||
server side window decorations, such a GNOME or Weston not working
|
||||
correctly (:iss:`1659`)
|
||||
|
||||
- Wayland: Fix crash when enabling disabling monitors on sway (:iss:`1696`)
|
||||
|
||||
|
||||
0.14.1 [2019-05-29]
|
||||
---------------------
|
||||
|
||||
- Add an option :opt:`command_on_bell` to run an arbitrary command when
|
||||
a bell occurs (:iss:`1660`)
|
||||
|
||||
- Add a shortcut to toggle maximized window state :sc:`toggle_maximized`
|
||||
|
||||
- Add support for the underscore key found in some keyboard layouts
|
||||
(:iss:`1639`)
|
||||
|
||||
- Fix a missing newline when using the pipe command between the
|
||||
scrollback and screen contents (:iss:`1642`)
|
||||
|
||||
- Fix colors not being preserved when using the pipe command with
|
||||
the pager history buffer (:pull:`1657`)
|
||||
|
||||
- macOS: Fix a regression that could cause rendering of a kitty window
|
||||
to occasionally freeze in certain situations, such as moving it between
|
||||
monitors or transitioning from/to fullscreen (:iss:`1641`)
|
||||
|
||||
- macOS: Fix a regression that caused :kbd:`cmd+v` to double up in the dvorak
|
||||
keyboard layout (:iss:`1652`)
|
||||
|
||||
- When resizing and only a single window is present in the current layout,
|
||||
use that window's background color to fill in the blank areas.
|
||||
|
||||
- Linux: Automatically increase cell height if the font being used is broken
|
||||
and draws the underscore outside the bounding box (:iss:`690`)
|
||||
|
||||
- Wayland: Fix maximizing the window on a compositor that does not provide
|
||||
server side window decorations, such a GNOME or Weston not working
|
||||
(:iss:`1662`)
|
||||
|
||||
|
||||
0.14.0 [2019-05-24]
|
||||
---------------------
|
||||
|
||||
- macOS: The default behavior of the Option key has changed. It now generates
|
||||
unicode characters rather than acting as the :kbd:`Alt` modifier. See
|
||||
:opt:`macos_option_as_alt`.
|
||||
|
||||
- Support for an arbitrary number of internal clipboard buffers to copy/paste
|
||||
from, see (:ref:`cpbuf`)
|
||||
|
||||
- Allow using the new private internal clipboard buffers with the
|
||||
:opt:`copy_on_select` option (:iss:`1390`)
|
||||
|
||||
- macOS: Allow opening new kitty tabs/top-level windows from Finder
|
||||
(:pull:`1350`)
|
||||
|
||||
- Add an option :opt:`disable_ligatures` to disable
|
||||
multi-character ligatures under the cursor to make editing easier
|
||||
or disable them completely (:iss:`461`)
|
||||
|
||||
- Allow creating new OS windows in session files (:iss:`1514`)
|
||||
|
||||
- Allow setting OS window size in session files
|
||||
|
||||
- Add an option :opt:`tab_switch_strategy` to control which
|
||||
tab becomes active when the current tab is closed (:pull:`1524`)
|
||||
|
||||
- Allow specifying a value of ``none`` for the :opt:`selection_foreground`
|
||||
which will cause kitty to not change text color in selections (:iss:`1358`)
|
||||
|
||||
- Make live resizing of OS windows smoother and add an option
|
||||
:opt:`resize_draw_strategy` to control what is drawn while a
|
||||
resize is in progress.
|
||||
|
||||
- macOS: Improve handling of IME extended input. Compose characters
|
||||
are now highlighted and the IME panel moves along with the text
|
||||
(:pull:`1586`). Also fixes handling of delete key in Chinese IME
|
||||
(:iss:`1461`)
|
||||
|
||||
- When a window is closed, switch focus to the previously active window (if
|
||||
any) instead of picking the previous window in the layout (:iss:`1450`)
|
||||
|
||||
- icat kitten: Add support for displaying images at http(s) URLs (:iss:`1340`)
|
||||
|
||||
- A new option :opt:`strip_trailing_spaces` to optionally remove trailing
|
||||
spaces from lines when copying to clipboard.
|
||||
|
||||
- A new option :opt:`tab_bar_min_tabs` to control how many tabs must be
|
||||
present before the tab-bar is shown (:iss:`1382`)
|
||||
|
||||
- Automatically check for new releases and notify when an update is available,
|
||||
via the system notification facilities. Can be controlled by
|
||||
:opt:`update_check_interval` (:iss:`1342`)
|
||||
|
||||
- macOS: Fix :kbd:`cmd+period` key not working (:iss:`1318`)
|
||||
|
||||
- macOS: Add an option `macos_show_window_title_in_menubar` to not
|
||||
show the current window title in the menu-bar (:iss:`1066`)
|
||||
|
||||
- macOS: Workaround for cocoa bug that could cause the mouse cursor to become
|
||||
hidden in other applications in rare circumstances (:iss:`1218`)
|
||||
|
||||
- macOS: Allow assigning only the left or right :kbd:`Option` key to work as the
|
||||
:kbd:`Alt` key. See :opt:`macos_option_as_alt` for details (:iss:`1022`)
|
||||
|
||||
- Fix using remote control to set cursor text color causing errors when
|
||||
creating new windows (:iss:`1326`)
|
||||
|
||||
- Fix window title for minimized windows not being updated (:iss:`1332`)
|
||||
|
||||
- macOS: Fix using multi-key sequences to input text ignoring the
|
||||
first few key presses if the sequence is aborted (:iss:`1311`)
|
||||
|
||||
- macOS: Add a number of common macOS keyboard shortcuts
|
||||
|
||||
- macOS: Reduce energy consumption by not rendering occluded windows
|
||||
|
||||
- Fix scrollback pager history not being cleared when clearing the
|
||||
main scrollback buffer (:iss:`1387`)
|
||||
|
||||
- macOS: When closing a top-level window only switch focus to the previous kitty
|
||||
window if it is on the same workspace (:iss:`1379`)
|
||||
|
||||
- macOS: Fix :opt:`sync_to_monitor` not working on Mojave.
|
||||
|
||||
- macOS: Use the system cursor blink interval by default
|
||||
:opt:`cursor_blink_interval`.
|
||||
|
||||
- Wayland: Use the kitty Wayland backend by default. Can be switched back
|
||||
to using XWayland by setting the environment variable:
|
||||
``KITTY_DISABLE_WAYLAND=1``
|
||||
|
||||
- Add a ``no-append`` setting to :opt:`clipboard_control` to disable
|
||||
the kitty copy concatenation protocol extension for OSC 52.
|
||||
|
||||
- Update to using the Unicode 12 standard
|
||||
|
||||
- Unicode input kitten: Allow using the arrow keys in code mode to go to next
|
||||
and previous unicode symbol.
|
||||
|
||||
- macOS: Fix specifying initial window size in cells not working correctly on
|
||||
Retina screens (:iss:`1444`)
|
||||
|
||||
- Fix a regression in version 0.13.0 that caused background colors of space
|
||||
characters after private use unicode characters to not be respected
|
||||
(:iss:`1455`)
|
||||
|
||||
- Only update the selected text to clipboard when the selection is finished,
|
||||
not continuously as it is updated. (:iss:`1460`)
|
||||
|
||||
- Allow setting :opt:`active_border_color` to ``none`` to not draw a border
|
||||
around the active window (:iss:`805`)
|
||||
|
||||
- Use negative values for :opt:`mouse_hide_wait` to hide the mouse cursor
|
||||
immediately when pressing a key (:iss:`1534`)
|
||||
|
||||
- When encountering errors in :file:`kitty.conf` report them to the user
|
||||
instead of failing to start.
|
||||
|
||||
- Allow the user to control the resize debounce time via
|
||||
:opt:`resize_debounce_time`.
|
||||
|
||||
- Remote control: Make the :ref:`at_set-font-size` command more capable.
|
||||
It can now increment font size and reset it. It also only acts on the
|
||||
active top-level window, by default (:iss:`1581`)
|
||||
|
||||
- When launching child processes set the :code:`PWD` environment variable
|
||||
(:iss:`1595`)
|
||||
|
||||
- X11: use the window manager's native full-screen implementation when
|
||||
making windows full-screen (:iss:`1605`)
|
||||
|
||||
- Mouse selection: When extending by word, fix extending selection to non-word
|
||||
characters not working well (:iss:`1616`)
|
||||
|
||||
0.13.3 [2019-01-19]
|
||||
------------------------------
|
||||
|
||||
180
docs/conf.py
180
docs/conf.py
@@ -1,33 +1,46 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#!/usr/bin/env python3
|
||||
# vim:fileencoding=utf-8
|
||||
#
|
||||
# Configuration file for the Sphinx documentation builder.
|
||||
#
|
||||
# This file does only contain a selection of the most common options. For a
|
||||
# full list see the documentation:
|
||||
# http://www.sphinx-doc.org/en/master/config
|
||||
# https://www.sphinx-doc.org/en/master/config
|
||||
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
from functools import partial
|
||||
from typing import (
|
||||
Any, Callable, Dict, Iterable, List, Match, Optional, Sequence, Tuple,
|
||||
Union
|
||||
)
|
||||
|
||||
from docutils import nodes
|
||||
from docutils.parsers.rst.roles import set_classes
|
||||
from pygments.lexer import RegexLexer, bygroups
|
||||
from pygments.token import (
|
||||
from pygments.lexer import RegexLexer, bygroups # type: ignore
|
||||
from pygments.token import ( # type: ignore
|
||||
Comment, Keyword, Literal, Name, Number, String, Whitespace
|
||||
)
|
||||
from sphinx import addnodes
|
||||
from sphinx.util.logging import getLogger
|
||||
from sphinx import addnodes # type: ignore
|
||||
from sphinx.environment.adapters.toctree import TocTree # type: ignore
|
||||
from sphinx.util.logging import getLogger # type: ignore
|
||||
|
||||
kitty_src = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
if kitty_src not in sys.path:
|
||||
sys.path.insert(0, kitty_src)
|
||||
|
||||
from kitty.conf.definition import Option, Shortcut # noqa
|
||||
from kitty.constants import str_version # noqa
|
||||
|
||||
from kitty.constants import str_version
|
||||
|
||||
# config {{{
|
||||
# -- Project information -----------------------------------------------------
|
||||
|
||||
project = 'kitty'
|
||||
copyright = '2018, Kovid Goyal'
|
||||
copyright = time.strftime('%Y, Kovid Goyal')
|
||||
author = 'Kovid Goyal'
|
||||
building_man_pages = 'man' in sys.argv
|
||||
|
||||
@@ -70,7 +83,7 @@ master_doc = 'index'
|
||||
#
|
||||
# This is also used if you do content translation via gettext catalogs.
|
||||
# Usually you set "language" from the command line for these cases.
|
||||
language = None
|
||||
language: Optional[str] = None
|
||||
|
||||
# List of patterns, relative to source directory, that match files and
|
||||
# directories to ignore when looking for source files.
|
||||
@@ -175,9 +188,9 @@ texinfo_documents = [
|
||||
# }}}
|
||||
|
||||
|
||||
# GitHub linking inlne 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 '
|
||||
try:
|
||||
issue_num = int(text)
|
||||
@@ -195,10 +208,11 @@ def num_role(which, name, rawtext, text, lineno, inliner, options={}, content=[]
|
||||
return [node], []
|
||||
|
||||
|
||||
def commit_role(name, rawtext, text, lineno, inliner, options={}, content=[]):
|
||||
def commit_role(name: str, rawtext: str, text: str, lineno: int, inliner: Any, options: Any = {}, content: Any = []) -> Tuple[List, List]:
|
||||
' Link to a github commit '
|
||||
try:
|
||||
commit_id = subprocess.check_output(f'git rev-list --max-count=1 --skip=# {text}'.split()).decode('utf-8').strip()
|
||||
commit_id = subprocess.check_output(
|
||||
f'git rev-list --max-count=1 --skip=# {text}'.split()).decode('utf-8').strip()
|
||||
except Exception:
|
||||
msg = inliner.reporter.error(
|
||||
f'GitHub commit id "{text}" not recognized.', line=lineno)
|
||||
@@ -206,20 +220,22 @@ def commit_role(name, rawtext, text, lineno, inliner, options={}, content=[]):
|
||||
return [prb], [msg]
|
||||
url = f'https://github.com/kovidgoyal/kitty/commit/{commit_id}'
|
||||
set_classes(options)
|
||||
short_id = subprocess.check_output(f'git rev-list --max-count=1 --abbrev-commit --skip=# {commit_id}'.split()).decode('utf-8').strip()
|
||||
short_id = subprocess.check_output(
|
||||
f'git rev-list --max-count=1 --abbrev-commit --skip=# {commit_id}'.split()).decode('utf-8').strip()
|
||||
node = nodes.reference(rawtext, f'commit: {short_id}', refuri=url, **options)
|
||||
return [node], []
|
||||
# }}}
|
||||
|
||||
|
||||
# Sidebar ToC {{{
|
||||
def create_toc(app, pagename):
|
||||
toctree = app.env.get_toc_for(pagename, app.builder)
|
||||
def create_toc(app: Any, pagename: str) -> Optional[Any]:
|
||||
tt = TocTree(app.env)
|
||||
toctree = tt.get_toc_for(pagename, app.builder)
|
||||
if toctree is not None:
|
||||
subtree = toctree[toctree.first_child_matching_class(nodes.list_item)]
|
||||
bl = subtree.first_child_matching_class(nodes.bullet_list)
|
||||
if bl is None:
|
||||
return # Empty ToC
|
||||
return None # Empty ToC
|
||||
subtree = subtree[bl]
|
||||
# for li in subtree.traverse(nodes.list_item):
|
||||
# modify_li(li)
|
||||
@@ -227,29 +243,40 @@ def create_toc(app, pagename):
|
||||
return app.builder.render_partial(subtree)['fragment']
|
||||
|
||||
|
||||
def add_html_context(app, pagename, templatename, context, *args):
|
||||
def add_html_context(app: Any, pagename: str, templatename: str, context: Any, *args: Any) -> None:
|
||||
if 'toc' in context:
|
||||
context['toc'] = create_toc(app, pagename) or context['toc']
|
||||
# }}}
|
||||
|
||||
|
||||
# CLI docs {{{
|
||||
def write_cli_docs(all_kitten_names):
|
||||
def write_cli_docs(all_kitten_names: Iterable[str]) -> None:
|
||||
from kitty.launch import options_spec as launch_options_spec
|
||||
from kitty.cli import option_spec_as_rst
|
||||
with open('generated/launch.rst', 'w') as f:
|
||||
f.write(option_spec_as_rst(
|
||||
appname='launch', ospec=launch_options_spec, heading_char='_',
|
||||
message='''\
|
||||
Launch an arbitrary program in a new kitty window/tab. Note that
|
||||
if you specify a program-to-run you can use the special placeholder
|
||||
:code:`@selection` which will be replaced by the current selection.
|
||||
'''
|
||||
))
|
||||
with open('generated/cli-kitty.rst', 'w') as f:
|
||||
f.write(option_spec_as_rst(appname='kitty').replace(
|
||||
'kitty --to', 'kitty @ --to'))
|
||||
as_rst = partial(option_spec_as_rst, heading_char='_')
|
||||
from kitty.remote_control import global_options_spec, cli_msg, cmap, all_commands
|
||||
from kitty.rc.base import all_command_names, command_for_name
|
||||
from kitty.remote_control import global_options_spec, cli_msg
|
||||
with open('generated/cli-kitty-at.rst', 'w') as f:
|
||||
p = partial(print, file=f)
|
||||
p('kitty @\n' + '-' * 80)
|
||||
p('.. program::', 'kitty @')
|
||||
p('\n\n' + as_rst(
|
||||
global_options_spec, message=cli_msg, usage='command ...', appname='kitty @'))
|
||||
from kitty.cmds import cli_params_for
|
||||
for cmd_name in all_commands:
|
||||
func = cmap[cmd_name]
|
||||
from kitty.rc.base import cli_params_for
|
||||
for cmd_name in sorted(all_command_names()):
|
||||
func = command_for_name(cmd_name)
|
||||
p(f'.. _at_{func.name}:\n')
|
||||
p('kitty @', func.name + '\n' + '-' * 120)
|
||||
p('.. program::', 'kitty @', func.name)
|
||||
@@ -268,6 +295,48 @@ def write_cli_docs(all_kitten_names):
|
||||
# }}}
|
||||
|
||||
|
||||
def write_remote_control_protocol_docs() -> None: # {{{
|
||||
from kitty.rc.base import all_command_names, command_for_name, RemoteCommand
|
||||
field_pat = re.compile(r'\s*([a-zA-Z0-9_+]+)\s*:\s*(.+)')
|
||||
|
||||
def format_cmd(p: Callable, name: str, cmd: RemoteCommand) -> None:
|
||||
p(name)
|
||||
p('-' * 80)
|
||||
lines = (cmd.__doc__ or '').strip().splitlines()
|
||||
fields = []
|
||||
for line in lines:
|
||||
m = field_pat.match(line)
|
||||
if m is None:
|
||||
p(line)
|
||||
else:
|
||||
fields.append((m.group(1), m.group(2)))
|
||||
if fields:
|
||||
p('\nFields are:\n')
|
||||
for (name, desc) in fields:
|
||||
if '+' in name:
|
||||
title = name.replace('+', ' (required)')
|
||||
else:
|
||||
title = name
|
||||
defval = cmd.get_default(name.replace('-', '_'), cmd)
|
||||
if defval is not cmd:
|
||||
title = f'{title} (default: {defval})'
|
||||
else:
|
||||
title = f'{title} (optional)'
|
||||
p(f':code:`{title}`')
|
||||
p(' ', desc), p()
|
||||
p(), p()
|
||||
|
||||
with open('generated/rc.rst', 'w') as f:
|
||||
p = partial(print, file=f)
|
||||
for name in sorted(all_command_names()):
|
||||
cmd = command_for_name(name)
|
||||
if not cmd.__doc__:
|
||||
continue
|
||||
name = name.replace('_', '-')
|
||||
format_cmd(p, name, cmd)
|
||||
# }}}
|
||||
|
||||
|
||||
# config file docs {{{
|
||||
|
||||
class ConfLexer(RegexLexer):
|
||||
@@ -323,7 +392,7 @@ class SessionLexer(RegexLexer):
|
||||
}
|
||||
|
||||
|
||||
def link_role(name, rawtext, text, lineno, inliner, options={}, content=[]):
|
||||
def link_role(name: str, rawtext: str, text: str, lineno: int, inliner: Any, options: Any = {}, content: Any = []) -> Tuple[List, List]:
|
||||
m = re.match(r'(.+)\s+<(.+?)>', text)
|
||||
if m is None:
|
||||
msg = inliner.reporter.error(f'link "{text}" not recognized', line=lineno)
|
||||
@@ -335,24 +404,24 @@ def link_role(name, rawtext, text, lineno, inliner, options={}, content=[]):
|
||||
return [node], []
|
||||
|
||||
|
||||
def expand_opt_references(conf_name, text):
|
||||
def expand_opt_references(conf_name: str, text: str) -> str:
|
||||
conf_name += '.'
|
||||
|
||||
def expand(m):
|
||||
def expand(m: Match) -> str:
|
||||
ref = m.group(1)
|
||||
if '<' not in ref and '.' not in ref:
|
||||
full_ref = conf_name + ref
|
||||
return ':opt:`{} <{}>`'.format(ref, full_ref)
|
||||
return m.group()
|
||||
return str(m.group())
|
||||
|
||||
return re.sub(r':opt:`(.+?)`', expand, text)
|
||||
|
||||
|
||||
opt_aliases = {}
|
||||
shortcut_slugs = {}
|
||||
opt_aliases: Dict[str, str] = {}
|
||||
shortcut_slugs: Dict[str, Tuple[str, str]] = {}
|
||||
|
||||
|
||||
def parse_opt_node(env, sig, signode):
|
||||
def parse_opt_node(env: Any, sig: str, signode: Any) -> str:
|
||||
"""Transform an option description into RST nodes."""
|
||||
count = 0
|
||||
firstname = ''
|
||||
@@ -374,22 +443,22 @@ def parse_opt_node(env, sig, signode):
|
||||
return firstname
|
||||
|
||||
|
||||
def parse_shortcut_node(env, sig, signode):
|
||||
def parse_shortcut_node(env: Any, sig: str, signode: Any) -> str:
|
||||
"""Transform a shortcut description into RST nodes."""
|
||||
conf_name, text = sig.split('.', 1)
|
||||
signode += addnodes.desc_name(text, text)
|
||||
return sig
|
||||
|
||||
|
||||
def render_conf(conf_name, all_options):
|
||||
from kitty.conf.definition import merged_opts, Option
|
||||
def render_conf(conf_name: str, all_options: Iterable[Union['Option', Sequence['Shortcut']]]) -> str:
|
||||
from kitty.conf.definition import merged_opts, Option, Group
|
||||
ans = ['.. default-domain:: conf', '']
|
||||
a = ans.append
|
||||
current_group = None
|
||||
all_options = list(all_options)
|
||||
current_group: Optional[Group] = None
|
||||
all_options_ = list(all_options)
|
||||
kitty_mod = 'kitty_mod'
|
||||
|
||||
def render_group(group):
|
||||
def render_group(group: Group) -> None:
|
||||
a('')
|
||||
a(f'.. _conf-{conf_name}-{group.name}:')
|
||||
a('')
|
||||
@@ -401,11 +470,12 @@ def render_conf(conf_name, all_options):
|
||||
a(group.start_text)
|
||||
a('')
|
||||
|
||||
def handle_group_end(group):
|
||||
def handle_group_end(group: Group) -> None:
|
||||
if group.end_text:
|
||||
assert current_group is not None
|
||||
a(''), a(current_group.end_text)
|
||||
|
||||
def handle_group(new_group, new_group_is_shortcut=False):
|
||||
def handle_group(new_group: Group, new_group_is_shortcut: bool = False) -> None:
|
||||
nonlocal current_group
|
||||
if new_group is not current_group:
|
||||
if current_group:
|
||||
@@ -413,14 +483,14 @@ def render_conf(conf_name, all_options):
|
||||
current_group = new_group
|
||||
render_group(current_group)
|
||||
|
||||
def handle_option(i, opt):
|
||||
def handle_option(i: int, opt: Option) -> None:
|
||||
nonlocal kitty_mod
|
||||
if not opt.long_text or not opt.add_to_docs:
|
||||
return
|
||||
handle_group(opt.group)
|
||||
if opt.name == 'kitty_mod':
|
||||
kitty_mod = opt.defval_as_string
|
||||
mopts = list(merged_opts(all_options, opt, i))
|
||||
mopts = list(merged_opts(all_options_, opt, i))
|
||||
a('.. opt:: ' + ', '.join(conf_name + '.' + mo.name for mo in mopts))
|
||||
a('.. code-block:: conf')
|
||||
a('')
|
||||
@@ -432,7 +502,7 @@ def render_conf(conf_name, all_options):
|
||||
a(expand_opt_references(conf_name, opt.long_text))
|
||||
a('')
|
||||
|
||||
def handle_shortcuts(shortcuts):
|
||||
def handle_shortcuts(shortcuts: Sequence[Shortcut]) -> None:
|
||||
sc = shortcuts[0]
|
||||
handle_group(sc.group, True)
|
||||
sc_text = f'{conf_name}.{sc.short_text}'
|
||||
@@ -450,7 +520,7 @@ def render_conf(conf_name, all_options):
|
||||
a(expand_opt_references(conf_name, sc.long_text))
|
||||
a('')
|
||||
|
||||
for i, opt in enumerate(all_options):
|
||||
for i, opt in enumerate(all_options_):
|
||||
if isinstance(opt, Option):
|
||||
handle_option(i, opt)
|
||||
else:
|
||||
@@ -461,7 +531,7 @@ def render_conf(conf_name, all_options):
|
||||
return '\n'.join(ans)
|
||||
|
||||
|
||||
def process_opt_link(env, refnode, has_explicit_title, title, target):
|
||||
def process_opt_link(env: Any, refnode: Any, has_explicit_title: bool, title: str, target: str) -> Tuple[str, str]:
|
||||
conf_name, opt = target.partition('.')[::2]
|
||||
if not opt:
|
||||
conf_name, opt = 'kitty', conf_name
|
||||
@@ -469,20 +539,23 @@ def process_opt_link(env, refnode, has_explicit_title, title, target):
|
||||
return title, opt_aliases.get(full_name, full_name)
|
||||
|
||||
|
||||
def process_shortcut_link(env, refnode, has_explicit_title, title, target):
|
||||
def process_shortcut_link(env: Any, refnode: Any, has_explicit_title: bool, title: str, target: str) -> Tuple[str, str]:
|
||||
conf_name, slug = target.partition('.')[::2]
|
||||
if not slug:
|
||||
conf_name, slug = 'kitty', conf_name
|
||||
full_name = conf_name + '.' + slug
|
||||
try:
|
||||
target, title = shortcut_slugs[full_name]
|
||||
target, stitle = shortcut_slugs[full_name]
|
||||
except KeyError:
|
||||
logger.warning('Unknown shortcut: {}'.format(target), location=refnode)
|
||||
else:
|
||||
if not has_explicit_title:
|
||||
title = stitle
|
||||
return title, target
|
||||
|
||||
|
||||
def write_conf_docs(app, all_kitten_names):
|
||||
app.add_lexer('conf', ConfLexer())
|
||||
def write_conf_docs(app: Any, all_kitten_names: Iterable[str]) -> None:
|
||||
app.add_lexer('conf', ConfLexer)
|
||||
app.add_object_type(
|
||||
'opt', 'opt',
|
||||
indextemplate="pair: %s; Config Setting",
|
||||
@@ -502,7 +575,7 @@ def write_conf_docs(app, all_kitten_names):
|
||||
sc_role.warn_dangling = True
|
||||
sc_role.process_link = process_shortcut_link
|
||||
|
||||
def generate_default_config(all_options, name):
|
||||
def generate_default_config(all_options: Dict[str, Union[Option, Sequence[Shortcut]]], name: str) -> None:
|
||||
from kitty.conf.definition import as_conf_file
|
||||
with open(f'generated/conf-{name}.rst', 'w', encoding='utf-8') as f:
|
||||
print('.. highlight:: conf\n', file=f)
|
||||
@@ -524,13 +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)
|
||||
from kittens.runner import all_kitten_names
|
||||
all_kitten_names = all_kitten_names()
|
||||
write_cli_docs(all_kitten_names)
|
||||
write_conf_docs(app, all_kitten_names)
|
||||
app.add_lexer('session', SessionLexer())
|
||||
kn = all_kitten_names()
|
||||
write_cli_docs(kn)
|
||||
write_remote_control_protocol_docs()
|
||||
write_conf_docs(app, kn)
|
||||
app.add_lexer('session', SessionLexer)
|
||||
app.add_role('link', link_role)
|
||||
app.add_role('iss', partial(num_role, 'issues'))
|
||||
app.add_role('pull', partial(num_role, 'pull'))
|
||||
|
||||
@@ -20,6 +20,10 @@ You can also display the current configuration by running ``kitty
|
||||
:option:`kitty --config` option or use the ``KITTY_CONFIG_DIRECTORY``
|
||||
environment variable. See the :option:`kitty --config` option for full details.
|
||||
|
||||
Comments can be added to the config file as lines starting with the ``#``
|
||||
character. This works only if the ``#`` character is the first character
|
||||
in the line.
|
||||
|
||||
You can include secondary config files via the :code:`include` directive. If
|
||||
you use a relative path for include, it is resolved with respect to the
|
||||
location of the current config file. Note that environment variables are
|
||||
|
||||
144
docs/faq.rst
144
docs/faq.rst
@@ -63,6 +63,18 @@ Really, the correct solution for this is to convince the OpenSSH maintainers to
|
||||
have ssh do this automatically, if possible, when connecting to a server, so that
|
||||
all terminals work transparently.
|
||||
|
||||
If the server is running FreeBSD, or another system that relies on termcap
|
||||
rather than terminfo, you will need to convert the terminfo file on your local
|
||||
machine by running (on local machine with |kitty|)::
|
||||
|
||||
infocmp -C xterm-kitty
|
||||
|
||||
The output of this command is the termcap description, which should be appended
|
||||
to :file:`/usr/share/misc/termcap` on the remote server. Then run the following
|
||||
command to apply your change (on the server)::
|
||||
|
||||
cap_mkdb /usr/share/misc/termcap
|
||||
|
||||
|
||||
Keys such as arrow keys, backspace, delete, home/end, etc. do not work when using su or sudo?
|
||||
-------------------------------------------------------------------------------------------------
|
||||
@@ -81,6 +93,11 @@ Shell providing the right terminfo path::
|
||||
sudo … env TERMINFO=$HOME/.terminfo bash -i
|
||||
TERMINFO=/home/ORIGINALUSER/.terminfo exec bash -i
|
||||
|
||||
You can configure sudo to preserve TERMINFO by running ``sudo
|
||||
visudo`` and adding the following line::
|
||||
|
||||
Defaults env_keep += "TERM TERMINFO"
|
||||
|
||||
If you have double width characters in your prompt, you may also need to
|
||||
explicitly set a UTF-8 locale, like::
|
||||
|
||||
@@ -91,9 +108,39 @@ How do I change the colors in a running kitty instance?
|
||||
------------------------------------------------------------
|
||||
|
||||
You can either use the
|
||||
`OSC terminal escape codes <http://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Operating-System-Commands>`_
|
||||
to set colors or you can enable :doc:`remote control <remote-control>`
|
||||
for |kitty| and use :ref:`at_set-colors`.
|
||||
`OSC terminal escape codes <https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Operating-System-Commands>`_
|
||||
to set colors or you can define keyboard shortcuts to set colors, for example::
|
||||
|
||||
map f1 set_colors --configured /path/to/some/config/file/colors.conf
|
||||
|
||||
Or you can enable :doc:`remote control <remote-control>` for |kitty| and use :ref:`at_set-colors`.
|
||||
The shortcut mapping technique has the same syntax as the remote control
|
||||
command, for details, see :ref:`at_set-colors`.
|
||||
|
||||
A list of pre-made color themes for kitty is available at:
|
||||
`kitty-themes <https://github.com/dexpota/kitty-themes>`_
|
||||
|
||||
Examples of using OSC escape codes to set colors::
|
||||
|
||||
Change the default foreground color:
|
||||
printf '\x1b]10;#ff0000\x1b\\'
|
||||
Change the default background color:
|
||||
printf '\x1b]11;blue\x1b\\'
|
||||
Change the cursor color:
|
||||
printf '\x1b]12;blue\x1b\\'
|
||||
Change the selection background color:
|
||||
printf '\x1b]17;blue\x1b\\'
|
||||
Change the selection foreground color:
|
||||
printf '\x1b]19;blue\x1b\\'
|
||||
Change the nth color (0 - 255):
|
||||
printf '\x1b]4;n;green\x1b\\'
|
||||
|
||||
You can use various syntaxes/names for color specifications in the above
|
||||
examples. See `XParseColor <https://linux.die.net/man/3/xparsecolor>`_
|
||||
for full details.
|
||||
|
||||
If a ``?`` is given rather than a color specification, kitty will respond
|
||||
with the current value for the specified color.
|
||||
|
||||
|
||||
How do I specify command line options for kitty on macOS?
|
||||
@@ -118,11 +165,39 @@ kitty is not able to use my favorite font?
|
||||
|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.
|
||||
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
|
||||
your font is not listed in ``kitty list-fonts`` it means that it is not
|
||||
monospace. On Linux you can list all monospace fonts with::
|
||||
only monospace fonts, since every cell in the grid has to be the same size.
|
||||
Furthermore, it needs fonts to be freely resizable, so it does not support
|
||||
bitmapped fonts.
|
||||
|
||||
fc-list : family spacing | grep spacing=100
|
||||
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
|
||||
glyph widths in the font. If for some reason fontconfig concludes your favorite
|
||||
monospace font does not have ``spacing=100`` you can override it by using the
|
||||
following :file:`~/.config/fontconfig/fonts.conf`::
|
||||
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
|
||||
<fontconfig>
|
||||
<match target="font">
|
||||
<test name="family">
|
||||
<string>Your Font Family Name</string>
|
||||
</test>
|
||||
<edit name="spacing">
|
||||
<int>100</int>
|
||||
</edit>
|
||||
</match>
|
||||
</fontconfig>
|
||||
|
||||
After creating (or modifying) this file, you may need to run the following
|
||||
command to rebuild your fontconfig cache::
|
||||
|
||||
fc-cache -r
|
||||
|
||||
Then, the font will be available in ``kitty list-fonts``.
|
||||
|
||||
|
||||
How can I assign a single global shortcut to bring up the kitty terminal?
|
||||
@@ -132,3 +207,58 @@ Bringing up applications on a single key press is the job of the window
|
||||
manager/desktop environment. For ways to do it with kitty (or indeed any
|
||||
terminal) in different environments,
|
||||
see `here <https://github.com/kovidgoyal/kitty/issues/45>`_.
|
||||
|
||||
|
||||
How do I map key presses in kitty to different keys in the terminal program?
|
||||
--------------------------------------------------------------------------------------
|
||||
|
||||
This is accomplished by using ``map`` with :sc:`send_text <send_text>` in :file:`kitty.conf`.
|
||||
For example::
|
||||
|
||||
map alt+s send_text all \x13
|
||||
|
||||
This maps :kbd:`alt+s` to :kbd:`ctrl+s`. To figure out what bytes to use for
|
||||
the :sc:`send_text <send_text>` you can use the ``showkey`` utility. Run::
|
||||
|
||||
showkey -a
|
||||
|
||||
Then press the key you want to emulate. On macOS, this utility is currently not
|
||||
available. The manual way to figure it out is:
|
||||
|
||||
1. Look up your key's decimal value in the table at the bottom of `this
|
||||
page <http://ascii-table.com/ansi-escape-sequences.php>`_ or any
|
||||
ANSI escape sequence table. There are different modifiers for :kbd:`ctrl`,
|
||||
:kbd:`alt`, etc. For e.g., for :kbd:`ctrl+s`, find the ``S`` row and look at
|
||||
the third column value, ``19``.
|
||||
|
||||
2. Convert the decimal value to hex with ``kitty +runpy "print(hex(19))"``.
|
||||
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``
|
||||
|
||||
|
||||
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:
|
||||
|
||||
* `termpdf <https://github.com/dsanson/termpdf>`_ - a terminal PDF/DJVU/CBR viewer
|
||||
* `termpdf.py <https://github.com/dsanson/termpdf.py>`_ - a terminal PDF/DJVU/CBR viewer
|
||||
* `ranger <https://github.com/ranger/ranger>`_ - a terminal file manager, with
|
||||
image previews, see this `PR <https://github.com/ranger/ranger/pull/1077>`_
|
||||
* :doc:`kitty-diff <kittens/diff>` - a side-by-side terminal diff program with support for images
|
||||
* `pixcat <https://github.com/mirukana/pixcat>`_ - a third party CLI and python library that wraps the graphics protocol
|
||||
* `neofetch <https://github.com/dylanaraps/neofetch>`_ - A command line system
|
||||
information tool
|
||||
* `viu <https://github.com/atanunq/viu>`_ - a terminal image viewer
|
||||
|
||||
|
||||
.. contents::
|
||||
@@ -53,27 +55,34 @@ In C:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
struct ttysize ts;
|
||||
ioctl(0, TIOCGWINSZ, &ts);
|
||||
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);
|
||||
#include <stdio.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
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:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import array, fcntl, termios
|
||||
import array, fcntl, sys, termios
|
||||
buf = array.array('H', [0, 0, 0, 0])
|
||||
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
|
||||
terminals should be modified to return the correct values. Examples of
|
||||
terminals that return correct values: ``kitty, xterm``
|
||||
|
||||
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>[4;<height>;<width>t`` where *height* and *width* are the window size in
|
||||
pixels. This escape code is supported in many terminals, not just kitty.
|
||||
``<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 pixels. This escape code is supported in many terminals, not just
|
||||
kitty.
|
||||
|
||||
A minimal example
|
||||
------------------
|
||||
@@ -107,7 +116,8 @@ features of the graphics protocol:
|
||||
sys.stdout.flush()
|
||||
cmd.clear()
|
||||
|
||||
write_chunked({'a': 'T', 'f': 100}, open(sys.argv[-1], 'rb').read())
|
||||
with open(sys.argv[-1], 'rb') as f:
|
||||
write_chunked({'a': 'T', 'f': 100}, f.read())
|
||||
|
||||
|
||||
Save this script as :file:`png.py`, then you can use it to display any PNG
|
||||
@@ -152,9 +162,10 @@ of transmitting paletted images.
|
||||
RGB and RGBA data
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
In these formats the pixel data is stored directly as 3 or 4 bytes per pixel, respectively.
|
||||
When specifying images in this format, the image dimensions **must** be sent in the control data.
|
||||
For example::
|
||||
In these formats the pixel data is stored directly as 3 or 4 bytes per pixel,
|
||||
respectively. The colors in the data **must** be in the *sRGB color space*. When
|
||||
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>\
|
||||
|
||||
@@ -255,11 +266,14 @@ sequence of escape codes to the terminal emulator::
|
||||
Note that only the first escape code needs to have the full set of control
|
||||
codes such as width, height, format etc. Subsequent chunks must have
|
||||
only the ``m`` key. The client **must** finish sending all chunks for a single image
|
||||
before sending any other graphics related escape codes.
|
||||
before sending any other graphics related escape codes. Note that the cursor
|
||||
position used to display the image **must** be the position when the final chunk is
|
||||
received. Finally, terminals must not display anything, until the entire sequence is
|
||||
received and validated.
|
||||
|
||||
|
||||
Detecting available transmission mediums
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Querying support and available transmission mediums
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Since a client has no a-priori knowledge of whether it shares a filesystem/shared memory
|
||||
with the terminal emulator, it can send an id with the control data, using the ``i`` key
|
||||
@@ -285,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
|
||||
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
|
||||
-----------------------------
|
||||
@@ -330,7 +365,9 @@ Finally, you can specify the image *z-index*, i.e. the vertical stacking order.
|
||||
placed in the same location with different z-index values will be blended if
|
||||
they are semi-transparent. You can specify z-index values using the ``z`` key.
|
||||
Negative z-index values mean that the images will be drawn under the text. This
|
||||
allows rendering of text on top of images.
|
||||
allows rendering of text on top of images. Negative z-index values below
|
||||
INT32_MIN/2 (-1,073,741,824) will be drawn under cells with non-default background
|
||||
colors.
|
||||
|
||||
Deleting images
|
||||
---------------------
|
||||
@@ -362,10 +399,10 @@ Value of ``d`` Meaning
|
||||
|
||||
Some examples::
|
||||
|
||||
<ESC>_Ga=d<ESC>\ # delete all visible images
|
||||
<ESC>_Ga=d,i=10<ESC>\ # delete the image with id=10
|
||||
<ESC>_Ga=Z,z=-1<ESC>\ # delete the images with z-index -1, also freeing up image data
|
||||
<ESC>_Ga=P,x=3,y=4<ESC>\ # delete all images that intersect the cell at (3, 4)
|
||||
<ESC>_Ga=d<ESC>\ # delete all visible images
|
||||
<ESC>_Ga=d,d=i,i=10<ESC>\ # delete the image with id=10, without freeing data
|
||||
<ESC>_Ga=d,d=Z,z=-1<ESC>\ # delete the images with z-index -1, also freeing up image data
|
||||
<ESC>_Ga=d,d=p,x=3,y=4<ESC>\ # delete all images that intersect the cell at (3, 4), without freeing data
|
||||
|
||||
Image persistence and storage quotas
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
@@ -413,7 +450,7 @@ Key Value Default Description
|
||||
``Y`` Positive integer ``0`` The y-offset within the first cell at which to start displaying the image
|
||||
``c`` Positive integer ``0`` The number of columns to display the image over
|
||||
``r`` Positive integer ``0`` The number of rows to display the image over
|
||||
``z`` Integer ``0`` The *z-index* vertical stacking order of the image
|
||||
``z`` 32-bit integer ``0`` The *z-index* vertical stacking order of the image
|
||||
**Keys for deleting images**
|
||||
-----------------------------------------------------------
|
||||
``d`` Single character. ``a`` What to delete.
|
||||
|
||||
218
docs/index.rst
218
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.
|
||||
|
||||
* Supports all modern terminal features: :doc:`graphics (images)
|
||||
<graphics-protocol>`, unicode, true-color, OpenType ligatures, mouse
|
||||
protocol, focus tracking, `bracketed paste
|
||||
<https://cirw.in/blog/bracketed-paste>`_ and several :doc:`new terminal
|
||||
protocol extensions <protocol-extensions>`.
|
||||
<graphics-protocol>`, unicode, `true-color
|
||||
<https://gist.github.com/XVilka/8346728>`_,
|
||||
OpenType ligatures, mouse protocol, :doc:`hyperlinks <open_actions>`,
|
||||
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
|
||||
:ref:`layouts <layouts>` without needing to use an extra program like tmux
|
||||
@@ -36,6 +38,8 @@ kitty - the fast, featureful, GPU based terminal emulator
|
||||
separate window using arbitrary programs of your choice. This is useful for
|
||||
browsing the history comfortably in a pager or editor.
|
||||
|
||||
* Has :ref:`multiple copy/paste buffers <cpbuf>`, like vim.
|
||||
|
||||
|
||||
.. figure:: screenshots/screenshot.png
|
||||
:alt: Screenshot, showing three programs in the 'Tall' layout
|
||||
@@ -51,18 +55,21 @@ Quickstart
|
||||
--------------
|
||||
|
||||
Pre-built binaries of |kitty| are available for both macOS and Linux.
|
||||
See the :doc:`binary install instructions </binary>`. You can also
|
||||
See the :doc:`binary install instructions </binary>`. You can
|
||||
:doc:`build from source </build>`.
|
||||
|
||||
If you are on Linux, you can also use your distribution's |kitty| package.
|
||||
You can also use your favorite package manager to install the |kitty| package.
|
||||
|kitty| packages are available for:
|
||||
`macOS with Homebrew (Cask) <https://formulae.brew.sh/cask/kitty>`_,
|
||||
`macOS and Linux with Nix <https://nixos.org/nixos/packages.html?channel=nixpkgs-unstable&query=kitty>`_,
|
||||
`Ubuntu <https://launchpad.net/ubuntu/+source/kitty>`_,
|
||||
`Debian <https://packages.debian.org/buster/kitty>`_,
|
||||
`openSUSE <https://build.opensuse.org/package/show/X11:terminals/kitty>`_,
|
||||
`Arch Linux <https://www.archlinux.org/packages/community/x86_64/kitty/>`_,
|
||||
`NixOS <https://github.com/NixOS/nixpkgs/blob/master/pkgs/applications/misc/kitty/default.nix>`_,
|
||||
`Gentoo <https://packages.gentoo.org/packages/x11-terms/kitty>`_,
|
||||
`Fedora <https://copr.fedorainfracloud.org/coprs/gagbo/kitty-latest/>`_,
|
||||
`Void Linux <https://github.com/void-linux/void-packages/blob/master/srcpkgs/kitty/template>`_.
|
||||
`Fedora <https://src.fedoraproject.org/rpms/kitty>`_,
|
||||
`Void Linux <https://github.com/void-linux/void-packages/blob/master/srcpkgs/kitty/template>`_,
|
||||
and `Solus <https://dev.getsol.us/source/kitty/>`_.
|
||||
|
||||
See :doc:`Configuring kitty <conf>` for help on configuring |kitty| and
|
||||
:doc:`Invocation <invocation>` for the command line arguments |kitty| supports.
|
||||
@@ -90,7 +97,7 @@ formatting, etc. It even extends existing text formatting escape codes,
|
||||
to add support for features not available elsewhere, such as colored and
|
||||
styled (curly) underlines. One of the design goals of |kitty| is to be
|
||||
easily extensible so that new features can be added in the future with
|
||||
relatively less effort.
|
||||
relatively little effort.
|
||||
|
||||
Tabs and Windows
|
||||
-------------------
|
||||
@@ -108,12 +115,12 @@ Scrolling
|
||||
======================== =======================
|
||||
Action Shortcut
|
||||
======================== =======================
|
||||
Scroll line up :sc:`scroll_line_up`
|
||||
Scroll line down :sc:`scroll_line_down`
|
||||
Scroll page up :sc:`scroll_page_up`
|
||||
Scroll page down :sc:`scroll_page_down`
|
||||
Scroll to top :sc:`scroll_home`
|
||||
Scroll to bottom :sc:`scroll_end`
|
||||
Scroll line up :sc:`scroll_line_up` (also :kbd:`⌥+⌘+⇞` and :kbd:`⌘+↑` on macOS)
|
||||
Scroll line down :sc:`scroll_line_down` (also :kbd:`⌥+⌘+⇟` and :kbd:`⌘+↓` on macOS)
|
||||
Scroll page up :sc:`scroll_page_up` (also :kbd:`⌘+⇞` on macOS)
|
||||
Scroll page down :sc:`scroll_page_down` (also :kbd:`⌘+⇟` on macOS)
|
||||
Scroll to top :sc:`scroll_home` (also :kbd:`⌘+↖` on macOS)
|
||||
Scroll to bottom :sc:`scroll_end` (also :kbd:`⌘+↘` on macOS)
|
||||
======================== =======================
|
||||
|
||||
Tabs
|
||||
@@ -123,13 +130,13 @@ Tabs
|
||||
Action Shortcut
|
||||
======================== =======================
|
||||
New tab :sc:`new_tab` (also :kbd:`⌘+t` on macOS)
|
||||
Close tab :sc:`close_tab`
|
||||
Next tab :sc:`next_tab` (also :kbd:`control+tab` on macOS)
|
||||
Previous tab :sc:`previous_tab` (also :kbd:`control+shift+tab` on macOS)
|
||||
Close tab :sc:`close_tab` (also :kbd:`⌘+w` on macOS)
|
||||
Next tab :sc:`next_tab` (also :kbd:`^+⇥` and :kbd:`⇧+⌘+]` on macOS)
|
||||
Previous tab :sc:`previous_tab` (also :kbd:`⇧+^+⇥` and :kbd:`⇧+⌘+[` on macOS)
|
||||
Next layout :sc:`next_layout`
|
||||
Move tab forward :sc:`move_tab_forward`
|
||||
Move tab backward :sc:`move_tab_backward`
|
||||
Set tab title :sc:`set_tab_title`
|
||||
Set tab title :sc:`set_tab_title` (also :kbd:`⇧+⌘+i` on macOS)
|
||||
======================== =======================
|
||||
|
||||
|
||||
@@ -139,15 +146,16 @@ Windows
|
||||
======================== =======================
|
||||
Action Shortcut
|
||||
======================== =======================
|
||||
New window :sc:`new_window`
|
||||
New window :sc:`new_window` (also :kbd:`⌘+↩` on macOS)
|
||||
New OS window :sc:`new_os_window` (also :kbd:`⌘+n` on macOS)
|
||||
Close window :sc:`close_window` (also :kbd:`⌘+w` on macOS)
|
||||
Close window :sc:`close_window` (also :kbd:`⇧+⌘+d` on macOS)
|
||||
Next window :sc:`next_window`
|
||||
Previous window :sc:`previous_window`
|
||||
Move window forward :sc:`move_window_forward`
|
||||
Move window backward :sc:`move_window_backward`
|
||||
Move window to top :sc:`move_window_to_top`
|
||||
Focus specific window :sc:`first_window`, :sc:`second_window` ... :sc:`tenth_window`
|
||||
(also :kbd:`⌘+1`, :kbd:`⌘+2` ... :kbd:`⌘+9` on macOS)
|
||||
(clockwise from the top-left)
|
||||
======================== =======================
|
||||
|
||||
@@ -167,6 +175,30 @@ You can also define a shortcut to switch to the previously active window::
|
||||
``nth_window`` will focus the nth window for positive numbers and the
|
||||
previously active windows for negative numbers.
|
||||
|
||||
.. _detach_window:
|
||||
|
||||
You can define shortcuts to detach the current window and
|
||||
move it to another tab or another OS window::
|
||||
|
||||
# moves the window into a new OS window
|
||||
map ctrl+f2 detach_window
|
||||
# moves the window into a new Tab
|
||||
map ctrl+f3 detach_window new-tab
|
||||
# asks which tab to move the window into
|
||||
map ctrl+f4 detach_window ask
|
||||
|
||||
Similarly, you can detach the current tab, with::
|
||||
|
||||
# moves the tab into a new OS window
|
||||
map ctrl+f2 detach_tab
|
||||
# asks which OS Window to move the tab into
|
||||
map ctrl+f4 detach_tab ask
|
||||
|
||||
Finally, you can define a shortcut to close all windows in a tab other than
|
||||
the currently active window::
|
||||
|
||||
map f9 close_other_windows_in_tab
|
||||
|
||||
|
||||
Other keyboard shortcuts
|
||||
----------------------------------
|
||||
@@ -177,11 +209,11 @@ Action Shortcut
|
||||
Copy to clipboard :sc:`copy_to_clipboard` (also :kbd:`⌘+c` on macOS)
|
||||
Paste from clipboard :sc:`paste_from_clipboard` (also :kbd:`⌘+v` on macOS)
|
||||
Paste from selection :sc:`paste_from_selection`
|
||||
Increase font size :sc:`increase_font_size`
|
||||
Decrease font size :sc:`decrease_font_size`
|
||||
Restore font size :sc:`reset_font_size`
|
||||
Toggle fullscreen :sc:`toggle_fullscreen` (also :kbd:`^⌘+f` on macOS)
|
||||
on
|
||||
Increase font size :sc:`increase_font_size` (also :kbd:`⌘++` on macOS)
|
||||
Decrease font size :sc:`decrease_font_size` (also :kbd:`⌘+-` on macOS)
|
||||
Restore font size :sc:`reset_font_size` (also :kbd:`⌘+0` on macOS)
|
||||
Toggle fullscreen :sc:`toggle_fullscreen` (also :kbd:`^+⌘+f` on macOS)
|
||||
Toggle maximized :sc:`toggle_maximized`
|
||||
Input unicode character :sc:`input_unicode_character`
|
||||
Click URL using the keyboard :sc:`open_url`
|
||||
Reset the terminal :sc:`reset_terminal`
|
||||
@@ -200,55 +232,26 @@ Reset background opacity :sc:`reset_background_opacity`
|
||||
Layouts
|
||||
----------
|
||||
|
||||
A layout is an arrangement of multiple *windows*. You can create a new window
|
||||
A layout is an arrangement of multiple kitty *windows* inside a top-level OS window. You can create a new window
|
||||
using the :sc:`new_window` key combination.
|
||||
|
||||
Currently, there are five layouts available,
|
||||
Currently, there are six layouts available:
|
||||
|
||||
* **Stack** -- Only a single maximized window is shown at a time
|
||||
* **Tall** -- One window is shown full height on the left, the rest of the windows are shown one below the other on the right
|
||||
* **Fat** -- One window is shown full width on the top, the rest of the windows are shown side-by-side on the bottom
|
||||
* **Fat** -- One (or optionally more) windows are shown full width on the top, the rest of the windows are shown side-by-side on the bottom
|
||||
* **Grid** -- All windows are shown in a grid
|
||||
* **Horizontal** -- All windows are shown side-by-side
|
||||
* **Splits** -- Windows arranged in arbitrary patterns created using horizontal and vertical splits
|
||||
* **Stack** -- Only a single maximized window is shown at a time
|
||||
* **Tall** -- One (or optionally more) windows are shown full height on the left, the rest of the windows are shown one below the other on the right
|
||||
* **Vertical** -- All windows are shown one below the other
|
||||
|
||||
You can switch between layouts using the :sc:`next_layout` key combination. You can
|
||||
also create shortcuts to select particular layouts, and choose which layouts
|
||||
you want to enable/disable, see :ref:`conf-kitty-shortcuts.layout` for examples.
|
||||
By default, all layouts are enabled and you can switch between layouts using
|
||||
the :sc:`next_layout` key combination. You can also create shortcuts to select
|
||||
particular layouts, and choose which layouts you want to enable/disable, see
|
||||
:ref:`conf-kitty-shortcuts.layout` for examples. The first layout listed in
|
||||
:opt:`enabled_layouts` becomes the default layout.
|
||||
|
||||
You can resize windows inside layouts. Press :sc:`start_resizing_window` to
|
||||
enter resizing mode and follow the on-screen instructions. In a given window
|
||||
layout only some operations may be possible for a particular window. For
|
||||
example, in the Tall layout you can make the first window wider/narrower, but
|
||||
not taller/shorter. Note that what you are resizing is actually not a window,
|
||||
but a row/column in the layout, all windows in that row/column will be resized.
|
||||
|
||||
You can also define shortcuts in :file:`kitty.conf` to make the active window
|
||||
wider, narrower, taller, or shorter by mapping to the ``resize_window``
|
||||
action, for example::
|
||||
|
||||
map ctrl+left resize_window narrower
|
||||
map ctrl+right resize_window wider
|
||||
map ctrl+up resize_window taller
|
||||
map ctrl+down resize_window shorter 3
|
||||
|
||||
The ``resize_window`` action has a second, optional argument to control
|
||||
the resizing increment (a positive integer that defaults to 1).
|
||||
|
||||
|
||||
Some layouts take options to control their behavior. For example, the ``fat``
|
||||
and ``tall`` layouts accept the ``bias`` option to control how the available
|
||||
space is split up. To specify the option, in :opt:`kitty.conf <enabled_layouts>` use::
|
||||
|
||||
enabled_layouts tall:bias=70
|
||||
|
||||
This will make the tall window occupy ``70%`` of available width. ``bias`` can be
|
||||
any number between 10 and 90.
|
||||
|
||||
Writing a new layout only requires about a hundred lines of code, so if there
|
||||
is some layout you want, take a look at `layout.py
|
||||
<https://github.com/kovidgoyal/kitty/blob/master/kitty/layout.py>`_ and submit
|
||||
a pull request!
|
||||
For more details on the layouts and how to use them see :doc:`layouts`.
|
||||
|
||||
.. _kittens:
|
||||
|
||||
@@ -340,19 +343,42 @@ For example:
|
||||
# Set the current layout
|
||||
layout stack
|
||||
launch zsh
|
||||
|
||||
# Create a new OS window
|
||||
new_os_window
|
||||
# set new window size to 80x25 cells
|
||||
os_window_size 80c 25c
|
||||
# set the --class for the new OS window
|
||||
os_window_class mywindow
|
||||
launch sh
|
||||
# Make the current window the active (focused) window
|
||||
focus
|
||||
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
|
||||
-------------------
|
||||
|
||||
* You can also hold down :kbd:`ctrl+shift` and click on a URL to open it in a browser.
|
||||
* You can double click to select a word and triple click to select a line.
|
||||
* You can right click to extend a previous selection
|
||||
* You can hold down :kbd:`ctrl+shift` and click on a URL to open it in a browser.
|
||||
* You can double click to select a word and then drag to select more words.
|
||||
* You can triple click to select a line and then drag to select more lines.
|
||||
* You can right click to extend a previous selection.
|
||||
* You can hold down :kbd:`ctrl+alt` and drag with the mouse to select in
|
||||
columns
|
||||
columns (see also :opt:`rectangle_select_modifiers`).
|
||||
* Selecting text automatically copies it to the primary clipboard (on
|
||||
platforms with a primary clipboard).
|
||||
* You can select text with kitty even when a terminal program has grabbed
|
||||
the mouse by holding down the :kbd:`shift` key (see also
|
||||
:opt:`terminal_select_modifiers`).
|
||||
|
||||
|
||||
Font control
|
||||
@@ -385,7 +411,7 @@ comfortably within the pager.
|
||||
Additionally, you can pipe the contents of the scrollback buffer to an
|
||||
arbitrary, command running in a new window, tab or overlay, for example::
|
||||
|
||||
map f1 pipe @ansi window less +G -R
|
||||
map f1 launch --stdin-source=@screen_scrollback --stdin-add-formatting less +G -R
|
||||
|
||||
Would open the scrollback buffer in a new window when you press the :kbd:`F1`
|
||||
key. See :sc:`show_scrollback` for details.
|
||||
@@ -394,6 +420,31 @@ If you wish to store very large amounts of scrollback to view using the piping o
|
||||
:sc:`show_scrollback` features, you can use the :opt:`scrollback_pager_history_size`
|
||||
option.
|
||||
|
||||
.. _cpbuf:
|
||||
|
||||
Multiple copy/paste buffers
|
||||
-----------------------------
|
||||
|
||||
In addition to being able to copy/paste from the system clipboard, in |kitty| you
|
||||
can also setup an arbitrary number of copy paste buffers. To do so, simply add
|
||||
something like the following to your :file:`kitty.conf`::
|
||||
|
||||
map f1 copy_to_buffer a
|
||||
map f2 paste_from_buffer a
|
||||
|
||||
This will allow you to press :kbd:`F1` to copy the current selection to an
|
||||
internal buffer named ``a`` and :kbd:`F2` to paste from that buffer. The buffer
|
||||
names are arbitrary strings, so you can define as many such buffers as you
|
||||
need.
|
||||
|
||||
Marks
|
||||
-------------
|
||||
|
||||
kitty has the ability to mark text on the screen based on regular expressions.
|
||||
This can be useful to highlight words or phrases when browsing output from long
|
||||
running programs or similar. To learn how this feature works, see :doc:`marks`.
|
||||
|
||||
|
||||
Frequently Asked Questions
|
||||
---------------------------------
|
||||
|
||||
@@ -401,6 +452,15 @@ The list of Frequently Asked Questions (*FAQ*) is :doc:`available here <faq>`.
|
||||
|
||||
.. _completion:
|
||||
|
||||
|
||||
Cool integrations for kitty with other CLI tools
|
||||
--------------------------------------------------
|
||||
|
||||
kitty provides extremely powerful interfaces such as :doc:`remote-control` and
|
||||
:doc:`kittens/custom` and :doc:`kittens/icat`
|
||||
that allow it to be integrated with other tools seamlessly. For a list of such
|
||||
user created integrations, see: :doc:`integrations`.
|
||||
|
||||
Completion for kitty
|
||||
---------------------------------
|
||||
|
||||
@@ -416,6 +476,14 @@ Add the following to your :file:`~/.bashrc`
|
||||
|
||||
source <(kitty + complete setup bash)
|
||||
|
||||
Older versions of bash (for example, v3.2) do not support
|
||||
process substitution with the source command, in which
|
||||
case you can try an alternative:
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
source /dev/stdin <<<"$(kitty + complete setup bash)"
|
||||
|
||||
|
||||
zsh
|
||||
~~~~~~~~~
|
||||
@@ -436,7 +504,8 @@ completions happens after the call to :file:`compinit`.
|
||||
fish
|
||||
~~~~~~~~
|
||||
|
||||
Add the following to your :file:`~/.config/fish/config.fish`
|
||||
For versions of fish earlier than 3.0.0, add the following to your
|
||||
:file:`~/.config/fish/config.fish`. Later versions source completions by default.
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
@@ -454,3 +523,4 @@ See :doc:`changelog`.
|
||||
|
||||
*
|
||||
kittens/*
|
||||
generated/rc
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/env python3
|
||||
# vim:fileencoding=utf-8
|
||||
# License: GPL v3 Copyright: 2018, Kovid Goyal <kovid at kovidgoyal.net>
|
||||
|
||||
@@ -20,6 +20,10 @@ import tempfile
|
||||
py3 = sys.version_info[0] > 2
|
||||
is64bit = platform.architecture()[0] == '64bit'
|
||||
is_macos = 'darwin' in sys.platform.lower()
|
||||
if is_macos:
|
||||
mac_ver = tuple(map(int, platform.mac_ver()[0].split('.')))
|
||||
if mac_ver[:2] < (10, 12):
|
||||
raise SystemExit('Your version of macOS is too old, at least 10.12 is required')
|
||||
|
||||
try:
|
||||
__file__
|
||||
@@ -72,7 +76,10 @@ class Reporter: # {{{
|
||||
def get_latest_release_data():
|
||||
print('Checking for latest release on GitHub...')
|
||||
req = urllib.Request('https://api.github.com/repos/kovidgoyal/kitty/releases/latest', headers={'Accept': 'application/vnd.github.v3+json'})
|
||||
res = urllib.urlopen(req).read().decode('utf-8')
|
||||
try:
|
||||
res = urllib.urlopen(req).read().decode('utf-8')
|
||||
except Exception as err:
|
||||
raise SystemExit('Failed to contact {} with error: {}'.format(req.get_full_url(), err))
|
||||
data = json.loads(res)
|
||||
html_url = data['html_url'].replace('/tag/', '/download/').rstrip('/')
|
||||
for asset in data.get('assets', ()):
|
||||
@@ -222,7 +229,8 @@ def script_launch():
|
||||
|
||||
def update_intaller_wrapper():
|
||||
# To run: python3 -c "import runpy; runpy.run_path('installer.py', run_name='update_wrapper')" installer.sh
|
||||
src = open(__file__, 'rb').read().decode('utf-8')
|
||||
with open(__file__, 'rb') as f:
|
||||
src = f.read().decode('utf-8')
|
||||
wrapper = sys.argv[-1]
|
||||
with open(wrapper, 'r+b') as f:
|
||||
raw = f.read().decode('utf-8')
|
||||
|
||||
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
|
||||
|
||||
def main(args):
|
||||
# this is the main entry point of the kitten, it will be executed in
|
||||
# the overlay window when the kitten is launched
|
||||
answer = input('Enter some text: ')
|
||||
# whatever this function returns will be available in the
|
||||
# handle_result() function
|
||||
return answer
|
||||
def main(args: List[str]) -> str:
|
||||
# this is the main entry point of the kitten, it will be executed in
|
||||
# the overlay window when the kitten is launched
|
||||
answer = input('Enter some text: ')
|
||||
# whatever this function returns will be available in the
|
||||
# handle_result() function
|
||||
return answer
|
||||
|
||||
def handle_result(args, answer, target_window_id, boss):
|
||||
# get the kitty window into which to paste answer
|
||||
w = boss.window_id_map.get(target_window_id)
|
||||
if w is not None:
|
||||
w.paste(answer)
|
||||
def handle_result(args: List[str], answer: str, target_window_id: int, boss: kitty.boss.Boss) -> None:
|
||||
# get the kitty window into which to paste answer
|
||||
w = boss.window_id_map.get(target_window_id)
|
||||
if w is not None:
|
||||
w.paste(answer)
|
||||
|
||||
|
||||
Now in :file:`kitty.conf` add the lines::
|
||||
|
||||
map ctrl+k kitten mykitten.py
|
||||
map ctrl+k kitten mykitten.py
|
||||
|
||||
|
||||
Start kitty and press :kbd:`ctrl+k` and you should see the kitten running.
|
||||
@@ -53,12 +53,13 @@ Passing arguments to kittens
|
||||
You can pass arguments to kittens by defining them in the map directive in
|
||||
:file:`kitty.conf`. For example::
|
||||
|
||||
map ctrl+k kitten mykitten.py arg1 arg2
|
||||
map ctrl+k kitten mykitten.py arg1 arg2
|
||||
|
||||
These will be available as the ``args`` parameter in the ``main()`` and
|
||||
``handle_result()`` functions. Note also that the current working directory
|
||||
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
|
||||
@@ -70,23 +71,25 @@ function, telling kitty what kind of input your kitten would like. For example:
|
||||
|
||||
.. code-block:: py
|
||||
|
||||
# in main, STDIN is for the kitten process and will contain
|
||||
# the contents of the screen
|
||||
def main(args):
|
||||
return sys.stdin.read()
|
||||
# in main, STDIN is for the kitten process and will contain
|
||||
# the contents of the screen
|
||||
def main(args):
|
||||
return sys.stdin.read()
|
||||
|
||||
# in handle_result, STDIN is for the kitty process itself, rather
|
||||
# than the kitten process and should not be read from.
|
||||
def handle_result(args, stdin_data, target_window_id, boss):
|
||||
pass
|
||||
# in handle_result, STDIN is for the kitty process itself, rather
|
||||
# than the kitten process and should not be read from.
|
||||
from kittens.tui.handler import result_handler
|
||||
@result_handler(type_of_input='text')
|
||||
def handle_result(args, stdin_data, target_window_id, boss):
|
||||
pass
|
||||
|
||||
handle_result.type_of_input = 'text'
|
||||
|
||||
This will send the plain text of the active window to the kitten's
|
||||
:file:`STDIN`. For text with formatting escape codes, use ``ansi``
|
||||
instead. If you want line wrap markers as well, use ``screen-ansi``
|
||||
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
|
||||
@@ -103,23 +106,23 @@ Create a file in the kitty config folder, :file:`~/.config/kitty/zoom_toggle.py`
|
||||
|
||||
.. code-block:: py
|
||||
|
||||
def main(args):
|
||||
pass
|
||||
def main(args):
|
||||
pass
|
||||
|
||||
def handle_result(args, answer, target_window_id, boss):
|
||||
tab = boss.active_tab
|
||||
if tab is not None:
|
||||
if tab.current_layout.name == 'stack':
|
||||
tab.last_used_layout()
|
||||
else:
|
||||
tab.goto_layout('stack')
|
||||
|
||||
handle_result.no_ui = True
|
||||
from kittens.tui.handler import result_handler
|
||||
@result_handler(no_ui=True)
|
||||
def handle_result(args, answer, target_window_id, boss):
|
||||
tab = boss.active_tab
|
||||
if tab is not None:
|
||||
if tab.current_layout.name == 'stack':
|
||||
tab.last_used_layout()
|
||||
else:
|
||||
tab.goto_layout('stack')
|
||||
|
||||
|
||||
Now in kitty.conf add::
|
||||
|
||||
map f11 kitten zoom_toggle.py
|
||||
map f11 kitten zoom_toggle.py
|
||||
|
||||
Pressing :kbd:`F11` will now act as a zoom toggle function. You can get even
|
||||
more fancy, switching the kitty OS window to fullscreen as well as changing the
|
||||
@@ -128,7 +131,56 @@ layout, by simply adding the line::
|
||||
boss.toggle_fullscreen()
|
||||
|
||||
|
||||
to the ``handle_result()`` function, above.
|
||||
To the ``handle_result()`` function, above.
|
||||
|
||||
|
||||
.. _send_mouse_event:
|
||||
|
||||
Sending mouse events
|
||||
--------------------
|
||||
|
||||
If the program running in a window is receiving mouse events you can simulate
|
||||
those using::
|
||||
|
||||
from kitty.fast_data_types import send_mouse_event
|
||||
send_mouse_event(screen, x, y, button, action, mods)
|
||||
|
||||
``screen`` is the ``screen`` attribute of the window you want to send the event
|
||||
to. ``x`` and ``y`` are the 0-indexed coordinates. ``button`` is a number using
|
||||
the same numbering as X11 (left: ``1``, middle: ``2``, right: ``3``, scroll up:
|
||||
``4``, scroll down: ``5``, scroll left: ``6``, scroll right: ``7``, back:
|
||||
``8``, forward: ``9``). ``action`` is one of ``PRESS``, ``RELEASE``, ``DRAG``
|
||||
or ``MOVE``. ``mods`` is a bitmask of ``GLFW_MOD_{mod}`` where ``{mod}`` is one
|
||||
of ``SHIFT``, ``CONTROL`` or ``ALT``. All the mentioned constants are imported
|
||||
from ``kitty.fast_data_types``.
|
||||
|
||||
For example, to send a left click at position x: 2, y: 3 to the active window::
|
||||
|
||||
from kitty.fast_data_types import send_mouse_event, 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
|
||||
--------------------
|
||||
|
||||
The part of the kitten that runs in ``main()`` is just a normal program and
|
||||
the output of print statements will be visible in the kitten window. Or
|
||||
alternately, you can use::
|
||||
|
||||
from kittens.tui.loop import debug
|
||||
debug('whatever')
|
||||
|
||||
The ``debug()`` function is just like ``print()`` except that the output
|
||||
will appear in the ``STDOUT`` of the kitty process inside which the kitten is
|
||||
running.
|
||||
|
||||
The ``handle_result()`` part of the kitten runs inside the kitty process.
|
||||
The output of print statements will go to the ``STDOUT`` of the kitty process.
|
||||
So if you run kitty from another kitty instance, the output will be visible
|
||||
in the first kitty instance.
|
||||
|
||||
.. _external_kittens:
|
||||
|
||||
@@ -136,11 +188,15 @@ Kittens created by kitty users
|
||||
---------------------------------------------
|
||||
|
||||
`vim-kitty-navigator <https://github.com/knubie/vim-kitty-navigator>`_
|
||||
Allows you to navigate seamlessly between vim and kitty splits using a consistent set of hotkeys.
|
||||
Allows you to navigate seamlessly between vim and kitty splits using a consistent set of hotkeys.
|
||||
|
||||
`smart-scroll <https://github.com/yurikhan/kitty-smart-scroll>`_
|
||||
Makes the kitty scroll bindings work in full screen applications
|
||||
Makes the kitty scroll bindings work in full screen applications
|
||||
|
||||
`insert password <https://github.com/kovidgoyal/kitty/issues/1222>`_
|
||||
Insert a password from a CLI password manager, taking care to only do it at
|
||||
a password prompt.
|
||||
Insert a password from a CLI password manager, taking care to only do it at
|
||||
a password prompt.
|
||||
|
||||
`weechat-hints <https://github.com/GermainZ/kitty-weechat-hints>`_
|
||||
URL hints kitten for WeeChat that works without having to use WeeChat's
|
||||
raw-mode.
|
||||
|
||||
@@ -18,11 +18,71 @@ select anything that looks like a path or filename and then insert it into the
|
||||
terminal, very useful for picking files from the output of a ``git`` or ``ls`` command and
|
||||
adding them to the command line for the next command.
|
||||
|
||||
You can also press :sc:`goto_file_line` to select anything that looks
|
||||
like a path or filename followed by a colon and a line number and open
|
||||
the file in vim at the specified line number. The patterns and editor
|
||||
to be used can be modified using options passed to the kitten. For example::
|
||||
|
||||
map ctrl+g kitten hints --type=linenum --linenum-action=tab nvim +{line} {path}
|
||||
|
||||
will open the selected file in a new tab inside neovim when you press
|
||||
:kbd:`ctrl+g`.
|
||||
|
||||
The hints kitten is very powerful to see more detailed help on its various
|
||||
options and modes of operation, see below. You can use these options to
|
||||
create mappings in :file:`kitty.conf` to select various different text
|
||||
snippets. See :sc:`insert_selected_path` for examples.
|
||||
|
||||
Completely customizing the matching and actions of the kitten
|
||||
---------------------------------------------------------------
|
||||
|
||||
The hints kitten supports writing simple python scripts that can be used to
|
||||
completely customize how it finds matches and what happens when a match is
|
||||
selected. This allows the hints kitten to provide the user interface, while
|
||||
you can provide the logic for finding matches and performing actions on them.
|
||||
This is best illustrated with an example. Create the file
|
||||
:file:`custom-hints.py` in the kitty config directory with the following
|
||||
contents:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import re
|
||||
|
||||
def mark(text, args, Mark, extra_cli_args, *a):
|
||||
# This function is responsible for finding all
|
||||
# matching text. extra_cli_args are any extra arguments
|
||||
# passed on the command line when invoking the kitten.
|
||||
# We mark all individual word for potential selection
|
||||
for idx, m in enumerate(re.finditer(r'\w+', text)):
|
||||
start, end = m.span()
|
||||
mark_text = text[start:end].replace('\n', '').replace('\0', '')
|
||||
# The empty dictionary below will be available as groupdicts
|
||||
# in handle_result() and can contain arbitrary data.
|
||||
yield Mark(idx, start, end, mark_text, {})
|
||||
|
||||
|
||||
def handle_result(args, data, target_window_id, boss, extra_cli_args, *a):
|
||||
# This function is responsible for performing some
|
||||
# action on the selected text.
|
||||
# matches is a list of the selected entries and groupdicts contains
|
||||
# the arbitrary data associated with each entry in mark() above
|
||||
matches, groupdicts = [], []
|
||||
for m, g in zip(data['match'], data['groupdicts']):
|
||||
if m:
|
||||
matches.append(m), groupdicts.append(g)
|
||||
for word, match_data in zip(matches, groupdicts):
|
||||
# Lookup the word in a dictionary, the open_url function
|
||||
# will open the provided url in the system browser
|
||||
boss.open_url(f'https://www.google.com/search?q=define:{word}')
|
||||
|
||||
Now run kitty with::
|
||||
|
||||
kitty -o 'map f1 kitten hints --customize-processing custom-hints.py'
|
||||
|
||||
When you press the :kbd:`F1` key you will be able to select a word to
|
||||
look it up in the Google dictionary.
|
||||
|
||||
|
||||
Command Line Interface
|
||||
-------------------------
|
||||
|
||||
|
||||
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
|
||||
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
|
||||
|
||||
|
||||
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.
|
||||
@@ -15,8 +15,19 @@ In :guilabel:`Code` mode, you enter a unicode character by typing in the hex cod
|
||||
character and pressing enter, for example, type in ``2716`` and press enter to get
|
||||
✖. You can also choose a character from the list of recently used characters by
|
||||
typing a leading period and then the two character index and pressing Enter.
|
||||
The up and down arrow keys can be used to choose the previous and next unicode
|
||||
symbol respectively.
|
||||
|
||||
In :guilabel:`Name` mode you instead type words from the character name and use the arrow
|
||||
keys/tab to select the character from the displayed matches. You can also type
|
||||
a leading period and the index for the match if you don't like to use arrow
|
||||
keys.
|
||||
|
||||
You can switch between modes using either the function keys or by pressing
|
||||
:kbd:`Ctrl+[` and :kbd:`Ctrl+]`.
|
||||
|
||||
|
||||
Command Line Interface
|
||||
-------------------------
|
||||
|
||||
.. include:: ../generated/cli-kitten-unicode_input.rst
|
||||
|
||||
99
docs/launch.rst
Normal file
99
docs/launch.rst
Normal file
@@ -0,0 +1,99 @@
|
||||
Launching programs in new windows/tabs
|
||||
========================================
|
||||
|
||||
.. program:: launch
|
||||
|
||||
|
||||
|kitty| has a :code:`launch` action that can be used to run arbitrary programs
|
||||
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
|
||||
the current window to the launched program, as well as many other options.
|
||||
|
||||
In the simplest form, you can use it to open a new kitty window running the
|
||||
shell, as shown below::
|
||||
|
||||
map f1 launch
|
||||
|
||||
To run a different program simply pass the command line as arguments to
|
||||
launch::
|
||||
|
||||
map f1 launch vim path/to/some/file
|
||||
|
||||
|
||||
To open a new window with the same working directory as the currently
|
||||
active window::
|
||||
|
||||
map f1 launch --cwd=current
|
||||
|
||||
To open the new window in a new tab::
|
||||
|
||||
map f1 launch --type=tab
|
||||
|
||||
To pass the contents of the current screen and scrollback to the started process::
|
||||
|
||||
map f1 launch --stdin-source=@screen_scrollback less
|
||||
|
||||
There are many more powerful options, refer to the complete list below.
|
||||
|
||||
The piping environment
|
||||
--------------------------
|
||||
|
||||
When using :option:`launch --stdin-source`, the program to which the data is
|
||||
piped has a special environment variable declared, ``KITTY_PIPE_DATA`` whose
|
||||
contents are::
|
||||
|
||||
KITTY_PIPE_DATA={scrolled_by}:{cursor_x},{cursor_y}:{lines},{columns}
|
||||
|
||||
where ``scrolled_by`` is the number of lines kitty is currently scrolled by,
|
||||
``cursor_(x|y)`` is the position of the cursor on the screen with ``(1,1)``
|
||||
being the top left corner and ``{lines},{columns}`` being the number of rows
|
||||
and columns of the screen.
|
||||
|
||||
|
||||
Special arguments
|
||||
-------------------
|
||||
|
||||
There are a few special placeholder arguments that can be specified as part of
|
||||
the command line. Namely ``@selection`` which is replaced by the current
|
||||
selection and ``@active-kitty-window-id`` which is replaced by the id of the
|
||||
currently active kitty window. For example::
|
||||
|
||||
map f1 launch my-program @active-kitty-window-id
|
||||
|
||||
|
||||
Watching launched windows
|
||||
---------------------------
|
||||
|
||||
The :option:`launch --watcher` option allows you to specify python functions
|
||||
that will be called at specific events, such as when the window is resized or
|
||||
closed. Simply specify the path to a python module that specifies callback
|
||||
functions for the events you are interested in, for example:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def on_resize(boss, window, data):
|
||||
# Here data will contain old_geometry and new_geometry
|
||||
|
||||
def on_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
|
||||
------------------
|
||||
|
||||
.. include:: /generated/launch.rst
|
||||
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!
|
||||
125
docs/marks.rst
Normal file
125
docs/marks.rst
Normal file
@@ -0,0 +1,125 @@
|
||||
Marks
|
||||
=================
|
||||
|
||||
|
||||
kitty has the ability to mark text on the screen based on regular expressions.
|
||||
This can be useful to highlight words or phrases when browsing output from long
|
||||
running programs or similar. Lets start with a few examples:
|
||||
|
||||
Suppose we want to be able to highlight the word ERROR in the current window.
|
||||
Add the following to :file:`kitty.conf`::
|
||||
|
||||
map f1 toggle_marker text 1 ERROR
|
||||
|
||||
Now when you press :kbd:`F1` all instances of the word :code:`ERROR` will be
|
||||
highlighted. To turn off the highlighting, press :kbd:`F1` again.
|
||||
If you want to make it case-insensitive, use::
|
||||
|
||||
map f1 toggle_marker itext 1 ERROR
|
||||
|
||||
To make it match only complete words, use::
|
||||
|
||||
map f1 toggle_marker regex 1 \bERROR\b
|
||||
|
||||
Suppose you want to highlight both :code:`ERROR` and :code:`WARNING`, case
|
||||
insensitively::
|
||||
|
||||
map f1 toggle_marker iregex 1 \bERROR\b 2 \bWARNING\b
|
||||
|
||||
kitty supports up to 3 mark groups (the numbers in the commands above). You
|
||||
can control the colors used for these groups in :file:`kitty.conf` with::
|
||||
|
||||
mark1_foreground red
|
||||
mark1_background gray
|
||||
mark2_foreground green
|
||||
...
|
||||
|
||||
|
||||
.. note::
|
||||
For performance reasons, matching is done per line only, and only when that line is
|
||||
altered in any way. So you cannot match text that stretches across multiple
|
||||
lines.
|
||||
|
||||
|
||||
Creating markers dynamically
|
||||
---------------------------------
|
||||
|
||||
If you want to create markers dynamically rather than pre-defining them in
|
||||
:file:`kitty.conf` you can do so as follows::
|
||||
|
||||
map f1 create_marker
|
||||
map f2 remove_marker
|
||||
|
||||
Then pressing :kbd:`F1` will allow you to enter the marker definition and set
|
||||
it and pressing :kbd:`F2` will remove the marker. ``create_marker`` accepts
|
||||
the same syntax as ``toggle_marker`` above. Note that while creating
|
||||
markers, the prompt has history so you can easily re-use previous marker
|
||||
expressions.
|
||||
|
||||
You can also use the facilities for :doc:`remote-control` to dynamically
|
||||
add/remove markers.
|
||||
|
||||
|
||||
Scrolling to marks
|
||||
--------------------
|
||||
|
||||
kitty has an action to scroll to the next line that contains a mark. You can
|
||||
use it by mapping it to some shortcut in :file:`kitty.conf`::
|
||||
|
||||
map ctrl+p scroll_to_mark prev
|
||||
map ctrl+n scroll_to_mark next
|
||||
|
||||
Then pressing :kbd:`ctrl+p` will scroll to the first line in the scrollback
|
||||
buffer above the current top line that contains a mark. Pressing :kbd:`ctrl+n`
|
||||
will scroll to show the first line below the current last line that contains
|
||||
a mark. If you wish to jump to a mark of a specific type, you can add that to
|
||||
the mapping::
|
||||
|
||||
map ctrl+1 scroll_to_mark prev 1
|
||||
|
||||
Which will scroll only to marks of type 1.
|
||||
|
||||
|
||||
The full syntax for creating marks
|
||||
-------------------------------------
|
||||
|
||||
The syntax of the :code:`toggle_marker` command is::
|
||||
|
||||
toggle_marker <marker-type> <specification>
|
||||
|
||||
Here :code:`marker-type` is one of:
|
||||
|
||||
* :code:`text` - simple substring matching
|
||||
* :code:`itext` - case-insensitive substring matching
|
||||
* :code:`regex` - A python regular expression
|
||||
* :code:`iregex` - A case-insensitive python regular expression
|
||||
* :code:`function` - An arbitrary function defined in a python file, see
|
||||
:ref:`marker_funcs`.
|
||||
|
||||
.. _marker_funcs:
|
||||
|
||||
Arbitrary marker functions
|
||||
-----------------------------
|
||||
|
||||
You can create your own marker functions. Create a python file named
|
||||
:file:`mymarker.py` and in it create a :code:`marker` function. This
|
||||
function receives the text of the line as input and must yield three numbers,
|
||||
the starting character position, the ending character position and the mark
|
||||
group (1-3). For example:
|
||||
|
||||
.. code-block::
|
||||
|
||||
def marker(text):
|
||||
# Function to highlight the letter X
|
||||
for i, ch in enumerate(text):
|
||||
if ch.lower() == 'x':
|
||||
yield i, i, 3
|
||||
|
||||
|
||||
Save this file somewhere and in :file:`kitty.conf`, use::
|
||||
|
||||
map f1 toggle_marker function /path/to/mymarker.py
|
||||
|
||||
If you save the file in the kitty config directory, you can use::
|
||||
|
||||
map f1 toggle_marker function mymarker.py
|
||||
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``
|
||||
@@ -14,12 +14,12 @@ render loop to reduce CPU usage. See :ref:`conf-kitty-performance` for details.
|
||||
See also the :opt:`sync_to_monitor` option to further decrease latency at the cost
|
||||
of some `tearing <https://en.wikipedia.org/wiki/Screen_tearing>`_ while scrolling.
|
||||
|
||||
You can generate detailed per-function performance data using
|
||||
`gperftools <https://github.com/gperftools/gperftools>`_. Build |kitty| with
|
||||
`make profile` which will create an executable called `kitty-profile`. Run
|
||||
that and perform the task you want to analyse, for example, scrolling a large
|
||||
file with `less`. After you quit, function call statistics will be printed to
|
||||
`stdout` and you can use tools like *kcachegrind* for more detailed analysis.
|
||||
You can generate detailed per-function performance data using `gperftools
|
||||
<https://github.com/gperftools/gperftools>`_. Build |kitty| with `make
|
||||
profile`. Run kitty and perform the task you want to analyse, for example,
|
||||
scrolling a large file with `less`. After you quit, function call statistics
|
||||
will be printed to `stdout` and you can use tools like *kcachegrind* for more
|
||||
detailed analysis.
|
||||
|
||||
Here are some CPU usage numbers for the task of scrolling a file continuously
|
||||
in less. The CPU usage is for the terminal process and X together and is
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
Working with the screen and history buffer contents
|
||||
======================================================
|
||||
|
||||
.. warning::
|
||||
The pipe action has been deprecated in favor of the
|
||||
:doc:`launch <launch>` action which is more powerful.
|
||||
|
||||
You can pipe the contents of the current screen and history buffer as
|
||||
:file:`STDIN` to an arbitrary program using the ``pipe`` function. The program
|
||||
@@ -43,6 +46,10 @@ You can choose where to run the pipe program:
|
||||
``tab``
|
||||
A new window in a new tab
|
||||
|
||||
``clipboard, primary``
|
||||
Copy the text directly to the clipboard. In this case the specified program
|
||||
is not run, so use some dummy program name for it.
|
||||
|
||||
``none``
|
||||
Run it in the background
|
||||
|
||||
@@ -52,6 +59,9 @@ Input placeholders
|
||||
|
||||
There are various different kinds of placeholders
|
||||
|
||||
``@selection``
|
||||
Plain text, currently selected text
|
||||
|
||||
``@text``
|
||||
Plain text, current screen + scrollback buffer
|
||||
|
||||
|
||||
@@ -51,6 +51,9 @@ To reset the underline color (also previously reserved and unused)::
|
||||
|
||||
<ESC>[59m
|
||||
|
||||
The underline color must remain the same under reverse video, if it has a
|
||||
color, if not, it should follow the foreground color.
|
||||
|
||||
To detect support for this feature in a terminal emulator, query the terminfo database
|
||||
for the ``Su`` boolean capability.
|
||||
|
||||
@@ -133,6 +136,10 @@ Alt -- ``0x2``, Control -- ``0x4`` and Super -- ``0x8``. ``<key>`` is a number
|
||||
(encoded in base85) corresponding to the key pressed. The key name to number
|
||||
mapping is defined in :doc:`this table <key-encoding>`.
|
||||
|
||||
Client programs must ignore events for keys they do not know. The mapping in
|
||||
the above table is stable and will never change, however, new codes might be
|
||||
added to it in the future, for new keys.
|
||||
|
||||
For example::
|
||||
|
||||
<ESC>_KpGp<ESC>\ is <Ctrl>+<Alt>+x (press)
|
||||
@@ -141,6 +148,10 @@ For example::
|
||||
This encoding means each key event is represented by 8 or 9 printable ascii
|
||||
only bytes, for maximum robustness.
|
||||
|
||||
To see the full mode in action, run::
|
||||
|
||||
kitty +kitten key_demo
|
||||
|
||||
Support for this mode is indicated by the ``fullkbd`` boolean capability
|
||||
in the terminfo database, in case querying for it via DECQRM is inconvenient.
|
||||
|
||||
@@ -160,7 +171,7 @@ The motivation for this extension is the various problems with the existing
|
||||
solution for erasing to background color, namely the *background color erase
|
||||
(bce)* capability. See
|
||||
`this discussion <https://github.com/kovidgoyal/kitty/issues/160#issuecomment-346470545>`_
|
||||
and `this FAQ <http://invisible-island.net/ncurses/ncurses.faq.html#bce_mismatches>`_
|
||||
and `this FAQ <https://invisible-island.net/ncurses/ncurses.faq.html#bce_mismatches>`_
|
||||
for a summary of problems with *bce*.
|
||||
|
||||
For example, to set the background color to blue in a
|
||||
@@ -208,3 +219,136 @@ first, for example::
|
||||
<ESC>]52;c;!<ESC>\
|
||||
|
||||
Here ``!`` is not valid base64 encoded text, so it clears the clipboard.
|
||||
Further, since it is invalid, it should be ignored by terminal emulators
|
||||
that do not support this extension, thereby making it safe to use, simply
|
||||
always send it before starting a new OSC 52 paste, even if you aren't chunking
|
||||
up large pastes, that way kitty 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
|
||||
protocol extension, it can be disabled by specifying ``no-append`` to the
|
||||
: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.
|
||||
|
||||
29
docs/rc_protocol.rst
Normal file
29
docs/rc_protocol.rst
Normal file
@@ -0,0 +1,29 @@
|
||||
Documentation for the kitty remote control protocol
|
||||
======================================================
|
||||
|
||||
The kitty remote control protocol is a simple protocol that involves sending
|
||||
data to kitty in the form of JSON. Any individual command of kitty has the
|
||||
form::
|
||||
|
||||
<ESC>P@kitty-cmd<JSON object><ESC>\
|
||||
|
||||
Where ``<ESC>`` is the byte ``0x1b``. The JSON object has the form::
|
||||
|
||||
{
|
||||
"cmd": "command name",
|
||||
"version": <kitty version>,
|
||||
"no_response": Optional Boolean,
|
||||
"payload": <Optional JSON object>,
|
||||
}
|
||||
|
||||
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
|
||||
a version greater than the version of the kitty instance you are talking to,
|
||||
will cause a failure.
|
||||
|
||||
Set ``no_response`` to ``true`` if you don't want a response from kitty.
|
||||
|
||||
The optional payload is a JSON object that is specific to the actual command being sent.
|
||||
The fields in the object for every command are documented below.
|
||||
|
||||
.. include:: generated/rc.rst
|
||||
@@ -21,7 +21,7 @@ In order for control to work, :opt:`allow_remote_control` must be enabled in
|
||||
|
||||
Now, in the new |kitty| window, enter the command::
|
||||
|
||||
kitty @ new-window --title Output --keep-focus cat
|
||||
kitty @ launch --title Output --keep-focus cat
|
||||
|
||||
This will open a new window, running the ``cat`` program that will appear next
|
||||
to the current window.
|
||||
@@ -54,7 +54,7 @@ window. Type ``Ctrl+D`` when you are ready to stop.
|
||||
|
||||
Now, let's open a new tab::
|
||||
|
||||
kitty @ new-window --new-tab --tab-title "My Tab" --keep-focus bash
|
||||
kitty @ launch --type=tab --tab-title "My Tab" --keep-focus bash
|
||||
|
||||
This will open a new tab running the bash shell with the title "My Tab".
|
||||
We can change the title of the tab with::
|
||||
@@ -126,7 +126,7 @@ If you do not want to allow all programs running in |kitty| to control it, you c
|
||||
enable remote control for only some |kitty| windows. Simply create a shortcut
|
||||
such as::
|
||||
|
||||
map ctrl+k new_window @ some_program
|
||||
map ctrl+k launch --allow-remote-control some_program
|
||||
|
||||
Then programs running in windows created with that shortcut can use ``kitty @``
|
||||
to control kitty. Note that any program with the right level of permissions can
|
||||
@@ -134,5 +134,24 @@ still write to the pipes of any other program on the same computer and
|
||||
therefore can control |kitty|. It can, however, be useful to block programs
|
||||
running on other computers (for example, over ssh) or as other users.
|
||||
|
||||
Mapping key presses to remote control commands
|
||||
--------------------------------------------------
|
||||
|
||||
If you wish to trigger a remote control command easily with just a keypress,
|
||||
you can map it in :file:`kitty.conf`. For example::
|
||||
|
||||
map F1 remote_control set-spacing margin=30
|
||||
|
||||
Then pressing the :kbd:`F1` key will set the active window margins to 30.
|
||||
The syntax for what follows :code:`remote_control` is exactly the same
|
||||
as the syntax for what follows :code:`kitty @` above. You do not need
|
||||
to enable remote control to use these mappings.
|
||||
|
||||
|
||||
Documentation for the remote control protocol
|
||||
-----------------------------------------------
|
||||
|
||||
If you wish to develop your own client to talk to |kitty|, you
|
||||
can use the :doc:`rc_protocol`.
|
||||
|
||||
.. include:: generated/cli-kitty-at.rst
|
||||
|
||||
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 |
@@ -1,21 +1,26 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/env python3
|
||||
# vim:fileencoding=utf-8
|
||||
# License: GPLv3 Copyright: 2018, Kovid Goyal <kovid at kovidgoyal.net>
|
||||
|
||||
import subprocess
|
||||
from collections import defaultdict
|
||||
from typing import Any, DefaultDict, Dict, FrozenSet, List, Tuple, Union
|
||||
|
||||
KeymapType = Dict[str, Tuple[str, Union[FrozenSet[str], str]]]
|
||||
|
||||
|
||||
def resolve_keys(keymap):
|
||||
ans = defaultdict(list)
|
||||
def resolve_keys(keymap: KeymapType) -> DefaultDict[str, List[str]]:
|
||||
ans: DefaultDict[str, List[str]] = defaultdict(list)
|
||||
for ch, (attr, atype) in keymap.items():
|
||||
if atype not in ('int', 'uint'):
|
||||
atype = 'flag'
|
||||
ans[atype].append(ch)
|
||||
if isinstance(atype, str) and atype in ('int', 'uint'):
|
||||
q = atype
|
||||
else:
|
||||
q = 'flag'
|
||||
ans[q].append(ch)
|
||||
return ans
|
||||
|
||||
|
||||
def enum(keymap):
|
||||
def enum(keymap: KeymapType) -> str:
|
||||
lines = []
|
||||
for ch, (attr, atype) in keymap.items():
|
||||
lines.append(f"{attr}='{ch}'")
|
||||
@@ -26,15 +31,15 @@ def enum(keymap):
|
||||
'''.format(',\n'.join(lines))
|
||||
|
||||
|
||||
def parse_key(keymap):
|
||||
def parse_key(keymap: KeymapType) -> str:
|
||||
lines = []
|
||||
for attr, atype in keymap.values():
|
||||
vs = atype.upper() if atype in ('uint', 'int') else 'FLAG'
|
||||
vs = atype.upper() if isinstance(atype, str) and atype in ('uint', 'int') else 'FLAG'
|
||||
lines.append(f'case {attr}: value_state = {vs}; break;')
|
||||
return ' \n'.join(lines)
|
||||
|
||||
|
||||
def parse_flag(keymap, type_map, command_class):
|
||||
def parse_flag(keymap: KeymapType, type_map: Dict[str, Any], command_class: str) -> str:
|
||||
lines = []
|
||||
for ch in type_map['flag']:
|
||||
attr, allowed_values = keymap[ch]
|
||||
@@ -52,14 +57,14 @@ def parse_flag(keymap, type_map, command_class):
|
||||
return ' \n'.join(lines)
|
||||
|
||||
|
||||
def parse_number(keymap):
|
||||
def parse_number(keymap: KeymapType) -> Tuple[str, str]:
|
||||
int_keys = [f'I({attr})' for attr, atype in keymap.values() if atype == 'int']
|
||||
uint_keys = [f'U({attr})' for attr, atype in keymap.values() if atype == 'uint']
|
||||
return '; '.join(int_keys), '; '.join(uint_keys)
|
||||
|
||||
|
||||
def cmd_for_report(report_name, keymap, type_map, payload_allowed):
|
||||
def group(atype, conv):
|
||||
def cmd_for_report(report_name: str, keymap: KeymapType, type_map: Dict[str, Any], payload_allowed: bool) -> str:
|
||||
def group(atype: str, conv: str) -> Tuple[str, str]:
|
||||
flag_fmt, flag_attrs = [], []
|
||||
cv = {'flag': 'c', 'int': 'i', 'uint': 'I'}[atype]
|
||||
for ch in type_map[atype]:
|
||||
@@ -84,7 +89,15 @@ def cmd_for_report(report_name, keymap, type_map, payload_allowed):
|
||||
return '\n'.join(ans)
|
||||
|
||||
|
||||
def generate(function_name, callback_name, report_name, keymap, command_class, initial_key='a', payload_allowed=True):
|
||||
def generate(
|
||||
function_name: str,
|
||||
callback_name: str,
|
||||
report_name: str,
|
||||
keymap: KeymapType,
|
||||
command_class: str,
|
||||
initial_key: str = 'a',
|
||||
payload_allowed: bool = True
|
||||
) -> str:
|
||||
type_map = resolve_keys(keymap)
|
||||
keys_enum = enum(keymap)
|
||||
handle_key = parse_key(keymap)
|
||||
@@ -93,7 +106,7 @@ def generate(function_name, callback_name, report_name, keymap, command_class, i
|
||||
report_cmd = cmd_for_report(report_name, keymap, type_map, payload_allowed)
|
||||
if payload_allowed:
|
||||
payload_after_value = "case ';': state = PAYLOAD; break;"
|
||||
payload = payload = ', PAYLOAD'
|
||||
payload = ', PAYLOAD'
|
||||
parr = 'static uint8_t payload[4096];'
|
||||
payload_case = f'''
|
||||
case PAYLOAD: {{
|
||||
@@ -124,6 +137,7 @@ static inline void
|
||||
{parr}
|
||||
{keys_enum}
|
||||
enum KEYS key = '{initial_key}';
|
||||
if (screen->parser_buf[pos] == ';') state = AFTER_VALUE;
|
||||
|
||||
while (pos < screen->parser_buf_pos) {{
|
||||
switch(state) {{
|
||||
@@ -225,7 +239,7 @@ static inline void
|
||||
'''
|
||||
|
||||
|
||||
def write_header(text, path):
|
||||
def write_header(text: str, path: str) -> None:
|
||||
with open(path, 'w') as f:
|
||||
print(f'// This file is generated by {__file__} do not edit!', file=f, end='\n\n')
|
||||
print('#pragma once', file=f)
|
||||
@@ -233,9 +247,9 @@ def write_header(text, path):
|
||||
subprocess.check_call(['clang-format', '-i', path])
|
||||
|
||||
|
||||
def graphics_parser():
|
||||
def graphics_parser() -> None:
|
||||
flag = frozenset
|
||||
keymap = {
|
||||
keymap: KeymapType = {
|
||||
'a': ('action', flag('tTqpd')),
|
||||
'd': ('delete_action', flag('aAiIcCpPqQxXyYzZ')),
|
||||
't': ('transmission_type', flag('dfts')),
|
||||
|
||||
271
gen-wcwidth.py
271
gen-wcwidth.py
@@ -3,6 +3,7 @@
|
||||
# License: GPL v3 Copyright: 2017, Kovid Goyal <kovid at kovidgoyal.net>
|
||||
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
from collections import defaultdict
|
||||
from contextlib import contextmanager
|
||||
@@ -11,6 +12,10 @@ from functools import partial
|
||||
from html.entities import html5
|
||||
from itertools import groupby
|
||||
from operator import itemgetter
|
||||
from typing import (
|
||||
Callable, DefaultDict, Dict, FrozenSet, Generator, Iterable, List,
|
||||
Optional, Set, Tuple, Union
|
||||
)
|
||||
from urllib.request import urlopen
|
||||
|
||||
os.chdir(os.path.dirname(os.path.abspath(__file__)))
|
||||
@@ -23,15 +28,17 @@ if len(non_characters) != 66:
|
||||
emoji_skin_tone_modifiers = frozenset(range(0x1f3fb, 0x1F3FF + 1))
|
||||
|
||||
|
||||
def get_data(fname, folder='UCD'):
|
||||
def get_data(fname: str, folder: str = 'UCD') -> Iterable[str]:
|
||||
url = f'https://www.unicode.org/Public/{folder}/latest/{fname}'
|
||||
bn = os.path.basename(url)
|
||||
local = os.path.join('/tmp', bn)
|
||||
if os.path.exists(local):
|
||||
data = open(local, 'rb').read()
|
||||
with open(local, 'rb') as f:
|
||||
data = f.read()
|
||||
else:
|
||||
data = urlopen(url).read()
|
||||
open(local, 'wb').write(data)
|
||||
with open(local, 'wb') as f:
|
||||
f.write(data)
|
||||
for line in data.decode('utf-8').splitlines():
|
||||
line = line.strip()
|
||||
if line and not line.startswith('#'):
|
||||
@@ -39,23 +46,25 @@ def get_data(fname, folder='UCD'):
|
||||
|
||||
|
||||
# Map of class names to set of codepoints in class
|
||||
class_maps = {}
|
||||
name_map = {}
|
||||
word_search_map = defaultdict(set)
|
||||
class_maps: Dict[str, Set[int]] = {}
|
||||
all_symbols: Set[int] = set()
|
||||
name_map: Dict[int, str] = {}
|
||||
word_search_map: DefaultDict[str, Set[int]] = defaultdict(set)
|
||||
zwj = 0x200d
|
||||
marks = set(emoji_skin_tone_modifiers) | {zwj}
|
||||
flag_codepoints = frozenset(range(0x1F1E6, 0x1F1E6 + 26))
|
||||
marks = set(emoji_skin_tone_modifiers) | {zwj} | flag_codepoints
|
||||
not_assigned = set(range(0, sys.maxunicode))
|
||||
|
||||
|
||||
def parse_ucd():
|
||||
def parse_ucd() -> None:
|
||||
|
||||
def add_word(w, c):
|
||||
def add_word(w: str, c: int) -> None:
|
||||
if c <= 32 or c == 127 or 128 <= c <= 159:
|
||||
return
|
||||
if len(w) > 1:
|
||||
word_search_map[w.lower()].add(c)
|
||||
|
||||
first = None
|
||||
first: Optional[int] = None
|
||||
for word, c in html5.items():
|
||||
if len(c) == 1:
|
||||
add_word(word.rstrip(';'), ord(c))
|
||||
@@ -73,7 +82,7 @@ def parse_ucd():
|
||||
category = parts[2]
|
||||
s = class_maps.setdefault(category, set())
|
||||
desc = parts[1]
|
||||
codepoints = (codepoint,)
|
||||
codepoints: Union[Tuple[int, ...], Iterable[int]] = (codepoint,)
|
||||
if first is None:
|
||||
if desc.endswith(', First>'):
|
||||
first = codepoint
|
||||
@@ -86,6 +95,20 @@ def parse_ucd():
|
||||
not_assigned.discard(codepoint)
|
||||
if category.startswith('M'):
|
||||
marks.add(codepoint)
|
||||
elif category.startswith('S'):
|
||||
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
|
||||
word_search_map['bee'] |= word_search_map['honeybee']
|
||||
@@ -93,43 +116,97 @@ def parse_ucd():
|
||||
word_search_map['lamda'] |= word_search_map['lambda']
|
||||
|
||||
|
||||
def split_two(line):
|
||||
spec, rest = line.split(';', 1)
|
||||
spec, rest = spec.strip(), rest.strip().split(' ', 1)[0].strip()
|
||||
def parse_range_spec(spec: str) -> Set[int]:
|
||||
spec = spec.strip()
|
||||
if '..' in spec:
|
||||
chars = tuple(map(lambda x: int(x, 16), filter(None, spec.split('.'))))
|
||||
chars = set(range(chars[0], chars[1] + 1))
|
||||
chars_ = tuple(map(lambda x: int(x, 16), filter(None, spec.split('.'))))
|
||||
chars = set(range(chars_[0], chars_[1] + 1))
|
||||
else:
|
||||
chars = {int(spec, 16)}
|
||||
return chars, rest
|
||||
return chars
|
||||
|
||||
|
||||
all_emoji = set()
|
||||
emoji_categories = {}
|
||||
emoji_presentation_bases = set()
|
||||
def split_two(line: str) -> Tuple[Set[int], str]:
|
||||
spec, rest = line.split(';', 1)
|
||||
spec, rest = spec.strip(), rest.strip().split(' ', 1)[0].strip()
|
||||
return parse_range_spec(spec), rest
|
||||
|
||||
|
||||
def parse_emoji():
|
||||
for line in get_data('emoji-data.txt', 'emoji'):
|
||||
chars, rest = split_two(line)
|
||||
s = emoji_categories.setdefault(rest, set())
|
||||
s.update(chars)
|
||||
all_emoji.update(chars)
|
||||
for line in get_data('emoji-variation-sequences.txt', 'emoji'):
|
||||
base, var, *rest = line.split()
|
||||
if base.startswith('#'):
|
||||
all_emoji: Set[int] = set()
|
||||
emoji_presentation_bases: Set[int] = set()
|
||||
narrow_emoji: Set[int] = set()
|
||||
wide_emoji: Set[int] = set()
|
||||
flags: Dict[int, List[int]] = {}
|
||||
|
||||
|
||||
def parse_basic_emoji(spec: str) -> None:
|
||||
parts = list(filter(None, spec.split()))
|
||||
has_emoji_presentation = len(parts) < 2
|
||||
chars = parse_range_spec(parts[0])
|
||||
all_emoji.update(chars)
|
||||
emoji_presentation_bases.update(chars)
|
||||
(wide_emoji if has_emoji_presentation else narrow_emoji).update(chars)
|
||||
|
||||
|
||||
def parse_keycap_sequence(spec: str) -> None:
|
||||
base, fe0f, cc = list(filter(None, spec.split()))
|
||||
chars = parse_range_spec(base)
|
||||
all_emoji.update(chars)
|
||||
emoji_presentation_bases.update(chars)
|
||||
narrow_emoji.update(chars)
|
||||
|
||||
|
||||
def parse_flag_emoji_sequence(spec: str) -> None:
|
||||
a, b = list(filter(None, spec.split()))
|
||||
left, right = int(a, 16), int(b, 16)
|
||||
chars = {left, right}
|
||||
all_emoji.update(chars)
|
||||
wide_emoji.update(chars)
|
||||
emoji_presentation_bases.update(chars)
|
||||
flags.setdefault(left, []).append(right)
|
||||
|
||||
|
||||
def parse_emoji_tag_sequence(spec: str) -> None:
|
||||
a = int(spec.split()[0], 16)
|
||||
all_emoji.add(a)
|
||||
wide_emoji.add(a)
|
||||
emoji_presentation_bases.add(a)
|
||||
|
||||
|
||||
def parse_emoji_modifier_sequence(spec: str) -> None:
|
||||
a, b = list(filter(None, spec.split()))
|
||||
char, mod = int(a, 16), int(b, 16)
|
||||
mod
|
||||
all_emoji.add(char)
|
||||
wide_emoji.add(char)
|
||||
emoji_presentation_bases.add(char)
|
||||
|
||||
|
||||
def parse_emoji() -> None:
|
||||
for line in get_data('emoji-sequences.txt', 'emoji'):
|
||||
parts = [x.strip() for x in line.split(';')]
|
||||
if len(parts) < 2:
|
||||
continue
|
||||
base = int(base, 16)
|
||||
if var.upper() == 'FE0F':
|
||||
emoji_presentation_bases.add(base)
|
||||
data, etype = parts[:2]
|
||||
if etype == 'Basic_Emoji':
|
||||
parse_basic_emoji(data)
|
||||
elif etype == 'Emoji_Keycap_Sequence':
|
||||
parse_keycap_sequence(data)
|
||||
elif etype == 'RGI_Emoji_Flag_Sequence':
|
||||
parse_flag_emoji_sequence(data)
|
||||
elif etype == 'RGI_Emoji_Tag_Sequence':
|
||||
parse_emoji_tag_sequence(data)
|
||||
elif etype == 'RGI_Emoji_Modifier_Sequence':
|
||||
parse_emoji_modifier_sequence(data)
|
||||
|
||||
|
||||
doublewidth, ambiguous = set(), set()
|
||||
doublewidth: Set[int] = set()
|
||||
ambiguous: Set[int] = set()
|
||||
|
||||
|
||||
def parse_eaw():
|
||||
def parse_eaw() -> None:
|
||||
global doublewidth, ambiguous
|
||||
seen = set()
|
||||
seen: Set[int] = set()
|
||||
for line in get_data('ucd/EastAsianWidth.txt'):
|
||||
chars, eaw = split_two(line)
|
||||
if eaw == 'A':
|
||||
@@ -145,7 +222,7 @@ def parse_eaw():
|
||||
doublewidth |= set(range(0x30000, 0x3FFFD + 1)) - seen
|
||||
|
||||
|
||||
def get_ranges(items):
|
||||
def get_ranges(items: List[int]) -> Generator[Union[int, Tuple[int, int]], None, None]:
|
||||
items.sort()
|
||||
for k, g in groupby(enumerate(items), lambda m: m[0]-m[1]):
|
||||
group = tuple(map(itemgetter(1), g))
|
||||
@@ -156,7 +233,7 @@ def get_ranges(items):
|
||||
yield a, b
|
||||
|
||||
|
||||
def write_case(spec, p):
|
||||
def write_case(spec: Union[Tuple, int], p: Callable) -> None:
|
||||
if isinstance(spec, tuple):
|
||||
p('\t\tcase 0x{:x} ... 0x{:x}:'.format(*spec))
|
||||
else:
|
||||
@@ -164,25 +241,24 @@ def write_case(spec, p):
|
||||
|
||||
|
||||
@contextmanager
|
||||
def create_header(path, include_data_types=True):
|
||||
f = open(path, 'w')
|
||||
p = partial(print, file=f)
|
||||
p('// unicode data, built from the unicode standard on:', date.today())
|
||||
p('// see gen-wcwidth.py')
|
||||
if path.endswith('.h'):
|
||||
p('#pragma once')
|
||||
if include_data_types:
|
||||
p('#include "data-types.h"\n')
|
||||
p('START_ALLOW_CASE_RANGE')
|
||||
p()
|
||||
yield p
|
||||
p()
|
||||
if include_data_types:
|
||||
p('END_ALLOW_CASE_RANGE')
|
||||
f.close()
|
||||
def create_header(path: str, include_data_types: bool = True) -> Generator[Callable, None, None]:
|
||||
with open(path, 'w') as f:
|
||||
p = partial(print, file=f)
|
||||
p('// unicode data, built from the unicode standard on:', date.today())
|
||||
p('// see gen-wcwidth.py')
|
||||
if path.endswith('.h'):
|
||||
p('#pragma once')
|
||||
if include_data_types:
|
||||
p('#include "data-types.h"\n')
|
||||
p('START_ALLOW_CASE_RANGE')
|
||||
p()
|
||||
yield p
|
||||
p()
|
||||
if include_data_types:
|
||||
p('END_ALLOW_CASE_RANGE')
|
||||
|
||||
|
||||
def gen_emoji():
|
||||
def gen_emoji() -> None:
|
||||
with create_header('kitty/emoji.h') as p:
|
||||
p('static inline bool\nis_emoji(char_type code) {')
|
||||
p('\tswitch(code) {')
|
||||
@@ -192,9 +268,10 @@ def gen_emoji():
|
||||
p('\t\tdefault: return false;')
|
||||
p('\t}')
|
||||
p('\treturn false;\n}')
|
||||
p('static inline bool\nis_emoji_modifier(char_type code) {')
|
||||
|
||||
p('static inline bool\nis_symbol(char_type code) {')
|
||||
p('\tswitch(code) {')
|
||||
for spec in get_ranges(list(emoji_categories['Emoji_Modifier'])):
|
||||
for spec in get_ranges(list(all_symbols)):
|
||||
write_case(spec, p)
|
||||
p('\t\t\treturn true;')
|
||||
p('\t\tdefault: return false;')
|
||||
@@ -202,24 +279,39 @@ def gen_emoji():
|
||||
p('\treturn false;\n}')
|
||||
|
||||
|
||||
def category_test(name, p, classes, comment, static=False, extra_chars=frozenset(), exclude=frozenset()):
|
||||
static = 'static inline ' if static else ''
|
||||
chars = set()
|
||||
def category_test(
|
||||
name: str,
|
||||
p: Callable,
|
||||
classes: Iterable[str],
|
||||
comment: str,
|
||||
use_static: bool = False,
|
||||
extra_chars: Union[FrozenSet[int], Set[int]] = frozenset(),
|
||||
exclude: Union[Set[int], FrozenSet[int]] = frozenset(),
|
||||
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:
|
||||
chars |= class_maps[c]
|
||||
chars |= extra_chars
|
||||
chars -= exclude
|
||||
p(f'{static}bool\n{name}(char_type code) {{')
|
||||
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) {')
|
||||
for spec in get_ranges(list(chars)):
|
||||
write_case(spec, p)
|
||||
p(f'\t\t\treturn true;')
|
||||
p('\t\t\treturn true;')
|
||||
p('\t} // }}}\n')
|
||||
p('\treturn false;\n}\n')
|
||||
|
||||
|
||||
def codepoint_to_mark_map(p, mark_map):
|
||||
def codepoint_to_mark_map(p: Callable, mark_map: List[int]) -> Dict[int, int]:
|
||||
p('\tswitch(c) { // {{{')
|
||||
rmap = {c: m for m, c in enumerate(mark_map)}
|
||||
for spec in get_ranges(mark_map):
|
||||
@@ -234,14 +326,14 @@ def codepoint_to_mark_map(p, mark_map):
|
||||
return rmap
|
||||
|
||||
|
||||
def classes_to_regex(classes, exclude=''):
|
||||
chars = set()
|
||||
def classes_to_regex(classes: Iterable[str], exclude: str = '') -> Iterable[str]:
|
||||
chars: Set[int] = set()
|
||||
for c in classes:
|
||||
chars |= class_maps[c]
|
||||
for c in map(ord, exclude):
|
||||
chars.discard(c)
|
||||
for x in map(ord, exclude):
|
||||
chars.discard(x)
|
||||
|
||||
def as_string(codepoint):
|
||||
def as_string(codepoint: int) -> str:
|
||||
if codepoint < 256:
|
||||
return r'\x{:02x}'.format(codepoint)
|
||||
if codepoint <= 0xffff:
|
||||
@@ -255,7 +347,7 @@ def classes_to_regex(classes, exclude=''):
|
||||
yield as_string(spec)
|
||||
|
||||
|
||||
def gen_ucd():
|
||||
def gen_ucd() -> None:
|
||||
cz = {c for c in class_maps if c[0] in 'CZ'}
|
||||
with create_header('kitty/unicode-data.c') as p:
|
||||
p('#include "unicode-data.h"')
|
||||
@@ -264,11 +356,15 @@ def gen_ucd():
|
||||
{c for c in class_maps if c.startswith('M')},
|
||||
'M category (marks)',
|
||||
# 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(
|
||||
'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_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)')
|
||||
@@ -281,7 +377,12 @@ def gen_ucd():
|
||||
p('combining_type mark_for_codepoint(char_type c) {')
|
||||
rmap = codepoint_to_mark_map(p, mark_map)
|
||||
p('}\n')
|
||||
if rmap[0xfe0e] != 1281:
|
||||
with open('kitty/unicode-data.h') as f:
|
||||
unicode_data = f.read()
|
||||
m = re.search(r'^#define VS15 (\d+)', unicode_data, re.M)
|
||||
if m is not None:
|
||||
expected = int(m.group(1))
|
||||
if rmap[0xfe0e] != expected:
|
||||
raise ValueError('The mark for 0xfe0e has changed, you have to update VS15 to {} and VS16 to {} in unicode-data.h'.format(
|
||||
rmap[0xfe0e], rmap[0xfe0f]
|
||||
))
|
||||
@@ -289,7 +390,7 @@ def gen_ucd():
|
||||
f.write("url_delimiters = '{}' # noqa".format(''.join(classes_to_regex(cz, exclude='\n'))))
|
||||
|
||||
|
||||
def gen_names():
|
||||
def gen_names() -> None:
|
||||
with create_header('kittens/unicode_input/names.h') as p:
|
||||
mark_to_cp = list(sorted(name_map))
|
||||
cp_to_mark = {cp: m for m, cp in enumerate(mark_to_cp)}
|
||||
@@ -343,29 +444,29 @@ def gen_names():
|
||||
p('}; // }}}\n')
|
||||
|
||||
# The trie
|
||||
p(f'typedef struct {{ uint32_t children_offset; uint32_t match_offset; }} word_trie;\n')
|
||||
all_trie_nodes = []
|
||||
p('typedef struct { uint32_t children_offset; uint32_t match_offset; } word_trie;\n')
|
||||
all_trie_nodes: List['TrieNode'] = [] # noqa
|
||||
|
||||
class TrieNode:
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self) -> None:
|
||||
self.match_offset = 0
|
||||
self.children_offset = 0
|
||||
self.children = {}
|
||||
self.children: Dict[int, int] = {}
|
||||
|
||||
def add_letter(self, letter):
|
||||
def add_letter(self, letter: int) -> int:
|
||||
if letter not in self.children:
|
||||
self.children[letter] = len(all_trie_nodes)
|
||||
all_trie_nodes.append(TrieNode())
|
||||
return self.children[letter]
|
||||
|
||||
def __str__(self):
|
||||
def __str__(self) -> str:
|
||||
return f'{{ .children_offset={self.children_offset}, .match_offset={self.match_offset} }}'
|
||||
|
||||
root = TrieNode()
|
||||
all_trie_nodes.append(root)
|
||||
|
||||
def add_word(word_idx, word):
|
||||
def add_word(word_idx: int, word: str) -> None:
|
||||
parent = root
|
||||
for letter in map(ord, word):
|
||||
idx = parent.add_letter(letter)
|
||||
@@ -390,10 +491,10 @@ def gen_names():
|
||||
p('}; // }}}\n')
|
||||
|
||||
|
||||
def gen_wcwidth():
|
||||
seen = set()
|
||||
def gen_wcwidth() -> None:
|
||||
seen: Set[int] = set()
|
||||
|
||||
def add(p, comment, chars_, ret):
|
||||
def add(p: Callable, comment: str, chars_: Union[Set[int], FrozenSet[int]], ret: int) -> None:
|
||||
chars = chars_ - seen
|
||||
seen.update(chars)
|
||||
p(f'\t\t// {comment} ({len(chars)} codepoints)' + ' {{' '{')
|
||||
@@ -404,16 +505,18 @@ def gen_wcwidth():
|
||||
|
||||
with create_header('kitty/wcwidth-std.h') as p:
|
||||
p('static int\nwcwidth_std(int32_t code) {')
|
||||
p('\tif (LIKELY(0x20 <= code && code <= 0x7e)) return 1;')
|
||||
p('\tswitch(code) {')
|
||||
|
||||
non_printing = class_maps['Cc'] | class_maps['Cf'] | class_maps['Cs']
|
||||
add(p, 'Flags', flag_codepoints, 2)
|
||||
add(p, 'Marks', marks | {0}, 0)
|
||||
add(p, 'Non-printing characters', non_printing, -1)
|
||||
add(p, 'Private use', class_maps['Co'], -3)
|
||||
add(p, 'Text Presentation', emoji_categories['Emoji'] - emoji_categories['Emoji_Presentation'], 1)
|
||||
add(p, 'Text Presentation', narrow_emoji, 1)
|
||||
add(p, 'East Asian ambiguous width', ambiguous, -2)
|
||||
add(p, 'East Asian double width', doublewidth, 2)
|
||||
add(p, 'Emoji Presentation', emoji_categories['Emoji_Presentation'], 2)
|
||||
add(p, 'Emoji Presentation', wide_emoji, 2)
|
||||
|
||||
add(p, 'Not assigned in the unicode character database', not_assigned, -4)
|
||||
|
||||
@@ -421,7 +524,7 @@ def gen_wcwidth():
|
||||
p('\t}')
|
||||
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) {')
|
||||
for spec in get_ranges(list(emoji_presentation_bases)):
|
||||
write_case(spec, p)
|
||||
|
||||
@@ -8,9 +8,11 @@ import shlex
|
||||
import shutil
|
||||
import subprocess
|
||||
|
||||
|
||||
cmdline = (
|
||||
'glad --profile core --out-path {dest} --api gl=3.3 --generator {generator} --spec gl'
|
||||
' --extensions GL_ARB_texture_storage,GL_ARB_copy_image,GL_ARB_multisample,GL_ARB_robustness,GL_KHR_debug'
|
||||
'glad --out-path {dest} --api gl:core=3.3 '
|
||||
' --extensions GL_ARB_texture_storage,GL_ARB_copy_image,GL_ARB_multisample,GL_ARB_robustness,GL_KHR_debug '
|
||||
'c --header-only --debug'
|
||||
)
|
||||
|
||||
|
||||
@@ -23,7 +25,7 @@ def regenerate():
|
||||
clean('out')
|
||||
|
||||
subprocess.check_call(
|
||||
shlex.split(cmdline.format(dest='out', generator='c-debug'))
|
||||
shlex.split(cmdline.format(dest='out'))
|
||||
)
|
||||
|
||||
|
||||
@@ -32,33 +34,12 @@ def strip_trailing_whitespace(c):
|
||||
|
||||
|
||||
def export():
|
||||
c = open('out/src/glad.c', 'rb').read().decode('utf-8')
|
||||
functions = []
|
||||
with open('out/include/glad/gl.h', 'r', encoding='utf-8') as source:
|
||||
data = source.read()
|
||||
data = strip_trailing_whitespace(data)
|
||||
|
||||
def sub(m):
|
||||
functions.append(m.group(2))
|
||||
return m.group()
|
||||
|
||||
c = re.sub(r'^([A-Z0-9]+) glad_debug_([a-zA-Z0-9]+) = glad_debug_impl_\2;$', sub, c, flags=re.M)
|
||||
switch = ['glad_debug_{0} = glad_{0}'.format(f) for f in functions]
|
||||
c = c.replace('<glad/glad.h>', '"gl-wrapper.h"', 1)
|
||||
c = '#pragma GCC diagnostic ignored "-Wpedantic"\n' + c
|
||||
c += '''
|
||||
int
|
||||
init_glad(GLADloadproc load, int debug) {
|
||||
int ret = gladLoadGLLoader(load);
|
||||
if (ret && !debug) {
|
||||
SUB;
|
||||
}
|
||||
return ret;
|
||||
}'''.replace('SUB', ';\n '.join(switch), 1)
|
||||
open('../kitty/gl-wrapper.c', 'w').write(strip_trailing_whitespace(c))
|
||||
raw = open('out/include/glad/glad.h').read()
|
||||
raw = raw.replace('<KHR/khrplatform.h>', '"khrplatform.h"')
|
||||
raw += '\nint init_glad(GLADloadproc, int);\n'
|
||||
open('../kitty/gl-wrapper.h', 'w').write(strip_trailing_whitespace(raw))
|
||||
raw = open('out/include/KHR/khrplatform.h', 'rb').read().decode('utf-8')
|
||||
open('../kitty/khrplatform.h', 'w').write(strip_trailing_whitespace(raw))
|
||||
with open('../kitty/gl-wrapper.h', 'w', encoding='utf-8') as dest:
|
||||
dest.write(data)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
0
glfw/__init__.py
Normal file
0
glfw/__init__.py
Normal file
224
glfw/backend_utils.c
vendored
224
glfw/backend_utils.c
vendored
@@ -11,6 +11,8 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <float.h>
|
||||
#include <time.h>
|
||||
@@ -20,19 +22,6 @@
|
||||
#define ppoll pollts
|
||||
#endif
|
||||
|
||||
static inline double
|
||||
monotonic() {
|
||||
struct timespec ts = {0};
|
||||
#ifdef CLOCK_HIGHRES
|
||||
clock_gettime(CLOCK_HIGHRES, &ts);
|
||||
#elif CLOCK_MONOTONIC_RAW
|
||||
clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
|
||||
#else
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
#endif
|
||||
return (((double)ts.tv_nsec) / 1e9) + (double)ts.tv_sec;
|
||||
}
|
||||
|
||||
void
|
||||
update_fds(EventLoopData *eld) {
|
||||
for (nfds_t i = 0; i < eld->watches_count; i++) {
|
||||
@@ -55,6 +44,7 @@ addWatch(EventLoopData *eld, const char* name, int fd, int events, int enabled,
|
||||
w->fd = fd; w->events = events; w->enabled = enabled;
|
||||
w->callback = cb;
|
||||
w->callback_data = cb_data;
|
||||
w->free = NULL;
|
||||
w->id = ++watch_counter;
|
||||
update_fds(eld);
|
||||
return w->id;
|
||||
@@ -64,6 +54,10 @@ addWatch(EventLoopData *eld, const char* name, int fd, int events, int enabled,
|
||||
for (nfds_t i = 0; i < eld->which##_count; i++) { \
|
||||
if (eld->which[i].id == item_id) { \
|
||||
eld->which##_count--; \
|
||||
if (eld->which[i].callback_data && eld->which[i].free) { \
|
||||
eld->which[i].free(eld->which[i].id, eld->which[i].callback_data); \
|
||||
eld->which[i].callback_data = NULL; eld->which[i].free = NULL; \
|
||||
} \
|
||||
if (i < eld->which##_count) { \
|
||||
memmove(eld->which + i, eld->which + i + 1, sizeof(eld->which[0]) * (eld->which##_count - i)); \
|
||||
} \
|
||||
@@ -102,7 +96,7 @@ update_timers(EventLoopData *eld) {
|
||||
}
|
||||
|
||||
id_type
|
||||
addTimer(EventLoopData *eld, const char *name, double interval, int enabled, timer_callback_func cb, void *cb_data) {
|
||||
addTimer(EventLoopData *eld, const char *name, monotonic_t interval, int enabled, bool repeats, timer_callback_func cb, void *cb_data, GLFWuserdatafreefun free) {
|
||||
if (eld->timers_count >= sizeof(eld->timers)/sizeof(eld->timers[0])) {
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR, "Too many timers added");
|
||||
return 0;
|
||||
@@ -110,12 +104,14 @@ addTimer(EventLoopData *eld, const char *name, double interval, int enabled, tim
|
||||
Timer *t = eld->timers + eld->timers_count++;
|
||||
t->interval = interval;
|
||||
t->name = name;
|
||||
t->trigger_at = enabled ? monotonic() + interval : DBL_MAX;
|
||||
t->trigger_at = enabled ? monotonic() + interval : MONOTONIC_T_MAX;
|
||||
t->repeats = repeats;
|
||||
t->callback = cb;
|
||||
t->callback_data = cb_data;
|
||||
t->free = free;
|
||||
t->id = ++timer_counter;
|
||||
update_timers(eld);
|
||||
return t->id;
|
||||
return timer_counter;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -123,11 +119,19 @@ removeTimer(EventLoopData *eld, id_type timer_id) {
|
||||
removeX(timers, timer_id, update_timers);
|
||||
}
|
||||
|
||||
void
|
||||
removeAllTimers(EventLoopData *eld) {
|
||||
for (nfds_t i = 0; i < eld->timers_count; i++) {
|
||||
if (eld->timers[i].free && eld->timers[i].callback_data) eld->timers[i].free(eld->timers[i].id, eld->timers[i].callback_data);
|
||||
}
|
||||
eld->timers_count = 0;
|
||||
}
|
||||
|
||||
void
|
||||
toggleTimer(EventLoopData *eld, id_type timer_id, int enabled) {
|
||||
for (nfds_t i = 0; i < eld->timers_count; i++) {
|
||||
if (eld->timers[i].id == timer_id) {
|
||||
double trigger_at = enabled ? (monotonic() + eld->timers[i].interval) : DBL_MAX;
|
||||
monotonic_t trigger_at = enabled ? (monotonic() + eld->timers[i].interval) : MONOTONIC_T_MAX;
|
||||
if (trigger_at != eld->timers[i].trigger_at) {
|
||||
eld->timers[i].trigger_at = trigger_at;
|
||||
update_timers(eld);
|
||||
@@ -138,7 +142,7 @@ toggleTimer(EventLoopData *eld, id_type timer_id, int enabled) {
|
||||
}
|
||||
|
||||
void
|
||||
changeTimerInterval(EventLoopData *eld, id_type timer_id, double interval) {
|
||||
changeTimerInterval(EventLoopData *eld, id_type timer_id, monotonic_t interval) {
|
||||
for (nfds_t i = 0; i < eld->timers_count; i++) {
|
||||
if (eld->timers[i].id == timer_id) {
|
||||
eld->timers[i].interval = interval;
|
||||
@@ -148,22 +152,28 @@ changeTimerInterval(EventLoopData *eld, id_type timer_id, double interval) {
|
||||
}
|
||||
|
||||
|
||||
double
|
||||
prepareForPoll(EventLoopData *eld, double timeout) {
|
||||
monotonic_t
|
||||
prepareForPoll(EventLoopData *eld, monotonic_t timeout) {
|
||||
for (nfds_t i = 0; i < eld->watches_count; i++) eld->fds[i].revents = 0;
|
||||
if (!eld->timers_count || eld->timers[0].trigger_at == DBL_MAX) return timeout;
|
||||
double now = monotonic(), next_repeat_at = eld->timers[0].trigger_at;
|
||||
if (!eld->timers_count || eld->timers[0].trigger_at == MONOTONIC_T_MAX) return timeout;
|
||||
monotonic_t now = monotonic(), next_repeat_at = eld->timers[0].trigger_at;
|
||||
if (timeout < 0 || now + timeout > next_repeat_at) {
|
||||
timeout = next_repeat_at <= now ? 0 : next_repeat_at - now;
|
||||
}
|
||||
return timeout;
|
||||
}
|
||||
|
||||
static inline struct timespec
|
||||
calc_time(monotonic_t nsec) {
|
||||
struct timespec result;
|
||||
result.tv_sec = nsec / (1000LL * 1000LL * 1000LL);
|
||||
result.tv_nsec = nsec % (1000LL * 1000LL * 1000LL);
|
||||
return result;
|
||||
}
|
||||
|
||||
int
|
||||
pollWithTimeout(struct pollfd *fds, nfds_t nfds, double timeout) {
|
||||
const long seconds = (long) timeout;
|
||||
const long nanoseconds = (long) ((timeout - seconds) * 1e9);
|
||||
struct timespec tv = { seconds, nanoseconds };
|
||||
pollWithTimeout(struct pollfd *fds, nfds_t nfds, monotonic_t timeout) {
|
||||
struct timespec tv = calc_time(timeout);
|
||||
return ppoll(fds, nfds, &tv, NULL);
|
||||
}
|
||||
|
||||
@@ -181,50 +191,121 @@ dispatchEvents(EventLoopData *eld) {
|
||||
|
||||
unsigned
|
||||
dispatchTimers(EventLoopData *eld) {
|
||||
if (!eld->timers_count || eld->timers[0].trigger_at == DBL_MAX) return 0;
|
||||
static struct { timer_callback_func func; id_type id; void* data; } dispatches[sizeof(eld->timers)/sizeof(eld->timers[0])];
|
||||
if (!eld->timers_count || eld->timers[0].trigger_at == MONOTONIC_T_MAX) return 0;
|
||||
static struct { timer_callback_func func; id_type id; void* data; bool repeats; } dispatches[sizeof(eld->timers)/sizeof(eld->timers[0])];
|
||||
unsigned num_dispatches = 0;
|
||||
double now = monotonic();
|
||||
monotonic_t now = monotonic();
|
||||
for (nfds_t i = 0; i < eld->timers_count && eld->timers[i].trigger_at <= now; i++) {
|
||||
eld->timers[i].trigger_at = now + eld->timers[i].interval;
|
||||
dispatches[num_dispatches].func = eld->timers[i].callback;
|
||||
dispatches[num_dispatches].id = eld->timers[i].id;
|
||||
dispatches[num_dispatches].data = eld->timers[i].callback_data;
|
||||
dispatches[num_dispatches].repeats = eld->timers[i].repeats;
|
||||
num_dispatches++;
|
||||
}
|
||||
// we dispatch separately so that the callbacks can modify timers
|
||||
for (unsigned i = 0; i < num_dispatches; i++) {
|
||||
dispatches[i].func(dispatches[i].id, dispatches[i].data);
|
||||
if (!dispatches[i].repeats) {
|
||||
removeTimer(eld, dispatches[i].id);
|
||||
}
|
||||
}
|
||||
if (num_dispatches) update_timers(eld);
|
||||
return num_dispatches;
|
||||
}
|
||||
|
||||
static void
|
||||
drain_wakeup_fd(int fd, int events, void* data) {
|
||||
drain_wakeup_fd(int fd, EventLoopData* eld) {
|
||||
static char drain_buf[64];
|
||||
while(read(fd, drain_buf, sizeof(drain_buf)) < 0 && errno == EINTR);
|
||||
eld->wakeup_data_read = false;
|
||||
while(true) {
|
||||
ssize_t ret = read(fd, drain_buf, sizeof(drain_buf));
|
||||
if (ret < 0) {
|
||||
if (errno == EINTR) continue;
|
||||
break;
|
||||
}
|
||||
if (ret > 0) { eld->wakeup_data_read = true; continue; }
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
mark_wakep_fd_ready(int fd UNUSED, int events UNUSED, void *data) {
|
||||
((EventLoopData*)(data))->wakeup_fd_ready = true;
|
||||
}
|
||||
|
||||
bool
|
||||
initPollData(EventLoopData *eld, int display_fd) {
|
||||
if (!addWatch(eld, "display", display_fd, POLLIN, 1, NULL, NULL)) return false;
|
||||
#ifdef HAS_EVENT_FD
|
||||
eld->wakeupFd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
|
||||
if (eld->wakeupFd == -1) return false;
|
||||
const int wakeup_fd = eld->wakeupFd;
|
||||
#else
|
||||
if (pipe2(eld->wakeupFds, O_CLOEXEC | O_NONBLOCK) != 0) return false;
|
||||
const int wakeup_fd = eld->wakeupFds[0];
|
||||
#endif
|
||||
if (!addWatch(eld, "wakeup", wakeup_fd, POLLIN, 1, mark_wakep_fd_ready, eld)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
initPollData(EventLoopData *eld, int wakeup_fd, int display_fd) {
|
||||
addWatch(eld, "display", display_fd, POLLIN, 1, NULL, NULL);
|
||||
addWatch(eld, "wakeup", wakeup_fd, POLLIN, 1, drain_wakeup_fd, NULL);
|
||||
check_for_wakeup_events(EventLoopData *eld) {
|
||||
#ifdef HAS_EVENT_FD
|
||||
int fd = eld->wakeupFd;
|
||||
#else
|
||||
int fd = eld->wakeupFds[0];
|
||||
#endif
|
||||
drain_wakeup_fd(fd, eld);
|
||||
}
|
||||
|
||||
void
|
||||
wakeupEventLoop(EventLoopData *eld) {
|
||||
#ifdef HAS_EVENT_FD
|
||||
static const uint64_t value = 1;
|
||||
while (write(eld->wakeupFd, &value, sizeof value) < 0 && (errno == EINTR || errno == EAGAIN));
|
||||
#else
|
||||
while (write(eld->wakeupFds[1], "w", 1) < 0 && (errno == EINTR || errno == EAGAIN));
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef HAS_EVENT_FD
|
||||
static inline void
|
||||
closeFds(int *fds, size_t count) {
|
||||
while(count--) {
|
||||
if (*fds > 0) {
|
||||
close(*fds);
|
||||
*fds = -1;
|
||||
}
|
||||
fds++;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
finalizePollData(EventLoopData *eld) {
|
||||
#ifdef HAS_EVENT_FD
|
||||
close(eld->wakeupFd); eld->wakeupFd = -1;
|
||||
#else
|
||||
closeFds(eld->wakeupFds, arraysz(eld->wakeupFds));
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
pollForEvents(EventLoopData *eld, double timeout) {
|
||||
pollForEvents(EventLoopData *eld, monotonic_t timeout, watch_callback_func display_callback) {
|
||||
int read_ok = 0;
|
||||
timeout = prepareForPoll(eld, timeout);
|
||||
EVDBG("pollForEvents final timeout: %.3f", monotonic_t_to_s_double(timeout));
|
||||
int result;
|
||||
double end_time = monotonic() + timeout;
|
||||
monotonic_t end_time = monotonic() + timeout;
|
||||
eld->wakeup_fd_ready = false;
|
||||
|
||||
while(1) {
|
||||
if (timeout >= 0) {
|
||||
errno = 0;
|
||||
result = pollWithTimeout(eld->fds, eld->watches_count, timeout);
|
||||
int saved_errno = errno;
|
||||
if (display_callback) display_callback(result, eld->fds[0].revents && eld->watches[0].events, NULL);
|
||||
dispatchTimers(eld);
|
||||
if (result > 0) {
|
||||
dispatchEvents(eld);
|
||||
@@ -239,6 +320,7 @@ pollForEvents(EventLoopData *eld, double timeout) {
|
||||
errno = 0;
|
||||
result = poll(eld->fds, eld->watches_count, -1);
|
||||
int saved_errno = errno;
|
||||
if (display_callback) display_callback(result, eld->fds[0].revents && eld->watches[0].events, NULL);
|
||||
dispatchTimers(eld);
|
||||
if (result > 0) {
|
||||
dispatchEvents(eld);
|
||||
@@ -251,64 +333,20 @@ pollForEvents(EventLoopData *eld, double timeout) {
|
||||
return read_ok;
|
||||
}
|
||||
|
||||
void
|
||||
closeFds(int *fds, size_t count) {
|
||||
while(count--) {
|
||||
if (*fds > 0) {
|
||||
close(*fds);
|
||||
*fds = -1;
|
||||
}
|
||||
fds++;
|
||||
}
|
||||
}
|
||||
|
||||
// Splits and translates a text/uri-list into separate file paths
|
||||
// NOTE: This function destroys the provided string
|
||||
//
|
||||
char** parseUriList(char* text, int* count)
|
||||
{
|
||||
const char* prefix = "file://";
|
||||
char** paths = NULL;
|
||||
char* line;
|
||||
|
||||
*count = 0;
|
||||
|
||||
while ((line = strtok(text, "\r\n")))
|
||||
{
|
||||
text = NULL;
|
||||
|
||||
if (line[0] == '#')
|
||||
continue;
|
||||
|
||||
if (strncmp(line, prefix, strlen(prefix)) == 0)
|
||||
{
|
||||
line += strlen(prefix);
|
||||
// TODO: Validate hostname
|
||||
while (*line != '/')
|
||||
line++;
|
||||
}
|
||||
|
||||
(*count)++;
|
||||
|
||||
char* path = calloc(strlen(line) + 1, 1);
|
||||
paths = realloc(paths, *count * sizeof(char*));
|
||||
paths[*count - 1] = path;
|
||||
|
||||
while (*line)
|
||||
{
|
||||
if (line[0] == '%' && line[1] && line[2])
|
||||
{
|
||||
const char digits[3] = { line[1], line[2], '\0' };
|
||||
*path = strtol(digits, NULL, 16);
|
||||
line += 2;
|
||||
}
|
||||
else
|
||||
*path = *line;
|
||||
|
||||
path++;
|
||||
line++;
|
||||
// Duplicate a UTF-8 encoded string
|
||||
// but cut it so that it has at most max_length bytes plus the null byte.
|
||||
// This does not take combining characters into account.
|
||||
GLFWAPI char* utf_8_strndup(const char* source, size_t max_length) {
|
||||
if (!source) return NULL;
|
||||
size_t length = strnlen(source, max_length);
|
||||
if (length >= max_length) {
|
||||
for (length = max_length; length > 0; length--) {
|
||||
if ((source[length] & 0xC0) != 0x80) break;
|
||||
}
|
||||
}
|
||||
|
||||
return paths;
|
||||
char* result = malloc(length + 1);
|
||||
memcpy(result, source, length);
|
||||
result[length] = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
44
glfw/backend_utils.h
vendored
44
glfw/backend_utils.h
vendored
@@ -1,5 +1,5 @@
|
||||
//========================================================================
|
||||
// GLFW 3.3 Wayland - www.glfw.org
|
||||
// GLFW 3.4 Wayland - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2014 Jonas Ådahl <jadahl@gmail.com>
|
||||
//
|
||||
@@ -25,50 +25,74 @@
|
||||
//========================================================================
|
||||
|
||||
#pragma once
|
||||
#include "../kitty/monotonic.h"
|
||||
#include <poll.h>
|
||||
#include <unistd.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __has_include
|
||||
#if __has_include(<sys/eventfd.h>)
|
||||
#define HAS_EVENT_FD
|
||||
#include <sys/eventfd.h>
|
||||
#endif
|
||||
#else
|
||||
#define HAS_EVENT_FD
|
||||
#include <sys/eventfd.h>
|
||||
#endif
|
||||
|
||||
typedef unsigned long long id_type;
|
||||
typedef void(*watch_callback_func)(int, int, void*);
|
||||
typedef void(*timer_callback_func)(id_type, void*);
|
||||
typedef void (* GLFWuserdatafreefun)(id_type, void*);
|
||||
|
||||
typedef struct {
|
||||
int fd, events, enabled, ready;
|
||||
watch_callback_func callback;
|
||||
void *callback_data;
|
||||
GLFWuserdatafreefun free;
|
||||
id_type id;
|
||||
const char *name;
|
||||
} Watch;
|
||||
|
||||
typedef struct {
|
||||
id_type id;
|
||||
double interval, trigger_at;
|
||||
monotonic_t interval, trigger_at;
|
||||
timer_callback_func callback;
|
||||
void *callback_data;
|
||||
GLFWuserdatafreefun free;
|
||||
const char *name;
|
||||
bool repeats;
|
||||
} Timer;
|
||||
|
||||
|
||||
typedef struct {
|
||||
struct pollfd fds[32];
|
||||
#ifdef HAS_EVENT_FD
|
||||
int wakeupFd;
|
||||
#else
|
||||
int wakeupFds[2];
|
||||
#endif
|
||||
bool wakeup_data_read, wakeup_fd_ready;
|
||||
nfds_t watches_count, timers_count;
|
||||
Watch watches[32];
|
||||
Timer timers[128];
|
||||
} EventLoopData;
|
||||
|
||||
|
||||
void check_for_wakeup_events(EventLoopData *eld);
|
||||
id_type addWatch(EventLoopData *eld, const char *name, int fd, int events, int enabled, watch_callback_func cb, void *cb_data);
|
||||
void removeWatch(EventLoopData *eld, id_type watch_id);
|
||||
void toggleWatch(EventLoopData *eld, id_type watch_id, int enabled);
|
||||
id_type addTimer(EventLoopData *eld, const char *name, double interval, int enabled, timer_callback_func cb, void *cb_data);
|
||||
id_type addTimer(EventLoopData *eld, const char *name, monotonic_t interval, int enabled, bool repeats, timer_callback_func cb, void *cb_data, GLFWuserdatafreefun free);
|
||||
void removeTimer(EventLoopData *eld, id_type timer_id);
|
||||
void removeAllTimers(EventLoopData *eld);
|
||||
void toggleTimer(EventLoopData *eld, id_type timer_id, int enabled);
|
||||
void changeTimerInterval(EventLoopData *eld, id_type timer_id, double interval);
|
||||
double prepareForPoll(EventLoopData *eld, double timeout);
|
||||
int pollWithTimeout(struct pollfd *fds, nfds_t nfds, double timeout);
|
||||
int pollForEvents(EventLoopData *eld, double timeout);
|
||||
void changeTimerInterval(EventLoopData *eld, id_type timer_id, monotonic_t interval);
|
||||
monotonic_t prepareForPoll(EventLoopData *eld, monotonic_t timeout);
|
||||
int pollWithTimeout(struct pollfd *fds, nfds_t nfds, monotonic_t timeout);
|
||||
int pollForEvents(EventLoopData *eld, monotonic_t timeout, watch_callback_func);
|
||||
unsigned dispatchTimers(EventLoopData *eld);
|
||||
void closeFds(int *fds, size_t count);
|
||||
void initPollData(EventLoopData *eld, int wakeup_fd, int display_fd);
|
||||
char** parseUriList(char* text, int* count);
|
||||
void finalizePollData(EventLoopData *eld);
|
||||
bool initPollData(EventLoopData *eld, int display_fd);
|
||||
void wakeupEventLoop(EventLoopData *eld);
|
||||
char* utf_8_strndup(const char* source, size_t max_length);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//========================================================================
|
||||
// GLFW 3.3 macOS - www.glfw.org
|
||||
// GLFW 3.4 macOS - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2009-2016 Camilla Löwy <elmindreda@glfw.org>
|
||||
// Copyright (c) 2009-2019 Camilla Löwy <elmindreda@glfw.org>
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
@@ -23,14 +23,16 @@
|
||||
// distribution.
|
||||
//
|
||||
//========================================================================
|
||||
// It is fine to use C99 in this file because it will not be built with VS
|
||||
//========================================================================
|
||||
|
||||
#include "internal.h"
|
||||
#include "../kitty/monotonic.h"
|
||||
#include <sys/param.h> // For MAXPATHLEN
|
||||
#if MAC_OS_X_VERSION_MAX_ALLOWED < 101200
|
||||
#define NSEventMaskKeyUp NSKeyUpMask
|
||||
#define NSEventMaskKeyDown NSKeyDownMask
|
||||
#define NSEventModifierFlagCommand NSCommandKeyMask
|
||||
#endif
|
||||
#include <pthread.h>
|
||||
|
||||
// Needed for _NSGetProgname
|
||||
#include <crt_externs.h>
|
||||
|
||||
// Change to our application bundle's resources directory, if present
|
||||
//
|
||||
@@ -68,14 +70,119 @@ static void changeToResourcesDirectory(void)
|
||||
chdir(resourcesPath);
|
||||
}
|
||||
|
||||
// Set up the menu bar (manually)
|
||||
// This is nasty, nasty stuff -- calls to undocumented semi-private APIs that
|
||||
// could go away at any moment, lots of stuff that really should be
|
||||
// localize(d|able), etc. Add a nib to save us this horror.
|
||||
//
|
||||
static void createMenuBar(void)
|
||||
{
|
||||
size_t i;
|
||||
NSString* appName = nil;
|
||||
NSDictionary* bundleInfo = [[NSBundle mainBundle] infoDictionary];
|
||||
NSString* nameKeys[] =
|
||||
{
|
||||
@"CFBundleDisplayName",
|
||||
@"CFBundleName",
|
||||
@"CFBundleExecutable",
|
||||
};
|
||||
|
||||
// Try to figure out what the calling application is called
|
||||
|
||||
for (i = 0; i < sizeof(nameKeys) / sizeof(nameKeys[0]); i++)
|
||||
{
|
||||
id name = bundleInfo[nameKeys[i]];
|
||||
if (name &&
|
||||
[name isKindOfClass:[NSString class]] &&
|
||||
![name isEqualToString:@""])
|
||||
{
|
||||
appName = name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!appName)
|
||||
{
|
||||
char** progname = _NSGetProgname();
|
||||
if (progname && *progname)
|
||||
appName = @(*progname);
|
||||
else
|
||||
appName = @"GLFW Application";
|
||||
}
|
||||
|
||||
NSMenu* bar = [[NSMenu alloc] init];
|
||||
[NSApp setMainMenu:bar];
|
||||
|
||||
NSMenuItem* appMenuItem =
|
||||
[bar addItemWithTitle:@"" action:NULL keyEquivalent:@""];
|
||||
NSMenu* appMenu = [[NSMenu alloc] init];
|
||||
[appMenuItem setSubmenu:appMenu];
|
||||
|
||||
[appMenu addItemWithTitle:[NSString stringWithFormat:@"About %@", appName]
|
||||
action:@selector(orderFrontStandardAboutPanel:)
|
||||
keyEquivalent:@""];
|
||||
[appMenu addItem:[NSMenuItem separatorItem]];
|
||||
NSMenu* servicesMenu = [[NSMenu alloc] init];
|
||||
[NSApp setServicesMenu:servicesMenu];
|
||||
[[appMenu addItemWithTitle:@"Services"
|
||||
action:NULL
|
||||
keyEquivalent:@""] setSubmenu:servicesMenu];
|
||||
[servicesMenu release];
|
||||
[appMenu addItem:[NSMenuItem separatorItem]];
|
||||
[appMenu addItemWithTitle:[NSString stringWithFormat:@"Hide %@", appName]
|
||||
action:@selector(hide:)
|
||||
keyEquivalent:@"h"];
|
||||
[[appMenu addItemWithTitle:@"Hide Others"
|
||||
action:@selector(hideOtherApplications:)
|
||||
keyEquivalent:@"h"]
|
||||
setKeyEquivalentModifierMask:NSEventModifierFlagOption | NSEventModifierFlagCommand];
|
||||
[appMenu addItemWithTitle:@"Show All"
|
||||
action:@selector(unhideAllApplications:)
|
||||
keyEquivalent:@""];
|
||||
[appMenu addItem:[NSMenuItem separatorItem]];
|
||||
[appMenu addItemWithTitle:[NSString stringWithFormat:@"Quit %@", appName]
|
||||
action:@selector(terminate:)
|
||||
keyEquivalent:@"q"];
|
||||
|
||||
NSMenuItem* windowMenuItem =
|
||||
[bar addItemWithTitle:@"" action:NULL keyEquivalent:@""];
|
||||
[bar release];
|
||||
NSMenu* windowMenu = [[NSMenu alloc] initWithTitle:@"Window"];
|
||||
[NSApp setWindowsMenu:windowMenu];
|
||||
[windowMenuItem setSubmenu:windowMenu];
|
||||
|
||||
[windowMenu addItemWithTitle:@"Minimize"
|
||||
action:@selector(performMiniaturize:)
|
||||
keyEquivalent:@"m"];
|
||||
[windowMenu addItemWithTitle:@"Zoom"
|
||||
action:@selector(performZoom:)
|
||||
keyEquivalent:@""];
|
||||
[windowMenu addItem:[NSMenuItem separatorItem]];
|
||||
[windowMenu addItemWithTitle:@"Bring All to Front"
|
||||
action:@selector(arrangeInFront:)
|
||||
keyEquivalent:@""];
|
||||
|
||||
// TODO: Make this appear at the bottom of the menu (for consistency)
|
||||
[windowMenu addItem:[NSMenuItem separatorItem]];
|
||||
[[windowMenu addItemWithTitle:@"Enter Full Screen"
|
||||
action:@selector(toggleFullScreen:)
|
||||
keyEquivalent:@"f"]
|
||||
setKeyEquivalentModifierMask:NSEventModifierFlagControl | NSEventModifierFlagCommand];
|
||||
|
||||
// Prior to Snow Leopard, we need to use this oddly-named semi-private API
|
||||
// to get the application menu working properly.
|
||||
SEL setAppleMenuSelector = NSSelectorFromString(@"setAppleMenu:");
|
||||
[NSApp performSelector:setAppleMenuSelector withObject:appMenu];
|
||||
}
|
||||
|
||||
// Create key code translation tables
|
||||
//
|
||||
static void createKeyTables(void)
|
||||
{
|
||||
int scancode;
|
||||
int keycode;
|
||||
|
||||
memset(_glfw.ns.keycodes, -1, sizeof(_glfw.ns.keycodes));
|
||||
memset(_glfw.ns.scancodes, -1, sizeof(_glfw.ns.scancodes));
|
||||
memset(_glfw.ns.key_to_keycode, -1, sizeof(_glfw.ns.key_to_keycode));
|
||||
|
||||
_glfw.ns.keycodes[0x1D] = GLFW_KEY_0;
|
||||
_glfw.ns.keycodes[0x12] = GLFW_KEY_1;
|
||||
@@ -192,17 +299,17 @@ static void createKeyTables(void)
|
||||
_glfw.ns.keycodes[0x43] = GLFW_KEY_KP_MULTIPLY;
|
||||
_glfw.ns.keycodes[0x4E] = GLFW_KEY_KP_SUBTRACT;
|
||||
|
||||
for (scancode = 0; scancode < 256; scancode++)
|
||||
for (keycode = 0; keycode < 256; keycode++)
|
||||
{
|
||||
// Store the reverse translation for faster key name lookup
|
||||
if (_glfw.ns.keycodes[scancode] >= 0)
|
||||
_glfw.ns.scancodes[_glfw.ns.keycodes[scancode]] = scancode;
|
||||
if (_glfw.ns.keycodes[keycode] >= 0)
|
||||
_glfw.ns.key_to_keycode[_glfw.ns.keycodes[keycode]] = keycode;
|
||||
}
|
||||
}
|
||||
|
||||
// Retrieve Unicode data for the current keyboard layout
|
||||
//
|
||||
static GLFWbool updateUnicodeDataNS(void)
|
||||
static bool updateUnicodeDataNS(void)
|
||||
{
|
||||
if (_glfw.ns.inputSource)
|
||||
{
|
||||
@@ -219,7 +326,7 @@ static GLFWbool updateUnicodeDataNS(void)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Cocoa: Failed to retrieve keyboard layout input source");
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
}
|
||||
|
||||
_glfw.ns.unicodeData =
|
||||
@@ -229,15 +336,15 @@ static GLFWbool updateUnicodeDataNS(void)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Cocoa: Failed to retrieve keyboard layout Unicode data");
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
}
|
||||
|
||||
return GLFW_TRUE;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Load HIToolbox.framework and the TIS symbols we need from it
|
||||
//
|
||||
static GLFWbool initializeTIS(void)
|
||||
static bool initializeTIS(void)
|
||||
{
|
||||
// This works only because Cocoa has already loaded it properly
|
||||
_glfw.ns.tis.bundle =
|
||||
@@ -246,19 +353,19 @@ static GLFWbool initializeTIS(void)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Cocoa: Failed to load HIToolbox.framework");
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
}
|
||||
|
||||
CFStringRef* kPropertyUnicodeKeyLayoutData =
|
||||
CFBundleGetDataPointerForName(_glfw.ns.tis.bundle,
|
||||
CFSTR("kTISPropertyUnicodeKeyLayoutData"));
|
||||
_glfw.ns.tis.CopyCurrentKeyboardLayoutInputSource =
|
||||
*(void **)&_glfw.ns.tis.CopyCurrentKeyboardLayoutInputSource =
|
||||
CFBundleGetFunctionPointerForName(_glfw.ns.tis.bundle,
|
||||
CFSTR("TISCopyCurrentKeyboardLayoutInputSource"));
|
||||
_glfw.ns.tis.GetInputSourceProperty =
|
||||
*(void **)&_glfw.ns.tis.GetInputSourceProperty =
|
||||
CFBundleGetFunctionPointerForName(_glfw.ns.tis.bundle,
|
||||
CFSTR("TISGetInputSourceProperty"));
|
||||
_glfw.ns.tis.GetKbdType =
|
||||
*(void **)&_glfw.ns.tis.GetKbdType =
|
||||
CFBundleGetFunctionPointerForName(_glfw.ns.tis.bundle,
|
||||
CFSTR("LMGetKbdType"));
|
||||
|
||||
@@ -269,7 +376,7 @@ static GLFWbool initializeTIS(void)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Cocoa: Failed to load TIS API symbols");
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
}
|
||||
|
||||
_glfw.ns.tis.kPropertyUnicodeKeyLayoutData =
|
||||
@@ -278,6 +385,17 @@ static GLFWbool initializeTIS(void)
|
||||
return updateUnicodeDataNS();
|
||||
}
|
||||
|
||||
static void
|
||||
display_reconfigured(CGDirectDisplayID display UNUSED, CGDisplayChangeSummaryFlags flags, void *userInfo UNUSED)
|
||||
{
|
||||
if (flags & kCGDisplayBeginConfigurationFlag) {
|
||||
return;
|
||||
}
|
||||
if (flags & kCGDisplaySetModeFlag) {
|
||||
// GPU possibly changed
|
||||
}
|
||||
}
|
||||
|
||||
@interface GLFWHelper : NSObject
|
||||
@end
|
||||
|
||||
@@ -285,14 +403,152 @@ static GLFWbool initializeTIS(void)
|
||||
|
||||
- (void)selectedKeyboardInputSourceChanged:(NSObject* )object
|
||||
{
|
||||
(void)object;
|
||||
updateUnicodeDataNS();
|
||||
}
|
||||
|
||||
- (void)doNothing:(id)object
|
||||
{
|
||||
(void)object;
|
||||
}
|
||||
|
||||
@end // GLFWHelper
|
||||
@end // GLFWHelper
|
||||
|
||||
// Delegate for application related notifications {{{
|
||||
|
||||
@interface GLFWApplicationDelegate : NSObject <NSApplicationDelegate>
|
||||
@end
|
||||
|
||||
@implementation GLFWApplicationDelegate
|
||||
|
||||
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
|
||||
{
|
||||
(void)sender;
|
||||
if (_glfw.callbacks.application_close) _glfw.callbacks.application_close(0);
|
||||
return NSTerminateCancel;
|
||||
}
|
||||
|
||||
static GLFWapplicationshouldhandlereopenfun handle_reopen_callback = NULL;
|
||||
|
||||
- (BOOL)applicationShouldHandleReopen:(NSApplication *)sender hasVisibleWindows:(BOOL)flag
|
||||
{
|
||||
(void)sender;
|
||||
if (!handle_reopen_callback) return YES;
|
||||
if (handle_reopen_callback(flag)) return YES;
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (void)applicationDidChangeScreenParameters:(NSNotification *) notification
|
||||
{
|
||||
(void)notification;
|
||||
_GLFWwindow* window;
|
||||
|
||||
for (window = _glfw.windowListHead; window; window = window->next)
|
||||
{
|
||||
if (window->context.client != GLFW_NO_API)
|
||||
[window->context.nsgl.object update];
|
||||
}
|
||||
|
||||
_glfwPollMonitorsNS();
|
||||
}
|
||||
|
||||
static GLFWapplicationwillfinishlaunchingfun finish_launching_callback = NULL;
|
||||
|
||||
- (void)applicationWillFinishLaunching:(NSNotification *)notification
|
||||
{
|
||||
(void)notification;
|
||||
if (_glfw.hints.init.ns.menubar)
|
||||
{
|
||||
// In case we are unbundled, make us a proper UI application
|
||||
[NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
|
||||
|
||||
// Menu bar setup must go between sharedApplication and finishLaunching
|
||||
// in order to properly emulate the behavior of NSApplicationMain
|
||||
|
||||
if ([[NSBundle mainBundle] pathForResource:@"MainMenu" ofType:@"nib"])
|
||||
{
|
||||
[[NSBundle mainBundle] loadNibNamed:@"MainMenu"
|
||||
owner:NSApp
|
||||
topLevelObjects:&_glfw.ns.nibObjects];
|
||||
}
|
||||
else
|
||||
createMenuBar();
|
||||
}
|
||||
if (finish_launching_callback)
|
||||
finish_launching_callback();
|
||||
}
|
||||
|
||||
- (void)applicationDidFinishLaunching:(NSNotification *)notification
|
||||
{
|
||||
(void)notification;
|
||||
[NSApp stop:nil];
|
||||
|
||||
CGDisplayRegisterReconfigurationCallback(display_reconfigured, NULL);
|
||||
_glfwCocoaPostEmptyEvent();
|
||||
}
|
||||
|
||||
- (void)applicationWillTerminate:(NSNotification *)aNotification
|
||||
{
|
||||
(void)aNotification;
|
||||
CGDisplayRemoveReconfigurationCallback(display_reconfigured, NULL);
|
||||
}
|
||||
|
||||
- (void)applicationDidHide:(NSNotification *)notification
|
||||
{
|
||||
(void)notification;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < _glfw.monitorCount; i++)
|
||||
_glfwRestoreVideoModeNS(_glfw.monitors[i]);
|
||||
}
|
||||
|
||||
@end // GLFWApplicationDelegate
|
||||
// }}}
|
||||
|
||||
|
||||
@interface GLFWApplication : NSApplication
|
||||
- (void)tick_callback;
|
||||
- (void)render_frame_received:(id)displayIDAsID;
|
||||
@end
|
||||
|
||||
@implementation GLFWApplication
|
||||
- (void)tick_callback
|
||||
{
|
||||
_glfwDispatchTickCallback();
|
||||
}
|
||||
|
||||
- (void)render_frame_received:(id)displayIDAsID
|
||||
{
|
||||
CGDirectDisplayID displayID = [(NSNumber*)displayIDAsID unsignedIntValue];
|
||||
_glfwDispatchRenderFrame(displayID);
|
||||
}
|
||||
@end
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW internal API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void* _glfwLoadLocalVulkanLoaderNS(void)
|
||||
{
|
||||
CFBundleRef bundle = CFBundleGetMainBundle();
|
||||
if (!bundle)
|
||||
return NULL;
|
||||
|
||||
CFURLRef url =
|
||||
CFBundleCopyAuxiliaryExecutableURL(bundle, CFSTR("libvulkan.1.dylib"));
|
||||
if (!url)
|
||||
return NULL;
|
||||
|
||||
char path[PATH_MAX];
|
||||
void* handle = NULL;
|
||||
|
||||
if (CFURLGetFileSystemRepresentation(url, true, (UInt8*) path, sizeof(path) - 1))
|
||||
handle = _glfw_dlopen(path);
|
||||
|
||||
CFRelease(url);
|
||||
return handle;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
@@ -300,27 +556,64 @@ static GLFWbool initializeTIS(void)
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static inline bool
|
||||
is_ctrl_tab(NSEvent *event) {
|
||||
NSEventModifierFlags modifierFlags = [event modifierFlags] & NSEventModifierFlagDeviceIndependentFlagsMask;
|
||||
return event.keyCode == kVK_Tab && (modifierFlags == NSEventModifierFlagControl || modifierFlags == (
|
||||
NSEventModifierFlagControl | NSEventModifierFlagShift));
|
||||
is_ctrl_tab(NSEvent *event, NSEventModifierFlags modifierFlags) {
|
||||
if (
|
||||
(modifierFlags == NSEventModifierFlagControl &&
|
||||
[event.charactersIgnoringModifiers isEqualToString:@"\t"]) ||
|
||||
(modifierFlags == (NSEventModifierFlagControl | NSEventModifierFlagShift) &&
|
||||
[event.charactersIgnoringModifiers isEqualToString:@"\x19"])
|
||||
) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
is_cmd_period(NSEvent *event, NSEventModifierFlags modifierFlags) {
|
||||
if (modifierFlags != NSEventModifierFlagCommand) return false;
|
||||
if ([event.charactersIgnoringModifiers isEqualToString:@"."]) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
GLFWAPI GLFWapplicationshouldhandlereopenfun glfwSetApplicationShouldHandleReopen(GLFWapplicationshouldhandlereopenfun callback) {
|
||||
GLFWapplicationshouldhandlereopenfun previous = handle_reopen_callback;
|
||||
handle_reopen_callback = callback;
|
||||
return previous;
|
||||
}
|
||||
|
||||
GLFWAPI GLFWapplicationwillfinishlaunchingfun glfwSetApplicationWillFinishLaunching(GLFWapplicationwillfinishlaunchingfun callback) {
|
||||
GLFWapplicationwillfinishlaunchingfun previous = finish_launching_callback;
|
||||
finish_launching_callback = callback;
|
||||
return previous;
|
||||
}
|
||||
|
||||
int _glfwPlatformInit(void)
|
||||
{
|
||||
_glfw.ns.autoreleasePool = [[NSAutoreleasePool alloc] init];
|
||||
@autoreleasepool {
|
||||
|
||||
_glfw.ns.helper = [[GLFWHelper alloc] init];
|
||||
|
||||
[NSThread detachNewThreadSelector:@selector(doNothing:)
|
||||
toTarget:_glfw.ns.helper
|
||||
withObject:nil];
|
||||
|
||||
[NSApplication sharedApplication];
|
||||
if (NSApp)
|
||||
_glfw.ns.finishedLaunching = true;
|
||||
|
||||
[GLFWApplication sharedApplication];
|
||||
|
||||
_glfw.ns.delegate = [[GLFWApplicationDelegate alloc] init];
|
||||
if (_glfw.ns.delegate == nil)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Cocoa: Failed to create application delegate");
|
||||
return false;
|
||||
}
|
||||
|
||||
[NSApp setDelegate:_glfw.ns.delegate];
|
||||
|
||||
NSEvent* (^keydown_block)(NSEvent*) = ^ NSEvent* (NSEvent* event)
|
||||
{
|
||||
if (is_ctrl_tab(event)) {
|
||||
NSEventModifierFlags modifierFlags = [event modifierFlags] & NSEventModifierFlagDeviceIndependentFlagsMask;
|
||||
if (is_ctrl_tab(event, modifierFlags) || is_cmd_period(event, modifierFlags)) {
|
||||
// Cocoa swallows Ctrl+Tab to cycle between views
|
||||
[[NSApp keyWindow].contentView keyDown:event];
|
||||
}
|
||||
@@ -330,13 +623,14 @@ int _glfwPlatformInit(void)
|
||||
|
||||
NSEvent* (^keyup_block)(NSEvent*) = ^ NSEvent* (NSEvent* event)
|
||||
{
|
||||
if ([event modifierFlags] & NSEventModifierFlagCommand) {
|
||||
NSEventModifierFlags modifierFlags = [event modifierFlags] & NSEventModifierFlagDeviceIndependentFlagsMask;
|
||||
if (modifierFlags & NSEventModifierFlagCommand) {
|
||||
// From http://cocoadev.com/index.pl?GameKeyboardHandlingAlmost
|
||||
// This works around an AppKit bug, where key up events while holding
|
||||
// down the command key don't get sent to the key window.
|
||||
[[NSApp keyWindow] sendEvent:event];
|
||||
}
|
||||
if (is_ctrl_tab(event)) {
|
||||
if (is_ctrl_tab(event, modifierFlags) || is_cmd_period(event, modifierFlags)) {
|
||||
// Cocoa swallows Ctrl+Tab to cycle between views
|
||||
[[NSApp keyWindow].contentView keyUp:event];
|
||||
}
|
||||
@@ -350,9 +644,14 @@ int _glfwPlatformInit(void)
|
||||
_glfw.ns.keyDownMonitor =
|
||||
[NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskKeyDown
|
||||
handler:keydown_block];
|
||||
|
||||
if (_glfw.hints.init.ns.chdir)
|
||||
changeToResourcesDirectory();
|
||||
|
||||
// Press and Hold prevents some keys from emitting repeated characters
|
||||
NSDictionary* defaults = @{@"ApplePressAndHoldEnabled":@NO};
|
||||
[[NSUserDefaults standardUserDefaults] registerDefaults:defaults];
|
||||
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
addObserver:_glfw.ns.helper
|
||||
selector:@selector(selectedKeyboardInputSourceChanged:)
|
||||
@@ -363,22 +662,25 @@ int _glfwPlatformInit(void)
|
||||
|
||||
_glfw.ns.eventSource = CGEventSourceCreate(kCGEventSourceStateHIDSystemState);
|
||||
if (!_glfw.ns.eventSource)
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
|
||||
CGEventSourceSetLocalEventsSuppressionInterval(_glfw.ns.eventSource, 0.0);
|
||||
|
||||
if (!initializeTIS())
|
||||
return GLFW_FALSE;
|
||||
|
||||
_glfwInitTimerNS();
|
||||
_glfwInitJoysticksNS();
|
||||
return false;
|
||||
|
||||
_glfwPollMonitorsNS();
|
||||
return GLFW_TRUE;
|
||||
return true;
|
||||
|
||||
} // autoreleasepool
|
||||
}
|
||||
|
||||
void _glfwPlatformTerminate(void)
|
||||
{
|
||||
@autoreleasepool {
|
||||
|
||||
_glfwClearDisplayLinks();
|
||||
|
||||
if (_glfw.ns.inputSource)
|
||||
{
|
||||
CFRelease(_glfw.ns.inputSource);
|
||||
@@ -410,6 +712,7 @@ void _glfwPlatformTerminate(void)
|
||||
[_glfw.ns.helper release];
|
||||
_glfw.ns.helper = nil;
|
||||
}
|
||||
|
||||
if (_glfw.ns.keyUpMonitor)
|
||||
[NSEvent removeMonitor:_glfw.ns.keyUpMonitor];
|
||||
if (_glfw.ns.keyDownMonitor)
|
||||
@@ -418,17 +721,144 @@ void _glfwPlatformTerminate(void)
|
||||
free(_glfw.ns.clipboardString);
|
||||
|
||||
_glfwTerminateNSGL();
|
||||
_glfwTerminateJoysticksNS();
|
||||
|
||||
[_glfw.ns.autoreleasePool release];
|
||||
_glfw.ns.autoreleasePool = nil;
|
||||
} // autoreleasepool
|
||||
}
|
||||
|
||||
const char* _glfwPlatformGetVersionString(void)
|
||||
{
|
||||
return _GLFW_VERSION_NUMBER " Cocoa NSGL"
|
||||
return _GLFW_VERSION_NUMBER " Cocoa NSGL EGL OSMesa"
|
||||
#if defined(_GLFW_BUILD_DLL)
|
||||
" dynamic"
|
||||
#endif
|
||||
;
|
||||
}
|
||||
|
||||
static GLFWtickcallback tick_callback = NULL;
|
||||
static void* tick_callback_data = NULL;
|
||||
static bool tick_callback_requested = false;
|
||||
static pthread_t main_thread;
|
||||
static NSLock *tick_lock = NULL;
|
||||
|
||||
|
||||
void _glfwDispatchTickCallback() {
|
||||
if (tick_lock && tick_callback) {
|
||||
[tick_lock lock];
|
||||
while(tick_callback_requested) {
|
||||
tick_callback_requested = false;
|
||||
tick_callback(tick_callback_data);
|
||||
}
|
||||
[tick_lock unlock];
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
request_tick_callback() {
|
||||
if (!tick_callback_requested) {
|
||||
tick_callback_requested = true;
|
||||
[NSApp performSelectorOnMainThread:@selector(tick_callback) withObject:nil waitUntilDone:NO];
|
||||
}
|
||||
}
|
||||
|
||||
void _glfwPlatformPostEmptyEvent(void)
|
||||
{
|
||||
if (pthread_equal(pthread_self(), main_thread)) {
|
||||
request_tick_callback();
|
||||
} else if (tick_lock) {
|
||||
[tick_lock lock];
|
||||
request_tick_callback();
|
||||
[tick_lock unlock];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void _glfwPlatformStopMainLoop(void) {
|
||||
[NSApp stop:nil];
|
||||
_glfwCocoaPostEmptyEvent();
|
||||
}
|
||||
|
||||
void _glfwPlatformRunMainLoop(GLFWtickcallback callback, void* data) {
|
||||
main_thread = pthread_self();
|
||||
tick_callback = callback;
|
||||
tick_callback_data = data;
|
||||
tick_lock = [NSLock new];
|
||||
[NSApp run];
|
||||
[tick_lock release];
|
||||
tick_lock = NULL;
|
||||
tick_callback = NULL;
|
||||
tick_callback_data = NULL;
|
||||
}
|
||||
|
||||
|
||||
typedef struct {
|
||||
NSTimer *os_timer;
|
||||
unsigned long long id;
|
||||
bool repeats;
|
||||
monotonic_t interval;
|
||||
GLFWuserdatafun callback;
|
||||
void *callback_data;
|
||||
GLFWuserdatafun free_callback_data;
|
||||
} Timer;
|
||||
|
||||
static Timer timers[128] = {{0}};
|
||||
static size_t num_timers = 0;
|
||||
|
||||
static inline void
|
||||
remove_timer_at(size_t idx) {
|
||||
if (idx < num_timers) {
|
||||
Timer *t = timers + idx;
|
||||
if (t->os_timer) { [t->os_timer invalidate]; t->os_timer = NULL; }
|
||||
if (t->callback_data && t->free_callback_data) { t->free_callback_data(t->id, t->callback_data); t->callback_data = NULL; }
|
||||
remove_i_from_array(timers, idx, num_timers);
|
||||
}
|
||||
}
|
||||
|
||||
static void schedule_timer(Timer *t) {
|
||||
t->os_timer = [NSTimer scheduledTimerWithTimeInterval:monotonic_t_to_s_double(t->interval) repeats:(t->repeats ? YES: NO) block:^(NSTimer *os_timer) {
|
||||
for (size_t i = 0; i < num_timers; i++) {
|
||||
if (timers[i].os_timer == os_timer) {
|
||||
timers[i].callback(timers[i].id, timers[i].callback_data);
|
||||
if (!timers[i].repeats) remove_timer_at(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
unsigned long long _glfwPlatformAddTimer(monotonic_t interval, bool repeats, GLFWuserdatafun callback, void *callback_data, GLFWuserdatafun free_callback) {
|
||||
static unsigned long long timer_counter = 0;
|
||||
if (num_timers >= sizeof(timers)/sizeof(timers[0]) - 1) {
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR, "Too many timers added");
|
||||
return 0;
|
||||
}
|
||||
Timer *t = timers + num_timers++;
|
||||
t->id = ++timer_counter;
|
||||
t->repeats = repeats;
|
||||
t->interval = interval;
|
||||
t->callback = callback;
|
||||
t->callback_data = callback_data;
|
||||
t->free_callback_data = free_callback;
|
||||
schedule_timer(t);
|
||||
return timer_counter;
|
||||
}
|
||||
|
||||
void _glfwPlatformRemoveTimer(unsigned long long timer_id) {
|
||||
for (size_t i = 0; i < num_timers; i++) {
|
||||
if (timers[i].id == timer_id) {
|
||||
remove_timer_at(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void _glfwPlatformUpdateTimer(unsigned long long timer_id, monotonic_t interval, bool enabled) {
|
||||
for (size_t i = 0; i < num_timers; i++) {
|
||||
if (timers[i].id == timer_id) {
|
||||
Timer *t = timers + i;
|
||||
if (t->os_timer) { [t->os_timer invalidate]; t->os_timer = NULL; }
|
||||
t->interval = interval;
|
||||
if (enabled) schedule_timer(t);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
8
glfw/cocoa_joystick.h
vendored
8
glfw/cocoa_joystick.h
vendored
@@ -1,7 +1,7 @@
|
||||
//========================================================================
|
||||
// GLFW 3.3 Cocoa - www.glfw.org
|
||||
// GLFW 3.4 Cocoa - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
|
||||
// Copyright (c) 2006-2017 Camilla Löwy <elmindreda@glfw.org>
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
@@ -44,7 +44,3 @@ typedef struct _GLFWjoystickNS
|
||||
CFMutableArrayRef hats;
|
||||
} _GLFWjoystickNS;
|
||||
|
||||
|
||||
void _glfwInitJoysticksNS(void);
|
||||
void _glfwTerminateJoysticksNS(void);
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//========================================================================
|
||||
// GLFW 3.3 Cocoa - www.glfw.org
|
||||
// GLFW 3.4 Cocoa - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2009-2016 Camilla Löwy <elmindreda@glfw.org>
|
||||
// Copyright (c) 2009-2019 Camilla Löwy <elmindreda@glfw.org>
|
||||
// Copyright (c) 2012 Torsten Walluhn <tw@mad-cad.net>
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
@@ -24,6 +24,8 @@
|
||||
// distribution.
|
||||
//
|
||||
//========================================================================
|
||||
// It is fine to use C99 in this file because it will not be built with VS
|
||||
//========================================================================
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
@@ -75,7 +77,7 @@ static long getElementValue(_GLFWjoystick* js, _GLFWjoyelementNS* element)
|
||||
//
|
||||
static CFComparisonResult compareElements(const void* fp,
|
||||
const void* sp,
|
||||
void* user)
|
||||
void* user UNUSED)
|
||||
{
|
||||
const _GLFWjoyelementNS* fe = fp;
|
||||
const _GLFWjoyelementNS* se = sp;
|
||||
@@ -117,9 +119,9 @@ static void closeJoystick(_GLFWjoystick* js)
|
||||
|
||||
// Callback for user-initiated joystick addition
|
||||
//
|
||||
static void matchCallback(void* context,
|
||||
IOReturn result,
|
||||
void* sender,
|
||||
static void matchCallback(void* context UNUSED,
|
||||
IOReturn result UNUSED,
|
||||
void* sender UNUSED,
|
||||
IOHIDDeviceRef device)
|
||||
{
|
||||
int jid;
|
||||
@@ -220,9 +222,31 @@ static void matchCallback(void* context,
|
||||
case kHIDUsage_GD_Hatswitch:
|
||||
target = hats;
|
||||
break;
|
||||
case kHIDUsage_GD_DPadUp:
|
||||
case kHIDUsage_GD_DPadRight:
|
||||
case kHIDUsage_GD_DPadDown:
|
||||
case kHIDUsage_GD_DPadLeft:
|
||||
case kHIDUsage_GD_SystemMainMenu:
|
||||
case kHIDUsage_GD_Select:
|
||||
case kHIDUsage_GD_Start:
|
||||
target = buttons;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (page == kHIDPage_Button)
|
||||
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)
|
||||
target = buttons;
|
||||
|
||||
if (target)
|
||||
@@ -261,9 +285,9 @@ static void matchCallback(void* context,
|
||||
|
||||
// Callback for user-initiated joystick removal
|
||||
//
|
||||
static void removeCallback(void* context,
|
||||
IOReturn result,
|
||||
void* sender,
|
||||
static void removeCallback(void* context UNUSED,
|
||||
IOReturn result UNUSED,
|
||||
void* sender UNUSED,
|
||||
IOHIDDeviceRef device)
|
||||
{
|
||||
int jid;
|
||||
@@ -280,12 +304,10 @@ static void removeCallback(void* context,
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW internal API //////
|
||||
////// GLFW platform API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Initialize joystick interface
|
||||
//
|
||||
void _glfwInitJoysticksNS(void)
|
||||
bool _glfwPlatformInitJoysticks(void)
|
||||
{
|
||||
CFMutableArrayRef matching;
|
||||
const long usages[] =
|
||||
@@ -304,10 +326,10 @@ void _glfwInitJoysticksNS(void)
|
||||
if (!matching)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR, "Cocoa: Failed to create array");
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < sizeof(usages) / sizeof(long); i++)
|
||||
for (size_t i = 0; i < sizeof(usages) / sizeof(long); i++)
|
||||
{
|
||||
const long page = kHIDPage_GenericDesktop;
|
||||
|
||||
@@ -359,26 +381,24 @@ void _glfwInitJoysticksNS(void)
|
||||
// Execute the run loop once in order to register any initially-attached
|
||||
// joysticks
|
||||
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Close all opened joystick handles
|
||||
//
|
||||
void _glfwTerminateJoysticksNS(void)
|
||||
void _glfwPlatformTerminateJoysticks(void)
|
||||
{
|
||||
int jid;
|
||||
|
||||
for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++)
|
||||
closeJoystick(_glfw.joysticks + jid);
|
||||
|
||||
CFRelease(_glfw.ns.hidManager);
|
||||
_glfw.ns.hidManager = NULL;
|
||||
if (_glfw.ns.hidManager)
|
||||
{
|
||||
CFRelease(_glfw.ns.hidManager);
|
||||
_glfw.ns.hidManager = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW platform API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int _glfwPlatformPollJoystick(_GLFWjoystick* js, int mode)
|
||||
{
|
||||
if (mode & _GLFW_POLL_AXES)
|
||||
@@ -397,12 +417,12 @@ int _glfwPlatformPollJoystick(_GLFWjoystick* js, int mode)
|
||||
if (raw > axis->maximum)
|
||||
axis->maximum = raw;
|
||||
|
||||
const long delta = axis->maximum - axis->minimum;
|
||||
if (delta == 0)
|
||||
const long size = axis->maximum - axis->minimum;
|
||||
if (size == 0)
|
||||
_glfwInputJoystickAxis(js, (int) i, 0.f);
|
||||
else
|
||||
{
|
||||
const float value = (2.f * (raw - axis->minimum) / delta) - 1.f;
|
||||
const float value = (2.f * (raw - axis->minimum) / size) - 1.f;
|
||||
_glfwInputJoystickAxis(js, (int) i, value);
|
||||
}
|
||||
}
|
||||
@@ -417,7 +437,8 @@ int _glfwPlatformPollJoystick(_GLFWjoystick* js, int mode)
|
||||
_GLFWjoyelementNS* button = (_GLFWjoyelementNS*)
|
||||
CFArrayGetValueAtIndex(js->ns.buttons, i);
|
||||
const char value = getElementValue(js, button) - button->minimum;
|
||||
_glfwInputJoystickButton(js, (int) i, value);
|
||||
const int state = (value > 0) ? GLFW_PRESS : GLFW_RELEASE;
|
||||
_glfwInputJoystickButton(js, (int) i, state);
|
||||
}
|
||||
|
||||
for (i = 0; i < CFArrayGetCount(js->ns.hats); i++)
|
||||
@@ -454,9 +475,8 @@ void _glfwPlatformUpdateGamepadGUID(char* guid)
|
||||
(strncmp(guid + 20, "000000000000", 12) == 0))
|
||||
{
|
||||
char original[33];
|
||||
strcpy(original, guid);
|
||||
strncpy(original, guid, sizeof(original) - 1);
|
||||
sprintf(guid, "03000000%.4s0000%.4s000000000000",
|
||||
original, original + 16);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
//========================================================================
|
||||
// GLFW 3.3 macOS - www.glfw.org
|
||||
// GLFW 3.4 macOS - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||
// Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
|
||||
// Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
@@ -24,11 +24,14 @@
|
||||
// distribution.
|
||||
//
|
||||
//========================================================================
|
||||
// It is fine to use C99 in this file because it will not be built with VS
|
||||
//========================================================================
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
#include <math.h>
|
||||
|
||||
#include <IOKit/graphics/IOGraphicsLib.h>
|
||||
#include <CoreVideo/CVBase.h>
|
||||
@@ -115,16 +118,16 @@ static char* getDisplayName(CGDirectDisplayID displayID)
|
||||
|
||||
// Check whether the display mode should be included in enumeration
|
||||
//
|
||||
static GLFWbool modeIsGood(CGDisplayModeRef mode)
|
||||
static bool modeIsGood(CGDisplayModeRef mode)
|
||||
{
|
||||
uint32_t flags = CGDisplayModeGetIOFlags(mode);
|
||||
|
||||
if (!(flags & kDisplayModeValidFlag) || !(flags & kDisplayModeSafeFlag))
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
if (flags & kDisplayModeInterlacedFlag)
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
if (flags & kDisplayModeStretchedFlag)
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
|
||||
#if MAC_OS_X_VERSION_MAX_ALLOWED <= 101100
|
||||
CFStringRef format = CGDisplayModeCopyPixelEncoding(mode);
|
||||
@@ -132,30 +135,26 @@ static GLFWbool modeIsGood(CGDisplayModeRef mode)
|
||||
CFStringCompare(format, CFSTR(IO32BitDirectPixels), 0))
|
||||
{
|
||||
CFRelease(format);
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
}
|
||||
|
||||
CFRelease(format);
|
||||
#endif /* MAC_OS_X_VERSION_MAX_ALLOWED */
|
||||
return GLFW_TRUE;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Convert Core Graphics display mode to GLFW video mode
|
||||
//
|
||||
static GLFWvidmode vidmodeFromCGDisplayMode(CGDisplayModeRef mode,
|
||||
CVDisplayLinkRef link)
|
||||
double fallbackRefreshRate)
|
||||
{
|
||||
GLFWvidmode result;
|
||||
result.width = (int) CGDisplayModeGetWidth(mode);
|
||||
result.height = (int) CGDisplayModeGetHeight(mode);
|
||||
result.refreshRate = (int) CGDisplayModeGetRefreshRate(mode);
|
||||
result.refreshRate = (int) round(CGDisplayModeGetRefreshRate(mode));
|
||||
|
||||
if (result.refreshRate == 0)
|
||||
{
|
||||
const CVTime time = CVDisplayLinkGetNominalOutputVideoRefreshPeriod(link);
|
||||
if (!(time.flags & kCVTimeIsIndefinite))
|
||||
result.refreshRate = (int) (time.timeScale / (double) time.timeValue);
|
||||
}
|
||||
result.refreshRate = (int) round(fallbackRefreshRate);
|
||||
|
||||
#if MAC_OS_X_VERSION_MAX_ALLOWED <= 101100
|
||||
CFStringRef format = CGDisplayModeCopyPixelEncoding(mode);
|
||||
@@ -212,27 +211,156 @@ static void endFadeReservation(CGDisplayFadeReservationToken token)
|
||||
}
|
||||
}
|
||||
|
||||
// Finds and caches the NSScreen corresponding to the specified monitor
|
||||
//
|
||||
static bool refreshMonitorScreen(_GLFWmonitor* monitor)
|
||||
{
|
||||
if (monitor->ns.screen)
|
||||
return true;
|
||||
|
||||
for (NSScreen* screen in [NSScreen screens])
|
||||
{
|
||||
NSNumber* displayID = [screen deviceDescription][@"NSScreenNumber"];
|
||||
|
||||
// HACK: Compare unit numbers instead of display IDs to work around
|
||||
// display replacement on machines with automatic graphics
|
||||
// switching
|
||||
if (monitor->ns.unitNumber == CGDisplayUnitNumber([displayID unsignedIntValue]))
|
||||
{
|
||||
monitor->ns.screen = screen;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR, "Cocoa: Failed to find a screen for monitor");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Returns the display refresh rate queried from the I/O registry
|
||||
//
|
||||
static double getFallbackRefreshRate(CGDirectDisplayID displayID)
|
||||
{
|
||||
double refreshRate = 60.0;
|
||||
|
||||
io_iterator_t it;
|
||||
io_service_t service;
|
||||
|
||||
if (IOServiceGetMatchingServices(kIOMasterPortDefault,
|
||||
IOServiceMatching("IOFramebuffer"),
|
||||
&it) != 0)
|
||||
{
|
||||
return refreshRate;
|
||||
}
|
||||
|
||||
while ((service = IOIteratorNext(it)) != 0)
|
||||
{
|
||||
const CFNumberRef indexRef =
|
||||
IORegistryEntryCreateCFProperty(service,
|
||||
CFSTR("IOFramebufferOpenGLIndex"),
|
||||
kCFAllocatorDefault,
|
||||
kNilOptions);
|
||||
if (!indexRef)
|
||||
continue;
|
||||
|
||||
uint32_t index = 0;
|
||||
CFNumberGetValue(indexRef, kCFNumberIntType, &index);
|
||||
CFRelease(indexRef);
|
||||
|
||||
if (CGOpenGLDisplayMaskToDisplayID(1 << index) != displayID)
|
||||
continue;
|
||||
|
||||
const CFNumberRef clockRef =
|
||||
IORegistryEntryCreateCFProperty(service,
|
||||
CFSTR("IOFBCurrentPixelClock"),
|
||||
kCFAllocatorDefault,
|
||||
kNilOptions);
|
||||
const CFNumberRef countRef =
|
||||
IORegistryEntryCreateCFProperty(service,
|
||||
CFSTR("IOFBCurrentPixelCount"),
|
||||
kCFAllocatorDefault,
|
||||
kNilOptions);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW internal API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void _glfwClearDisplayLinks() {
|
||||
for (size_t i = 0; i < _glfw.ns.displayLinks.count; i++) {
|
||||
if (_glfw.ns.displayLinks.entries[i].displayLink) {
|
||||
CVDisplayLinkStop(_glfw.ns.displayLinks.entries[i].displayLink);
|
||||
CVDisplayLinkRelease(_glfw.ns.displayLinks.entries[i].displayLink);
|
||||
_glfw.ns.displayLinks.entries[i].displayLink = nil;
|
||||
_glfw.ns.displayLinks.entries[i].lastRenderFrameRequestedAt = 0;
|
||||
}
|
||||
}
|
||||
_glfw.ns.displayLinks.count = 0;
|
||||
}
|
||||
|
||||
static CVReturn displayLinkCallback(
|
||||
CVDisplayLinkRef displayLink UNUSED,
|
||||
const CVTimeStamp* now UNUSED, const CVTimeStamp* outputTime UNUSED,
|
||||
CVOptionFlags flagsIn UNUSED, CVOptionFlags* flagsOut UNUSED, void* userInfo)
|
||||
{
|
||||
CGDirectDisplayID displayID = (CGDirectDisplayID)userInfo;
|
||||
NSNumber *arg = [NSNumber numberWithUnsignedInt:displayID];
|
||||
[NSApp performSelectorOnMainThread:@selector(render_frame_received:) withObject:arg waitUntilDone:NO];
|
||||
[arg release];
|
||||
return kCVReturnSuccess;
|
||||
}
|
||||
|
||||
static inline void createDisplayLink(CGDirectDisplayID displayID) {
|
||||
if (_glfw.ns.displayLinks.count >= sizeof(_glfw.ns.displayLinks.entries)/sizeof(_glfw.ns.displayLinks.entries[0]) - 1) return;
|
||||
for (size_t i = 0; i < _glfw.ns.displayLinks.count; i++) {
|
||||
if (_glfw.ns.displayLinks.entries[i].displayID == displayID) return;
|
||||
}
|
||||
_GLFWDisplayLinkNS *entry = &_glfw.ns.displayLinks.entries[_glfw.ns.displayLinks.count++];
|
||||
memset(entry, 0, sizeof(_GLFWDisplayLinkNS));
|
||||
entry->displayID = displayID;
|
||||
CVDisplayLinkCreateWithCGDisplay(displayID, &entry->displayLink);
|
||||
CVDisplayLinkSetOutputCallback(entry->displayLink, &displayLinkCallback, (void*)(uintptr_t)displayID);
|
||||
}
|
||||
|
||||
// Poll for changes in the set of connected monitors
|
||||
//
|
||||
void _glfwPollMonitorsNS(void)
|
||||
{
|
||||
uint32_t i, j, displayCount, disconnectedCount;
|
||||
CGDirectDisplayID* displays;
|
||||
_GLFWmonitor** disconnected = NULL;
|
||||
uint32_t displayCount;
|
||||
|
||||
CGGetOnlineDisplayList(0, NULL, &displayCount);
|
||||
displays = calloc(displayCount, sizeof(CGDirectDisplayID));
|
||||
CGDirectDisplayID* displays = calloc(displayCount, sizeof(CGDirectDisplayID));
|
||||
CGGetOnlineDisplayList(displayCount, displays, &displayCount);
|
||||
_glfwClearDisplayLinks();
|
||||
|
||||
for (i = 0; i < _glfw.monitorCount; i++)
|
||||
for (int i = 0; i < _glfw.monitorCount; i++)
|
||||
_glfw.monitors[i]->ns.screen = nil;
|
||||
|
||||
disconnectedCount = _glfw.monitorCount;
|
||||
_GLFWmonitor** disconnected = NULL;
|
||||
uint32_t disconnectedCount = _glfw.monitorCount;
|
||||
if (disconnectedCount)
|
||||
{
|
||||
disconnected = calloc(_glfw.monitorCount, sizeof(_GLFWmonitor*));
|
||||
@@ -241,19 +369,18 @@ void _glfwPollMonitorsNS(void)
|
||||
_glfw.monitorCount * sizeof(_GLFWmonitor*));
|
||||
}
|
||||
|
||||
for (i = 0; i < displayCount; i++)
|
||||
for (uint32_t i = 0; i < displayCount; i++)
|
||||
{
|
||||
_GLFWmonitor* monitor;
|
||||
const uint32_t unitNumber = CGDisplayUnitNumber(displays[i]);
|
||||
|
||||
if (CGDisplayIsAsleep(displays[i]))
|
||||
continue;
|
||||
|
||||
for (j = 0; j < disconnectedCount; j++)
|
||||
// HACK: Compare unit numbers instead of display IDs to work around
|
||||
// display replacement on machines with automatic graphics
|
||||
// switching
|
||||
const uint32_t unitNumber = CGDisplayUnitNumber(displays[i]);
|
||||
|
||||
for (uint32_t j = 0; j < disconnectedCount; j++)
|
||||
{
|
||||
// HACK: Compare unit numbers instead of display IDs to work around
|
||||
// display replacement on machines with automatic graphics
|
||||
// switching
|
||||
if (disconnected[j] && disconnected[j]->ns.unitNumber == unitNumber)
|
||||
{
|
||||
disconnected[j] = NULL;
|
||||
@@ -266,16 +393,22 @@ void _glfwPollMonitorsNS(void)
|
||||
if (!name)
|
||||
name = _glfw_strdup("Unknown");
|
||||
|
||||
monitor = _glfwAllocMonitor(name, size.width, size.height);
|
||||
_GLFWmonitor* monitor = _glfwAllocMonitor(name, (int)size.width, (int)size.height);
|
||||
monitor->ns.displayID = displays[i];
|
||||
monitor->ns.unitNumber = unitNumber;
|
||||
createDisplayLink(monitor->ns.displayID);
|
||||
|
||||
free(name);
|
||||
|
||||
CGDisplayModeRef mode = CGDisplayCopyDisplayMode(displays[i]);
|
||||
if (CGDisplayModeGetRefreshRate(mode) == 0.0)
|
||||
monitor->ns.fallbackRefreshRate = getFallbackRefreshRate(displays[i]);
|
||||
CGDisplayModeRelease(mode);
|
||||
|
||||
_glfwInputMonitor(monitor, GLFW_CONNECTED, _GLFW_INSERT_LAST);
|
||||
}
|
||||
|
||||
for (i = 0; i < disconnectedCount; i++)
|
||||
for (uint32_t i = 0; i < disconnectedCount; i++)
|
||||
{
|
||||
if (disconnected[i])
|
||||
_glfwInputMonitor(disconnected[i], GLFW_DISCONNECTED, 0);
|
||||
@@ -283,36 +416,32 @@ void _glfwPollMonitorsNS(void)
|
||||
|
||||
free(disconnected);
|
||||
free(displays);
|
||||
_glfwRestartDisplayLinks();
|
||||
}
|
||||
|
||||
// Change the current video mode
|
||||
//
|
||||
void _glfwSetVideoModeNS(_GLFWmonitor* monitor, const GLFWvidmode* desired)
|
||||
{
|
||||
CFArrayRef modes;
|
||||
CFIndex count, i;
|
||||
CVDisplayLinkRef link;
|
||||
CGDisplayModeRef native = NULL;
|
||||
GLFWvidmode current;
|
||||
const GLFWvidmode* best;
|
||||
|
||||
best = _glfwChooseVideoMode(monitor, desired);
|
||||
_glfwPlatformGetVideoMode(monitor, ¤t);
|
||||
|
||||
const GLFWvidmode* best = _glfwChooseVideoMode(monitor, desired);
|
||||
if (_glfwCompareVideoModes(¤t, best) == 0)
|
||||
return;
|
||||
|
||||
CVDisplayLinkCreateWithCGDisplay(monitor->ns.displayID, &link);
|
||||
CFArrayRef modes = CGDisplayCopyAllDisplayModes(monitor->ns.displayID, NULL);
|
||||
const CFIndex count = CFArrayGetCount(modes);
|
||||
CGDisplayModeRef native = NULL;
|
||||
|
||||
modes = CGDisplayCopyAllDisplayModes(monitor->ns.displayID, NULL);
|
||||
count = CFArrayGetCount(modes);
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
for (CFIndex i = 0; i < count; i++)
|
||||
{
|
||||
CGDisplayModeRef dm = (CGDisplayModeRef) CFArrayGetValueAtIndex(modes, i);
|
||||
if (!modeIsGood(dm))
|
||||
continue;
|
||||
|
||||
const GLFWvidmode mode = vidmodeFromCGDisplayMode(dm, link);
|
||||
const GLFWvidmode mode =
|
||||
vidmodeFromCGDisplayMode(dm, monitor->ns.fallbackRefreshRate);
|
||||
if (_glfwCompareVideoModes(best, &mode) == 0)
|
||||
{
|
||||
native = dm;
|
||||
@@ -331,7 +460,6 @@ void _glfwSetVideoModeNS(_GLFWmonitor* monitor, const GLFWvidmode* desired)
|
||||
}
|
||||
|
||||
CFRelease(modes);
|
||||
CVDisplayLinkRelease(link);
|
||||
}
|
||||
|
||||
// Restore the previously saved (original) video mode
|
||||
@@ -355,7 +483,7 @@ void _glfwRestoreVideoModeNS(_GLFWmonitor* monitor)
|
||||
////// GLFW platform API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void _glfwPlatformFreeMonitor(_GLFWmonitor* monitor)
|
||||
void _glfwPlatformFreeMonitor(_GLFWmonitor* monitor UNUSED)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -372,35 +500,8 @@ void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos)
|
||||
void _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor,
|
||||
float* xscale, float* yscale)
|
||||
{
|
||||
if (!monitor->ns.screen)
|
||||
{
|
||||
NSUInteger i;
|
||||
NSArray* screens = [NSScreen screens];
|
||||
|
||||
for (i = 0; i < [screens count]; i++)
|
||||
{
|
||||
NSScreen* screen = [screens objectAtIndex:i];
|
||||
NSNumber* displayID =
|
||||
[[screen deviceDescription] objectForKey:@"NSScreenNumber"];
|
||||
|
||||
// HACK: Compare unit numbers instead of display IDs to work around
|
||||
// display replacement on machines with automatic graphics
|
||||
// switching
|
||||
if (monitor->ns.unitNumber ==
|
||||
CGDisplayUnitNumber([displayID unsignedIntValue]))
|
||||
{
|
||||
monitor->ns.screen = screen;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == [screens count])
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Cocoa: Failed to find a screen for monitor");
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!refreshMonitorScreen(monitor))
|
||||
return;
|
||||
|
||||
const NSRect points = [monitor->ns.screen frame];
|
||||
const NSRect pixels = [monitor->ns.screen convertRectToBacking:points];
|
||||
@@ -411,30 +512,43 @@ void _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor,
|
||||
*yscale = (float) (pixels.size.height / points.size.height);
|
||||
}
|
||||
|
||||
void _glfwPlatformGetMonitorWorkarea(_GLFWmonitor* monitor,
|
||||
int* xpos, int* ypos,
|
||||
int* width, int* height)
|
||||
{
|
||||
if (!refreshMonitorScreen(monitor))
|
||||
return;
|
||||
|
||||
const NSRect frameRect = [monitor->ns.screen visibleFrame];
|
||||
|
||||
if (xpos)
|
||||
*xpos = (int)frameRect.origin.x;
|
||||
if (ypos)
|
||||
*ypos = (int)_glfwTransformYNS(frameRect.origin.y + frameRect.size.height - 1);
|
||||
if (width)
|
||||
*width = (int)frameRect.size.width;
|
||||
if (height)
|
||||
*height = (int)frameRect.size.height;
|
||||
}
|
||||
|
||||
GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count)
|
||||
{
|
||||
CFArrayRef modes;
|
||||
CFIndex found, i, j;
|
||||
GLFWvidmode* result;
|
||||
CVDisplayLinkRef link;
|
||||
|
||||
*count = 0;
|
||||
|
||||
CVDisplayLinkCreateWithCGDisplay(monitor->ns.displayID, &link);
|
||||
CFArrayRef modes = CGDisplayCopyAllDisplayModes(monitor->ns.displayID, NULL);
|
||||
const CFIndex found = CFArrayGetCount(modes);
|
||||
GLFWvidmode* result = calloc(found, sizeof(GLFWvidmode));
|
||||
|
||||
modes = CGDisplayCopyAllDisplayModes(monitor->ns.displayID, NULL);
|
||||
found = CFArrayGetCount(modes);
|
||||
result = calloc(found, sizeof(GLFWvidmode));
|
||||
|
||||
for (i = 0; i < found; i++)
|
||||
for (CFIndex i = 0; i < found; i++)
|
||||
{
|
||||
CGDisplayModeRef dm = (CGDisplayModeRef) CFArrayGetValueAtIndex(modes, i);
|
||||
if (!modeIsGood(dm))
|
||||
continue;
|
||||
|
||||
const GLFWvidmode mode = vidmodeFromCGDisplayMode(dm, link);
|
||||
const GLFWvidmode mode =
|
||||
vidmodeFromCGDisplayMode(dm, monitor->ns.fallbackRefreshRate);
|
||||
|
||||
for (j = 0; j < *count; j++)
|
||||
for (CFIndex j = 0; j < *count; j++)
|
||||
{
|
||||
if (_glfwCompareVideoModes(result + j, &mode) == 0)
|
||||
break;
|
||||
@@ -449,27 +563,19 @@ GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count)
|
||||
}
|
||||
|
||||
CFRelease(modes);
|
||||
CVDisplayLinkRelease(link);
|
||||
return result;
|
||||
}
|
||||
|
||||
void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode *mode)
|
||||
{
|
||||
CGDisplayModeRef displayMode;
|
||||
CVDisplayLinkRef link;
|
||||
|
||||
CVDisplayLinkCreateWithCGDisplay(monitor->ns.displayID, &link);
|
||||
|
||||
displayMode = CGDisplayCopyDisplayMode(monitor->ns.displayID);
|
||||
*mode = vidmodeFromCGDisplayMode(displayMode, link);
|
||||
CGDisplayModeRelease(displayMode);
|
||||
|
||||
CVDisplayLinkRelease(link);
|
||||
CGDisplayModeRef native = CGDisplayCopyDisplayMode(monitor->ns.displayID);
|
||||
*mode = vidmodeFromCGDisplayMode(native, monitor->ns.fallbackRefreshRate);
|
||||
CGDisplayModeRelease(native);
|
||||
}
|
||||
|
||||
GLFWbool _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
|
||||
bool _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
|
||||
{
|
||||
uint32_t i, size = CGDisplayGammaTableCapacity(monitor->ns.displayID);
|
||||
uint32_t size = CGDisplayGammaTableCapacity(monitor->ns.displayID);
|
||||
CGGammaValue* values = calloc(size * 3, sizeof(CGGammaValue));
|
||||
|
||||
CGGetDisplayTransferByTable(monitor->ns.displayID,
|
||||
@@ -481,7 +587,7 @@ GLFWbool _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
|
||||
|
||||
_glfwAllocGammaArrays(ramp, size);
|
||||
|
||||
for (i = 0; i < size; i++)
|
||||
for (uint32_t i = 0; i < size; i++)
|
||||
{
|
||||
ramp->red[i] = (unsigned short) (values[i] * 65535);
|
||||
ramp->green[i] = (unsigned short) (values[i + size] * 65535);
|
||||
@@ -489,15 +595,14 @@ GLFWbool _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
|
||||
}
|
||||
|
||||
free(values);
|
||||
return GLFW_TRUE;
|
||||
return true;
|
||||
}
|
||||
|
||||
void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp)
|
||||
{
|
||||
int i;
|
||||
CGGammaValue* values = calloc(ramp->size * 3, sizeof(CGGammaValue));
|
||||
|
||||
for (i = 0; i < ramp->size; i++)
|
||||
for (unsigned int i = 0; i < ramp->size; i++)
|
||||
{
|
||||
values[i] = ramp->red[i] / 65535.f;
|
||||
values[i + ramp->size] = ramp->green[i] / 65535.f;
|
||||
|
||||
98
glfw/cocoa_platform.h
vendored
98
glfw/cocoa_platform.h
vendored
@@ -1,7 +1,7 @@
|
||||
//========================================================================
|
||||
// GLFW 3.3 macOS - www.glfw.org
|
||||
// GLFW 3.4 macOS - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2009-2016 Camilla Löwy <elmindreda@glfw.org>
|
||||
// Copyright (c) 2009-2019 Camilla Löwy <elmindreda@glfw.org>
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
@@ -30,14 +30,49 @@
|
||||
#include <Carbon/Carbon.h>
|
||||
#if defined(__OBJC__)
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import <CoreVideo/CoreVideo.h>
|
||||
#else
|
||||
typedef void* id;
|
||||
typedef void* CVDisplayLinkRef;
|
||||
#endif
|
||||
|
||||
// NOTE: Many Cocoa enum values have been renamed and we need to build across
|
||||
// SDK versions where one is unavailable or the other deprecated
|
||||
// We use the newer names in code and these macros to handle compatibility
|
||||
#if MAC_OS_X_VERSION_MAX_ALLOWED < 101200
|
||||
#define NSBitmapFormatAlphaNonpremultiplied NSAlphaNonpremultipliedBitmapFormat
|
||||
#define NSEventMaskAny NSAnyEventMask
|
||||
#define NSEventMaskKeyUp NSKeyUpMask
|
||||
#define NSEventModifierFlagCapsLock NSAlphaShiftKeyMask
|
||||
#define NSEventModifierFlagCommand NSCommandKeyMask
|
||||
#define NSEventModifierFlagControl NSControlKeyMask
|
||||
#define NSEventModifierFlagDeviceIndependentFlagsMask NSDeviceIndependentModifierFlagsMask
|
||||
#define NSEventModifierFlagOption NSAlternateKeyMask
|
||||
#define NSEventModifierFlagShift NSShiftKeyMask
|
||||
#define NSEventTypeApplicationDefined NSApplicationDefined
|
||||
#define NSWindowStyleMaskBorderless NSBorderlessWindowMask
|
||||
#define NSWindowStyleMaskClosable NSClosableWindowMask
|
||||
#define NSWindowStyleMaskMiniaturizable NSMiniaturizableWindowMask
|
||||
#define NSWindowStyleMaskResizable NSResizableWindowMask
|
||||
#define NSWindowStyleMaskTitled NSTitledWindowMask
|
||||
#endif
|
||||
|
||||
#if (MAC_OS_X_VERSION_MAX_ALLOWED < 101400)
|
||||
#define NSPasteboardTypeFileURL NSFilenamesPboardType
|
||||
#define NSBitmapFormatAlphaNonpremultiplied NSAlphaNonpremultipliedBitmapFormat
|
||||
#define NSPasteboardTypeString NSStringPboardType
|
||||
#define NSOpenGLContextParameterSurfaceOpacity NSOpenGLCPSurfaceOpacity
|
||||
#endif
|
||||
|
||||
|
||||
typedef int (* GLFWcocoatextinputfilterfun)(int,int,unsigned int, unsigned long);
|
||||
typedef bool (* GLFWapplicationshouldhandlereopenfun)(int);
|
||||
typedef void (* GLFWapplicationwillfinishlaunchingfun)(void);
|
||||
typedef bool (* GLFWcocoatogglefullscreenfun)(GLFWwindow*);
|
||||
typedef void (* GLFWcocoarenderframefun)(GLFWwindow*);
|
||||
|
||||
typedef VkFlags VkMacOSSurfaceCreateFlagsMVK;
|
||||
typedef int (* GLFWcocoatextinputfilterfun)(int,int,int);
|
||||
typedef int (* GLFWapplicationshouldhandlereopenfun)(int);
|
||||
typedef int (* GLFWcocoatogglefullscreenfun)(GLFWwindow*);
|
||||
typedef VkFlags VkMetalSurfaceCreateFlagsEXT;
|
||||
|
||||
typedef struct VkMacOSSurfaceCreateInfoMVK
|
||||
{
|
||||
@@ -47,21 +82,25 @@ typedef struct VkMacOSSurfaceCreateInfoMVK
|
||||
const void* pView;
|
||||
} VkMacOSSurfaceCreateInfoMVK;
|
||||
|
||||
typedef struct VkMetalSurfaceCreateInfoEXT
|
||||
{
|
||||
VkStructureType sType;
|
||||
const void* pNext;
|
||||
VkMetalSurfaceCreateFlagsEXT flags;
|
||||
const void* pLayer;
|
||||
} VkMetalSurfaceCreateInfoEXT;
|
||||
|
||||
typedef VkResult (APIENTRY *PFN_vkCreateMacOSSurfaceMVK)(VkInstance,const VkMacOSSurfaceCreateInfoMVK*,const VkAllocationCallbacks*,VkSurfaceKHR*);
|
||||
typedef VkResult (APIENTRY *PFN_vkCreateMetalSurfaceEXT)(VkInstance,const VkMetalSurfaceCreateInfoEXT*,const VkAllocationCallbacks*,VkSurfaceKHR*);
|
||||
|
||||
#include "posix_thread.h"
|
||||
#include "cocoa_joystick.h"
|
||||
#include "nsgl_context.h"
|
||||
#include "egl_context.h"
|
||||
#include "osmesa_context.h"
|
||||
|
||||
#define _glfw_dlopen(name) dlopen(name, RTLD_LAZY | RTLD_LOCAL)
|
||||
#define _glfw_dlclose(handle) dlclose(handle)
|
||||
#define _glfw_dlsym(handle, name) dlsym(handle, name)
|
||||
|
||||
#define _GLFW_EGL_NATIVE_WINDOW ((EGLNativeWindowType) window->ns.view)
|
||||
#define _GLFW_EGL_NATIVE_DISPLAY EGL_DEFAULT_DISPLAY
|
||||
|
||||
#define _GLFW_PLATFORM_WINDOW_STATE _GLFWwindowNS ns
|
||||
#define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryNS ns
|
||||
#define _GLFW_PLATFORM_LIBRARY_TIMER_STATE _GLFWtimerNS ns
|
||||
@@ -87,7 +126,8 @@ typedef struct _GLFWwindowNS
|
||||
id view;
|
||||
id layer;
|
||||
|
||||
GLFWbool maximized;
|
||||
bool maximized;
|
||||
bool retina;
|
||||
|
||||
// Cached window properties to filter out duplicate events
|
||||
int width, height;
|
||||
@@ -105,27 +145,38 @@ typedef struct _GLFWwindowNS
|
||||
GLFWcocoatogglefullscreenfun toggleFullscreenCallback;
|
||||
// Dead key state
|
||||
UInt32 deadKeyState;
|
||||
// Whether a render frame has been requested for this window
|
||||
bool renderFrameRequested;
|
||||
GLFWcocoarenderframefun renderFrameCallback;
|
||||
} _GLFWwindowNS;
|
||||
|
||||
typedef struct _GLFWDisplayLinkNS
|
||||
{
|
||||
CVDisplayLinkRef displayLink;
|
||||
CGDirectDisplayID displayID;
|
||||
monotonic_t lastRenderFrameRequestedAt;
|
||||
} _GLFWDisplayLinkNS;
|
||||
|
||||
// Cocoa-specific global data
|
||||
//
|
||||
typedef struct _GLFWlibraryNS
|
||||
{
|
||||
CGEventSourceRef eventSource;
|
||||
id delegate;
|
||||
id autoreleasePool;
|
||||
GLFWbool cursorHidden;
|
||||
bool finishedLaunching;
|
||||
bool cursorHidden;
|
||||
TISInputSourceRef inputSource;
|
||||
IOHIDManagerRef hidManager;
|
||||
id unicodeData;
|
||||
id helper;
|
||||
id keyUpMonitor;
|
||||
id keyDownMonitor;
|
||||
id nibObjects;
|
||||
|
||||
char keyName[64];
|
||||
char text[256];
|
||||
short int keycodes[256];
|
||||
short int scancodes[GLFW_KEY_LAST + 1];
|
||||
short int key_to_keycode[GLFW_KEY_LAST + 1];
|
||||
char* clipboardString;
|
||||
CGPoint cascadePoint;
|
||||
// Where to place the cursor when re-enabled
|
||||
@@ -141,6 +192,11 @@ typedef struct _GLFWlibraryNS
|
||||
CFStringRef kPropertyUnicodeKeyLayoutData;
|
||||
} tis;
|
||||
|
||||
struct {
|
||||
_GLFWDisplayLinkNS entries[256];
|
||||
size_t count;
|
||||
} displayLinks;
|
||||
|
||||
} _GLFWlibraryNS;
|
||||
|
||||
// Cocoa-specific per-monitor data
|
||||
@@ -151,6 +207,7 @@ typedef struct _GLFWmonitorNS
|
||||
CGDisplayModeRef previousMode;
|
||||
uint32_t unitNumber;
|
||||
id screen;
|
||||
double fallbackRefreshRate;
|
||||
|
||||
} _GLFWmonitorNS;
|
||||
|
||||
@@ -171,8 +228,17 @@ typedef struct _GLFWtimerNS
|
||||
} _GLFWtimerNS;
|
||||
|
||||
|
||||
void _glfwInitTimerNS(void);
|
||||
|
||||
void _glfwPollMonitorsNS(void);
|
||||
void _glfwSetVideoModeNS(_GLFWmonitor* monitor, const GLFWvidmode* desired);
|
||||
void _glfwRestoreVideoModeNS(_GLFWmonitor* monitor);
|
||||
|
||||
float _glfwTransformYNS(float y);
|
||||
|
||||
void* _glfwLoadLocalVulkanLoaderNS(void);
|
||||
|
||||
void _glfwClearDisplayLinks(void);
|
||||
void _glfwRestartDisplayLinks(void);
|
||||
void _glfwDispatchTickCallback(void);
|
||||
void _glfwDispatchRenderFrame(CGDirectDisplayID);
|
||||
void _glfwShutdownCVDisplayLink(unsigned long long, void*);
|
||||
void _glfwCocoaPostEmptyEvent(void);
|
||||
|
||||
60
glfw/cocoa_time.c
vendored
60
glfw/cocoa_time.c
vendored
@@ -1,60 +0,0 @@
|
||||
//========================================================================
|
||||
// GLFW 3.3 macOS - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2009-2016 Camilla Löwy <elmindreda@glfw.org>
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would
|
||||
// be appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such, and must not
|
||||
// be misrepresented as being the original software.
|
||||
//
|
||||
// 3. This notice may not be removed or altered from any source
|
||||
// distribution.
|
||||
//
|
||||
//========================================================================
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
#include <mach/mach_time.h>
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW internal API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Initialise timer
|
||||
//
|
||||
void _glfwInitTimerNS(void)
|
||||
{
|
||||
mach_timebase_info_data_t info;
|
||||
mach_timebase_info(&info);
|
||||
|
||||
_glfw.timer.ns.frequency = (info.denom * 1e9) / info.numer;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW platform API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
uint64_t _glfwPlatformGetTimerValue(void)
|
||||
{
|
||||
return mach_absolute_time();
|
||||
}
|
||||
|
||||
uint64_t _glfwPlatformGetTimerFrequency(void)
|
||||
{
|
||||
return _glfw.timer.ns.frequency;
|
||||
}
|
||||
|
||||
1571
glfw/cocoa_window.m
1571
glfw/cocoa_window.m
File diff suppressed because it is too large
Load Diff
241
glfw/context.c
vendored
241
glfw/context.c
vendored
@@ -1,5 +1,5 @@
|
||||
//========================================================================
|
||||
// GLFW 3.3 - www.glfw.org
|
||||
// GLFW 3.4 - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||
// Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
|
||||
@@ -24,6 +24,8 @@
|
||||
// distribution.
|
||||
//
|
||||
//========================================================================
|
||||
// Please use C89 style variable declarations in this file because VS 2010
|
||||
//========================================================================
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
@@ -44,7 +46,7 @@
|
||||
// exists and whether all relevant options have supported and non-conflicting
|
||||
// values
|
||||
//
|
||||
GLFWbool _glfwIsValidContextConfig(const _GLFWctxconfig* ctxconfig)
|
||||
bool _glfwIsValidContextConfig(const _GLFWctxconfig* ctxconfig)
|
||||
{
|
||||
if (ctxconfig->share)
|
||||
{
|
||||
@@ -52,7 +54,7 @@ GLFWbool _glfwIsValidContextConfig(const _GLFWctxconfig* ctxconfig)
|
||||
ctxconfig->share->context.client == GLFW_NO_API)
|
||||
{
|
||||
_glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,7 +65,7 @@ GLFWbool _glfwIsValidContextConfig(const _GLFWctxconfig* ctxconfig)
|
||||
_glfwInputError(GLFW_INVALID_ENUM,
|
||||
"Invalid context creation API 0x%08X",
|
||||
ctxconfig->source);
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ctxconfig->client != GLFW_NO_API &&
|
||||
@@ -73,7 +75,7 @@ GLFWbool _glfwIsValidContextConfig(const _GLFWctxconfig* ctxconfig)
|
||||
_glfwInputError(GLFW_INVALID_ENUM,
|
||||
"Invalid client API 0x%08X",
|
||||
ctxconfig->client);
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ctxconfig->client == GLFW_OPENGL_API)
|
||||
@@ -92,7 +94,7 @@ GLFWbool _glfwIsValidContextConfig(const _GLFWctxconfig* ctxconfig)
|
||||
_glfwInputError(GLFW_INVALID_VALUE,
|
||||
"Invalid OpenGL version %i.%i",
|
||||
ctxconfig->major, ctxconfig->minor);
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ctxconfig->profile)
|
||||
@@ -103,7 +105,7 @@ GLFWbool _glfwIsValidContextConfig(const _GLFWctxconfig* ctxconfig)
|
||||
_glfwInputError(GLFW_INVALID_ENUM,
|
||||
"Invalid OpenGL profile 0x%08X",
|
||||
ctxconfig->profile);
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ctxconfig->major <= 2 ||
|
||||
@@ -114,7 +116,7 @@ GLFWbool _glfwIsValidContextConfig(const _GLFWctxconfig* ctxconfig)
|
||||
|
||||
_glfwInputError(GLFW_INVALID_VALUE,
|
||||
"Context profiles are only defined for OpenGL version 3.2 and above");
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,7 +125,7 @@ GLFWbool _glfwIsValidContextConfig(const _GLFWctxconfig* ctxconfig)
|
||||
// Forward-compatible contexts are only defined for OpenGL version 3.0 and above
|
||||
_glfwInputError(GLFW_INVALID_VALUE,
|
||||
"Forward-compatibility is only defined for OpenGL version 3.0 and above");
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (ctxconfig->client == GLFW_OPENGL_ES_API)
|
||||
@@ -140,7 +142,7 @@ GLFWbool _glfwIsValidContextConfig(const _GLFWctxconfig* ctxconfig)
|
||||
_glfwInputError(GLFW_INVALID_VALUE,
|
||||
"Invalid OpenGL ES version %i.%i",
|
||||
ctxconfig->major, ctxconfig->minor);
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -152,7 +154,7 @@ GLFWbool _glfwIsValidContextConfig(const _GLFWctxconfig* ctxconfig)
|
||||
_glfwInputError(GLFW_INVALID_ENUM,
|
||||
"Invalid context robustness mode 0x%08X",
|
||||
ctxconfig->robustness);
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,184 +166,16 @@ GLFWbool _glfwIsValidContextConfig(const _GLFWctxconfig* ctxconfig)
|
||||
_glfwInputError(GLFW_INVALID_ENUM,
|
||||
"Invalid context release behavior 0x%08X",
|
||||
ctxconfig->release);
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return GLFW_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;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Retrieves the attributes of the current context
|
||||
//
|
||||
GLFWbool _glfwRefreshContextAttribs(_GLFWwindow* window,
|
||||
bool _glfwRefreshContextAttribs(_GLFWwindow* window,
|
||||
const _GLFWctxconfig* ctxconfig)
|
||||
{
|
||||
int i;
|
||||
@@ -358,7 +192,7 @@ GLFWbool _glfwRefreshContextAttribs(_GLFWwindow* window,
|
||||
window->context.source = ctxconfig->source;
|
||||
window->context.client = GLFW_OPENGL_API;
|
||||
|
||||
previous = _glfwPlatformGetTls(&_glfw.contextSlot);;
|
||||
previous = _glfwPlatformGetTls(&_glfw.contextSlot);
|
||||
glfwMakeContextCurrent((GLFWwindow*) window);
|
||||
|
||||
window->context.GetIntegerv = (PFNGLGETINTEGERVPROC)
|
||||
@@ -369,7 +203,7 @@ GLFWbool _glfwRefreshContextAttribs(_GLFWwindow* window,
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR, "Entry point retrieval is broken");
|
||||
glfwMakeContextCurrent((GLFWwindow*) previous);
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
}
|
||||
|
||||
version = (const char*) window->context.GetString(GL_VERSION);
|
||||
@@ -387,7 +221,7 @@ GLFWbool _glfwRefreshContextAttribs(_GLFWwindow* window,
|
||||
}
|
||||
|
||||
glfwMakeContextCurrent((GLFWwindow*) previous);
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
}
|
||||
|
||||
for (i = 0; prefixes[i]; i++)
|
||||
@@ -419,7 +253,7 @@ GLFWbool _glfwRefreshContextAttribs(_GLFWwindow* window,
|
||||
}
|
||||
|
||||
glfwMakeContextCurrent((GLFWwindow*) previous);
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (window->context.major < ctxconfig->major ||
|
||||
@@ -449,7 +283,7 @@ GLFWbool _glfwRefreshContextAttribs(_GLFWwindow* window,
|
||||
}
|
||||
|
||||
glfwMakeContextCurrent((GLFWwindow*) previous);
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (window->context.major >= 3)
|
||||
@@ -465,7 +299,7 @@ GLFWbool _glfwRefreshContextAttribs(_GLFWwindow* window,
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Entry point retrieval is broken");
|
||||
glfwMakeContextCurrent((GLFWwindow*) previous);
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -478,21 +312,21 @@ GLFWbool _glfwRefreshContextAttribs(_GLFWwindow* window,
|
||||
window->context.GetIntegerv(GL_CONTEXT_FLAGS, &flags);
|
||||
|
||||
if (flags & GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT)
|
||||
window->context.forward = GLFW_TRUE;
|
||||
window->context.forward = true;
|
||||
|
||||
if (flags & GL_CONTEXT_FLAG_DEBUG_BIT)
|
||||
window->context.debug = GLFW_TRUE;
|
||||
window->context.debug = true;
|
||||
else if (glfwExtensionSupported("GL_ARB_debug_output") &&
|
||||
ctxconfig->debug)
|
||||
{
|
||||
// HACK: This is a workaround for older drivers (pre KHR_debug)
|
||||
// not setting the debug bit in the context flags for
|
||||
// debug contexts
|
||||
window->context.debug = GLFW_TRUE;
|
||||
window->context.debug = true;
|
||||
}
|
||||
|
||||
if (flags & GL_CONTEXT_FLAG_NO_ERROR_BIT_KHR)
|
||||
window->context.noerror = GLFW_TRUE;
|
||||
window->context.noerror = true;
|
||||
}
|
||||
|
||||
// Read back OpenGL context profile (OpenGL 3.2 and above)
|
||||
@@ -572,12 +406,12 @@ GLFWbool _glfwRefreshContextAttribs(_GLFWwindow* window,
|
||||
}
|
||||
|
||||
glfwMakeContextCurrent((GLFWwindow*) previous);
|
||||
return GLFW_TRUE;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Searches an extension string for the specified extension
|
||||
//
|
||||
GLFWbool _glfwStringInExtensionString(const char* string, const char* extensions)
|
||||
bool _glfwStringInExtensionString(const char* string, const char* extensions)
|
||||
{
|
||||
const char* start = extensions;
|
||||
|
||||
@@ -588,7 +422,7 @@ GLFWbool _glfwStringInExtensionString(const char* string, const char* extensions
|
||||
|
||||
where = strstr(start, string);
|
||||
if (!where)
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
|
||||
terminator = where + strlen(string);
|
||||
if (where == start || *(where - 1) == ' ')
|
||||
@@ -600,7 +434,7 @@ GLFWbool _glfwStringInExtensionString(const char* string, const char* extensions
|
||||
start = terminator;
|
||||
}
|
||||
|
||||
return GLFW_TRUE;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -677,20 +511,20 @@ GLFWAPI int glfwExtensionSupported(const char* extension)
|
||||
_GLFWwindow* window;
|
||||
assert(extension != NULL);
|
||||
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE);
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(false);
|
||||
|
||||
window = _glfwPlatformGetTls(&_glfw.contextSlot);
|
||||
if (!window)
|
||||
{
|
||||
_glfwInputError(GLFW_NO_CURRENT_CONTEXT,
|
||||
"Cannot query extension without a current OpenGL or OpenGL ES context");
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (*extension == '\0')
|
||||
{
|
||||
_glfwInputError(GLFW_INVALID_VALUE, "Extension name cannot be an empty string");
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (window->context.major >= 3)
|
||||
@@ -710,11 +544,11 @@ GLFWAPI int glfwExtensionSupported(const char* extension)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Extension string retrieval is broken");
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (strcmp(en, extension) == 0)
|
||||
return GLFW_TRUE;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -727,11 +561,11 @@ GLFWAPI int glfwExtensionSupported(const char* extension)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Extension string retrieval is broken");
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_glfwStringInExtensionString(extension, extensions))
|
||||
return GLFW_TRUE;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check if extension is in the platform-specific string
|
||||
@@ -755,4 +589,3 @@ GLFWAPI GLFWglproc glfwGetProcAddress(const char* procname)
|
||||
|
||||
return window->context.getProcAddress(procname);
|
||||
}
|
||||
|
||||
|
||||
139
glfw/dbus_glfw.c
vendored
139
glfw/dbus_glfw.c
vendored
@@ -1,5 +1,5 @@
|
||||
//========================================================================
|
||||
// GLFW 3.3 XKB - www.glfw.org
|
||||
// GLFW 3.4 XKB - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2018 Kovid Goyal <kovid@kovidgoyal.net>
|
||||
//
|
||||
@@ -27,6 +27,7 @@
|
||||
|
||||
#include "internal.h"
|
||||
#include "dbus_glfw.h"
|
||||
#include "../kitty/monotonic.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
@@ -43,16 +44,17 @@ report_error(DBusError *err, const char *fmt, ...) {
|
||||
}
|
||||
|
||||
static _GLFWDBUSData *dbus_data = NULL;
|
||||
static DBusConnection *session_bus = NULL;
|
||||
|
||||
GLFWbool
|
||||
bool
|
||||
glfw_dbus_init(_GLFWDBUSData *dbus, EventLoopData *eld) {
|
||||
dbus->eld = eld;
|
||||
dbus_data = dbus;
|
||||
return GLFW_TRUE;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
on_dbus_watch_ready(int fd, int events, void *data) {
|
||||
on_dbus_watch_ready(int fd UNUSED, int events, void *data) {
|
||||
DBusWatch *watch = (DBusWatch*)data;
|
||||
unsigned int flags = 0;
|
||||
if (events & POLLERR) flags |= DBUS_WATCH_ERROR;
|
||||
@@ -83,19 +85,19 @@ add_dbus_watch(DBusWatch *watch, void *data) {
|
||||
}
|
||||
|
||||
static void
|
||||
remove_dbus_watch(DBusWatch *watch, void *data) {
|
||||
remove_dbus_watch(DBusWatch *watch, void *data UNUSED) {
|
||||
id_type *idp = dbus_watch_get_data(watch);
|
||||
if (idp) removeWatch(dbus_data->eld, *idp);
|
||||
}
|
||||
|
||||
static void
|
||||
toggle_dbus_watch(DBusWatch *watch, void *data) {
|
||||
toggle_dbus_watch(DBusWatch *watch, void *data UNUSED) {
|
||||
id_type *idp = dbus_watch_get_data(watch);
|
||||
if (idp) toggleWatch(dbus_data->eld, *idp, dbus_watch_get_enabled(watch));
|
||||
}
|
||||
|
||||
static void
|
||||
on_dbus_timer_ready(id_type timer_id, void *data) {
|
||||
on_dbus_timer_ready(id_type timer_id UNUSED, void *data) {
|
||||
if (data) {
|
||||
DBusTimeout *t = (DBusTimeout*)data;
|
||||
dbus_timeout_handle(t);
|
||||
@@ -106,9 +108,9 @@ on_dbus_timer_ready(id_type timer_id, void *data) {
|
||||
static dbus_bool_t
|
||||
add_dbus_timeout(DBusTimeout *timeout, void *data) {
|
||||
int enabled = dbus_timeout_get_enabled(timeout) ? 1 : 0;
|
||||
double interval = ((double)dbus_timeout_get_interval(timeout)) / 1000.0;
|
||||
monotonic_t interval = ms_to_monotonic_t(dbus_timeout_get_interval(timeout));
|
||||
if (interval < 0) return FALSE;
|
||||
id_type timer_id = addTimer(dbus_data->eld, data, interval, enabled, on_dbus_timer_ready, timeout);
|
||||
id_type timer_id = addTimer(dbus_data->eld, data, interval, enabled, true, on_dbus_timer_ready, timeout, NULL);
|
||||
if (!timer_id) return FALSE;
|
||||
id_type *idp = malloc(sizeof(id_type));
|
||||
if (!idp) {
|
||||
@@ -122,20 +124,20 @@ add_dbus_timeout(DBusTimeout *timeout, void *data) {
|
||||
}
|
||||
|
||||
static void
|
||||
remove_dbus_timeout(DBusTimeout *timeout, void *data) {
|
||||
remove_dbus_timeout(DBusTimeout *timeout, void *data UNUSED) {
|
||||
id_type *idp = dbus_timeout_get_data(timeout);
|
||||
if (idp) removeTimer(dbus_data->eld, *idp);
|
||||
}
|
||||
|
||||
static void
|
||||
toggle_dbus_timeout(DBusTimeout *timeout, void *data) {
|
||||
toggle_dbus_timeout(DBusTimeout *timeout, void *data UNUSED) {
|
||||
id_type *idp = dbus_timeout_get_data(timeout);
|
||||
if (idp) toggleTimer(dbus_data->eld, *idp, dbus_timeout_get_enabled(timeout));
|
||||
}
|
||||
|
||||
|
||||
DBusConnection*
|
||||
glfw_dbus_connect_to(const char *path, const char* err_msg, const char *name, GLFWbool register_on_bus) {
|
||||
glfw_dbus_connect_to(const char *path, const char* err_msg, const char *name, bool register_on_bus) {
|
||||
DBusError err;
|
||||
dbus_error_init(&err);
|
||||
DBusConnection *ans = dbus_connection_open_private(path, &err);
|
||||
@@ -172,11 +174,20 @@ glfw_dbus_dispatch(DBusConnection *conn) {
|
||||
}
|
||||
|
||||
void
|
||||
glfw_dbus_terminate(_GLFWDBUSData *dbus) {
|
||||
glfw_dbus_session_bus_dispatch() {
|
||||
if (session_bus) glfw_dbus_dispatch(session_bus);
|
||||
}
|
||||
|
||||
void
|
||||
glfw_dbus_terminate(_GLFWDBUSData *dbus UNUSED) {
|
||||
if (dbus_data) {
|
||||
dbus_data->eld = NULL;
|
||||
dbus_data = NULL;
|
||||
}
|
||||
if (session_bus) {
|
||||
dbus_connection_unref(session_bus);
|
||||
session_bus = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@@ -185,14 +196,14 @@ glfw_dbus_close_connection(DBusConnection *conn) {
|
||||
dbus_connection_unref(conn);
|
||||
}
|
||||
|
||||
GLFWbool
|
||||
bool
|
||||
glfw_dbus_get_args(DBusMessage *msg, const char *failmsg, ...) {
|
||||
DBusError err;
|
||||
dbus_error_init(&err);
|
||||
va_list ap;
|
||||
va_start(ap, failmsg);
|
||||
int firstarg = va_arg(ap, int);
|
||||
GLFWbool ret = dbus_message_get_args_valist(msg, &err, firstarg, ap) ? GLFW_TRUE : GLFW_FALSE;
|
||||
bool ret = dbus_message_get_args_valist(msg, &err, firstarg, ap) ? true : false;
|
||||
va_end(ap);
|
||||
if (!ret) report_error(&err, failmsg);
|
||||
return ret;
|
||||
@@ -223,34 +234,43 @@ method_reply_received(DBusPendingCall *pending, void *user_data) {
|
||||
}
|
||||
}
|
||||
|
||||
static GLFWbool
|
||||
bool
|
||||
call_method_with_msg(DBusConnection *conn, DBusMessage *msg, int timeout, dbus_pending_callback callback, void *user_data) {
|
||||
bool retval = false;
|
||||
#define REPORT(errs) _glfwInputError(GLFW_PLATFORM_ERROR, "Failed to call DBUS method: node=%s path=%s interface=%s method=%s, with error: %s", dbus_message_get_destination(msg), dbus_message_get_path(msg), dbus_message_get_interface(msg), dbus_message_get_member(msg), errs)
|
||||
if (callback) {
|
||||
DBusPendingCall *pending = NULL;
|
||||
if (dbus_connection_send_with_reply(conn, msg, &pending, timeout)) {
|
||||
MethodResponse *res = malloc(sizeof(MethodResponse));
|
||||
if (!res) return false;
|
||||
res->callback = callback;
|
||||
res->user_data = user_data;
|
||||
dbus_pending_call_set_notify(pending, method_reply_received, res, free);
|
||||
retval = true;
|
||||
} else {
|
||||
REPORT("out of memory");
|
||||
}
|
||||
} else {
|
||||
if (dbus_connection_send(conn, msg, NULL)) {
|
||||
retval = true;
|
||||
} else {
|
||||
REPORT("out of memory");
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
#undef REPORT
|
||||
}
|
||||
|
||||
static bool
|
||||
call_method(DBusConnection *conn, const char *node, const char *path, const char *interface, const char *method, int timeout, dbus_pending_callback callback, void *user_data, va_list ap) {
|
||||
if (!conn) return GLFW_FALSE;
|
||||
if (!conn) return false;
|
||||
DBusMessage *msg = dbus_message_new_method_call(node, path, interface, method);
|
||||
if (!msg) return GLFW_FALSE;
|
||||
GLFWbool retval = GLFW_FALSE;
|
||||
MethodResponse *res = malloc(sizeof(MethodResponse));
|
||||
if (!res) { dbus_message_unref(msg); return GLFW_FALSE; }
|
||||
res->callback = callback;
|
||||
res->user_data = user_data;
|
||||
if (!msg) return false;
|
||||
bool retval = false;
|
||||
|
||||
int firstarg = va_arg(ap, int);
|
||||
if ((firstarg == DBUS_TYPE_INVALID) || dbus_message_append_args_valist(msg, firstarg, ap)) {
|
||||
if (callback) {
|
||||
DBusPendingCall *pending = NULL;
|
||||
if (dbus_connection_send_with_reply(conn, msg, &pending, timeout)) {
|
||||
dbus_pending_call_set_notify(pending, method_reply_received, res, free);
|
||||
retval = GLFW_TRUE;
|
||||
} else {
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR, "Failed to call DBUS method: %s on node: %s and interface: %s out of memory", method, node, interface);
|
||||
}
|
||||
} else {
|
||||
if (dbus_connection_send(conn, msg, NULL)) {
|
||||
retval = GLFW_TRUE;
|
||||
} else {
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR, "Failed to call DBUS method: %s on node: %s and interface: %s out of memory", method, node, interface);
|
||||
}
|
||||
}
|
||||
retval = call_method_with_msg(conn, msg, timeout, callback, user_data);
|
||||
} else {
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR, "Failed to call DBUS method: %s on node: %s and interface: %s could not add arguments", method, node, interface);
|
||||
}
|
||||
@@ -259,9 +279,9 @@ call_method(DBusConnection *conn, const char *node, const char *path, const char
|
||||
return retval;
|
||||
}
|
||||
|
||||
GLFWbool
|
||||
bool
|
||||
glfw_dbus_call_method_with_reply(DBusConnection *conn, const char *node, const char *path, const char *interface, const char *method, int timeout, dbus_pending_callback callback, void* user_data, ...) {
|
||||
GLFWbool retval;
|
||||
bool retval;
|
||||
va_list ap;
|
||||
va_start(ap, user_data);
|
||||
retval = call_method(conn, node, path, interface, method, timeout, callback, user_data, ap);
|
||||
@@ -269,9 +289,9 @@ glfw_dbus_call_method_with_reply(DBusConnection *conn, const char *node, const c
|
||||
return retval;
|
||||
}
|
||||
|
||||
GLFWbool
|
||||
bool
|
||||
glfw_dbus_call_method_no_reply(DBusConnection *conn, const char *node, const char *path, const char *interface, const char *method, ...) {
|
||||
GLFWbool retval;
|
||||
bool retval;
|
||||
va_list ap;
|
||||
va_start(ap, method);
|
||||
retval = call_method(conn, node, path, interface, method, DBUS_TIMEOUT_USE_DEFAULT, NULL, NULL, ap);
|
||||
@@ -293,3 +313,38 @@ glfw_dbus_match_signal(DBusMessage *msg, const char *interface, ...) {
|
||||
va_end(ap);
|
||||
return ans;
|
||||
}
|
||||
|
||||
static void
|
||||
glfw_dbus_connect_to_session_bus(void) {
|
||||
DBusError error;
|
||||
dbus_error_init(&error);
|
||||
if (session_bus) {
|
||||
dbus_connection_unref(session_bus);
|
||||
}
|
||||
session_bus = dbus_bus_get(DBUS_BUS_SESSION, &error);
|
||||
if (dbus_error_is_set(&error)) {
|
||||
report_error(&error, "Failed to connect to DBUS session bus");
|
||||
session_bus = NULL;
|
||||
return;
|
||||
}
|
||||
static const char *name = "session-bus";
|
||||
if (!dbus_connection_set_watch_functions(session_bus, add_dbus_watch, remove_dbus_watch, toggle_dbus_watch, (void*)name, NULL)) {
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR, "Failed to set DBUS watches on connection to: %s", name);
|
||||
dbus_connection_close(session_bus);
|
||||
dbus_connection_unref(session_bus);
|
||||
return;
|
||||
}
|
||||
if (!dbus_connection_set_timeout_functions(session_bus, add_dbus_timeout, remove_dbus_timeout, toggle_dbus_timeout, (void*)name, NULL)) {
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR, "Failed to set DBUS timeout functions on connection to: %s", name);
|
||||
dbus_connection_close(session_bus);
|
||||
dbus_connection_unref(session_bus);
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
DBusConnection *
|
||||
glfw_dbus_session_bus() {
|
||||
if (!session_bus) glfw_dbus_connect_to_session_bus();
|
||||
return session_bus;
|
||||
}
|
||||
|
||||
16
glfw/dbus_glfw.h
vendored
16
glfw/dbus_glfw.h
vendored
@@ -1,5 +1,5 @@
|
||||
//========================================================================
|
||||
// GLFW 3.3 XKB - www.glfw.org
|
||||
// GLFW 3.4 XKB - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2018 Kovid Goyal <kovid@kovidgoyal.net>
|
||||
//
|
||||
@@ -37,14 +37,18 @@ typedef struct {
|
||||
} _GLFWDBUSData;
|
||||
|
||||
|
||||
GLFWbool glfw_dbus_init(_GLFWDBUSData *dbus, EventLoopData *eld);
|
||||
bool glfw_dbus_init(_GLFWDBUSData *dbus, EventLoopData *eld);
|
||||
void glfw_dbus_terminate(_GLFWDBUSData *dbus);
|
||||
DBusConnection* glfw_dbus_connect_to(const char *path, const char* err_msg, const char* name, GLFWbool register_on_bus);
|
||||
DBusConnection* glfw_dbus_connect_to(const char *path, const char* err_msg, const char* name, bool register_on_bus);
|
||||
void glfw_dbus_close_connection(DBusConnection *conn);
|
||||
GLFWbool
|
||||
bool
|
||||
call_method_with_msg(DBusConnection *conn, DBusMessage *msg, int timeout, dbus_pending_callback callback, void *user_data);
|
||||
bool
|
||||
glfw_dbus_call_method_no_reply(DBusConnection *conn, const char *node, const char *path, const char *interface, const char *method, ...);
|
||||
GLFWbool
|
||||
bool
|
||||
glfw_dbus_call_method_with_reply(DBusConnection *conn, const char *node, const char *path, const char *interface, const char *method, int timeout_ms, dbus_pending_callback callback, void *user_data, ...);
|
||||
void glfw_dbus_dispatch(DBusConnection *);
|
||||
GLFWbool glfw_dbus_get_args(DBusMessage *msg, const char *failmsg, ...);
|
||||
void glfw_dbus_session_bus_dispatch(void);
|
||||
bool glfw_dbus_get_args(DBusMessage *msg, const char *failmsg, ...);
|
||||
int glfw_dbus_match_signal(DBusMessage *msg, const char *interface, ...);
|
||||
DBusConnection* glfw_dbus_session_bus(void);
|
||||
|
||||
331
glfw/egl_context.c
vendored
331
glfw/egl_context.c
vendored
@@ -1,8 +1,8 @@
|
||||
//========================================================================
|
||||
// GLFW 3.3 EGL - www.glfw.org
|
||||
// GLFW 3.4 EGL - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||
// Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
|
||||
// Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
@@ -24,6 +24,8 @@
|
||||
// distribution.
|
||||
//
|
||||
//========================================================================
|
||||
// Please use C89 style variable declarations in this file because VS 2010
|
||||
//========================================================================
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
@@ -74,6 +76,7 @@ static const char* getEGLErrorString(EGLint error)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef _GLFW_X11
|
||||
// Returns the specified attribute of the specified EGLConfig
|
||||
//
|
||||
static int getEGLConfigAttrib(EGLConfig config, int attrib)
|
||||
@@ -82,108 +85,78 @@ static int getEGLConfigAttrib(EGLConfig config, int attrib)
|
||||
eglGetConfigAttrib(_glfw.egl.display, config, attrib, &value);
|
||||
return value;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Return the EGLConfig most closely matching the specified hints
|
||||
//
|
||||
static GLFWbool chooseEGLConfig(const _GLFWctxconfig* ctxconfig,
|
||||
static bool chooseEGLConfig(const _GLFWctxconfig* ctxconfig,
|
||||
const _GLFWfbconfig* desired,
|
||||
EGLConfig* result)
|
||||
{
|
||||
EGLConfig* nativeConfigs;
|
||||
_GLFWfbconfig* usableConfigs;
|
||||
const _GLFWfbconfig* closest;
|
||||
int i, nativeCount, usableCount;
|
||||
EGLConfig configs[512];
|
||||
int i = 0, nativeCount = 0, ans_idx = 0;
|
||||
EGLint attributes[64];
|
||||
#define ATTR(k, v) { attributes[i++] = k; attributes[i++] = v; }
|
||||
ATTR(EGL_COLOR_BUFFER_TYPE, EGL_RGB_BUFFER);
|
||||
ATTR(EGL_SURFACE_TYPE, EGL_WINDOW_BIT);
|
||||
if (ctxconfig->client == GLFW_OPENGL_ES_API) {
|
||||
if (ctxconfig->major == 1) ATTR(EGL_RENDERABLE_TYPE, EGL_OPENGL_ES_BIT)
|
||||
else ATTR(EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT);
|
||||
}
|
||||
else if (ctxconfig->client == GLFW_OPENGL_API) ATTR(EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT);
|
||||
if (desired->samples > 0) ATTR(EGL_SAMPLES, desired->samples);
|
||||
if (desired->depthBits > 0) ATTR(EGL_DEPTH_SIZE, desired->depthBits);
|
||||
if (desired->stencilBits > 0) ATTR(EGL_STENCIL_SIZE, desired->stencilBits);
|
||||
if (desired->redBits > 0) ATTR(EGL_RED_SIZE, desired->redBits);
|
||||
if (desired->greenBits > 0) ATTR(EGL_GREEN_SIZE, desired->greenBits);
|
||||
if (desired->blueBits > 0) ATTR(EGL_BLUE_SIZE, desired->blueBits);
|
||||
if (desired->alphaBits > 0) ATTR(EGL_ALPHA_SIZE, desired->alphaBits);
|
||||
ATTR(EGL_NONE, EGL_NONE);
|
||||
#undef ATTR
|
||||
if (!eglChooseConfig(_glfw.egl.display, attributes, configs, sizeof(configs)/sizeof(configs[0]), &nativeCount)) {
|
||||
_glfwInputError(GLFW_API_UNAVAILABLE, "EGL: eglChooseConfig failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
eglGetConfigs(_glfw.egl.display, NULL, 0, &nativeCount);
|
||||
if (!nativeCount)
|
||||
{
|
||||
_glfwInputError(GLFW_API_UNAVAILABLE, "EGL: No EGLConfigs returned");
|
||||
return GLFW_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++)
|
||||
{
|
||||
const EGLConfig n = nativeConfigs[i];
|
||||
_GLFWfbconfig* u = usableConfigs + usableCount;
|
||||
|
||||
// Only consider RGB(A) EGLConfigs
|
||||
if (getEGLConfigAttrib(n, EGL_COLOR_BUFFER_TYPE) != EGL_RGB_BUFFER)
|
||||
continue;
|
||||
|
||||
// Only consider window EGLConfigs
|
||||
if (!(getEGLConfigAttrib(n, EGL_SURFACE_TYPE) & EGL_WINDOW_BIT))
|
||||
continue;
|
||||
|
||||
#if defined(_GLFW_X11)
|
||||
XVisualInfo vi = {0};
|
||||
|
||||
// Only consider EGLConfigs with associated Visuals
|
||||
vi.visualid = getEGLConfigAttrib(n, EGL_NATIVE_VISUAL_ID);
|
||||
if (!vi.visualid)
|
||||
continue;
|
||||
|
||||
if (desired->transparent)
|
||||
{
|
||||
int count;
|
||||
XVisualInfo* vis = XGetVisualInfo(_glfw.x11.display,
|
||||
VisualIDMask, &vi,
|
||||
&count);
|
||||
if (vis)
|
||||
const EGLConfig n = configs[i];
|
||||
XVisualInfo vi = {0};
|
||||
|
||||
// Only consider EGLConfigs with associated Visuals
|
||||
vi.visualid = getEGLConfigAttrib(n, EGL_NATIVE_VISUAL_ID);
|
||||
if (!vi.visualid)
|
||||
continue;
|
||||
|
||||
if (desired->transparent)
|
||||
{
|
||||
u->transparent = _glfwIsVisualTransparentX11(vis[0].visual);
|
||||
XFree(vis);
|
||||
int count;
|
||||
XVisualInfo* vis =
|
||||
XGetVisualInfo(_glfw.x11.display, VisualIDMask, &vi, &count);
|
||||
if (vis)
|
||||
{
|
||||
bool transparent = _glfwIsVisualTransparentX11(vis[0].visual);
|
||||
XFree(vis);
|
||||
if (!transparent) continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // _GLFW_X11
|
||||
|
||||
if (ctxconfig->client == GLFW_OPENGL_ES_API)
|
||||
{
|
||||
if (ctxconfig->major == 1)
|
||||
{
|
||||
if (!(getEGLConfigAttrib(n, EGL_RENDERABLE_TYPE) & EGL_OPENGL_ES_BIT))
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(getEGLConfigAttrib(n, EGL_RENDERABLE_TYPE) & EGL_OPENGL_ES2_BIT))
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (ctxconfig->client == GLFW_OPENGL_API)
|
||||
{
|
||||
if (!(getEGLConfigAttrib(n, EGL_RENDERABLE_TYPE) & EGL_OPENGL_BIT))
|
||||
continue;
|
||||
}
|
||||
|
||||
u->redBits = getEGLConfigAttrib(n, EGL_RED_SIZE);
|
||||
u->greenBits = getEGLConfigAttrib(n, EGL_GREEN_SIZE);
|
||||
u->blueBits = getEGLConfigAttrib(n, EGL_BLUE_SIZE);
|
||||
|
||||
u->alphaBits = getEGLConfigAttrib(n, EGL_ALPHA_SIZE);
|
||||
u->depthBits = getEGLConfigAttrib(n, EGL_DEPTH_SIZE);
|
||||
u->stencilBits = getEGLConfigAttrib(n, EGL_STENCIL_SIZE);
|
||||
|
||||
u->samples = getEGLConfigAttrib(n, EGL_SAMPLES);
|
||||
u->doublebuffer = GLFW_TRUE;
|
||||
|
||||
u->handle = (uintptr_t) n;
|
||||
usableCount++;
|
||||
ans_idx = i;
|
||||
break;
|
||||
}
|
||||
|
||||
closest = _glfwChooseFBConfig(desired, usableConfigs, usableCount);
|
||||
if (closest)
|
||||
*result = (EGLConfig) closest->handle;
|
||||
|
||||
free(nativeConfigs);
|
||||
free(usableConfigs);
|
||||
|
||||
return closest != NULL;
|
||||
*result = configs[ans_idx];
|
||||
return true;
|
||||
}
|
||||
|
||||
static void makeContextCurrentEGL(_GLFWwindow* window)
|
||||
@@ -241,10 +214,10 @@ static int extensionSupportedEGL(const char* extension)
|
||||
if (extensions)
|
||||
{
|
||||
if (_glfwStringInExtensionString(extension, extensions))
|
||||
return GLFW_TRUE;
|
||||
return true;
|
||||
}
|
||||
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
}
|
||||
|
||||
static GLFWglproc getProcAddressEGL(const char* procname)
|
||||
@@ -253,8 +226,8 @@ static GLFWglproc getProcAddressEGL(const char* procname)
|
||||
|
||||
if (window->context.egl.client)
|
||||
{
|
||||
GLFWglproc proc = (GLFWglproc) _glfw_dlsym(window->context.egl.client,
|
||||
procname);
|
||||
GLFWglproc proc = NULL;
|
||||
glfw_dlsym(proc, window->context.egl.client, procname);
|
||||
if (proc)
|
||||
return proc;
|
||||
}
|
||||
@@ -297,9 +270,11 @@ static void destroyContextEGL(_GLFWwindow* window)
|
||||
|
||||
// Initialize EGL
|
||||
//
|
||||
GLFWbool _glfwInitEGL(void)
|
||||
bool _glfwInitEGL(void)
|
||||
{
|
||||
int i;
|
||||
EGLint* attribs = NULL;
|
||||
const char* extensions;
|
||||
const char* sonames[] =
|
||||
{
|
||||
#if defined(_GLFW_EGL_LIBRARY)
|
||||
@@ -318,7 +293,7 @@ GLFWbool _glfwInitEGL(void)
|
||||
};
|
||||
|
||||
if (_glfw.egl.handle)
|
||||
return GLFW_TRUE;
|
||||
return true;
|
||||
|
||||
for (i = 0; sonames[i]; i++)
|
||||
{
|
||||
@@ -330,46 +305,32 @@ GLFWbool _glfwInitEGL(void)
|
||||
if (!_glfw.egl.handle)
|
||||
{
|
||||
_glfwInputError(GLFW_API_UNAVAILABLE, "EGL: Library not found");
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
}
|
||||
|
||||
_glfw.egl.prefix = (strncmp(sonames[i], "lib", 3) == 0);
|
||||
|
||||
_glfw.egl.GetConfigAttrib = (PFN_eglGetConfigAttrib)
|
||||
_glfw_dlsym(_glfw.egl.handle, "eglGetConfigAttrib");
|
||||
_glfw.egl.GetConfigs = (PFN_eglGetConfigs)
|
||||
_glfw_dlsym(_glfw.egl.handle, "eglGetConfigs");
|
||||
_glfw.egl.GetDisplay = (PFN_eglGetDisplay)
|
||||
_glfw_dlsym(_glfw.egl.handle, "eglGetDisplay");
|
||||
_glfw.egl.GetError = (PFN_eglGetError)
|
||||
_glfw_dlsym(_glfw.egl.handle, "eglGetError");
|
||||
_glfw.egl.Initialize = (PFN_eglInitialize)
|
||||
_glfw_dlsym(_glfw.egl.handle, "eglInitialize");
|
||||
_glfw.egl.Terminate = (PFN_eglTerminate)
|
||||
_glfw_dlsym(_glfw.egl.handle, "eglTerminate");
|
||||
_glfw.egl.BindAPI = (PFN_eglBindAPI)
|
||||
_glfw_dlsym(_glfw.egl.handle, "eglBindAPI");
|
||||
_glfw.egl.CreateContext = (PFN_eglCreateContext)
|
||||
_glfw_dlsym(_glfw.egl.handle, "eglCreateContext");
|
||||
_glfw.egl.DestroySurface = (PFN_eglDestroySurface)
|
||||
_glfw_dlsym(_glfw.egl.handle, "eglDestroySurface");
|
||||
_glfw.egl.DestroyContext = (PFN_eglDestroyContext)
|
||||
_glfw_dlsym(_glfw.egl.handle, "eglDestroyContext");
|
||||
_glfw.egl.CreateWindowSurface = (PFN_eglCreateWindowSurface)
|
||||
_glfw_dlsym(_glfw.egl.handle, "eglCreateWindowSurface");
|
||||
_glfw.egl.MakeCurrent = (PFN_eglMakeCurrent)
|
||||
_glfw_dlsym(_glfw.egl.handle, "eglMakeCurrent");
|
||||
_glfw.egl.SwapBuffers = (PFN_eglSwapBuffers)
|
||||
_glfw_dlsym(_glfw.egl.handle, "eglSwapBuffers");
|
||||
_glfw.egl.SwapInterval = (PFN_eglSwapInterval)
|
||||
_glfw_dlsym(_glfw.egl.handle, "eglSwapInterval");
|
||||
_glfw.egl.QueryString = (PFN_eglQueryString)
|
||||
_glfw_dlsym(_glfw.egl.handle, "eglQueryString");
|
||||
_glfw.egl.GetProcAddress = (PFN_eglGetProcAddress)
|
||||
_glfw_dlsym(_glfw.egl.handle, "eglGetProcAddress");
|
||||
glfw_dlsym(_glfw.egl.GetConfigAttrib, _glfw.egl.handle, "eglGetConfigAttrib");
|
||||
glfw_dlsym(_glfw.egl.GetConfigs, _glfw.egl.handle, "eglGetConfigs");
|
||||
glfw_dlsym(_glfw.egl.ChooseConfig, _glfw.egl.handle, "eglChooseConfig");
|
||||
glfw_dlsym(_glfw.egl.GetDisplay, _glfw.egl.handle, "eglGetDisplay");
|
||||
glfw_dlsym(_glfw.egl.GetError, _glfw.egl.handle, "eglGetError");
|
||||
glfw_dlsym(_glfw.egl.Initialize, _glfw.egl.handle, "eglInitialize");
|
||||
glfw_dlsym(_glfw.egl.Terminate, _glfw.egl.handle, "eglTerminate");
|
||||
glfw_dlsym(_glfw.egl.BindAPI, _glfw.egl.handle, "eglBindAPI");
|
||||
glfw_dlsym(_glfw.egl.CreateContext, _glfw.egl.handle, "eglCreateContext");
|
||||
glfw_dlsym(_glfw.egl.DestroySurface, _glfw.egl.handle, "eglDestroySurface");
|
||||
glfw_dlsym(_glfw.egl.DestroyContext, _glfw.egl.handle, "eglDestroyContext");
|
||||
glfw_dlsym(_glfw.egl.CreateWindowSurface, _glfw.egl.handle, "eglCreateWindowSurface");
|
||||
glfw_dlsym(_glfw.egl.MakeCurrent, _glfw.egl.handle, "eglMakeCurrent");
|
||||
glfw_dlsym(_glfw.egl.SwapBuffers, _glfw.egl.handle, "eglSwapBuffers");
|
||||
glfw_dlsym(_glfw.egl.SwapInterval, _glfw.egl.handle, "eglSwapInterval");
|
||||
glfw_dlsym(_glfw.egl.QueryString, _glfw.egl.handle, "eglQueryString");
|
||||
glfw_dlsym(_glfw.egl.GetProcAddress, _glfw.egl.handle, "eglGetProcAddress");
|
||||
|
||||
if (!_glfw.egl.GetConfigAttrib ||
|
||||
!_glfw.egl.GetConfigs ||
|
||||
!_glfw.egl.ChooseConfig ||
|
||||
!_glfw.egl.GetDisplay ||
|
||||
!_glfw.egl.GetError ||
|
||||
!_glfw.egl.Initialize ||
|
||||
@@ -389,10 +350,54 @@ GLFWbool _glfwInitEGL(void)
|
||||
"EGL: Failed to load required entry points");
|
||||
|
||||
_glfwTerminateEGL();
|
||||
return GLFW_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)
|
||||
{
|
||||
_glfwInputError(GLFW_API_UNAVAILABLE,
|
||||
@@ -400,7 +405,7 @@ GLFWbool _glfwInitEGL(void)
|
||||
getEGLErrorString(eglGetError()));
|
||||
|
||||
_glfwTerminateEGL();
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!eglInitialize(_glfw.egl.display, &_glfw.egl.major, &_glfw.egl.minor))
|
||||
@@ -410,7 +415,7 @@ GLFWbool _glfwInitEGL(void)
|
||||
getEGLErrorString(eglGetError()));
|
||||
|
||||
_glfwTerminateEGL();
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
}
|
||||
|
||||
_glfw.egl.KHR_create_context =
|
||||
@@ -424,7 +429,7 @@ GLFWbool _glfwInitEGL(void)
|
||||
_glfw.egl.KHR_context_flush_control =
|
||||
extensionSupportedEGL("EGL_KHR_context_flush_control");
|
||||
|
||||
return GLFW_TRUE;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Terminate EGL
|
||||
@@ -446,26 +451,27 @@ void _glfwTerminateEGL(void)
|
||||
|
||||
#define setAttrib(a, v) \
|
||||
{ \
|
||||
assert((size_t) (index + 1) < sizeof(attribs) / sizeof(attribs[0])); \
|
||||
assert(((size_t) index + 1) < sizeof(attribs) / sizeof(attribs[0])); \
|
||||
attribs[index++] = a; \
|
||||
attribs[index++] = v; \
|
||||
}
|
||||
|
||||
// Create the OpenGL or OpenGL ES context
|
||||
//
|
||||
GLFWbool _glfwCreateContextEGL(_GLFWwindow* window,
|
||||
bool _glfwCreateContextEGL(_GLFWwindow* window,
|
||||
const _GLFWctxconfig* ctxconfig,
|
||||
const _GLFWfbconfig* fbconfig)
|
||||
{
|
||||
EGLint attribs[40];
|
||||
EGLConfig config;
|
||||
EGLContext share = NULL;
|
||||
EGLNativeWindowType native;
|
||||
int index = 0;
|
||||
|
||||
if (!_glfw.egl.display)
|
||||
{
|
||||
_glfwInputError(GLFW_API_UNAVAILABLE, "EGL: API not available");
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ctxconfig->share)
|
||||
@@ -475,7 +481,7 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window,
|
||||
{
|
||||
_glfwInputError(GLFW_FORMAT_UNAVAILABLE,
|
||||
"EGL: Failed to find a suitable EGLConfig");
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ctxconfig->client == GLFW_OPENGL_ES_API)
|
||||
@@ -485,7 +491,7 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window,
|
||||
_glfwInputError(GLFW_API_UNAVAILABLE,
|
||||
"EGL: Failed to bind OpenGL ES: %s",
|
||||
getEGLErrorString(eglGetError()));
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -495,7 +501,7 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window,
|
||||
_glfwInputError(GLFW_API_UNAVAILABLE,
|
||||
"EGL: Failed to bind OpenGL: %s",
|
||||
getEGLErrorString(eglGetError()));
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -536,7 +542,7 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window,
|
||||
if (ctxconfig->noerror)
|
||||
{
|
||||
if (_glfw.egl.KHR_create_context_no_error)
|
||||
setAttrib(EGL_CONTEXT_OPENGL_NO_ERROR_KHR, GLFW_TRUE);
|
||||
setAttrib(EGL_CONTEXT_OPENGL_NO_ERROR_KHR, true);
|
||||
}
|
||||
|
||||
if (ctxconfig->major != 1 || ctxconfig->minor != 0)
|
||||
@@ -581,37 +587,53 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window,
|
||||
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
|
||||
"EGL: Failed to create context: %s",
|
||||
getEGLErrorString(eglGetError()));
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set up attributes for surface creation
|
||||
index = 0;
|
||||
|
||||
if (fbconfig->sRGB)
|
||||
{
|
||||
int index = 0;
|
||||
|
||||
if (fbconfig->sRGB)
|
||||
{
|
||||
if (_glfw.egl.KHR_gl_colorspace)
|
||||
setAttrib(EGL_GL_COLORSPACE_KHR, EGL_GL_COLORSPACE_SRGB_KHR);
|
||||
}
|
||||
|
||||
setAttrib(EGL_NONE, EGL_NONE);
|
||||
if (_glfw.egl.KHR_gl_colorspace)
|
||||
setAttrib(EGL_GL_COLORSPACE_KHR, EGL_GL_COLORSPACE_SRGB_KHR);
|
||||
}
|
||||
|
||||
setAttrib(EGL_NONE, EGL_NONE);
|
||||
|
||||
native = _glfwPlatformGetEGLNativeWindow(window);
|
||||
// HACK: ANGLE does not implement eglCreatePlatformWindowSurfaceEXT
|
||||
// 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)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"EGL: Failed to create window surface: %s",
|
||||
getEGLErrorString(eglGetError()));
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
}
|
||||
|
||||
window->context.egl.config = config;
|
||||
|
||||
EGLint a = EGL_MIN_SWAP_INTERVAL;
|
||||
if (!eglGetConfigAttrib(_glfw.egl.display, config, a, &a)) {
|
||||
_glfwInputError(GLFW_VERSION_UNAVAILABLE, "EGL: could not check for non-blocking buffer swap with error: %s", getEGLErrorString(eglGetError()));
|
||||
} else {
|
||||
if (a > 0) {
|
||||
_glfwInputError(GLFW_VERSION_UNAVAILABLE, "EGL: non-blocking swap buffers not available, minimum swap interval is: %d", a);
|
||||
}
|
||||
}
|
||||
|
||||
// Load the appropriate client library
|
||||
if (!_glfw.egl.KHR_get_all_proc_addresses)
|
||||
{
|
||||
@@ -686,7 +708,7 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window,
|
||||
{
|
||||
_glfwInputError(GLFW_API_UNAVAILABLE,
|
||||
"EGL: Failed to load client library");
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -697,7 +719,7 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window,
|
||||
window->context.getProcAddress = getProcAddressEGL;
|
||||
window->context.destroy = destroyContextEGL;
|
||||
|
||||
return GLFW_TRUE;
|
||||
return true;
|
||||
}
|
||||
|
||||
#undef setAttrib
|
||||
@@ -705,7 +727,7 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window,
|
||||
// Returns the Visual and depth of the chosen EGLConfig
|
||||
//
|
||||
#if defined(_GLFW_X11)
|
||||
GLFWbool _glfwChooseVisualEGL(const _GLFWwndconfig* wndconfig,
|
||||
bool _glfwChooseVisualEGL(const _GLFWwndconfig* wndconfig UNUSED,
|
||||
const _GLFWctxconfig* ctxconfig,
|
||||
const _GLFWfbconfig* fbconfig,
|
||||
Visual** visual, int* depth)
|
||||
@@ -720,7 +742,7 @@ GLFWbool _glfwChooseVisualEGL(const _GLFWwndconfig* wndconfig,
|
||||
{
|
||||
_glfwInputError(GLFW_FORMAT_UNAVAILABLE,
|
||||
"EGL: Failed to find a suitable EGLConfig");
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
}
|
||||
|
||||
eglGetConfigAttrib(_glfw.egl.display, native,
|
||||
@@ -734,14 +756,14 @@ GLFWbool _glfwChooseVisualEGL(const _GLFWwndconfig* wndconfig,
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"EGL: Failed to retrieve Visual for EGLConfig");
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
}
|
||||
|
||||
*visual = result->visual;
|
||||
*depth = result->depth;
|
||||
|
||||
XFree(result);
|
||||
return GLFW_TRUE;
|
||||
return true;
|
||||
}
|
||||
#endif // _GLFW_X11
|
||||
|
||||
@@ -783,4 +805,3 @@ GLFWAPI EGLSurface glfwGetEGLSurface(GLFWwindow* handle)
|
||||
|
||||
return window->context.egl.surface;
|
||||
}
|
||||
|
||||
|
||||
97
glfw/egl_context.h
vendored
97
glfw/egl_context.h
vendored
@@ -1,8 +1,8 @@
|
||||
//========================================================================
|
||||
// GLFW 3.3 EGL - www.glfw.org
|
||||
// GLFW 3.4 EGL - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||
// Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
|
||||
// Copyright (c) 2006-2017 Camilla Löwy <elmindreda@glfw.org>
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
@@ -25,48 +25,32 @@
|
||||
//
|
||||
//========================================================================
|
||||
|
||||
#if defined(_GLFW_USE_EGLPLATFORM_H)
|
||||
#include <EGL/eglplatform.h>
|
||||
#elif defined(_GLFW_WIN32)
|
||||
#if defined(_GLFW_WIN32)
|
||||
#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
|
||||
#error "No supported EGL platform selected"
|
||||
#define EGLAPIENTRY
|
||||
#endif
|
||||
|
||||
#define EGL_SUCCESS 0x3000
|
||||
#define EGL_NOT_INITIALIZED 0x3001
|
||||
#define EGL_SUCCESS 0x3000
|
||||
#define EGL_NOT_INITIALIZED 0x3001
|
||||
#define EGL_BAD_ACCESS 0x3002
|
||||
#define EGL_BAD_ALLOC 0x3003
|
||||
#define EGL_BAD_ATTRIBUTE 0x3004
|
||||
#define EGL_BAD_CONFIG 0x3005
|
||||
#define EGL_BAD_CONTEXT 0x3006
|
||||
#define EGL_BAD_CURRENT_SURFACE 0x3007
|
||||
#define EGL_BAD_DISPLAY 0x3008
|
||||
#define EGL_BAD_CONTEXT 0x3006
|
||||
#define EGL_BAD_CURRENT_SURFACE 0x3007
|
||||
#define EGL_BAD_DISPLAY 0x3008
|
||||
#define EGL_BAD_MATCH 0x3009
|
||||
#define EGL_BAD_NATIVE_PIXMAP 0x300a
|
||||
#define EGL_BAD_NATIVE_WINDOW 0x300b
|
||||
#define EGL_BAD_PARAMETER 0x300c
|
||||
#define EGL_BAD_SURFACE 0x300d
|
||||
#define EGL_BAD_SURFACE 0x300d
|
||||
#define EGL_CONTEXT_LOST 0x300e
|
||||
#define EGL_COLOR_BUFFER_TYPE 0x303f
|
||||
#define EGL_RGB_BUFFER 0x308e
|
||||
#define EGL_SURFACE_TYPE 0x3033
|
||||
#define EGL_WINDOW_BIT 0x0004
|
||||
#define EGL_RENDERABLE_TYPE 0x3040
|
||||
#define EGL_RENDERABLE_TYPE 0x3040
|
||||
#define EGL_OPENGL_ES_BIT 0x0001
|
||||
#define EGL_OPENGL_ES2_BIT 0x0004
|
||||
#define EGL_OPENGL_BIT 0x0008
|
||||
@@ -76,7 +60,7 @@ typedef struct wl_egl_window* EGLNativeWindowType;
|
||||
#define EGL_RED_SIZE 0x3024
|
||||
#define EGL_DEPTH_SIZE 0x3025
|
||||
#define EGL_STENCIL_SIZE 0x3026
|
||||
#define EGL_SAMPLES 0x3031
|
||||
#define EGL_SAMPLES 0x3031
|
||||
#define EGL_OPENGL_ES_API 0x30a0
|
||||
#define EGL_OPENGL_API 0x30a2
|
||||
#define EGL_NONE 0x3038
|
||||
@@ -87,6 +71,8 @@ typedef struct wl_egl_window* EGLNativeWindowType;
|
||||
#define EGL_NO_DISPLAY ((EGLDisplay) 0)
|
||||
#define EGL_NO_CONTEXT ((EGLContext) 0)
|
||||
#define EGL_DEFAULT_DISPLAY ((EGLNativeDisplayType) 0)
|
||||
#define EGL_MIN_SWAP_INTERVAL 0x303B
|
||||
#define EGL_MAX_SWAP_INTERVAL 0x303C
|
||||
|
||||
#define EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR 0x00000002
|
||||
#define EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR 0x00000001
|
||||
@@ -106,6 +92,17 @@ typedef struct wl_egl_window* EGLNativeWindowType;
|
||||
#define EGL_CONTEXT_RELEASE_BEHAVIOR_KHR 0x2097
|
||||
#define EGL_CONTEXT_RELEASE_BEHAVIOR_NONE_KHR 0
|
||||
#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 unsigned int EGLBoolean;
|
||||
@@ -115,9 +112,13 @@ typedef void* EGLContext;
|
||||
typedef void* EGLDisplay;
|
||||
typedef void* EGLSurface;
|
||||
|
||||
typedef void* EGLNativeDisplayType;
|
||||
typedef void* EGLNativeWindowType;
|
||||
|
||||
// EGL function pointer typedefs
|
||||
typedef EGLBoolean (EGLAPIENTRY * PFN_eglGetConfigAttrib)(EGLDisplay,EGLConfig,EGLint,EGLint*);
|
||||
typedef EGLBoolean (EGLAPIENTRY * PFN_eglGetConfigs)(EGLDisplay,EGLConfig*,EGLint,EGLint*);
|
||||
typedef EGLBoolean (EGLAPIENTRY * PFN_eglChooseConfig)(EGLDisplay,EGLint const*,EGLConfig*,EGLint,EGLint*);
|
||||
typedef EGLDisplay (EGLAPIENTRY * PFN_eglGetDisplay)(EGLNativeDisplayType);
|
||||
typedef EGLint (EGLAPIENTRY * PFN_eglGetError)(void);
|
||||
typedef EGLBoolean (EGLAPIENTRY * PFN_eglInitialize)(EGLDisplay,EGLint*,EGLint*);
|
||||
@@ -134,6 +135,7 @@ typedef const char* (EGLAPIENTRY * PFN_eglQueryString)(EGLDisplay,EGLint);
|
||||
typedef GLFWglproc (EGLAPIENTRY * PFN_eglGetProcAddress)(const char*);
|
||||
#define eglGetConfigAttrib _glfw.egl.GetConfigAttrib
|
||||
#define eglGetConfigs _glfw.egl.GetConfigs
|
||||
#define eglChooseConfig _glfw.egl.ChooseConfig
|
||||
#define eglGetDisplay _glfw.egl.GetDisplay
|
||||
#define eglGetError _glfw.egl.GetError
|
||||
#define eglInitialize _glfw.egl.Initialize
|
||||
@@ -149,9 +151,10 @@ typedef GLFWglproc (EGLAPIENTRY * PFN_eglGetProcAddress)(const char*);
|
||||
#define eglQueryString _glfw.egl.QueryString
|
||||
#define eglGetProcAddress _glfw.egl.GetProcAddress
|
||||
|
||||
#define _GLFW_EGL_CONTEXT_STATE _GLFWcontextEGL egl
|
||||
#define _GLFW_EGL_LIBRARY_CONTEXT_STATE _GLFWlibraryEGL egl
|
||||
|
||||
typedef EGLDisplay (EGLAPIENTRY * PFNEGLGETPLATFORMDISPLAYEXTPROC)(EGLenum,void*,const EGLint*);
|
||||
typedef EGLSurface (EGLAPIENTRY * PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC)(EGLDisplay,EGLConfig,void*,const EGLint*);
|
||||
#define eglGetPlatformDisplayEXT _glfw.egl.GetPlatformDisplayEXT
|
||||
#define eglCreatePlatformWindowSurfaceEXT _glfw.egl.CreatePlatformWindowSurfaceEXT
|
||||
|
||||
// EGL-specific per-context data
|
||||
//
|
||||
@@ -169,20 +172,31 @@ typedef struct _GLFWcontextEGL
|
||||
//
|
||||
typedef struct _GLFWlibraryEGL
|
||||
{
|
||||
EGLenum platform;
|
||||
EGLDisplay display;
|
||||
EGLint major, minor;
|
||||
GLFWbool prefix;
|
||||
bool prefix;
|
||||
|
||||
GLFWbool KHR_create_context;
|
||||
GLFWbool KHR_create_context_no_error;
|
||||
GLFWbool KHR_gl_colorspace;
|
||||
GLFWbool KHR_get_all_proc_addresses;
|
||||
GLFWbool KHR_context_flush_control;
|
||||
bool KHR_create_context;
|
||||
bool KHR_create_context_no_error;
|
||||
bool KHR_gl_colorspace;
|
||||
bool KHR_get_all_proc_addresses;
|
||||
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;
|
||||
|
||||
PFN_eglGetConfigAttrib GetConfigAttrib;
|
||||
PFN_eglGetConfigs GetConfigs;
|
||||
PFN_eglChooseConfig ChooseConfig;
|
||||
PFN_eglGetDisplay GetDisplay;
|
||||
PFN_eglGetError GetError;
|
||||
PFN_eglInitialize Initialize;
|
||||
@@ -198,16 +212,19 @@ typedef struct _GLFWlibraryEGL
|
||||
PFN_eglQueryString QueryString;
|
||||
PFN_eglGetProcAddress GetProcAddress;
|
||||
|
||||
PFNEGLGETPLATFORMDISPLAYEXTPROC GetPlatformDisplayEXT;
|
||||
PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC CreatePlatformWindowSurfaceEXT;
|
||||
|
||||
} _GLFWlibraryEGL;
|
||||
|
||||
|
||||
GLFWbool _glfwInitEGL(void);
|
||||
bool _glfwInitEGL(void);
|
||||
void _glfwTerminateEGL(void);
|
||||
GLFWbool _glfwCreateContextEGL(_GLFWwindow* window,
|
||||
bool _glfwCreateContextEGL(_GLFWwindow* window,
|
||||
const _GLFWctxconfig* ctxconfig,
|
||||
const _GLFWfbconfig* fbconfig);
|
||||
#if defined(_GLFW_X11)
|
||||
GLFWbool _glfwChooseVisualEGL(const _GLFWwndconfig* wndconfig,
|
||||
bool _glfwChooseVisualEGL(const _GLFWwndconfig* wndconfig,
|
||||
const _GLFWctxconfig* ctxconfig,
|
||||
const _GLFWfbconfig* fbconfig,
|
||||
Visual** visual, int* depth);
|
||||
|
||||
181
glfw/glfw.py
181
glfw/glfw.py
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/env python3
|
||||
# vim:fileencoding=utf-8
|
||||
# License: GPL v3 Copyright: 2017, Kovid Goyal <kovid at kovidgoyal.net>
|
||||
|
||||
@@ -6,52 +6,76 @@ import json
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
from typing import Callable, Dict, List, Optional, Tuple
|
||||
|
||||
_plat = sys.platform.lower()
|
||||
is_macos = 'darwin' in _plat
|
||||
is_freebsd = 'freebsd' in _plat
|
||||
is_netbsd = 'netbsd' in _plat
|
||||
is_dragonflybsd = 'dragonfly' in _plat
|
||||
is_bsd = is_freebsd or is_netbsd or is_dragonflybsd
|
||||
is_linux = 'linux' in _plat
|
||||
is_openbsd = 'openbsd' in _plat
|
||||
base = os.path.dirname(os.path.abspath(__file__))
|
||||
|
||||
|
||||
def wayland_protocol_file_name(base, ext='c'):
|
||||
class Env:
|
||||
|
||||
cc: str = ''
|
||||
cppflags: List[str] = []
|
||||
cflags: List[str] = []
|
||||
ldflags: List[str] = []
|
||||
library_paths: Dict[str, List[str]] = {}
|
||||
ldpaths: List[str] = []
|
||||
ccver: Tuple[int, int]
|
||||
|
||||
# glfw stuff
|
||||
all_headers: List[str] = []
|
||||
sources: List[str] = []
|
||||
wayland_packagedir: str = ''
|
||||
wayland_scanner: str = ''
|
||||
wayland_scanner_code: str = ''
|
||||
wayland_protocols: Tuple[str, ...] = ()
|
||||
|
||||
def __init__(
|
||||
self, cc: str = '', cppflags: List[str] = [], cflags: List[str] = [], ldflags: List[str] = [],
|
||||
library_paths: Dict[str, List[str]] = {}, ldpaths: Optional[List[str]] = None, ccver: Tuple[int, int] = (0, 0)
|
||||
):
|
||||
self.cc, self.cppflags, self.cflags, self.ldflags, self.library_paths = cc, cppflags, cflags, ldflags, library_paths
|
||||
self.ldpaths, self.ccver = [] if ldpaths is None else ldpaths, ccver
|
||||
|
||||
def copy(self) -> 'Env':
|
||||
ans = Env(self.cc, list(self.cppflags), list(self.cflags), list(self.ldflags), dict(self.library_paths), list(self.ldpaths), self.ccver)
|
||||
ans.all_headers = list(self.all_headers)
|
||||
ans.sources = list(self.sources)
|
||||
ans.wayland_packagedir = self.wayland_packagedir
|
||||
ans.wayland_scanner = self.wayland_scanner
|
||||
ans.wayland_scanner_code = self.wayland_scanner_code
|
||||
ans.wayland_protocols = self.wayland_protocols
|
||||
return ans
|
||||
|
||||
|
||||
def wayland_protocol_file_name(base: str, ext: str = 'c') -> str:
|
||||
base = os.path.basename(base).rpartition('.')[0]
|
||||
return 'wayland-{}-client-protocol.{}'.format(base, ext)
|
||||
|
||||
|
||||
def init_env(env, pkg_config, at_least_version, test_compile, module='x11'):
|
||||
def init_env(env: Env, pkg_config: Callable, at_least_version: Callable, test_compile: Callable, module: str = 'x11') -> Env:
|
||||
ans = env.copy()
|
||||
ans.cflags = [
|
||||
x for x in ans.cflags
|
||||
if x not in '-Wpedantic -Wextra -pedantic-errors'.split()
|
||||
]
|
||||
if not is_macos:
|
||||
ans.cflags.append('-pthread')
|
||||
ans.ldpaths.append('-pthread')
|
||||
ans.cflags.append('-fpic')
|
||||
ans.cflags.append('-fPIC')
|
||||
ans.cppflags.append('-D_GLFW_' + module.upper())
|
||||
ans.cppflags.append('-D_GLFW_BUILD_DLL')
|
||||
|
||||
if is_macos:
|
||||
ans.cppflags.append('-DGL_SILENCE_DEPRECATION')
|
||||
ans.ldpaths.extend(
|
||||
"-framework Cocoa -framework IOKit -framework CoreFoundation -framework CoreVideo".
|
||||
split()
|
||||
)
|
||||
else:
|
||||
ans.ldpaths.extend('-lrt -lm -ldl'.split())
|
||||
sinfo = json.load(open(os.path.join(base, 'source-info.json')))
|
||||
with open(os.path.join(base, 'source-info.json')) as f:
|
||||
sinfo = json.load(f)
|
||||
module_sources = list(sinfo[module]['sources'])
|
||||
if module in ('x11', 'wayland'):
|
||||
remove = 'linux_joystick.c' if is_bsd else 'null_joystick.c'
|
||||
remove = 'null_joystick.c' if is_linux else 'linux_joystick.c'
|
||||
module_sources.remove(remove)
|
||||
|
||||
ans.sources = sinfo['common']['sources'] + module_sources
|
||||
ans.all_headers = [x for x in os.listdir(base) if x.endswith('.h')]
|
||||
|
||||
if module in ('x11', 'wayland'):
|
||||
ans.cflags.append('-pthread')
|
||||
ans.ldpaths.extend('-pthread -lm'.split())
|
||||
if not is_openbsd:
|
||||
ans.ldpaths.extend('-lrt -ldl'.split())
|
||||
at_least_version('xkbcommon', 0, 5)
|
||||
|
||||
if module == 'x11':
|
||||
@@ -60,8 +84,9 @@ def init_env(env, pkg_config, at_least_version, test_compile, module='x11'):
|
||||
ans.ldpaths.extend(pkg_config(dep, '--libs'))
|
||||
|
||||
elif module == 'cocoa':
|
||||
for f in 'Cocoa IOKit CoreFoundation CoreVideo'.split():
|
||||
ans.ldpaths.extend(('-framework', f))
|
||||
ans.cppflags.append('-DGL_SILENCE_DEPRECATION')
|
||||
for f_ in 'Cocoa IOKit CoreFoundation CoreVideo'.split():
|
||||
ans.ldpaths.extend(('-framework', f_))
|
||||
|
||||
elif module == 'wayland':
|
||||
at_least_version('wayland-protocols', *sinfo['wayland_protocols'])
|
||||
@@ -73,7 +98,7 @@ def init_env(env, pkg_config, at_least_version, test_compile, module='x11'):
|
||||
for p in ans.wayland_protocols:
|
||||
ans.sources.append(wayland_protocol_file_name(p))
|
||||
ans.all_headers.append(wayland_protocol_file_name(p, 'h'))
|
||||
for dep in 'wayland-egl wayland-client wayland-cursor xkbcommon dbus-1'.split():
|
||||
for dep in 'wayland-client wayland-cursor xkbcommon dbus-1'.split():
|
||||
ans.cflags.extend(pkg_config(dep, '--cflags-only-I'))
|
||||
ans.ldpaths.extend(pkg_config(dep, '--libs'))
|
||||
has_memfd_create = test_compile(env.cc, '-Werror', src='''#define _GNU_SOURCE
|
||||
@@ -88,7 +113,8 @@ def init_env(env, pkg_config, at_least_version, test_compile, module='x11'):
|
||||
return ans
|
||||
|
||||
|
||||
def build_wayland_protocols(env, run_tool, emphasis, newer, dest_dir):
|
||||
def build_wayland_protocols(env: Env, Command: Callable, parallel_run: Callable, emphasis: Callable, newer: Callable, dest_dir: str) -> None:
|
||||
items = []
|
||||
for protocol in env.wayland_protocols:
|
||||
src = os.path.join(env.wayland_packagedir, protocol)
|
||||
if not os.path.exists(src):
|
||||
@@ -98,47 +124,17 @@ def build_wayland_protocols(env, run_tool, emphasis, newer, dest_dir):
|
||||
dest = os.path.join(dest_dir, dest)
|
||||
if newer(dest, src):
|
||||
q = 'client-header' if ext == 'h' else env.wayland_scanner_code
|
||||
run_tool([env.wayland_scanner, q, src, dest],
|
||||
desc='Generating {} ...'.format(emphasis(os.path.basename(dest))))
|
||||
|
||||
|
||||
def collect_source_information():
|
||||
raw = open('src/CMakeLists.txt').read()
|
||||
mraw = open('CMakeLists.txt').read()
|
||||
|
||||
def extract_sources(group, start_pos=0):
|
||||
for which in 'HEADERS SOURCES'.split():
|
||||
yield which.lower(), list(filter(
|
||||
lambda x: x[0] not in '"$',
|
||||
re.search(
|
||||
r'{0}_{1}\s+([^)]+?)[)]'.format(group, which),
|
||||
raw[start_pos:]
|
||||
).group(1).strip().split()
|
||||
))
|
||||
|
||||
wayland_protocols = re.search(r'WaylandProtocols\s+(\S+)\s+', mraw).group(1)
|
||||
wayland_protocols = list(map(int, wayland_protocols.split('.')))
|
||||
ans = {
|
||||
'common': dict(extract_sources('common')),
|
||||
'wayland_protocols': wayland_protocols,
|
||||
}
|
||||
for group in 'cocoa win32 x11 wayland osmesa'.split():
|
||||
m = re.search('_GLFW_' + group.upper(), raw)
|
||||
ans[group] = dict(extract_sources('glfw', m.start()))
|
||||
if group in ('x11', 'wayland'):
|
||||
for joystick in ('linux', 'null'):
|
||||
ans[group]['headers'].append('{}_joystick.h'.format(joystick))
|
||||
ans[group]['sources'].append('{}_joystick.c'.format(joystick))
|
||||
if group == 'wayland':
|
||||
ans[group]['protocols'] = p = []
|
||||
for m in re.finditer(r'WAYLAND_PROTOCOLS_PKGDATADIR\}/(.+?)"?$', raw, flags=re.M):
|
||||
p.append(m.group(1))
|
||||
return ans
|
||||
items.append(Command(
|
||||
'Generating {} ...'.format(emphasis(os.path.basename(dest))),
|
||||
[env.wayland_scanner, q, src, dest],
|
||||
lambda: True, None, None, None))
|
||||
if items:
|
||||
parallel_run(items)
|
||||
|
||||
|
||||
class Arg:
|
||||
|
||||
def __init__(self, decl):
|
||||
def __init__(self, decl: str):
|
||||
self.type, self.name = decl.rsplit(' ', 1)
|
||||
self.type = self.type.strip()
|
||||
self.name = self.name.strip()
|
||||
@@ -146,13 +142,13 @@ class Arg:
|
||||
self.name = self.name[1:]
|
||||
self.type = self.type + '*'
|
||||
|
||||
def __repr__(self):
|
||||
def __repr__(self) -> str:
|
||||
return 'Arg({}, {})'.format(self.type, self.name)
|
||||
|
||||
|
||||
class Function:
|
||||
|
||||
def __init__(self, declaration, check_fail=True):
|
||||
def __init__(self, declaration: str, check_fail: bool = True):
|
||||
self.check_fail = check_fail
|
||||
m = re.match(
|
||||
r'(.+?)\s+(glfw[A-Z][a-zA-Z0-9]+)[(](.+)[)]$', declaration
|
||||
@@ -168,15 +164,17 @@ class Function:
|
||||
if a == 'void':
|
||||
continue
|
||||
self.args.append(Arg(a))
|
||||
if not self.args:
|
||||
self.args = [Arg('void v')]
|
||||
|
||||
def declaration(self):
|
||||
return 'typedef {restype} (*{name}_func)({args});\n{name}_func {name}_impl;\n#define {name} {name}_impl'.format(
|
||||
def declaration(self) -> str:
|
||||
return 'typedef {restype} (*{name}_func)({args});\nGFW_EXTERN {name}_func {name}_impl;\n#define {name} {name}_impl'.format(
|
||||
restype=self.restype,
|
||||
name=self.name,
|
||||
args=', '.join(a.type for a in self.args)
|
||||
)
|
||||
|
||||
def load(self):
|
||||
def load(self) -> str:
|
||||
ans = '*(void **) (&{name}_impl) = dlsym(handle, "{name}");'.format(
|
||||
name=self.name
|
||||
)
|
||||
@@ -187,8 +185,9 @@ class Function:
|
||||
return ans
|
||||
|
||||
|
||||
def generate_wrappers(glfw_header):
|
||||
src = open(glfw_header).read()
|
||||
def generate_wrappers(glfw_header: str) -> None:
|
||||
with open(glfw_header) as f:
|
||||
src = f.read()
|
||||
functions = []
|
||||
first = None
|
||||
for m in re.finditer(r'^GLFWAPI\s+(.+[)]);\s*$', src, flags=re.MULTILINE):
|
||||
@@ -205,13 +204,18 @@ def generate_wrappers(glfw_header):
|
||||
GLFWcocoatextinputfilterfun glfwSetCocoaTextInputFilter(GLFWwindow* window, GLFWcocoatextinputfilterfun callback)
|
||||
GLFWcocoatogglefullscreenfun glfwSetCocoaToggleFullscreenIntercept(GLFWwindow *window, GLFWcocoatogglefullscreenfun callback)
|
||||
GLFWapplicationshouldhandlereopenfun glfwSetApplicationShouldHandleReopen(GLFWapplicationshouldhandlereopenfun callback)
|
||||
void glfwGetCocoaKeyEquivalent(int glfw_key, int glfw_mods, void* cocoa_key, void* cocoa_mods)
|
||||
GLFWapplicationwillfinishlaunchingfun glfwSetApplicationWillFinishLaunching(GLFWapplicationwillfinishlaunchingfun callback)
|
||||
void glfwGetCocoaKeyEquivalent(int glfw_key, int glfw_mods, char* cocoa_key, size_t key_sz, int* cocoa_mods)
|
||||
void glfwCocoaRequestRenderFrame(GLFWwindow *w, GLFWcocoarenderframefun callback)
|
||||
void* glfwGetX11Display(void)
|
||||
int32_t glfwGetX11Window(GLFWwindow* window)
|
||||
void glfwSetPrimarySelectionString(GLFWwindow* window, const char* string)
|
||||
const char* glfwGetPrimarySelectionString(GLFWwindow* window, void)
|
||||
int glfwGetXKBScancode(const char* key_name, int case_sensitive)
|
||||
int glfwGetNativeKeyForName(const char* key_name, int case_sensitive)
|
||||
void glfwRequestWaylandFrameEvent(GLFWwindow *handle, unsigned long long id, GLFWwaylandframecallbackfunc callback)
|
||||
unsigned long long glfwDBusUserNotify(const char *app_name, const char* icon, const char *summary, const char *body, \
|
||||
const char *action_text, int32_t timeout, GLFWDBusnotificationcreatedfun callback, void *data)
|
||||
void glfwDBusSetUserNotificationHandler(GLFWDBusnotificationactivatedfun handler)
|
||||
'''.splitlines():
|
||||
if line:
|
||||
functions.append(Function(line.strip(), check_fail=False))
|
||||
@@ -221,16 +225,30 @@ def generate_wrappers(glfw_header):
|
||||
p = src.find('*/', p)
|
||||
preamble = src[p + 2:first]
|
||||
header = '''\
|
||||
//
|
||||
// THIS FILE IS GENERATED BY glfw.py
|
||||
//
|
||||
// SAVE YOURSELF SOME TIME, DO NOT MANUALLY EDIT
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include "monotonic.h"
|
||||
|
||||
#ifndef GFW_EXTERN
|
||||
#define GFW_EXTERN extern
|
||||
#endif
|
||||
{}
|
||||
|
||||
typedef int (* GLFWcocoatextinputfilterfun)(int,int,unsigned int);
|
||||
typedef int (* GLFWapplicationshouldhandlereopenfun)(int);
|
||||
typedef int (* GLFWcocoatogglefullscreenfun)(GLFWwindow*);
|
||||
typedef int (* GLFWcocoatextinputfilterfun)(int,int,unsigned int,unsigned long);
|
||||
typedef bool (* GLFWapplicationshouldhandlereopenfun)(int);
|
||||
typedef void (* GLFWapplicationwillfinishlaunchingfun)(void);
|
||||
typedef bool (* GLFWcocoatogglefullscreenfun)(GLFWwindow*);
|
||||
typedef void (* GLFWcocoarenderframefun)(GLFWwindow*);
|
||||
typedef void (*GLFWwaylandframecallbackfunc)(unsigned long long id);
|
||||
typedef void (*GLFWDBusnotificationcreatedfun)(unsigned long long, uint32_t, void*);
|
||||
typedef void (*GLFWDBusnotificationactivatedfun)(uint32_t, const char*);
|
||||
{}
|
||||
|
||||
const char* load_glfw(const char* path);
|
||||
@@ -239,6 +257,7 @@ const char* load_glfw(const char* path);
|
||||
f.write(header)
|
||||
|
||||
code = '''
|
||||
#define GFW_EXTERN
|
||||
#include "data-types.h"
|
||||
#include "glfw-wrapper.h"
|
||||
#include <dlfcn.h>
|
||||
@@ -260,7 +279,7 @@ load_glfw(const char* path) {
|
||||
}
|
||||
|
||||
void
|
||||
unload_glfw() {
|
||||
unload_glfw(void) {
|
||||
if (handle) { dlclose(handle); handle = NULL; }
|
||||
}
|
||||
'''.replace('LOAD', '\n\n '.join(f.load() for f in functions))
|
||||
@@ -268,7 +287,7 @@ unload_glfw() {
|
||||
f.write(code)
|
||||
|
||||
|
||||
def main():
|
||||
def main() -> None:
|
||||
os.chdir(os.path.dirname(os.path.abspath(__file__)))
|
||||
generate_wrappers('glfw3.h')
|
||||
|
||||
|
||||
1576
glfw/glfw3.h
vendored
1576
glfw/glfw3.h
vendored
File diff suppressed because it is too large
Load Diff
258
glfw/glx_context.c
vendored
258
glfw/glx_context.c
vendored
@@ -1,8 +1,8 @@
|
||||
//========================================================================
|
||||
// GLFW 3.3 GLX - www.glfw.org
|
||||
// GLFW 3.4 GLX - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||
// Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
|
||||
// Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
@@ -24,6 +24,8 @@
|
||||
// distribution.
|
||||
//
|
||||
//========================================================================
|
||||
// It is fine to use C99 in this file because it will not be built with VS
|
||||
//========================================================================
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
@@ -45,104 +47,92 @@ static int getGLXFBConfigAttrib(GLXFBConfig fbconfig, int attrib)
|
||||
return value;
|
||||
}
|
||||
|
||||
static GLXFBConfig*
|
||||
choose_fb_config(const _GLFWfbconfig* desired, bool trust_window_bit, int *nelements) {
|
||||
int attrib_list[64];
|
||||
int pos = 0;
|
||||
#define ATTR(x, y) { attrib_list[pos++] = x; attrib_list[pos++] = y; }
|
||||
|
||||
ATTR(GLX_DOUBLEBUFFER, desired->doublebuffer ? True : False);
|
||||
if (desired->stereo > 0) ATTR(GLX_STEREO, desired->stereo ? True : False);
|
||||
if (desired->auxBuffers > 0) ATTR(GLX_AUX_BUFFERS, desired->auxBuffers);
|
||||
if (_glfw.glx.ARB_multisample && desired->samples > 0) ATTR(GLX_SAMPLES, desired->samples);
|
||||
if (desired->depthBits != GLFW_DONT_CARE) ATTR(GLX_DEPTH_SIZE, desired->depthBits);
|
||||
if (desired->stencilBits != GLFW_DONT_CARE) ATTR(GLX_STENCIL_SIZE, desired->stencilBits);
|
||||
if (desired->redBits != GLFW_DONT_CARE) ATTR(GLX_RED_SIZE, desired->redBits);
|
||||
if (desired->greenBits != GLFW_DONT_CARE) ATTR(GLX_GREEN_SIZE, desired->greenBits);
|
||||
if (desired->blueBits != GLFW_DONT_CARE) ATTR(GLX_BLUE_SIZE, desired->blueBits);
|
||||
if (desired->alphaBits != GLFW_DONT_CARE) ATTR(GLX_ALPHA_SIZE, desired->alphaBits);
|
||||
if (desired->accumRedBits != GLFW_DONT_CARE) ATTR(GLX_ACCUM_RED_SIZE, desired->accumRedBits);
|
||||
if (desired->accumGreenBits != GLFW_DONT_CARE) ATTR(GLX_ACCUM_GREEN_SIZE, desired->accumGreenBits);
|
||||
if (desired->accumBlueBits != GLFW_DONT_CARE) ATTR(GLX_ACCUM_BLUE_SIZE, desired->accumBlueBits);
|
||||
if (desired->accumAlphaBits != GLFW_DONT_CARE) ATTR(GLX_ACCUM_ALPHA_SIZE, desired->accumAlphaBits);
|
||||
if (!trust_window_bit) ATTR(GLX_DRAWABLE_TYPE, 0);
|
||||
ATTR(None, None);
|
||||
return glXChooseFBConfig(_glfw.x11.display, _glfw.x11.screen, attrib_list, nelements);
|
||||
#undef ATTR
|
||||
}
|
||||
|
||||
|
||||
// Return the GLXFBConfig most closely matching the specified hints
|
||||
//
|
||||
static GLFWbool chooseGLXFBConfig(const _GLFWfbconfig* desired,
|
||||
static bool chooseGLXFBConfig(const _GLFWfbconfig* desired,
|
||||
GLXFBConfig* result)
|
||||
{
|
||||
GLXFBConfig* nativeConfigs;
|
||||
_GLFWfbconfig* usableConfigs;
|
||||
const _GLFWfbconfig* closest;
|
||||
int i, nativeCount, usableCount;
|
||||
int i, nativeCount, ans_idx = 0;
|
||||
const char* vendor;
|
||||
GLFWbool trustWindowBit = GLFW_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
|
||||
// (VirtualBox GL) not setting the window bit on any GLXFBConfigs
|
||||
vendor = glXGetClientString(_glfw.x11.display, GLX_VENDOR);
|
||||
if (vendor && strcmp(vendor, "Chromium") == 0)
|
||||
trustWindowBit = GLFW_FALSE;
|
||||
|
||||
nativeConfigs =
|
||||
glXGetFBConfigs(_glfw.x11.display, _glfw.x11.screen, &nativeCount);
|
||||
trustWindowBit = false;
|
||||
nativeConfigs = choose_fb_config(desired, trustWindowBit, &nativeCount);
|
||||
if (!nativeConfigs || !nativeCount)
|
||||
{
|
||||
_glfwInputError(GLFW_API_UNAVAILABLE, "GLX: No GLXFBConfigs returned");
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
}
|
||||
|
||||
usableConfigs = calloc(nativeCount, sizeof(_GLFWfbconfig));
|
||||
usableCount = 0;
|
||||
|
||||
for (i = 0; i < nativeCount; i++)
|
||||
{
|
||||
const GLXFBConfig n = nativeConfigs[i];
|
||||
_GLFWfbconfig* u = usableConfigs + usableCount;
|
||||
|
||||
// Only consider RGBA GLXFBConfigs
|
||||
if (!(getGLXFBConfigAttrib(n, GLX_RENDER_TYPE) & GLX_RGBA_BIT))
|
||||
continue;
|
||||
|
||||
// Only consider window GLXFBConfigs
|
||||
if (!(getGLXFBConfigAttrib(n, GLX_DRAWABLE_TYPE) & GLX_WINDOW_BIT))
|
||||
{
|
||||
if (trustWindowBit)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (desired->transparent)
|
||||
{
|
||||
bool transparency_matches = true, srgb_matches = true;
|
||||
if (desired->transparent) {
|
||||
transparency_matches = false;
|
||||
XVisualInfo* vi = glXGetVisualFromFBConfig(_glfw.x11.display, n);
|
||||
if (vi)
|
||||
{
|
||||
u->transparent = _glfwIsVisualTransparentX11(vi->visual);
|
||||
XFree(vi);
|
||||
}
|
||||
if (vi && _glfwIsVisualTransparentX11(vi->visual)) transparency_matches = true;
|
||||
}
|
||||
|
||||
u->redBits = getGLXFBConfigAttrib(n, GLX_RED_SIZE);
|
||||
u->greenBits = getGLXFBConfigAttrib(n, GLX_GREEN_SIZE);
|
||||
u->blueBits = getGLXFBConfigAttrib(n, GLX_BLUE_SIZE);
|
||||
if (desired->sRGB && (_glfw.glx.ARB_framebuffer_sRGB || _glfw.glx.EXT_framebuffer_sRGB)) {
|
||||
srgb_matches = getGLXFBConfigAttrib(n, GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB) ? true : false;
|
||||
}
|
||||
|
||||
u->alphaBits = getGLXFBConfigAttrib(n, GLX_ALPHA_SIZE);
|
||||
u->depthBits = getGLXFBConfigAttrib(n, GLX_DEPTH_SIZE);
|
||||
u->stencilBits = getGLXFBConfigAttrib(n, GLX_STENCIL_SIZE);
|
||||
if (transparency_matches && srgb_matches) {
|
||||
ans_idx = i; break;
|
||||
}
|
||||
|
||||
u->accumRedBits = getGLXFBConfigAttrib(n, GLX_ACCUM_RED_SIZE);
|
||||
u->accumGreenBits = getGLXFBConfigAttrib(n, GLX_ACCUM_GREEN_SIZE);
|
||||
u->accumBlueBits = getGLXFBConfigAttrib(n, GLX_ACCUM_BLUE_SIZE);
|
||||
u->accumAlphaBits = getGLXFBConfigAttrib(n, GLX_ACCUM_ALPHA_SIZE);
|
||||
|
||||
u->auxBuffers = getGLXFBConfigAttrib(n, GLX_AUX_BUFFERS);
|
||||
|
||||
if (getGLXFBConfigAttrib(n, GLX_STEREO))
|
||||
u->stereo = GLFW_TRUE;
|
||||
if (getGLXFBConfigAttrib(n, GLX_DOUBLEBUFFER))
|
||||
u->doublebuffer = GLFW_TRUE;
|
||||
|
||||
if (_glfw.glx.ARB_multisample)
|
||||
u->samples = getGLXFBConfigAttrib(n, GLX_SAMPLES);
|
||||
|
||||
if (_glfw.glx.ARB_framebuffer_sRGB || _glfw.glx.EXT_framebuffer_sRGB)
|
||||
u->sRGB = getGLXFBConfigAttrib(n, GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB);
|
||||
|
||||
u->handle = (uintptr_t) n;
|
||||
usableCount++;
|
||||
}
|
||||
|
||||
closest = _glfwChooseFBConfig(desired, usableConfigs, usableCount);
|
||||
if (closest)
|
||||
*result = (GLXFBConfig) closest->handle;
|
||||
*result = nativeConfigs[ans_idx];
|
||||
prev_result = nativeConfigs[ans_idx];
|
||||
|
||||
XFree(nativeConfigs);
|
||||
free(usableConfigs);
|
||||
|
||||
return closest != NULL;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Create the OpenGL context using legacy API
|
||||
//
|
||||
static GLXContext createLegacyContextGLX(_GLFWwindow* window,
|
||||
static GLXContext createLegacyContextGLX(_GLFWwindow* window UNUSED,
|
||||
GLXFBConfig fbconfig,
|
||||
GLXContext share)
|
||||
{
|
||||
@@ -210,10 +200,10 @@ static int extensionSupportedGLX(const char* extension)
|
||||
if (extensions)
|
||||
{
|
||||
if (_glfwStringInExtensionString(extension, extensions))
|
||||
return GLFW_TRUE;
|
||||
return true;
|
||||
}
|
||||
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
}
|
||||
|
||||
static GLFWglproc getProcAddressGLX(const char* procname)
|
||||
@@ -222,12 +212,13 @@ static GLFWglproc getProcAddressGLX(const char* procname)
|
||||
return _glfw.glx.GetProcAddress((const GLubyte*) procname);
|
||||
else if (_glfw.glx.GetProcAddressARB)
|
||||
return _glfw.glx.GetProcAddressARB((const GLubyte*) procname);
|
||||
else
|
||||
return _glfw_dlsym(_glfw.glx.handle, procname);
|
||||
else {
|
||||
GLFWglproc ans = NULL;
|
||||
glfw_dlsym(ans, _glfw.glx.handle, procname);
|
||||
return ans;
|
||||
}
|
||||
}
|
||||
|
||||
// Destroy the OpenGL context
|
||||
//
|
||||
static void destroyContextGLX(_GLFWwindow* window)
|
||||
{
|
||||
if (window->context.glx.window)
|
||||
@@ -250,7 +241,7 @@ static void destroyContextGLX(_GLFWwindow* window)
|
||||
|
||||
// Initialize GLX
|
||||
//
|
||||
GLFWbool _glfwInitGLX(void)
|
||||
bool _glfwInitGLX(void)
|
||||
{
|
||||
int i;
|
||||
const char* sonames[] =
|
||||
@@ -267,7 +258,7 @@ GLFWbool _glfwInitGLX(void)
|
||||
};
|
||||
|
||||
if (_glfw.glx.handle)
|
||||
return GLFW_TRUE;
|
||||
return true;
|
||||
|
||||
for (i = 0; sonames[i]; i++)
|
||||
{
|
||||
@@ -279,39 +270,25 @@ GLFWbool _glfwInitGLX(void)
|
||||
if (!_glfw.glx.handle)
|
||||
{
|
||||
_glfwInputError(GLFW_API_UNAVAILABLE, "GLX: Failed to load GLX");
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
}
|
||||
|
||||
_glfw.glx.GetFBConfigs =
|
||||
_glfw_dlsym(_glfw.glx.handle, "glXGetFBConfigs");
|
||||
_glfw.glx.GetFBConfigAttrib =
|
||||
_glfw_dlsym(_glfw.glx.handle, "glXGetFBConfigAttrib");
|
||||
_glfw.glx.GetClientString =
|
||||
_glfw_dlsym(_glfw.glx.handle, "glXGetClientString");
|
||||
_glfw.glx.QueryExtension =
|
||||
_glfw_dlsym(_glfw.glx.handle, "glXQueryExtension");
|
||||
_glfw.glx.QueryVersion =
|
||||
_glfw_dlsym(_glfw.glx.handle, "glXQueryVersion");
|
||||
_glfw.glx.DestroyContext =
|
||||
_glfw_dlsym(_glfw.glx.handle, "glXDestroyContext");
|
||||
_glfw.glx.MakeCurrent =
|
||||
_glfw_dlsym(_glfw.glx.handle, "glXMakeCurrent");
|
||||
_glfw.glx.SwapBuffers =
|
||||
_glfw_dlsym(_glfw.glx.handle, "glXSwapBuffers");
|
||||
_glfw.glx.QueryExtensionsString =
|
||||
_glfw_dlsym(_glfw.glx.handle, "glXQueryExtensionsString");
|
||||
_glfw.glx.CreateNewContext =
|
||||
_glfw_dlsym(_glfw.glx.handle, "glXCreateNewContext");
|
||||
_glfw.glx.CreateWindow =
|
||||
_glfw_dlsym(_glfw.glx.handle, "glXCreateWindow");
|
||||
_glfw.glx.DestroyWindow =
|
||||
_glfw_dlsym(_glfw.glx.handle, "glXDestroyWindow");
|
||||
_glfw.glx.GetProcAddress =
|
||||
_glfw_dlsym(_glfw.glx.handle, "glXGetProcAddress");
|
||||
_glfw.glx.GetProcAddressARB =
|
||||
_glfw_dlsym(_glfw.glx.handle, "glXGetProcAddressARB");
|
||||
_glfw.glx.GetVisualFromFBConfig =
|
||||
_glfw_dlsym(_glfw.glx.handle, "glXGetVisualFromFBConfig");
|
||||
glfw_dlsym(_glfw.glx.GetFBConfigs, _glfw.glx.handle, "glXGetFBConfigs");
|
||||
glfw_dlsym(_glfw.glx.GetFBConfigAttrib, _glfw.glx.handle, "glXGetFBConfigAttrib");
|
||||
glfw_dlsym(_glfw.glx.ChooseFBConfig, _glfw.glx.handle, "glXChooseFBConfig");
|
||||
glfw_dlsym(_glfw.glx.GetClientString, _glfw.glx.handle, "glXGetClientString");
|
||||
glfw_dlsym(_glfw.glx.QueryExtension, _glfw.glx.handle, "glXQueryExtension");
|
||||
glfw_dlsym(_glfw.glx.QueryVersion, _glfw.glx.handle, "glXQueryVersion");
|
||||
glfw_dlsym(_glfw.glx.DestroyContext, _glfw.glx.handle, "glXDestroyContext");
|
||||
glfw_dlsym(_glfw.glx.MakeCurrent, _glfw.glx.handle, "glXMakeCurrent");
|
||||
glfw_dlsym(_glfw.glx.SwapBuffers, _glfw.glx.handle, "glXSwapBuffers");
|
||||
glfw_dlsym(_glfw.glx.QueryExtensionsString, _glfw.glx.handle, "glXQueryExtensionsString");
|
||||
glfw_dlsym(_glfw.glx.CreateNewContext, _glfw.glx.handle, "glXCreateNewContext");
|
||||
glfw_dlsym(_glfw.glx.CreateWindow, _glfw.glx.handle, "glXCreateWindow");
|
||||
glfw_dlsym(_glfw.glx.DestroyWindow, _glfw.glx.handle, "glXDestroyWindow");
|
||||
glfw_dlsym(_glfw.glx.GetProcAddress, _glfw.glx.handle, "glXGetProcAddress");
|
||||
glfw_dlsym(_glfw.glx.GetProcAddressARB, _glfw.glx.handle, "glXGetProcAddressARB");
|
||||
glfw_dlsym(_glfw.glx.GetVisualFromFBConfig, _glfw.glx.handle, "glXGetVisualFromFBConfig");
|
||||
|
||||
if (!_glfw.glx.GetFBConfigs ||
|
||||
!_glfw.glx.GetFBConfigAttrib ||
|
||||
@@ -331,7 +308,7 @@ GLFWbool _glfwInitGLX(void)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"GLX: Failed to load required entry points");
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!glXQueryExtension(_glfw.x11.display,
|
||||
@@ -339,21 +316,21 @@ GLFWbool _glfwInitGLX(void)
|
||||
&_glfw.glx.eventBase))
|
||||
{
|
||||
_glfwInputError(GLFW_API_UNAVAILABLE, "GLX: GLX extension not found");
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!glXQueryVersion(_glfw.x11.display, &_glfw.glx.major, &_glfw.glx.minor))
|
||||
{
|
||||
_glfwInputError(GLFW_API_UNAVAILABLE,
|
||||
"GLX: Failed to query GLX version");
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_glfw.glx.major == 1 && _glfw.glx.minor < 3)
|
||||
{
|
||||
_glfwInputError(GLFW_API_UNAVAILABLE,
|
||||
"GLX: GLX version 1.3 is required");
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (extensionSupportedGLX("GLX_EXT_swap_control"))
|
||||
@@ -362,7 +339,7 @@ GLFWbool _glfwInitGLX(void)
|
||||
getProcAddressGLX("glXSwapIntervalEXT");
|
||||
|
||||
if (_glfw.glx.SwapIntervalEXT)
|
||||
_glfw.glx.EXT_swap_control = GLFW_TRUE;
|
||||
_glfw.glx.EXT_swap_control = true;
|
||||
}
|
||||
|
||||
if (extensionSupportedGLX("GLX_SGI_swap_control"))
|
||||
@@ -371,7 +348,7 @@ GLFWbool _glfwInitGLX(void)
|
||||
getProcAddressGLX("glXSwapIntervalSGI");
|
||||
|
||||
if (_glfw.glx.SwapIntervalSGI)
|
||||
_glfw.glx.SGI_swap_control = GLFW_TRUE;
|
||||
_glfw.glx.SGI_swap_control = true;
|
||||
}
|
||||
|
||||
if (extensionSupportedGLX("GLX_MESA_swap_control"))
|
||||
@@ -380,17 +357,17 @@ GLFWbool _glfwInitGLX(void)
|
||||
getProcAddressGLX("glXSwapIntervalMESA");
|
||||
|
||||
if (_glfw.glx.SwapIntervalMESA)
|
||||
_glfw.glx.MESA_swap_control = GLFW_TRUE;
|
||||
_glfw.glx.MESA_swap_control = true;
|
||||
}
|
||||
|
||||
if (extensionSupportedGLX("GLX_ARB_multisample"))
|
||||
_glfw.glx.ARB_multisample = GLFW_TRUE;
|
||||
_glfw.glx.ARB_multisample = true;
|
||||
|
||||
if (extensionSupportedGLX("GLX_ARB_framebuffer_sRGB"))
|
||||
_glfw.glx.ARB_framebuffer_sRGB = GLFW_TRUE;
|
||||
_glfw.glx.ARB_framebuffer_sRGB = true;
|
||||
|
||||
if (extensionSupportedGLX("GLX_EXT_framebuffer_sRGB"))
|
||||
_glfw.glx.EXT_framebuffer_sRGB = GLFW_TRUE;
|
||||
_glfw.glx.EXT_framebuffer_sRGB = true;
|
||||
|
||||
if (extensionSupportedGLX("GLX_ARB_create_context"))
|
||||
{
|
||||
@@ -398,25 +375,25 @@ GLFWbool _glfwInitGLX(void)
|
||||
getProcAddressGLX("glXCreateContextAttribsARB");
|
||||
|
||||
if (_glfw.glx.CreateContextAttribsARB)
|
||||
_glfw.glx.ARB_create_context = GLFW_TRUE;
|
||||
_glfw.glx.ARB_create_context = true;
|
||||
}
|
||||
|
||||
if (extensionSupportedGLX("GLX_ARB_create_context_robustness"))
|
||||
_glfw.glx.ARB_create_context_robustness = GLFW_TRUE;
|
||||
_glfw.glx.ARB_create_context_robustness = true;
|
||||
|
||||
if (extensionSupportedGLX("GLX_ARB_create_context_profile"))
|
||||
_glfw.glx.ARB_create_context_profile = GLFW_TRUE;
|
||||
_glfw.glx.ARB_create_context_profile = true;
|
||||
|
||||
if (extensionSupportedGLX("GLX_EXT_create_context_es2_profile"))
|
||||
_glfw.glx.EXT_create_context_es2_profile = GLFW_TRUE;
|
||||
_glfw.glx.EXT_create_context_es2_profile = true;
|
||||
|
||||
if (extensionSupportedGLX("GLX_ARB_create_context_no_error"))
|
||||
_glfw.glx.ARB_create_context_no_error = GLFW_TRUE;
|
||||
_glfw.glx.ARB_create_context_no_error = true;
|
||||
|
||||
if (extensionSupportedGLX("GLX_ARB_context_flush_control"))
|
||||
_glfw.glx.ARB_context_flush_control = GLFW_TRUE;
|
||||
_glfw.glx.ARB_context_flush_control = true;
|
||||
|
||||
return GLFW_TRUE;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Terminate GLX
|
||||
@@ -435,14 +412,14 @@ void _glfwTerminateGLX(void)
|
||||
|
||||
#define setAttrib(a, v) \
|
||||
{ \
|
||||
assert((size_t) (index + 1) < sizeof(attribs) / sizeof(attribs[0])); \
|
||||
assert(((size_t) index + 1) < sizeof(attribs) / sizeof(attribs[0])); \
|
||||
attribs[index++] = a; \
|
||||
attribs[index++] = v; \
|
||||
}
|
||||
|
||||
// Create the OpenGL or OpenGL ES context
|
||||
//
|
||||
GLFWbool _glfwCreateContextGLX(_GLFWwindow* window,
|
||||
bool _glfwCreateContextGLX(_GLFWwindow* window,
|
||||
const _GLFWctxconfig* ctxconfig,
|
||||
const _GLFWfbconfig* fbconfig)
|
||||
{
|
||||
@@ -457,7 +434,7 @@ GLFWbool _glfwCreateContextGLX(_GLFWwindow* window,
|
||||
{
|
||||
_glfwInputError(GLFW_FORMAT_UNAVAILABLE,
|
||||
"GLX: Failed to find a suitable GLXFBConfig");
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ctxconfig->client == GLFW_OPENGL_ES_API)
|
||||
@@ -468,7 +445,7 @@ GLFWbool _glfwCreateContextGLX(_GLFWwindow* window,
|
||||
{
|
||||
_glfwInputError(GLFW_API_UNAVAILABLE,
|
||||
"GLX: OpenGL ES requested but GLX_EXT_create_context_es2_profile is unavailable");
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -478,7 +455,7 @@ GLFWbool _glfwCreateContextGLX(_GLFWwindow* window,
|
||||
{
|
||||
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
|
||||
"GLX: Forward compatibility requested but GLX_ARB_create_context_profile is unavailable");
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -489,7 +466,7 @@ GLFWbool _glfwCreateContextGLX(_GLFWwindow* window,
|
||||
{
|
||||
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
|
||||
"GLX: An OpenGL profile requested but GLX_ARB_create_context_profile is unavailable");
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -554,7 +531,7 @@ GLFWbool _glfwCreateContextGLX(_GLFWwindow* window,
|
||||
if (ctxconfig->noerror)
|
||||
{
|
||||
if (_glfw.glx.ARB_create_context_no_error)
|
||||
setAttrib(GLX_CONTEXT_OPENGL_NO_ERROR_ARB, GLFW_TRUE);
|
||||
setAttrib(GLX_CONTEXT_OPENGL_NO_ERROR_ARB, true);
|
||||
}
|
||||
|
||||
// NOTE: Only request an explicitly versioned context when necessary, as
|
||||
@@ -590,7 +567,7 @@ GLFWbool _glfwCreateContextGLX(_GLFWwindow* window,
|
||||
if (_glfw.x11.errorCode == _glfw.glx.errorBase + GLXBadProfileARB &&
|
||||
ctxconfig->client == GLFW_OPENGL_API &&
|
||||
ctxconfig->profile == GLFW_OPENGL_ANY_PROFILE &&
|
||||
ctxconfig->forward == GLFW_FALSE)
|
||||
ctxconfig->forward == false)
|
||||
{
|
||||
window->context.glx.handle =
|
||||
createLegacyContextGLX(window, native, share);
|
||||
@@ -608,7 +585,7 @@ GLFWbool _glfwCreateContextGLX(_GLFWwindow* window,
|
||||
if (!window->context.glx.handle)
|
||||
{
|
||||
_glfwInputErrorX11(GLFW_VERSION_UNAVAILABLE, "GLX: Failed to create context");
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
}
|
||||
|
||||
window->context.glx.window =
|
||||
@@ -616,7 +593,7 @@ GLFWbool _glfwCreateContextGLX(_GLFWwindow* window,
|
||||
if (!window->context.glx.window)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR, "GLX: Failed to create window");
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
}
|
||||
|
||||
window->context.makeCurrent = makeContextCurrentGLX;
|
||||
@@ -626,15 +603,15 @@ GLFWbool _glfwCreateContextGLX(_GLFWwindow* window,
|
||||
window->context.getProcAddress = getProcAddressGLX;
|
||||
window->context.destroy = destroyContextGLX;
|
||||
|
||||
return GLFW_TRUE;
|
||||
return true;
|
||||
}
|
||||
|
||||
#undef setAttrib
|
||||
|
||||
// Returns the Visual and depth of the chosen GLXFBConfig
|
||||
//
|
||||
GLFWbool _glfwChooseVisualGLX(const _GLFWwndconfig* wndconfig,
|
||||
const _GLFWctxconfig* ctxconfig,
|
||||
bool _glfwChooseVisualGLX(const _GLFWwndconfig* wndconfig UNUSED,
|
||||
const _GLFWctxconfig* ctxconfig UNUSED,
|
||||
const _GLFWfbconfig* fbconfig,
|
||||
Visual** visual, int* depth)
|
||||
{
|
||||
@@ -645,7 +622,7 @@ GLFWbool _glfwChooseVisualGLX(const _GLFWwndconfig* wndconfig,
|
||||
{
|
||||
_glfwInputError(GLFW_FORMAT_UNAVAILABLE,
|
||||
"GLX: Failed to find a suitable GLXFBConfig");
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
}
|
||||
|
||||
result = glXGetVisualFromFBConfig(_glfw.x11.display, native);
|
||||
@@ -653,14 +630,14 @@ GLFWbool _glfwChooseVisualGLX(const _GLFWwndconfig* wndconfig,
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"GLX: Failed to retrieve Visual for GLXFBConfig");
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
}
|
||||
|
||||
*visual = result->visual;
|
||||
*depth = result->depth;
|
||||
|
||||
XFree(result);
|
||||
return GLFW_TRUE;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -695,4 +672,3 @@ GLFWAPI GLXWindow glfwGetGLXWindow(GLFWwindow* handle)
|
||||
|
||||
return window->context.glx.window;
|
||||
}
|
||||
|
||||
|
||||
48
glfw/glx_context.h
vendored
48
glfw/glx_context.h
vendored
@@ -1,8 +1,8 @@
|
||||
//========================================================================
|
||||
// GLFW 3.3 GLX - www.glfw.org
|
||||
// GLFW 3.4 GLX - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||
// Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
|
||||
// Copyright (c) 2006-2017 Camilla Löwy <elmindreda@glfw.org>
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
@@ -29,11 +29,11 @@
|
||||
#define GLX_RGBA_BIT 0x00000001
|
||||
#define GLX_WINDOW_BIT 0x00000001
|
||||
#define GLX_DRAWABLE_TYPE 0x8010
|
||||
#define GLX_RENDER_TYPE 0x8011
|
||||
#define GLX_RENDER_TYPE 0x8011
|
||||
#define GLX_RGBA_TYPE 0x8014
|
||||
#define GLX_DOUBLEBUFFER 5
|
||||
#define GLX_STEREO 6
|
||||
#define GLX_AUX_BUFFERS 7
|
||||
#define GLX_AUX_BUFFERS 7
|
||||
#define GLX_RED_SIZE 8
|
||||
#define GLX_GREEN_SIZE 9
|
||||
#define GLX_BLUE_SIZE 10
|
||||
@@ -42,7 +42,7 @@
|
||||
#define GLX_STENCIL_SIZE 13
|
||||
#define GLX_ACCUM_RED_SIZE 14
|
||||
#define GLX_ACCUM_GREEN_SIZE 15
|
||||
#define GLX_ACCUM_BLUE_SIZE 16
|
||||
#define GLX_ACCUM_BLUE_SIZE 16
|
||||
#define GLX_ACCUM_ALPHA_SIZE 17
|
||||
#define GLX_SAMPLES 0x186a1
|
||||
#define GLX_VISUAL_ID 0x800b
|
||||
@@ -73,6 +73,7 @@ typedef struct __GLXcontext* GLXContext;
|
||||
typedef void (*__GLXextproc)(void);
|
||||
|
||||
typedef int (*PFNGLXGETFBCONFIGATTRIBPROC)(Display*,GLXFBConfig,int,int*);
|
||||
typedef GLXFBConfig* (*PFNGLXCHOOSEFBCONFIGPROC)(Display*,int,const int*,int*);
|
||||
typedef const char* (*PFNGLXGETCLIENTSTRINGPROC)(Display*,int);
|
||||
typedef Bool (*PFNGLXQUERYEXTENSIONPROC)(Display*,int*,int*);
|
||||
typedef Bool (*PFNGLXQUERYVERSIONPROC)(Display*,int*,int*);
|
||||
@@ -95,6 +96,7 @@ typedef GLXContext (*PFNGLXCREATECONTEXTATTRIBSARBPROC)(Display*,GLXFBConfig,GLX
|
||||
// libGL.so function pointer typedefs
|
||||
#define glXGetFBConfigs _glfw.glx.GetFBConfigs
|
||||
#define glXGetFBConfigAttrib _glfw.glx.GetFBConfigAttrib
|
||||
#define glXChooseFBConfig _glfw.glx.ChooseFBConfig
|
||||
#define glXGetClientString _glfw.glx.GetClientString
|
||||
#define glXQueryExtension _glfw.glx.QueryExtension
|
||||
#define glXQueryVersion _glfw.glx.QueryVersion
|
||||
@@ -107,8 +109,8 @@ typedef GLXContext (*PFNGLXCREATECONTEXTATTRIBSARBPROC)(Display*,GLXFBConfig,GLX
|
||||
#define glXCreateWindow _glfw.glx.CreateWindow
|
||||
#define glXDestroyWindow _glfw.glx.DestroyWindow
|
||||
|
||||
#define _GLFW_PLATFORM_CONTEXT_STATE _GLFWcontextGLX glx
|
||||
#define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE _GLFWlibraryGLX glx
|
||||
#define _GLFW_PLATFORM_CONTEXT_STATE _GLFWcontextGLX glx;
|
||||
#define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE _GLFWlibraryGLX glx;
|
||||
|
||||
|
||||
// GLX-specific per-context data
|
||||
@@ -134,6 +136,7 @@ typedef struct _GLFWlibraryGLX
|
||||
// GLX 1.3 functions
|
||||
PFNGLXGETFBCONFIGSPROC GetFBConfigs;
|
||||
PFNGLXGETFBCONFIGATTRIBPROC GetFBConfigAttrib;
|
||||
PFNGLXCHOOSEFBCONFIGPROC ChooseFBConfig;
|
||||
PFNGLXGETCLIENTSTRINGPROC GetClientString;
|
||||
PFNGLXQUERYEXTENSIONPROC QueryExtension;
|
||||
PFNGLXQUERYVERSIONPROC QueryVersion;
|
||||
@@ -153,29 +156,28 @@ typedef struct _GLFWlibraryGLX
|
||||
PFNGLXSWAPINTERVALEXTPROC SwapIntervalEXT;
|
||||
PFNGLXSWAPINTERVALMESAPROC SwapIntervalMESA;
|
||||
PFNGLXCREATECONTEXTATTRIBSARBPROC CreateContextAttribsARB;
|
||||
GLFWbool SGI_swap_control;
|
||||
GLFWbool EXT_swap_control;
|
||||
GLFWbool MESA_swap_control;
|
||||
GLFWbool ARB_multisample;
|
||||
GLFWbool ARB_framebuffer_sRGB;
|
||||
GLFWbool EXT_framebuffer_sRGB;
|
||||
GLFWbool ARB_create_context;
|
||||
GLFWbool ARB_create_context_profile;
|
||||
GLFWbool ARB_create_context_robustness;
|
||||
GLFWbool EXT_create_context_es2_profile;
|
||||
GLFWbool ARB_create_context_no_error;
|
||||
GLFWbool ARB_context_flush_control;
|
||||
bool SGI_swap_control;
|
||||
bool EXT_swap_control;
|
||||
bool MESA_swap_control;
|
||||
bool ARB_multisample;
|
||||
bool ARB_framebuffer_sRGB;
|
||||
bool EXT_framebuffer_sRGB;
|
||||
bool ARB_create_context;
|
||||
bool ARB_create_context_profile;
|
||||
bool ARB_create_context_robustness;
|
||||
bool EXT_create_context_es2_profile;
|
||||
bool ARB_create_context_no_error;
|
||||
bool ARB_context_flush_control;
|
||||
|
||||
} _GLFWlibraryGLX;
|
||||
|
||||
GLFWbool _glfwInitGLX(void);
|
||||
bool _glfwInitGLX(void);
|
||||
void _glfwTerminateGLX(void);
|
||||
GLFWbool _glfwCreateContextGLX(_GLFWwindow* window,
|
||||
bool _glfwCreateContextGLX(_GLFWwindow* window,
|
||||
const _GLFWctxconfig* ctxconfig,
|
||||
const _GLFWfbconfig* fbconfig);
|
||||
void _glfwDestroyContextGLX(_GLFWwindow* window);
|
||||
GLFWbool _glfwChooseVisualGLX(const _GLFWwndconfig* wndconfig,
|
||||
bool _glfwChooseVisualGLX(const _GLFWwndconfig* wndconfig,
|
||||
const _GLFWctxconfig* ctxconfig,
|
||||
const _GLFWfbconfig* fbconfig,
|
||||
Visual** visual, int* depth);
|
||||
|
||||
|
||||
107
glfw/ibus_glfw.c
vendored
107
glfw/ibus_glfw.c
vendored
@@ -1,5 +1,5 @@
|
||||
//========================================================================
|
||||
// GLFW 3.3 XKB - www.glfw.org
|
||||
// GLFW 3.4 XKB - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2018 Kovid Goyal <kovid@kovidgoyal.net>
|
||||
//
|
||||
@@ -50,14 +50,14 @@ enum Capabilities {
|
||||
};
|
||||
|
||||
|
||||
static inline GLFWbool
|
||||
static inline bool
|
||||
test_env_var(const char *name, const char *val) {
|
||||
const char *q = getenv(name);
|
||||
return (q && strcmp(q, val) == 0) ? GLFW_TRUE : GLFW_FALSE;
|
||||
return (q && strcmp(q, val) == 0) ? true : false;
|
||||
}
|
||||
|
||||
static inline GLFWbool
|
||||
MIN(size_t a, size_t b) {
|
||||
static inline size_t
|
||||
GLFW_MIN(size_t a, size_t b) {
|
||||
return a < b ? a : b;
|
||||
}
|
||||
|
||||
@@ -107,17 +107,21 @@ get_ibus_text_from_message(DBusMessage *msg) {
|
||||
}
|
||||
|
||||
static inline void
|
||||
send_text(const char *text, int state) {
|
||||
send_text(const char *text, int ime_state) {
|
||||
_GLFWwindow *w = _glfwFocusedWindow();
|
||||
if (w && w->callbacks.keyboard) {
|
||||
w->callbacks.keyboard((GLFWwindow*) w, GLFW_KEY_UNKNOWN, 0, GLFW_PRESS, 0, text, state);
|
||||
GLFWkeyevent fake_ev;
|
||||
_glfwInitializeKeyEvent(&fake_ev, GLFW_KEY_UNKNOWN, 0, GLFW_PRESS, 0);
|
||||
fake_ev.text = text;
|
||||
fake_ev.ime_state = ime_state;
|
||||
w->callbacks.keyboard((GLFWwindow*) w, &fake_ev);
|
||||
}
|
||||
}
|
||||
|
||||
// Connection handling {{{
|
||||
|
||||
static DBusHandlerResult
|
||||
message_handler(DBusConnection *conn, DBusMessage *msg, void *user_data) {
|
||||
message_handler(DBusConnection *conn UNUSED, DBusMessage *msg, void *user_data) {
|
||||
// To monitor signals from IBUS, use
|
||||
// dbus-monitor --address `ibus address` "type='signal',interface='org.freedesktop.IBus.InputContext'"
|
||||
_GLFWIBUSData *ibus = (_GLFWIBUSData*)user_data;
|
||||
@@ -151,7 +155,7 @@ get_ibus_address_file_name(void) {
|
||||
addr = getenv("IBUS_ADDRESS");
|
||||
int offset = 0;
|
||||
if (addr && addr[0]) {
|
||||
memcpy(ans, addr, MIN(strlen(addr), sizeof(ans)));
|
||||
memcpy(ans, addr, GLFW_MIN(strlen(addr), sizeof(ans)));
|
||||
return ans;
|
||||
}
|
||||
|
||||
@@ -193,39 +197,39 @@ get_ibus_address_file_name(void) {
|
||||
}
|
||||
|
||||
|
||||
static inline GLFWbool
|
||||
static inline bool
|
||||
read_ibus_address(_GLFWIBUSData *ibus) {
|
||||
static char buf[1024];
|
||||
struct stat s;
|
||||
FILE *addr_file = fopen(ibus->address_file_name, "r");
|
||||
if (!addr_file) {
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR, "Failed to open IBUS address file: %s with error: %s", ibus->address_file_name, strerror(errno));
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
}
|
||||
int stat_result = fstat(fileno(addr_file), &s);
|
||||
GLFWbool found = GLFW_FALSE;
|
||||
bool found = false;
|
||||
while (fgets(buf, sizeof(buf), addr_file)) {
|
||||
if (strncmp(buf, "IBUS_ADDRESS=", sizeof("IBUS_ADDRESS=")-1) == 0) {
|
||||
size_t sz = strlen(buf);
|
||||
if (buf[sz-1] == '\n') buf[sz-1] = 0;
|
||||
if (buf[sz-2] == '\r') buf[sz-2] = 0;
|
||||
found = GLFW_TRUE;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
fclose(addr_file); addr_file = NULL;
|
||||
if (stat_result != 0) {
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR, "Failed to stat IBUS address file: %s with error: %s", ibus->address_file_name, strerror(errno));
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
}
|
||||
ibus->address_file_mtime = s.st_mtime;
|
||||
if (found) {
|
||||
free((void*)ibus->address);
|
||||
ibus->address = _glfw_strdup(buf + sizeof("IBUS_ADDRESS=") - 1);
|
||||
return GLFW_TRUE;
|
||||
return true;
|
||||
}
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR, "Could not find IBUS_ADDRESS in %s", ibus->address_file_name);
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -245,35 +249,35 @@ input_context_created(DBusMessage *msg, const char* errmsg, void *data) {
|
||||
dbus_connection_try_register_object_path(ibus->conn, ibus->input_ctx_path, &ibus_vtable, ibus, NULL);
|
||||
enum Capabilities caps = IBUS_CAP_FOCUS | IBUS_CAP_PREEDIT_TEXT;
|
||||
if (!glfw_dbus_call_method_no_reply(ibus->conn, IBUS_SERVICE, ibus->input_ctx_path, IBUS_INPUT_INTERFACE, "SetCapabilities", DBUS_TYPE_UINT32, &caps, DBUS_TYPE_INVALID)) return;
|
||||
ibus->ok = GLFW_TRUE;
|
||||
glfw_ibus_set_focused(ibus, GLFW_FALSE);
|
||||
ibus->ok = true;
|
||||
glfw_ibus_set_focused(ibus, false);
|
||||
glfw_ibus_set_cursor_geometry(ibus, 0, 0, 0, 0);
|
||||
debug("Connected to IBUS daemon for IME input management\n");
|
||||
}
|
||||
|
||||
GLFWbool
|
||||
bool
|
||||
setup_connection(_GLFWIBUSData *ibus) {
|
||||
const char *client_name = "GLFW_Application";
|
||||
const char *address_file_name = get_ibus_address_file_name();
|
||||
ibus->ok = GLFW_FALSE;
|
||||
if (!address_file_name) return GLFW_FALSE;
|
||||
ibus->ok = false;
|
||||
if (!address_file_name) return false;
|
||||
free((void*)ibus->address_file_name);
|
||||
ibus->address_file_name = _glfw_strdup(address_file_name);
|
||||
if (!read_ibus_address(ibus)) return GLFW_FALSE;
|
||||
if (!read_ibus_address(ibus)) return false;
|
||||
if (ibus->conn) {
|
||||
glfw_dbus_close_connection(ibus->conn);
|
||||
ibus->conn = NULL;
|
||||
}
|
||||
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", GLFW_FALSE);
|
||||
if (!ibus->conn) return GLFW_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;
|
||||
free((void*)ibus->input_ctx_path); ibus->input_ctx_path = NULL;
|
||||
if (!glfw_dbus_call_method_with_reply(
|
||||
ibus->conn, IBUS_SERVICE, IBUS_PATH, IBUS_INTERFACE, "CreateInputContext", DBUS_TIMEOUT_USE_DEFAULT, input_context_created, ibus,
|
||||
DBUS_TYPE_STRING, &client_name, DBUS_TYPE_INVALID)) {
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
}
|
||||
return GLFW_TRUE;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -281,7 +285,7 @@ void
|
||||
glfw_connect_to_ibus(_GLFWIBUSData *ibus) {
|
||||
if (ibus->inited) return;
|
||||
if (!test_env_var("GLFW_IM_MODULE", "ibus")) return;
|
||||
ibus->inited = GLFW_TRUE;
|
||||
ibus->inited = true;
|
||||
setup_connection(ibus);
|
||||
}
|
||||
|
||||
@@ -297,21 +301,21 @@ glfw_ibus_terminate(_GLFWIBUSData *ibus) {
|
||||
F(address_file_name);
|
||||
#undef F
|
||||
|
||||
ibus->ok = GLFW_FALSE;
|
||||
ibus->ok = false;
|
||||
}
|
||||
|
||||
static GLFWbool
|
||||
static bool
|
||||
check_connection(_GLFWIBUSData *ibus) {
|
||||
if (!ibus->inited) return GLFW_FALSE;
|
||||
if (!ibus->inited) return false;
|
||||
if (ibus->conn && dbus_connection_get_is_connected(ibus->conn)) {
|
||||
return ibus->ok;
|
||||
}
|
||||
struct stat s;
|
||||
if (stat(ibus->address_file_name, &s) != 0 || s.st_mtime != ibus->address_file_mtime) {
|
||||
if (!read_ibus_address(ibus)) return GLFW_FALSE;
|
||||
if (!read_ibus_address(ibus)) return false;
|
||||
setup_connection(ibus);
|
||||
}
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -329,7 +333,7 @@ simple_message(_GLFWIBUSData *ibus, const char *method) {
|
||||
}
|
||||
|
||||
void
|
||||
glfw_ibus_set_focused(_GLFWIBUSData *ibus, GLFWbool focused) {
|
||||
glfw_ibus_set_focused(_GLFWIBUSData *ibus, bool focused) {
|
||||
simple_message(ibus, focused ? "FocusIn" : "FocusOut");
|
||||
}
|
||||
|
||||
@@ -393,34 +397,39 @@ ibus_key_state(unsigned int glfw_modifiers, int action) {
|
||||
void
|
||||
key_event_processed(DBusMessage *msg, const char* errmsg, void *data) {
|
||||
uint32_t handled = 0;
|
||||
KeyEvent *ev = (KeyEvent*)data;
|
||||
GLFWbool is_release = ev->action == GLFW_RELEASE;
|
||||
GLFWbool failed = GLFW_FALSE;
|
||||
_GLFWIBUSKeyEvent *ev = (_GLFWIBUSKeyEvent*)data;
|
||||
// Restore key's text from the text embedded in the structure.
|
||||
ev->glfw_ev.text = ev->__embedded_text;
|
||||
bool is_release = ev->glfw_ev.action == GLFW_RELEASE;
|
||||
bool failed = false;
|
||||
if (errmsg) {
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR, "IBUS: Failed to process key with error: %s", errmsg);
|
||||
failed = GLFW_TRUE;
|
||||
failed = true;
|
||||
} else {
|
||||
glfw_dbus_get_args(msg, "Failed to get IBUS handled key from reply", DBUS_TYPE_BOOLEAN, &handled, DBUS_TYPE_INVALID);
|
||||
debug("IBUS processed scancode: 0x%x release: %d handled: %u\n", ev->keycode, is_release, handled);
|
||||
debug("IBUS processed native_key: 0x%x release: %d handled: %u\n", ev->glfw_ev.native_key, is_release, handled);
|
||||
}
|
||||
glfw_xkb_key_from_ime(ev, handled ? GLFW_TRUE : GLFW_FALSE, failed);
|
||||
glfw_xkb_key_from_ime(ev, handled ? true : false, failed);
|
||||
free(ev);
|
||||
}
|
||||
|
||||
GLFWbool
|
||||
ibus_process_key(const KeyEvent *ev_, _GLFWIBUSData *ibus) {
|
||||
if (!check_connection(ibus)) return GLFW_FALSE;
|
||||
KeyEvent *ev = malloc(sizeof(KeyEvent));
|
||||
if (!ev) return GLFW_FALSE;
|
||||
memcpy(ev, ev_, sizeof(KeyEvent));
|
||||
uint32_t state = ibus_key_state(ev->glfw_modifiers, ev->action);
|
||||
bool
|
||||
ibus_process_key(const _GLFWIBUSKeyEvent *ev_, _GLFWIBUSData *ibus) {
|
||||
if (!check_connection(ibus)) return false;
|
||||
_GLFWIBUSKeyEvent *ev = calloc(1, sizeof(_GLFWIBUSKeyEvent));
|
||||
if (!ev) return false;
|
||||
memcpy(ev, ev_, sizeof(_GLFWIBUSKeyEvent));
|
||||
// Put the key's text in a field IN the structure, for proper serialization.
|
||||
if (ev->glfw_ev.text) strncpy(ev->__embedded_text, ev->glfw_ev.text, sizeof(ev->__embedded_text) - 1);
|
||||
ev->glfw_ev.text = NULL;
|
||||
uint32_t state = ibus_key_state(ev->glfw_ev.mods, ev->glfw_ev.action);
|
||||
if (!glfw_dbus_call_method_with_reply(
|
||||
ibus->conn, IBUS_SERVICE, ibus->input_ctx_path, IBUS_INPUT_INTERFACE, "ProcessKeyEvent",
|
||||
3000, key_event_processed, ev,
|
||||
DBUS_TYPE_UINT32, &ev->ibus_sym, DBUS_TYPE_UINT32, &ev->ibus_keycode, DBUS_TYPE_UINT32,
|
||||
DBUS_TYPE_UINT32, &ev->ibus_keysym, DBUS_TYPE_UINT32, &ev->ibus_keycode, DBUS_TYPE_UINT32,
|
||||
&state, DBUS_TYPE_INVALID)) {
|
||||
free(ev);
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
}
|
||||
return GLFW_TRUE;
|
||||
return true;
|
||||
}
|
||||
|
||||
21
glfw/ibus_glfw.h
vendored
21
glfw/ibus_glfw.h
vendored
@@ -1,5 +1,5 @@
|
||||
//========================================================================
|
||||
// GLFW 3.3 XKB - www.glfw.org
|
||||
// GLFW 3.4 XKB - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2018 Kovid Goyal <kovid@kovidgoyal.net>
|
||||
//
|
||||
@@ -27,29 +27,28 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "internal.h"
|
||||
#include "dbus_glfw.h"
|
||||
#include <xkbcommon/xkbcommon.h>
|
||||
|
||||
typedef struct {
|
||||
GLFWbool ok, inited;
|
||||
bool ok, inited;
|
||||
time_t address_file_mtime;
|
||||
DBusConnection *conn;
|
||||
const char *input_ctx_path, *address_file_name, *address;
|
||||
} _GLFWIBUSData;
|
||||
|
||||
typedef struct {
|
||||
xkb_keycode_t keycode, ibus_keycode;
|
||||
xkb_keysym_t keysym, ibus_sym;
|
||||
unsigned int glfw_modifiers;
|
||||
int action;
|
||||
xkb_keycode_t ibus_keycode;
|
||||
xkb_keysym_t ibus_keysym;
|
||||
GLFWid window_id;
|
||||
int glfw_keycode;
|
||||
char text[64];
|
||||
} KeyEvent;
|
||||
GLFWkeyevent glfw_ev;
|
||||
char __embedded_text[64];
|
||||
} _GLFWIBUSKeyEvent;
|
||||
|
||||
void glfw_connect_to_ibus(_GLFWIBUSData *ibus);
|
||||
void glfw_ibus_terminate(_GLFWIBUSData *ibus);
|
||||
void glfw_ibus_set_focused(_GLFWIBUSData *ibus, GLFWbool focused);
|
||||
void glfw_ibus_set_focused(_GLFWIBUSData *ibus, bool focused);
|
||||
void glfw_ibus_dispatch(_GLFWIBUSData *ibus);
|
||||
GLFWbool ibus_process_key(const KeyEvent *ev_, _GLFWIBUSData *ibus);
|
||||
bool ibus_process_key(const _GLFWIBUSKeyEvent *ev_, _GLFWIBUSData *ibus);
|
||||
void glfw_ibus_set_cursor_geometry(_GLFWIBUSData *ibus, int x, int y, int w, int h);
|
||||
|
||||
95
glfw/init.c
vendored
95
glfw/init.c
vendored
@@ -1,8 +1,8 @@
|
||||
//========================================================================
|
||||
// GLFW 3.3 - www.glfw.org
|
||||
// GLFW 3.4 - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||
// Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
|
||||
// Copyright (c) 2006-2018 Camilla Löwy <elmindreda@glfw.org>
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
@@ -24,6 +24,8 @@
|
||||
// distribution.
|
||||
//
|
||||
//========================================================================
|
||||
// Please use C89 style variable declarations in this file because VS 2010
|
||||
//========================================================================
|
||||
|
||||
#include "internal.h"
|
||||
#include "mappings.h"
|
||||
@@ -41,7 +43,7 @@
|
||||
|
||||
// Global state shared between compilation units of GLFW
|
||||
//
|
||||
_GLFWlibrary _glfw = { GLFW_FALSE };
|
||||
_GLFWlibrary _glfw = { false };
|
||||
|
||||
// These are outside of _glfw so they can be used before initialization and
|
||||
// after termination
|
||||
@@ -50,12 +52,12 @@ static _GLFWerror _glfwMainThreadError;
|
||||
static GLFWerrorfun _glfwErrorCallback;
|
||||
static _GLFWinitconfig _glfwInitHints =
|
||||
{
|
||||
GLFW_TRUE, // hat buttons
|
||||
GLFW_FALSE, // debug keyboard
|
||||
GLFW_TRUE, // enable joystick
|
||||
true, // hat buttons
|
||||
GLFW_ANGLE_PLATFORM_TYPE_NONE, // ANGLE backend
|
||||
false, // debug keyboard
|
||||
{
|
||||
GLFW_TRUE, // macOS menu bar
|
||||
GLFW_TRUE // macOS bundle chdir
|
||||
true, // macOS menu bar
|
||||
true // macOS bundle chdir
|
||||
}
|
||||
};
|
||||
|
||||
@@ -90,9 +92,10 @@ static void terminate(void)
|
||||
_glfw.mappingCount = 0;
|
||||
|
||||
_glfwTerminateVulkan();
|
||||
_glfwPlatformTerminateJoysticks();
|
||||
_glfwPlatformTerminate();
|
||||
|
||||
_glfw.initialized = GLFW_FALSE;
|
||||
_glfw.initialized = false;
|
||||
|
||||
while (_glfw.errorListHead)
|
||||
{
|
||||
@@ -166,6 +169,10 @@ void _glfwInputError(int code, const char* format, ...)
|
||||
strcpy(description, "The requested format is unavailable");
|
||||
else if (code == GLFW_NO_WINDOW_CONTEXT)
|
||||
strcpy(description, "The specified window has no context");
|
||||
else if (code == GLFW_FEATURE_UNAVAILABLE)
|
||||
strcpy(description, "The requested feature cannot be implemented for this platform");
|
||||
else if (code == GLFW_FEATURE_UNIMPLEMENTED)
|
||||
strcpy(description, "The requested feature has not yet been implemented for this platform");
|
||||
else
|
||||
strcpy(description, "ERROR: UNKNOWN GLFW ERROR");
|
||||
}
|
||||
@@ -193,15 +200,30 @@ void _glfwInputError(int code, const char* format, ...)
|
||||
_glfwErrorCallback(code, description);
|
||||
}
|
||||
|
||||
void
|
||||
_glfwDebug(const char *format, ...) {
|
||||
if (format)
|
||||
{
|
||||
va_list vl;
|
||||
|
||||
fprintf(stderr, "[%.4f] ", monotonic_t_to_s_double(glfwGetTime()));
|
||||
va_start(vl, format);
|
||||
vfprintf(stderr, format, vl);
|
||||
va_end(vl);
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW public API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
GLFWAPI int glfwInit(void)
|
||||
GLFWAPI int glfwInit(monotonic_t start_time)
|
||||
{
|
||||
if (_glfw.initialized)
|
||||
return GLFW_TRUE;
|
||||
return true;
|
||||
monotonic_start_time = start_time;
|
||||
|
||||
memset(&_glfw, 0, sizeof(_glfw));
|
||||
_glfw.hints.init = _glfwInitHints;
|
||||
@@ -209,7 +231,7 @@ GLFWAPI int glfwInit(void)
|
||||
if (!_glfwPlatformInit())
|
||||
{
|
||||
terminate();
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!_glfwPlatformCreateMutex(&_glfw.errorLock) ||
|
||||
@@ -217,13 +239,12 @@ GLFWAPI int glfwInit(void)
|
||||
!_glfwPlatformCreateTls(&_glfw.contextSlot))
|
||||
{
|
||||
terminate();
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
}
|
||||
|
||||
_glfwPlatformSetTls(&_glfw.errorSlot, &_glfwMainThreadError);
|
||||
|
||||
_glfw.initialized = GLFW_TRUE;
|
||||
_glfw.timer.offset = _glfwPlatformGetTimerValue();
|
||||
_glfw.initialized = true;
|
||||
|
||||
glfwDefaultWindowHints();
|
||||
|
||||
@@ -235,12 +256,12 @@ GLFWAPI int glfwInit(void)
|
||||
if (!glfwUpdateGamepadMappings(_glfwDefaultMappings[i]))
|
||||
{
|
||||
terminate();
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return GLFW_TRUE;
|
||||
return true;
|
||||
}
|
||||
|
||||
GLFWAPI void glfwTerminate(void)
|
||||
@@ -255,12 +276,12 @@ GLFWAPI void glfwInitHint(int hint, int value)
|
||||
{
|
||||
switch (hint)
|
||||
{
|
||||
case GLFW_ENABLE_JOYSTICKS:
|
||||
_glfwInitHints.enableJoysticks = value;
|
||||
return;
|
||||
case GLFW_JOYSTICK_HAT_BUTTONS:
|
||||
_glfwInitHints.hatButtons = value;
|
||||
return;
|
||||
case GLFW_ANGLE_PLATFORM_TYPE:
|
||||
_glfwInitHints.angleType = value;
|
||||
return;
|
||||
case GLFW_DEBUG_KEYBOARD:
|
||||
_glfwInitHints.debugKeyboard = value;
|
||||
return;
|
||||
@@ -320,3 +341,37 @@ GLFWAPI GLFWerrorfun glfwSetErrorCallback(GLFWerrorfun cbfun)
|
||||
_GLFW_SWAP_POINTERS(_glfwErrorCallback, cbfun);
|
||||
return cbfun;
|
||||
}
|
||||
|
||||
|
||||
GLFWAPI void glfwRunMainLoop(GLFWtickcallback callback, void *data)
|
||||
{
|
||||
_GLFW_REQUIRE_INIT();
|
||||
_glfwPlatformRunMainLoop(callback, data);
|
||||
}
|
||||
|
||||
GLFWAPI void glfwStopMainLoop(void) {
|
||||
_GLFW_REQUIRE_INIT();
|
||||
_glfwPlatformStopMainLoop();
|
||||
}
|
||||
|
||||
GLFWAPI unsigned long long glfwAddTimer(
|
||||
monotonic_t interval, bool repeats, GLFWuserdatafun callback,
|
||||
void *callback_data, GLFWuserdatafun free_callback)
|
||||
{
|
||||
return _glfwPlatformAddTimer(interval, repeats, callback, callback_data, free_callback);
|
||||
}
|
||||
|
||||
GLFWAPI void glfwUpdateTimer(unsigned long long timer_id, monotonic_t interval, bool enabled) {
|
||||
_glfwPlatformUpdateTimer(timer_id, interval, enabled);
|
||||
}
|
||||
|
||||
GLFWAPI void glfwRemoveTimer(unsigned long long timer_id) {
|
||||
_glfwPlatformRemoveTimer(timer_id);
|
||||
}
|
||||
|
||||
GLFWAPI GLFWapplicationclosefun glfwSetApplicationCloseCallback(GLFWapplicationclosefun cbfun)
|
||||
{
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||
_GLFW_SWAP_POINTERS(_glfw.callbacks.application_close, cbfun);
|
||||
return cbfun;
|
||||
}
|
||||
|
||||
598
glfw/input.c
vendored
598
glfw/input.c
vendored
@@ -1,8 +1,8 @@
|
||||
//========================================================================
|
||||
// GLFW 3.3 - www.glfw.org
|
||||
// GLFW 3.4 - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||
// Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
|
||||
// Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
@@ -24,8 +24,11 @@
|
||||
// distribution.
|
||||
//
|
||||
//========================================================================
|
||||
// Please use C89 style variable declarations in this file because VS 2010
|
||||
//========================================================================
|
||||
|
||||
#include "internal.h"
|
||||
#include "../kitty/monotonic.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <float.h>
|
||||
@@ -41,6 +44,22 @@
|
||||
#define _GLFW_JOYSTICK_BUTTON 2
|
||||
#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
|
||||
//
|
||||
static _GLFWmapping* findMapping(const char* guid)
|
||||
@@ -58,17 +77,17 @@ static _GLFWmapping* findMapping(const char* guid)
|
||||
|
||||
// Checks whether a gamepad mapping element is present in the hardware
|
||||
//
|
||||
static GLFWbool isValidElementForJoystick(const _GLFWmapelement* e,
|
||||
static bool isValidElementForJoystick(const _GLFWmapelement* e,
|
||||
const _GLFWjoystick* js)
|
||||
{
|
||||
if (e->type == _GLFW_JOYSTICK_HATBIT && (e->index >> 4) >= js->hatCount)
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
else if (e->type == _GLFW_JOYSTICK_BUTTON && e->index >= js->buttonCount)
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
else if (e->type == _GLFW_JOYSTICK_AXIS && e->index >= js->axisCount)
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
|
||||
return GLFW_TRUE;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Finds a mapping based on joystick GUID and verifies element indices
|
||||
@@ -110,7 +129,7 @@ static _GLFWmapping* findValidMapping(const _GLFWjoystick* js)
|
||||
|
||||
// Parses an SDL_GameControllerDB line and adds it to the mapping list
|
||||
//
|
||||
static GLFWbool parseMapping(_GLFWmapping* mapping, const char* string)
|
||||
static bool parseMapping(_GLFWmapping* mapping, const char* string)
|
||||
{
|
||||
const char* c = string;
|
||||
size_t i, length;
|
||||
@@ -148,7 +167,7 @@ static GLFWbool parseMapping(_GLFWmapping* mapping, const char* string)
|
||||
if (length != 32 || c[length] != ',')
|
||||
{
|
||||
_glfwInputError(GLFW_INVALID_VALUE, NULL);
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(mapping->guid, c, length);
|
||||
@@ -158,7 +177,7 @@ static GLFWbool parseMapping(_GLFWmapping* mapping, const char* string)
|
||||
if (length >= sizeof(mapping->name) || c[length] != ',')
|
||||
{
|
||||
_glfwInputError(GLFW_INVALID_VALUE, NULL);
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(mapping->name, c, length);
|
||||
@@ -168,7 +187,7 @@ static GLFWbool parseMapping(_GLFWmapping* mapping, const char* string)
|
||||
{
|
||||
// TODO: Implement output modifiers
|
||||
if (*c == '+' || *c == '-')
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
|
||||
for (i = 0; i < sizeof(fields) / sizeof(fields[0]); i++)
|
||||
{
|
||||
@@ -229,7 +248,7 @@ static GLFWbool parseMapping(_GLFWmapping* mapping, const char* string)
|
||||
{
|
||||
length = strlen(_GLFW_PLATFORM_MAPPING_NAME);
|
||||
if (strncmp(c, _GLFW_PLATFORM_MAPPING_NAME, length) != 0)
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -246,7 +265,7 @@ static GLFWbool parseMapping(_GLFWmapping* mapping, const char* string)
|
||||
}
|
||||
|
||||
_glfwPlatformUpdateGamepadGUID(mapping->guid);
|
||||
return GLFW_TRUE;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -254,42 +273,53 @@ static GLFWbool parseMapping(_GLFWmapping* mapping, const char* string)
|
||||
////// GLFW event API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Notifies shared code of a key event
|
||||
//
|
||||
void _glfwInputKeyboard(_GLFWwindow* window, int key, int scancode, int action, int mods, const char* text, int state)
|
||||
void _glfwInitializeKeyEvent(GLFWkeyevent *ev, int key, int native_key, int action, int mods)
|
||||
{
|
||||
if (key >= 0 && key <= GLFW_KEY_LAST)
|
||||
{
|
||||
GLFWbool repeated = GLFW_FALSE;
|
||||
ev->key = key;
|
||||
ev->native_key = native_key;
|
||||
ev->action = action;
|
||||
ev->mods = mods;
|
||||
ev->text = NULL;
|
||||
ev->ime_state = 0;
|
||||
}
|
||||
|
||||
if (action == GLFW_RELEASE && window->keys[key] == GLFW_RELEASE)
|
||||
// Notifies shared code of a physical key event
|
||||
//
|
||||
void _glfwInputKeyboard(_GLFWwindow* window, GLFWkeyevent* ev)
|
||||
{
|
||||
if (ev->key >= 0 && ev->key <= GLFW_KEY_LAST)
|
||||
{
|
||||
bool repeated = false;
|
||||
|
||||
if (ev->action == GLFW_RELEASE && window->keys[ev->key] == GLFW_RELEASE)
|
||||
return;
|
||||
|
||||
if (action == GLFW_PRESS && window->keys[key] == GLFW_PRESS)
|
||||
repeated = GLFW_TRUE;
|
||||
if (ev->action == GLFW_PRESS && window->keys[ev->key] == GLFW_PRESS)
|
||||
repeated = true;
|
||||
|
||||
if (action == GLFW_RELEASE && window->stickyKeys)
|
||||
window->keys[key] = _GLFW_STICK;
|
||||
if (ev->action == GLFW_RELEASE && window->stickyKeys)
|
||||
window->keys[ev->key] = _GLFW_STICK;
|
||||
else
|
||||
window->keys[key] = (char) action;
|
||||
window->keys[ev->key] = (char) ev->action;
|
||||
|
||||
if (repeated)
|
||||
action = GLFW_REPEAT;
|
||||
ev->action = GLFW_REPEAT;
|
||||
}
|
||||
|
||||
|
||||
// FIXME: will need to update ev->virtual_mods here too?
|
||||
if (window->callbacks.keyboard) {
|
||||
if (!window->lockKeyMods) mods &= ~(GLFW_MOD_CAPS_LOCK | GLFW_MOD_NUM_LOCK);
|
||||
window->callbacks.keyboard((GLFWwindow*) window, key, scancode, action, mods, text, state);
|
||||
if (!window->lockKeyMods) ev->mods &= ~(GLFW_MOD_CAPS_LOCK | GLFW_MOD_NUM_LOCK);
|
||||
window->callbacks.keyboard((GLFWwindow*) window, ev);
|
||||
}
|
||||
}
|
||||
|
||||
// Notifies shared code of a scroll event
|
||||
//
|
||||
void _glfwInputScroll(_GLFWwindow* window, double xoffset, double yoffset, int flags)
|
||||
void _glfwInputScroll(_GLFWwindow* window, double xoffset, double yoffset, int flags, int mods)
|
||||
{
|
||||
if (window->callbacks.scroll)
|
||||
window->callbacks.scroll((GLFWwindow*) window, xoffset, yoffset, flags);
|
||||
window->callbacks.scroll((GLFWwindow*) window, xoffset, yoffset, flags, mods);
|
||||
}
|
||||
|
||||
// Notifies shared code of a mouse button click event
|
||||
@@ -312,7 +342,7 @@ void _glfwInputMouseClick(_GLFWwindow* window, int button, int action, int mods)
|
||||
}
|
||||
|
||||
// Notifies shared code of a cursor motion event
|
||||
// The position is specified in client-area relative screen coordinates
|
||||
// The position is specified in content area relative screen coordinates
|
||||
//
|
||||
void _glfwInputCursorPos(_GLFWwindow* window, double xpos, double ypos)
|
||||
{
|
||||
@@ -328,7 +358,7 @@ void _glfwInputCursorPos(_GLFWwindow* window, double xpos, double ypos)
|
||||
|
||||
// Notifies shared code of a cursor enter/leave event
|
||||
//
|
||||
void _glfwInputCursorEnter(_GLFWwindow* window, GLFWbool entered)
|
||||
void _glfwInputCursorEnter(_GLFWwindow* window, bool entered)
|
||||
{
|
||||
if (window->callbacks.cursorEnter)
|
||||
window->callbacks.cursorEnter((GLFWwindow*) window, entered);
|
||||
@@ -336,10 +366,11 @@ void _glfwInputCursorEnter(_GLFWwindow* window, GLFWbool entered)
|
||||
|
||||
// Notifies shared code of files or directories dropped on a window
|
||||
//
|
||||
void _glfwInputDrop(_GLFWwindow* window, int count, const char** paths)
|
||||
int _glfwInputDrop(_GLFWwindow* window, const char *mime, const char *text, size_t sz)
|
||||
{
|
||||
if (window->callbacks.drop)
|
||||
window->callbacks.drop((GLFWwindow*) window, count, paths);
|
||||
return window->callbacks.drop((GLFWwindow*) window, mime, text, sz);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Notifies shared code of a joystick connection or disconnection
|
||||
@@ -406,16 +437,16 @@ _GLFWjoystick* _glfwAllocJoystick(const char* name,
|
||||
return NULL;
|
||||
|
||||
js = _glfw.joysticks + jid;
|
||||
js->present = GLFW_TRUE;
|
||||
js->present = true;
|
||||
js->name = _glfw_strdup(name);
|
||||
js->axes = calloc(axisCount, sizeof(float));
|
||||
js->buttons = calloc(buttonCount + hatCount * 4, 1);
|
||||
js->buttons = calloc(buttonCount + (size_t) hatCount * 4, 1);
|
||||
js->hats = calloc(hatCount, 1);
|
||||
js->axisCount = axisCount;
|
||||
js->buttonCount = buttonCount;
|
||||
js->hatCount = hatCount;
|
||||
|
||||
strcpy(js->guid, guid);
|
||||
strncpy(js->guid, guid, sizeof(js->guid) - 1);
|
||||
js->mapping = findValidMapping(js);
|
||||
|
||||
return js;
|
||||
@@ -437,134 +468,208 @@ const char* _glfwGetKeyName(int key)
|
||||
switch (key)
|
||||
{
|
||||
// Printable keys
|
||||
case GLFW_KEY_A: return "A";
|
||||
case GLFW_KEY_B: return "B";
|
||||
case GLFW_KEY_C: return "C";
|
||||
case GLFW_KEY_D: return "D";
|
||||
case GLFW_KEY_E: return "E";
|
||||
case GLFW_KEY_F: return "F";
|
||||
case GLFW_KEY_G: return "G";
|
||||
case GLFW_KEY_H: return "H";
|
||||
case GLFW_KEY_I: return "I";
|
||||
case GLFW_KEY_J: return "J";
|
||||
case GLFW_KEY_K: return "K";
|
||||
case GLFW_KEY_L: return "L";
|
||||
case GLFW_KEY_M: return "M";
|
||||
case GLFW_KEY_N: return "N";
|
||||
case GLFW_KEY_O: return "O";
|
||||
case GLFW_KEY_P: return "P";
|
||||
case GLFW_KEY_Q: return "Q";
|
||||
case GLFW_KEY_R: return "R";
|
||||
case GLFW_KEY_S: return "S";
|
||||
case GLFW_KEY_T: return "T";
|
||||
case GLFW_KEY_U: return "U";
|
||||
case GLFW_KEY_V: return "V";
|
||||
case GLFW_KEY_W: return "W";
|
||||
case GLFW_KEY_X: return "X";
|
||||
case GLFW_KEY_Y: return "Y";
|
||||
case GLFW_KEY_Z: return "Z";
|
||||
case GLFW_KEY_1: return "1";
|
||||
case GLFW_KEY_2: return "2";
|
||||
case GLFW_KEY_3: return "3";
|
||||
case GLFW_KEY_4: return "4";
|
||||
case GLFW_KEY_5: return "5";
|
||||
case GLFW_KEY_6: return "6";
|
||||
case GLFW_KEY_7: return "7";
|
||||
case GLFW_KEY_8: return "8";
|
||||
case GLFW_KEY_9: return "9";
|
||||
case GLFW_KEY_0: return "0";
|
||||
case GLFW_KEY_SPACE: return "SPACE";
|
||||
case GLFW_KEY_MINUS: return "MINUS";
|
||||
case GLFW_KEY_EQUAL: return "EQUAL";
|
||||
case GLFW_KEY_LEFT_BRACKET: return "LEFT BRACKET";
|
||||
case GLFW_KEY_RIGHT_BRACKET: return "RIGHT BRACKET";
|
||||
case GLFW_KEY_BACKSLASH: return "BACKSLASH";
|
||||
case GLFW_KEY_SEMICOLON: return "SEMICOLON";
|
||||
case GLFW_KEY_APOSTROPHE: return "APOSTROPHE";
|
||||
case GLFW_KEY_GRAVE_ACCENT: return "GRAVE ACCENT";
|
||||
case GLFW_KEY_COMMA: return "COMMA";
|
||||
case GLFW_KEY_PERIOD: return "PERIOD";
|
||||
case GLFW_KEY_SLASH: return "SLASH";
|
||||
case GLFW_KEY_WORLD_1: return "WORLD 1";
|
||||
case GLFW_KEY_WORLD_2: return "WORLD 2";
|
||||
case GLFW_KEY_PLUS: return "PLUS";
|
||||
case GLFW_KEY_SPACE: return "SPACE";
|
||||
case GLFW_KEY_EXCLAM: return "EXCLAM";
|
||||
case GLFW_KEY_DOUBLE_QUOTE: return "DOUBLE_QUOTE";
|
||||
case GLFW_KEY_NUMBER_SIGN: return "NUMBER_SIGN";
|
||||
case GLFW_KEY_DOLLAR: return "DOLLAR";
|
||||
case GLFW_KEY_AMPERSAND: return "AMPERSAND";
|
||||
case GLFW_KEY_APOSTROPHE: return "APOSTROPHE";
|
||||
case GLFW_KEY_PARENTHESIS_LEFT: return "PARENTHESIS_LEFT";
|
||||
case GLFW_KEY_PARENTHESIS_RIGHT: return "PARENTHESIS_RIGHT";
|
||||
case GLFW_KEY_PLUS: return "PLUS";
|
||||
case GLFW_KEY_COMMA: return "COMMA";
|
||||
case GLFW_KEY_MINUS: return "MINUS";
|
||||
case GLFW_KEY_PERIOD: return "PERIOD";
|
||||
case GLFW_KEY_SLASH: return "SLASH";
|
||||
case GLFW_KEY_0: return "0";
|
||||
case GLFW_KEY_1: return "1";
|
||||
case GLFW_KEY_2: return "2";
|
||||
case GLFW_KEY_3: return "3";
|
||||
case GLFW_KEY_4: return "4";
|
||||
case GLFW_KEY_5: return "5";
|
||||
case GLFW_KEY_6: return "6";
|
||||
case GLFW_KEY_7: return "7";
|
||||
case GLFW_KEY_8: return "8";
|
||||
case GLFW_KEY_9: return "9";
|
||||
case GLFW_KEY_COLON: return "COLON";
|
||||
case GLFW_KEY_SEMICOLON: return "SEMICOLON";
|
||||
case GLFW_KEY_LESS: return "LESS";
|
||||
case GLFW_KEY_EQUAL: return "EQUAL";
|
||||
case GLFW_KEY_GREATER: return "GREATER";
|
||||
case GLFW_KEY_AT: return "AT";
|
||||
case GLFW_KEY_A: return "A";
|
||||
case GLFW_KEY_B: return "B";
|
||||
case GLFW_KEY_C: return "C";
|
||||
case GLFW_KEY_D: return "D";
|
||||
case GLFW_KEY_E: return "E";
|
||||
case GLFW_KEY_F: return "F";
|
||||
case GLFW_KEY_G: return "G";
|
||||
case GLFW_KEY_H: return "H";
|
||||
case GLFW_KEY_I: return "I";
|
||||
case GLFW_KEY_J: return "J";
|
||||
case GLFW_KEY_K: return "K";
|
||||
case GLFW_KEY_L: return "L";
|
||||
case GLFW_KEY_M: return "M";
|
||||
case GLFW_KEY_N: return "N";
|
||||
case GLFW_KEY_O: return "O";
|
||||
case GLFW_KEY_P: return "P";
|
||||
case GLFW_KEY_Q: return "Q";
|
||||
case GLFW_KEY_R: return "R";
|
||||
case GLFW_KEY_S: return "S";
|
||||
case GLFW_KEY_T: return "T";
|
||||
case GLFW_KEY_U: return "U";
|
||||
case GLFW_KEY_V: return "V";
|
||||
case GLFW_KEY_W: return "W";
|
||||
case GLFW_KEY_X: return "X";
|
||||
case GLFW_KEY_Y: return "Y";
|
||||
case GLFW_KEY_Z: return "Z";
|
||||
case GLFW_KEY_LEFT_BRACKET: return "LEFT_BRACKET";
|
||||
case GLFW_KEY_BACKSLASH: return "BACKSLASH";
|
||||
case GLFW_KEY_RIGHT_BRACKET: return "RIGHT_BRACKET";
|
||||
case GLFW_KEY_CIRCUMFLEX: return "CIRCUMFLEX";
|
||||
case GLFW_KEY_UNDERSCORE: return "UNDERSCORE";
|
||||
case GLFW_KEY_GRAVE_ACCENT: return "GRAVE_ACCENT";
|
||||
case GLFW_KEY_WORLD_1: return "WORLD_1";
|
||||
case GLFW_KEY_WORLD_2: return "WORLD_2";
|
||||
case GLFW_KEY_PARAGRAPH: return "PARAGRAPH";
|
||||
case GLFW_KEY_MASCULINE: return "MASCULINE";
|
||||
case GLFW_KEY_A_GRAVE: return "A_GRAVE";
|
||||
case GLFW_KEY_A_DIAERESIS: return "A_DIAERESIS";
|
||||
case GLFW_KEY_A_RING: return "A_RING";
|
||||
case GLFW_KEY_AE: return "AE";
|
||||
case GLFW_KEY_C_CEDILLA: return "C_CEDILLA";
|
||||
case GLFW_KEY_E_GRAVE: return "E_GRAVE";
|
||||
case GLFW_KEY_E_ACUTE: return "E_ACUTE";
|
||||
case GLFW_KEY_I_GRAVE: return "I_GRAVE";
|
||||
case GLFW_KEY_N_TILDE: return "N_TILDE";
|
||||
case GLFW_KEY_O_GRAVE: return "O_GRAVE";
|
||||
case GLFW_KEY_O_DIAERESIS: return "O_DIAERESIS";
|
||||
case GLFW_KEY_O_SLASH: return "O_SLASH";
|
||||
case GLFW_KEY_U_GRAVE: return "U_GRAVE";
|
||||
case GLFW_KEY_U_DIAERESIS: return "U_DIAERESIS";
|
||||
case GLFW_KEY_S_SHARP: return "S_SHARP";
|
||||
case GLFW_KEY_CYRILLIC_A: return "CYRILLIC_A";
|
||||
case GLFW_KEY_CYRILLIC_BE: return "CYRILLIC_BE";
|
||||
case GLFW_KEY_CYRILLIC_VE: return "CYRILLIC_VE";
|
||||
case GLFW_KEY_CYRILLIC_GHE: return "CYRILLIC_GHE";
|
||||
case GLFW_KEY_CYRILLIC_DE: return "CYRILLIC_DE";
|
||||
case GLFW_KEY_CYRILLIC_IE: return "CYRILLIC_IE";
|
||||
case GLFW_KEY_CYRILLIC_ZHE: return "CYRILLIC_ZHE";
|
||||
case GLFW_KEY_CYRILLIC_ZE: return "CYRILLIC_ZE";
|
||||
case GLFW_KEY_CYRILLIC_I: return "CYRILLIC_I";
|
||||
case GLFW_KEY_CYRILLIC_SHORT_I: return "CYRILLIC_SHORT_I";
|
||||
case GLFW_KEY_CYRILLIC_KA: return "CYRILLIC_KA";
|
||||
case GLFW_KEY_CYRILLIC_EL: return "CYRILLIC_EL";
|
||||
case GLFW_KEY_CYRILLIC_EM: return "CYRILLIC_EM";
|
||||
case GLFW_KEY_CYRILLIC_EN: return "CYRILLIC_EN";
|
||||
case GLFW_KEY_CYRILLIC_O: return "CYRILLIC_O";
|
||||
case GLFW_KEY_CYRILLIC_PE: return "CYRILLIC_PE";
|
||||
case GLFW_KEY_CYRILLIC_ER: return "CYRILLIC_ER";
|
||||
case GLFW_KEY_CYRILLIC_ES: return "CYRILLIC_ES";
|
||||
case GLFW_KEY_CYRILLIC_TE: return "CYRILLIC_TE";
|
||||
case GLFW_KEY_CYRILLIC_U: return "CYRILLIC_U";
|
||||
case GLFW_KEY_CYRILLIC_EF: return "CYRILLIC_EF";
|
||||
case GLFW_KEY_CYRILLIC_HA: return "CYRILLIC_HA";
|
||||
case GLFW_KEY_CYRILLIC_TSE: return "CYRILLIC_TSE";
|
||||
case GLFW_KEY_CYRILLIC_CHE: return "CYRILLIC_CHE";
|
||||
case GLFW_KEY_CYRILLIC_SHA: return "CYRILLIC_SHA";
|
||||
case GLFW_KEY_CYRILLIC_SHCHA: return "CYRILLIC_SHCHA";
|
||||
case GLFW_KEY_CYRILLIC_HARD_SIGN: return "CYRILLIC_HARD_SIGN";
|
||||
case GLFW_KEY_CYRILLIC_YERU: return "CYRILLIC_YERU";
|
||||
case GLFW_KEY_CYRILLIC_SOFT_SIGN: return "CYRILLIC_SOFT_SIGN";
|
||||
case GLFW_KEY_CYRILLIC_E: return "CYRILLIC_E";
|
||||
case GLFW_KEY_CYRILLIC_YU: return "CYRILLIC_YU";
|
||||
case GLFW_KEY_CYRILLIC_YA: return "CYRILLIC_YA";
|
||||
case GLFW_KEY_CYRILLIC_IO: return "CYRILLIC_IO";
|
||||
|
||||
// Function keys
|
||||
case GLFW_KEY_ESCAPE: return "ESCAPE";
|
||||
case GLFW_KEY_F1: return "F1";
|
||||
case GLFW_KEY_F2: return "F2";
|
||||
case GLFW_KEY_F3: return "F3";
|
||||
case GLFW_KEY_F4: return "F4";
|
||||
case GLFW_KEY_F5: return "F5";
|
||||
case GLFW_KEY_F6: return "F6";
|
||||
case GLFW_KEY_F7: return "F7";
|
||||
case GLFW_KEY_F8: return "F8";
|
||||
case GLFW_KEY_F9: return "F9";
|
||||
case GLFW_KEY_F10: return "F10";
|
||||
case GLFW_KEY_F11: return "F11";
|
||||
case GLFW_KEY_F12: return "F12";
|
||||
case GLFW_KEY_F13: return "F13";
|
||||
case GLFW_KEY_F14: return "F14";
|
||||
case GLFW_KEY_F15: return "F15";
|
||||
case GLFW_KEY_F16: return "F16";
|
||||
case GLFW_KEY_F17: return "F17";
|
||||
case GLFW_KEY_F18: return "F18";
|
||||
case GLFW_KEY_F19: return "F19";
|
||||
case GLFW_KEY_F20: return "F20";
|
||||
case GLFW_KEY_F21: return "F21";
|
||||
case GLFW_KEY_F22: return "F22";
|
||||
case GLFW_KEY_F23: return "F23";
|
||||
case GLFW_KEY_F24: return "F24";
|
||||
case GLFW_KEY_F25: return "F25";
|
||||
case GLFW_KEY_UP: return "UP";
|
||||
case GLFW_KEY_DOWN: return "DOWN";
|
||||
case GLFW_KEY_LEFT: return "LEFT";
|
||||
case GLFW_KEY_RIGHT: return "RIGHT";
|
||||
case GLFW_KEY_LEFT_SHIFT: return "LEFT SHIFT";
|
||||
case GLFW_KEY_RIGHT_SHIFT: return "RIGHT SHIFT";
|
||||
case GLFW_KEY_LEFT_CONTROL: return "LEFT CONTROL";
|
||||
case GLFW_KEY_RIGHT_CONTROL: return "RIGHT CONTROL";
|
||||
case GLFW_KEY_LEFT_ALT: return "LEFT ALT";
|
||||
case GLFW_KEY_RIGHT_ALT: return "RIGHT ALT";
|
||||
case GLFW_KEY_TAB: return "TAB";
|
||||
case GLFW_KEY_ENTER: return "ENTER";
|
||||
case GLFW_KEY_BACKSPACE: return "BACKSPACE";
|
||||
case GLFW_KEY_INSERT: return "INSERT";
|
||||
case GLFW_KEY_DELETE: return "DELETE";
|
||||
case GLFW_KEY_PAGE_UP: return "PAGE UP";
|
||||
case GLFW_KEY_PAGE_DOWN: return "PAGE DOWN";
|
||||
case GLFW_KEY_HOME: return "HOME";
|
||||
case GLFW_KEY_END: return "END";
|
||||
case GLFW_KEY_KP_0: return "KEYPAD 0";
|
||||
case GLFW_KEY_KP_1: return "KEYPAD 1";
|
||||
case GLFW_KEY_KP_2: return "KEYPAD 2";
|
||||
case GLFW_KEY_KP_3: return "KEYPAD 3";
|
||||
case GLFW_KEY_KP_4: return "KEYPAD 4";
|
||||
case GLFW_KEY_KP_5: return "KEYPAD 5";
|
||||
case GLFW_KEY_KP_6: return "KEYPAD 6";
|
||||
case GLFW_KEY_KP_7: return "KEYPAD 7";
|
||||
case GLFW_KEY_KP_8: return "KEYPAD 8";
|
||||
case GLFW_KEY_KP_9: return "KEYPAD 9";
|
||||
case GLFW_KEY_KP_DIVIDE: return "KEYPAD DIVIDE";
|
||||
case GLFW_KEY_KP_MULTIPLY: return "KEYPAD MULTPLY";
|
||||
case GLFW_KEY_KP_SUBTRACT: return "KEYPAD SUBTRACT";
|
||||
case GLFW_KEY_KP_ADD: return "KEYPAD ADD";
|
||||
case GLFW_KEY_KP_DECIMAL: return "KEYPAD DECIMAL";
|
||||
case GLFW_KEY_KP_EQUAL: return "KEYPAD EQUAL";
|
||||
case GLFW_KEY_KP_ENTER: return "KEYPAD ENTER";
|
||||
case GLFW_KEY_PRINT_SCREEN: return "PRINT SCREEN";
|
||||
case GLFW_KEY_NUM_LOCK: return "NUM LOCK";
|
||||
case GLFW_KEY_CAPS_LOCK: return "CAPS LOCK";
|
||||
case GLFW_KEY_SCROLL_LOCK: return "SCROLL LOCK";
|
||||
case GLFW_KEY_PAUSE: return "PAUSE";
|
||||
case GLFW_KEY_LEFT_SUPER: return "LEFT SUPER";
|
||||
case GLFW_KEY_RIGHT_SUPER: return "RIGHT SUPER";
|
||||
case GLFW_KEY_MENU: return "MENU";
|
||||
case GLFW_KEY_ESCAPE: return "ESCAPE";
|
||||
case GLFW_KEY_F1: return "F1";
|
||||
case GLFW_KEY_F2: return "F2";
|
||||
case GLFW_KEY_F3: return "F3";
|
||||
case GLFW_KEY_F4: return "F4";
|
||||
case GLFW_KEY_F5: return "F5";
|
||||
case GLFW_KEY_F6: return "F6";
|
||||
case GLFW_KEY_F7: return "F7";
|
||||
case GLFW_KEY_F8: return "F8";
|
||||
case GLFW_KEY_F9: return "F9";
|
||||
case GLFW_KEY_F10: return "F10";
|
||||
case GLFW_KEY_F11: return "F11";
|
||||
case GLFW_KEY_F12: return "F12";
|
||||
case GLFW_KEY_F13: return "F13";
|
||||
case GLFW_KEY_F14: return "F14";
|
||||
case GLFW_KEY_F15: return "F15";
|
||||
case GLFW_KEY_F16: return "F16";
|
||||
case GLFW_KEY_F17: return "F17";
|
||||
case GLFW_KEY_F18: return "F18";
|
||||
case GLFW_KEY_F19: return "F19";
|
||||
case GLFW_KEY_F20: return "F20";
|
||||
case GLFW_KEY_F21: return "F21";
|
||||
case GLFW_KEY_F22: return "F22";
|
||||
case GLFW_KEY_F23: return "F23";
|
||||
case GLFW_KEY_F24: return "F24";
|
||||
case GLFW_KEY_F25: return "F25";
|
||||
case GLFW_KEY_UP: return "UP";
|
||||
case GLFW_KEY_DOWN: return "DOWN";
|
||||
case GLFW_KEY_LEFT: return "LEFT";
|
||||
case GLFW_KEY_RIGHT: return "RIGHT";
|
||||
case GLFW_KEY_LEFT_SHIFT: return "LEFT SHIFT";
|
||||
case GLFW_KEY_RIGHT_SHIFT: return "RIGHT SHIFT";
|
||||
case GLFW_KEY_LEFT_CONTROL: return "LEFT CONTROL";
|
||||
case GLFW_KEY_RIGHT_CONTROL: return "RIGHT CONTROL";
|
||||
case GLFW_KEY_LEFT_ALT: return "LEFT ALT";
|
||||
case GLFW_KEY_RIGHT_ALT: return "RIGHT ALT";
|
||||
case GLFW_KEY_TAB: return "TAB";
|
||||
case GLFW_KEY_ENTER: return "ENTER";
|
||||
case GLFW_KEY_BACKSPACE: return "BACKSPACE";
|
||||
case GLFW_KEY_INSERT: return "INSERT";
|
||||
case GLFW_KEY_DELETE: return "DELETE";
|
||||
case GLFW_KEY_PAGE_UP: return "PAGE UP";
|
||||
case GLFW_KEY_PAGE_DOWN: return "PAGE DOWN";
|
||||
case GLFW_KEY_HOME: return "HOME";
|
||||
case GLFW_KEY_END: return "END";
|
||||
case GLFW_KEY_KP_0: return "KEYPAD 0";
|
||||
case GLFW_KEY_KP_1: return "KEYPAD 1";
|
||||
case GLFW_KEY_KP_2: return "KEYPAD 2";
|
||||
case GLFW_KEY_KP_3: return "KEYPAD 3";
|
||||
case GLFW_KEY_KP_4: return "KEYPAD 4";
|
||||
case GLFW_KEY_KP_5: return "KEYPAD 5";
|
||||
case GLFW_KEY_KP_6: return "KEYPAD 6";
|
||||
case GLFW_KEY_KP_7: return "KEYPAD 7";
|
||||
case GLFW_KEY_KP_8: return "KEYPAD 8";
|
||||
case GLFW_KEY_KP_9: return "KEYPAD 9";
|
||||
case GLFW_KEY_KP_DIVIDE: return "KEYPAD DIVIDE";
|
||||
case GLFW_KEY_KP_MULTIPLY: return "KEYPAD MULTIPLY";
|
||||
case GLFW_KEY_KP_SUBTRACT: return "KEYPAD SUBTRACT";
|
||||
case GLFW_KEY_KP_ADD: return "KEYPAD ADD";
|
||||
case GLFW_KEY_KP_DECIMAL: return "KEYPAD DECIMAL";
|
||||
case GLFW_KEY_KP_EQUAL: return "KEYPAD EQUAL";
|
||||
case GLFW_KEY_KP_ENTER: return "KEYPAD ENTER";
|
||||
case GLFW_KEY_PRINT_SCREEN: return "PRINT SCREEN";
|
||||
case GLFW_KEY_NUM_LOCK: return "NUM LOCK";
|
||||
case GLFW_KEY_CAPS_LOCK: return "CAPS LOCK";
|
||||
case GLFW_KEY_SCROLL_LOCK: return "SCROLL LOCK";
|
||||
case GLFW_KEY_PAUSE: return "PAUSE";
|
||||
case GLFW_KEY_LEFT_SUPER: return "LEFT SUPER";
|
||||
case GLFW_KEY_RIGHT_SUPER: return "RIGHT SUPER";
|
||||
case GLFW_KEY_MENU: return "MENU";
|
||||
|
||||
default: return "UNKNOWN";
|
||||
default: return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
// Center the cursor in the content area of the specified window
|
||||
//
|
||||
void _glfwCenterCursorInContentArea(_GLFWwindow* window)
|
||||
{
|
||||
int width, height;
|
||||
|
||||
_glfwPlatformGetWindowSize(window, &width, &height);
|
||||
_glfwPlatformSetCursorPos(window, width / 2.0, height / 2.0);
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW public API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
@@ -586,6 +691,8 @@ GLFWAPI int glfwGetInputMode(GLFWwindow* handle, int mode)
|
||||
return window->stickyMouseButtons;
|
||||
case GLFW_LOCK_KEY_MODS:
|
||||
return window->lockKeyMods;
|
||||
case GLFW_RAW_MOUSE_MOTION:
|
||||
return window->rawMouseMotion;
|
||||
}
|
||||
|
||||
_glfwInputError(GLFW_INVALID_ENUM, "Invalid input mode 0x%08X", mode);
|
||||
@@ -623,7 +730,7 @@ GLFWAPI void glfwSetInputMode(GLFWwindow* handle, int mode, int value)
|
||||
}
|
||||
else if (mode == GLFW_STICKY_KEYS)
|
||||
{
|
||||
value = value ? GLFW_TRUE : GLFW_FALSE;
|
||||
value = value ? true : false;
|
||||
if (window->stickyKeys == value)
|
||||
return;
|
||||
|
||||
@@ -643,7 +750,7 @@ GLFWAPI void glfwSetInputMode(GLFWwindow* handle, int mode, int value)
|
||||
}
|
||||
else if (mode == GLFW_STICKY_MOUSE_BUTTONS)
|
||||
{
|
||||
value = value ? GLFW_TRUE : GLFW_FALSE;
|
||||
value = value ? true : false;
|
||||
if (window->stickyMouseButtons == value)
|
||||
return;
|
||||
|
||||
@@ -662,12 +769,36 @@ GLFWAPI void glfwSetInputMode(GLFWwindow* handle, int mode, int value)
|
||||
window->stickyMouseButtons = value;
|
||||
}
|
||||
else if (mode == GLFW_LOCK_KEY_MODS)
|
||||
window->lockKeyMods = value ? GLFW_TRUE : GLFW_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
|
||||
_glfwInputError(GLFW_INVALID_ENUM, "Invalid input mode 0x%08X", mode);
|
||||
}
|
||||
|
||||
GLFWAPI const char* glfwGetKeyName(int key, int scancode)
|
||||
GLFWAPI int glfwRawMouseMotionSupported(void)
|
||||
{
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(false);
|
||||
return _glfwPlatformRawMouseMotionSupported();
|
||||
}
|
||||
|
||||
GLFWAPI const char* glfwGetKeyName(int key, int native_key)
|
||||
{
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||
|
||||
@@ -675,18 +806,18 @@ GLFWAPI const char* glfwGetKeyName(int key, int scancode)
|
||||
{
|
||||
if (key != GLFW_KEY_KP_EQUAL &&
|
||||
(key < GLFW_KEY_KP_0 || key > GLFW_KEY_KP_ADD) &&
|
||||
(key < GLFW_KEY_APOSTROPHE || key > GLFW_KEY_WORLD_2))
|
||||
(key < GLFW_KEY_APOSTROPHE || key > GLFW_KEY_LAST_PRINTABLE))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
scancode = _glfwPlatformGetKeyScancode(key);
|
||||
native_key = _glfwPlatformGetNativeKeyForKey(key);
|
||||
}
|
||||
|
||||
return _glfwPlatformGetScancodeName(scancode);
|
||||
return _glfwPlatformGetNativeKeyName(native_key);
|
||||
}
|
||||
|
||||
GLFWAPI int glfwGetKeyScancode(int key)
|
||||
GLFWAPI int glfwGetNativeKeyForKey(int key)
|
||||
{
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(-1);
|
||||
|
||||
@@ -696,7 +827,7 @@ GLFWAPI int glfwGetKeyScancode(int key)
|
||||
return GLFW_RELEASE;
|
||||
}
|
||||
|
||||
return _glfwPlatformGetKeyScancode(key);
|
||||
return _glfwPlatformGetNativeKeyForKey(key);
|
||||
}
|
||||
|
||||
GLFWAPI int glfwGetKey(GLFWwindow* handle, int key)
|
||||
@@ -822,20 +953,15 @@ GLFWAPI GLFWcursor* glfwCreateCursor(const GLFWimage* image, int xhot, int yhot,
|
||||
return (GLFWcursor*) cursor;
|
||||
}
|
||||
|
||||
GLFWAPI GLFWcursor* glfwCreateStandardCursor(int shape)
|
||||
GLFWAPI GLFWcursor* glfwCreateStandardCursor(GLFWCursorShape shape)
|
||||
{
|
||||
_GLFWcursor* cursor;
|
||||
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||
|
||||
if (shape != GLFW_ARROW_CURSOR &&
|
||||
shape != GLFW_IBEAM_CURSOR &&
|
||||
shape != GLFW_CROSSHAIR_CURSOR &&
|
||||
shape != GLFW_HAND_CURSOR &&
|
||||
shape != GLFW_HRESIZE_CURSOR &&
|
||||
shape != GLFW_VRESIZE_CURSOR)
|
||||
if (shape >= GLFW_INVALID_CURSOR)
|
||||
{
|
||||
_glfwInputError(GLFW_INVALID_ENUM, "Invalid standard cursor 0x%08X", shape);
|
||||
_glfwInputError(GLFW_INVALID_ENUM, "Invalid standard cursor: %d", shape);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -915,7 +1041,7 @@ GLFWAPI void glfwUpdateIMEState(GLFWwindow* handle, int which, int a, int b, int
|
||||
assert(window != NULL);
|
||||
|
||||
_GLFW_REQUIRE_INIT();
|
||||
#if defined(_GLFW_X11) || defined(_GLFW_WAYLAND)
|
||||
#if defined(_GLFW_X11) || defined(_GLFW_WAYLAND) || defined(_GLFW_COCOA)
|
||||
_glfwPlatformUpdateIMEState(window, which, a, b, c, d);
|
||||
#else
|
||||
(void)window; (void)which; (void)a; (void)b; (void)c; (void)d;
|
||||
@@ -983,17 +1109,20 @@ GLFWAPI int glfwJoystickPresent(int jid)
|
||||
assert(jid >= GLFW_JOYSTICK_1);
|
||||
assert(jid <= GLFW_JOYSTICK_LAST);
|
||||
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE);
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(false);
|
||||
|
||||
if (jid < 0 || jid > GLFW_JOYSTICK_LAST)
|
||||
{
|
||||
_glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid);
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!initJoysticks())
|
||||
return false;
|
||||
|
||||
js = _glfw.joysticks + jid;
|
||||
if (!js->present)
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
|
||||
return _glfwPlatformPollJoystick(js, _GLFW_POLL_PRESENCE);
|
||||
}
|
||||
@@ -1016,6 +1145,9 @@ GLFWAPI const float* glfwGetJoystickAxes(int jid, int* count)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!initJoysticks())
|
||||
return NULL;
|
||||
|
||||
js = _glfw.joysticks + jid;
|
||||
if (!js->present)
|
||||
return NULL;
|
||||
@@ -1045,6 +1177,9 @@ GLFWAPI const unsigned char* glfwGetJoystickButtons(int jid, int* count)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!initJoysticks())
|
||||
return NULL;
|
||||
|
||||
js = _glfw.joysticks + jid;
|
||||
if (!js->present)
|
||||
return NULL;
|
||||
@@ -1078,6 +1213,9 @@ GLFWAPI const unsigned char* glfwGetJoystickHats(int jid, int* count)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!initJoysticks())
|
||||
return NULL;
|
||||
|
||||
js = _glfw.joysticks + jid;
|
||||
if (!js->present)
|
||||
return NULL;
|
||||
@@ -1104,6 +1242,9 @@ GLFWAPI const char* glfwGetJoystickName(int jid)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!initJoysticks())
|
||||
return NULL;
|
||||
|
||||
js = _glfw.joysticks + jid;
|
||||
if (!js->present)
|
||||
return NULL;
|
||||
@@ -1129,6 +1270,9 @@ GLFWAPI const char* glfwGetJoystickGUID(int jid)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!initJoysticks())
|
||||
return NULL;
|
||||
|
||||
js = _glfw.joysticks + jid;
|
||||
if (!js->present)
|
||||
return NULL;
|
||||
@@ -1174,6 +1318,10 @@ GLFWAPI void* glfwGetJoystickUserPointer(int jid)
|
||||
GLFWAPI GLFWjoystickfun glfwSetJoystickCallback(GLFWjoystickfun cbfun)
|
||||
{
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||
|
||||
if (!initJoysticks())
|
||||
return NULL;
|
||||
|
||||
_GLFW_SWAP_POINTERS(_glfw.callbacks.joystick, cbfun);
|
||||
return cbfun;
|
||||
}
|
||||
@@ -1185,7 +1333,7 @@ GLFWAPI int glfwUpdateGamepadMappings(const char* string)
|
||||
|
||||
assert(string != NULL);
|
||||
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE);
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(false);
|
||||
|
||||
while (*c)
|
||||
{
|
||||
@@ -1235,7 +1383,7 @@ GLFWAPI int glfwUpdateGamepadMappings(const char* string)
|
||||
js->mapping = findValidMapping(js);
|
||||
}
|
||||
|
||||
return GLFW_TRUE;
|
||||
return true;
|
||||
}
|
||||
|
||||
GLFWAPI int glfwJoystickIsGamepad(int jid)
|
||||
@@ -1245,20 +1393,23 @@ GLFWAPI int glfwJoystickIsGamepad(int jid)
|
||||
assert(jid >= GLFW_JOYSTICK_1);
|
||||
assert(jid <= GLFW_JOYSTICK_LAST);
|
||||
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE);
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(false);
|
||||
|
||||
if (jid < 0 || jid > GLFW_JOYSTICK_LAST)
|
||||
{
|
||||
_glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid);
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!initJoysticks())
|
||||
return false;
|
||||
|
||||
js = _glfw.joysticks + jid;
|
||||
if (!js->present)
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
|
||||
if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_PRESENCE))
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
|
||||
return js->mapping != NULL;
|
||||
}
|
||||
@@ -1278,6 +1429,9 @@ GLFWAPI const char* glfwGetGamepadName(int jid)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!initJoysticks())
|
||||
return NULL;
|
||||
|
||||
js = _glfw.joysticks + jid;
|
||||
if (!js->present)
|
||||
return NULL;
|
||||
@@ -1302,23 +1456,26 @@ GLFWAPI int glfwGetGamepadState(int jid, GLFWgamepadstate* state)
|
||||
|
||||
memset(state, 0, sizeof(GLFWgamepadstate));
|
||||
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE);
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(false);
|
||||
|
||||
if (jid < 0 || jid > GLFW_JOYSTICK_LAST)
|
||||
{
|
||||
_glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid);
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!initJoysticks())
|
||||
return false;
|
||||
|
||||
js = _glfw.joysticks + jid;
|
||||
if (!js->present)
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
|
||||
if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_ALL))
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
|
||||
if (!js->mapping)
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
|
||||
for (i = 0; i <= GLFW_GAMEPAD_BUTTON_LAST; i++)
|
||||
{
|
||||
@@ -1326,8 +1483,18 @@ GLFWAPI int glfwGetGamepadState(int jid, GLFWgamepadstate* state)
|
||||
if (e->type == _GLFW_JOYSTICK_AXIS)
|
||||
{
|
||||
const float value = js->axes[e->index] * e->axisScale + e->axisOffset;
|
||||
if (value > 0.f)
|
||||
state->buttons[i] = GLFW_PRESS;
|
||||
// HACK: This should be baked into the value transform
|
||||
// TODO: Bake into transform when implementing output modifiers
|
||||
if (e->axisOffset < 0 || (e->axisOffset == 0 && e->axisScale > 0))
|
||||
{
|
||||
if (value >= 0.f)
|
||||
state->buttons[i] = GLFW_PRESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (value <= 0.f)
|
||||
state->buttons[i] = GLFW_PRESS;
|
||||
}
|
||||
}
|
||||
else if (e->type == _GLFW_JOYSTICK_HATBIT)
|
||||
{
|
||||
@@ -1354,15 +1521,17 @@ GLFWAPI int glfwGetGamepadState(int jid, GLFWgamepadstate* state)
|
||||
const unsigned int bit = e->index & 0xf;
|
||||
if (js->hats[hat] & bit)
|
||||
state->axes[i] = 1.f;
|
||||
else
|
||||
state->axes[i] = -1.f;
|
||||
}
|
||||
else if (e->type == _GLFW_JOYSTICK_BUTTON)
|
||||
state->axes[i] = (float) js->buttons[e->index];
|
||||
state->axes[i] = js->buttons[e->index] * 2.f - 1.f;
|
||||
}
|
||||
|
||||
return GLFW_TRUE;
|
||||
return true;
|
||||
}
|
||||
|
||||
GLFWAPI void glfwSetClipboardString(GLFWwindow* handle, const char* string)
|
||||
GLFWAPI void glfwSetClipboardString(GLFWwindow* handle UNUSED, const char* string)
|
||||
{
|
||||
assert(string != NULL);
|
||||
|
||||
@@ -1370,14 +1539,14 @@ GLFWAPI void glfwSetClipboardString(GLFWwindow* handle, const char* string)
|
||||
_glfwPlatformSetClipboardString(string);
|
||||
}
|
||||
|
||||
GLFWAPI const char* glfwGetClipboardString(GLFWwindow* handle)
|
||||
GLFWAPI const char* glfwGetClipboardString(GLFWwindow* handle UNUSED)
|
||||
{
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||
return _glfwPlatformGetClipboardString();
|
||||
}
|
||||
|
||||
#if defined(_GLFW_X11) || defined(_GLFW_WAYLAND)
|
||||
GLFWAPI void glfwSetPrimarySelectionString(GLFWwindow* handle, const char* string)
|
||||
GLFWAPI void glfwSetPrimarySelectionString(GLFWwindow* handle UNUSED, const char* string)
|
||||
{
|
||||
assert(string != NULL);
|
||||
|
||||
@@ -1385,42 +1554,15 @@ GLFWAPI void glfwSetPrimarySelectionString(GLFWwindow* handle, const char* strin
|
||||
_glfwPlatformSetPrimarySelectionString(string);
|
||||
}
|
||||
|
||||
GLFWAPI const char* glfwGetPrimarySelectionString(GLFWwindow* handle)
|
||||
GLFWAPI const char* glfwGetPrimarySelectionString(GLFWwindow* handle UNUSED)
|
||||
{
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||
return _glfwPlatformGetPrimarySelectionString();
|
||||
}
|
||||
#endif
|
||||
|
||||
GLFWAPI double glfwGetTime(void)
|
||||
{
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(0.0);
|
||||
return (double) (_glfwPlatformGetTimerValue() - _glfw.timer.offset) /
|
||||
_glfwPlatformGetTimerFrequency();
|
||||
}
|
||||
|
||||
GLFWAPI void glfwSetTime(double time)
|
||||
{
|
||||
_GLFW_REQUIRE_INIT();
|
||||
|
||||
if (time != time || time < 0.0 || time > 18446744073.0)
|
||||
{
|
||||
_glfwInputError(GLFW_INVALID_VALUE, "Invalid time %f", time);
|
||||
return;
|
||||
}
|
||||
|
||||
_glfw.timer.offset = _glfwPlatformGetTimerValue() -
|
||||
(uint64_t) (time * _glfwPlatformGetTimerFrequency());
|
||||
}
|
||||
|
||||
GLFWAPI uint64_t glfwGetTimerValue(void)
|
||||
GLFWAPI monotonic_t glfwGetTime(void)
|
||||
{
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(0);
|
||||
return _glfwPlatformGetTimerValue();
|
||||
}
|
||||
|
||||
GLFWAPI uint64_t glfwGetTimerFrequency(void)
|
||||
{
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(0);
|
||||
return _glfwPlatformGetTimerFrequency();
|
||||
return monotonic();
|
||||
}
|
||||
|
||||
250
glfw/internal.h
vendored
250
glfw/internal.h
vendored
@@ -1,8 +1,8 @@
|
||||
//========================================================================
|
||||
// GLFW 3.3 - www.glfw.org
|
||||
// GLFW 3.4 - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||
// Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
|
||||
// Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
@@ -27,6 +27,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../kitty/monotonic.h"
|
||||
|
||||
#if defined(_GLFW_USE_CONFIG_H)
|
||||
#include "glfw_config.h"
|
||||
#endif
|
||||
@@ -60,7 +62,6 @@
|
||||
|
||||
#define _GLFW_MESSAGE_SIZE 1024
|
||||
|
||||
typedef int GLFWbool;
|
||||
typedef unsigned long long GLFWid;
|
||||
|
||||
typedef struct _GLFWerror _GLFWerror;
|
||||
@@ -87,8 +88,8 @@ typedef GLFWglproc (* _GLFWgetprocaddressfun)(const char*);
|
||||
typedef void (* _GLFWdestroycontextfun)(_GLFWwindow*);
|
||||
|
||||
#define GL_VERSION 0x1f02
|
||||
#define GL_NONE 0
|
||||
#define GL_COLOR_BUFFER_BIT 0x00004000
|
||||
#define GL_NONE 0
|
||||
#define GL_COLOR_BUFFER_BIT 0x00004000
|
||||
#define GL_UNSIGNED_BYTE 0x1401
|
||||
#define GL_EXTENSIONS 0x1f03
|
||||
#define GL_NUM_EXTENSIONS 0x821d
|
||||
@@ -105,7 +106,7 @@ typedef void (* _GLFWdestroycontextfun)(_GLFWwindow*);
|
||||
#define GL_CONTEXT_RELEASE_BEHAVIOR_FLUSH 0x82fc
|
||||
#define GL_CONTEXT_FLAG_NO_ERROR_BIT_KHR 0x00000008
|
||||
|
||||
typedef int GLint;
|
||||
typedef int GLint;
|
||||
typedef unsigned int GLuint;
|
||||
typedef unsigned int GLenum;
|
||||
typedef unsigned int GLbitfield;
|
||||
@@ -131,6 +132,7 @@ typedef enum VkStructureType
|
||||
VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR = 1000006000,
|
||||
VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR = 1000009000,
|
||||
VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK = 1000123000,
|
||||
VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT = 1000217000,
|
||||
VK_STRUCTURE_TYPE_MAX_ENUM = 0x7FFFFFFF
|
||||
} VkStructureType;
|
||||
|
||||
@@ -196,6 +198,16 @@ typedef void (APIENTRY * PFN_vkVoidFunction)(void);
|
||||
#error "No supported window creation API selected"
|
||||
#endif
|
||||
|
||||
#include "egl_context.h"
|
||||
#include "osmesa_context.h"
|
||||
|
||||
#define remove_i_from_array(array, i, count) { \
|
||||
(count)--; \
|
||||
if ((i) < (count)) { \
|
||||
memmove((array) + (i), (array) + (i) + 1, sizeof((array)[0]) * ((count) - (i))); \
|
||||
}}
|
||||
|
||||
|
||||
// Constructs a version number string from the public header macros
|
||||
#define _GLFW_CONCAT_VERSION(m, n, r) #m "." #n "." #r
|
||||
#define _GLFW_MAKE_VERSION(m, n, r) _GLFW_CONCAT_VERSION(m, n, r)
|
||||
@@ -219,12 +231,32 @@ typedef void (APIENTRY * PFN_vkVoidFunction)(void);
|
||||
|
||||
// Swaps the provided pointers
|
||||
#define _GLFW_SWAP_POINTERS(x, y) \
|
||||
{ \
|
||||
void* t; \
|
||||
do{ \
|
||||
__typeof__(x) t; \
|
||||
t = x; \
|
||||
x = y; \
|
||||
y = t; \
|
||||
}
|
||||
}while(0)
|
||||
|
||||
|
||||
// Suppress some pedantic warnings
|
||||
#ifdef __clang__
|
||||
#define START_ALLOW_CASE_RANGE _Pragma("clang diagnostic push") _Pragma("clang diagnostic ignored \"-Wpedantic\"")
|
||||
#define END_ALLOW_CASE_RANGE _Pragma("clang diagnostic pop")
|
||||
#define ALLOW_UNUSED_RESULT _Pragma("clang diagnostic push") _Pragma("clang diagnostic ignored \"-Wunused-result\"")
|
||||
#define END_ALLOW_UNUSED_RESULT _Pragma("clang diagnostic pop")
|
||||
#else
|
||||
#define START_ALLOW_CASE_RANGE _Pragma("GCC diagnostic ignored \"-Wpedantic\"")
|
||||
#define END_ALLOW_CASE_RANGE _Pragma("GCC diagnostic pop")
|
||||
#define ALLOW_UNUSED_RESULT _Pragma("GCC diagnostic ignored \"-Wunused-result\"")
|
||||
#define END_ALLOW_UNUSED_RESULT _Pragma("GCC diagnostic pop")
|
||||
#endif
|
||||
|
||||
// dlsym that works with -Wpedantic
|
||||
#define glfw_dlsym(dest, handle, name) do {*(void **)&(dest) = _glfw_dlsym(handle, name);}while (0)
|
||||
|
||||
// Mark function arguments as unused
|
||||
#define UNUSED __attribute__ ((unused))
|
||||
|
||||
// Per-thread error structure
|
||||
//
|
||||
@@ -241,12 +273,12 @@ struct _GLFWerror
|
||||
//
|
||||
struct _GLFWinitconfig
|
||||
{
|
||||
GLFWbool hatButtons;
|
||||
GLFWbool debugKeyboard;
|
||||
GLFWbool enableJoysticks;
|
||||
bool hatButtons;
|
||||
int angleType;
|
||||
bool debugKeyboard;
|
||||
struct {
|
||||
GLFWbool menubar;
|
||||
GLFWbool chdir;
|
||||
bool menubar;
|
||||
bool chdir;
|
||||
} ns;
|
||||
};
|
||||
|
||||
@@ -261,18 +293,19 @@ struct _GLFWwndconfig
|
||||
int width;
|
||||
int height;
|
||||
const char* title;
|
||||
GLFWbool resizable;
|
||||
GLFWbool visible;
|
||||
GLFWbool decorated;
|
||||
GLFWbool focused;
|
||||
GLFWbool autoIconify;
|
||||
GLFWbool floating;
|
||||
GLFWbool maximized;
|
||||
GLFWbool centerCursor;
|
||||
GLFWbool focusOnShow;
|
||||
GLFWbool scaleToMonitor;
|
||||
bool resizable;
|
||||
bool visible;
|
||||
bool decorated;
|
||||
bool focused;
|
||||
bool autoIconify;
|
||||
bool floating;
|
||||
bool maximized;
|
||||
bool centerCursor;
|
||||
bool focusOnShow;
|
||||
bool mousePassthrough;
|
||||
bool scaleToMonitor;
|
||||
struct {
|
||||
GLFWbool retina;
|
||||
bool retina;
|
||||
char frameName[256];
|
||||
} ns;
|
||||
struct {
|
||||
@@ -296,15 +329,15 @@ struct _GLFWctxconfig
|
||||
int source;
|
||||
int major;
|
||||
int minor;
|
||||
GLFWbool forward;
|
||||
GLFWbool debug;
|
||||
GLFWbool noerror;
|
||||
bool forward;
|
||||
bool debug;
|
||||
bool noerror;
|
||||
int profile;
|
||||
int robustness;
|
||||
int release;
|
||||
_GLFWwindow* share;
|
||||
struct {
|
||||
GLFWbool offline;
|
||||
bool offline;
|
||||
} nsgl;
|
||||
};
|
||||
|
||||
@@ -329,11 +362,11 @@ struct _GLFWfbconfig
|
||||
int accumBlueBits;
|
||||
int accumAlphaBits;
|
||||
int auxBuffers;
|
||||
GLFWbool stereo;
|
||||
bool stereo;
|
||||
int samples;
|
||||
GLFWbool sRGB;
|
||||
GLFWbool doublebuffer;
|
||||
GLFWbool transparent;
|
||||
bool sRGB;
|
||||
bool doublebuffer;
|
||||
bool transparent;
|
||||
uintptr_t handle;
|
||||
};
|
||||
|
||||
@@ -344,7 +377,7 @@ struct _GLFWcontext
|
||||
int client;
|
||||
int source;
|
||||
int major, minor, revision;
|
||||
GLFWbool forward, debug, noerror;
|
||||
bool forward, debug, noerror;
|
||||
int profile;
|
||||
int robustness;
|
||||
int release;
|
||||
@@ -361,11 +394,11 @@ struct _GLFWcontext
|
||||
_GLFWdestroycontextfun destroy;
|
||||
|
||||
// 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
|
||||
_GLFW_EGL_CONTEXT_STATE;
|
||||
_GLFWcontextEGL egl;
|
||||
// This is defined in osmesa_context.h
|
||||
_GLFW_OSMESA_CONTEXT_STATE;
|
||||
_GLFWcontextOSMesa osmesa;
|
||||
};
|
||||
|
||||
// Window and context structure
|
||||
@@ -375,12 +408,13 @@ struct _GLFWwindow
|
||||
struct _GLFWwindow* next;
|
||||
|
||||
// Window settings and state
|
||||
GLFWbool resizable;
|
||||
GLFWbool decorated;
|
||||
GLFWbool autoIconify;
|
||||
GLFWbool floating;
|
||||
GLFWbool focusOnShow;
|
||||
GLFWbool shouldClose;
|
||||
bool resizable;
|
||||
bool decorated;
|
||||
bool autoIconify;
|
||||
bool floating;
|
||||
bool focusOnShow;
|
||||
bool mousePassthrough;
|
||||
bool shouldClose;
|
||||
void* userPointer;
|
||||
GLFWid id;
|
||||
GLFWvidmode videoMode;
|
||||
@@ -390,15 +424,17 @@ struct _GLFWwindow
|
||||
int minwidth, minheight;
|
||||
int maxwidth, maxheight;
|
||||
int numer, denom;
|
||||
int widthincr, heightincr;
|
||||
|
||||
GLFWbool stickyKeys;
|
||||
GLFWbool stickyMouseButtons;
|
||||
GLFWbool lockKeyMods;
|
||||
bool stickyKeys;
|
||||
bool stickyMouseButtons;
|
||||
bool lockKeyMods;
|
||||
int cursorMode;
|
||||
char mouseButtons[GLFW_MOUSE_BUTTON_LAST + 1];
|
||||
char keys[GLFW_KEY_LAST + 1];
|
||||
// Virtual cursor position when cursor is disabled
|
||||
double virtualCursorPosX, virtualCursorPosY;
|
||||
bool rawMouseMotion;
|
||||
|
||||
_GLFWcontext context;
|
||||
|
||||
@@ -408,6 +444,7 @@ struct _GLFWwindow
|
||||
GLFWwindowclosefun close;
|
||||
GLFWwindowrefreshfun refresh;
|
||||
GLFWwindowfocusfun focus;
|
||||
GLFWwindowocclusionfun occlusion;
|
||||
GLFWwindowiconifyfun iconify;
|
||||
GLFWwindowmaximizefun maximize;
|
||||
GLFWframebuffersizefun fbsize;
|
||||
@@ -418,6 +455,7 @@ struct _GLFWwindow
|
||||
GLFWscrollfun scroll;
|
||||
GLFWkeyboardfun keyboard;
|
||||
GLFWdropfun drop;
|
||||
GLFWliveresizefun liveResize;
|
||||
} callbacks;
|
||||
|
||||
// This is defined in the window API's platform.h
|
||||
@@ -482,7 +520,7 @@ struct _GLFWmapping
|
||||
//
|
||||
struct _GLFWjoystick
|
||||
{
|
||||
GLFWbool present;
|
||||
bool present;
|
||||
float* axes;
|
||||
int axisCount;
|
||||
unsigned char* buttons;
|
||||
@@ -518,7 +556,7 @@ struct _GLFWmutex
|
||||
//
|
||||
struct _GLFWlibrary
|
||||
{
|
||||
GLFWbool initialized;
|
||||
bool initialized;
|
||||
|
||||
struct {
|
||||
_GLFWinitconfig init;
|
||||
@@ -536,6 +574,7 @@ struct _GLFWlibrary
|
||||
_GLFWmonitor** monitors;
|
||||
int monitorCount;
|
||||
|
||||
bool joysticksInitialized;
|
||||
_GLFWjoystick joysticks[GLFW_JOYSTICK_LAST + 1];
|
||||
_GLFWmapping* mappings;
|
||||
int mappingCount;
|
||||
@@ -545,47 +584,44 @@ struct _GLFWlibrary
|
||||
_GLFWmutex errorLock;
|
||||
|
||||
struct {
|
||||
uint64_t offset;
|
||||
// This is defined in the platform's time.h
|
||||
_GLFW_PLATFORM_LIBRARY_TIMER_STATE;
|
||||
} timer;
|
||||
|
||||
struct {
|
||||
GLFWbool available;
|
||||
bool available;
|
||||
void* handle;
|
||||
char* extensions[2];
|
||||
#if !defined(_GLFW_VULKAN_STATIC)
|
||||
PFN_vkEnumerateInstanceExtensionProperties EnumerateInstanceExtensionProperties;
|
||||
PFN_vkGetInstanceProcAddr GetInstanceProcAddr;
|
||||
#endif
|
||||
GLFWbool KHR_surface;
|
||||
bool KHR_surface;
|
||||
#if defined(_GLFW_WIN32)
|
||||
GLFWbool KHR_win32_surface;
|
||||
bool KHR_win32_surface;
|
||||
#elif defined(_GLFW_COCOA)
|
||||
GLFWbool MVK_macos_surface;
|
||||
bool MVK_macos_surface;
|
||||
bool EXT_metal_surface;
|
||||
#elif defined(_GLFW_X11)
|
||||
GLFWbool KHR_xlib_surface;
|
||||
GLFWbool KHR_xcb_surface;
|
||||
bool KHR_xlib_surface;
|
||||
bool KHR_xcb_surface;
|
||||
#elif defined(_GLFW_WAYLAND)
|
||||
GLFWbool KHR_wayland_surface;
|
||||
bool KHR_wayland_surface;
|
||||
#endif
|
||||
} vk;
|
||||
|
||||
struct {
|
||||
GLFWmonitorfun monitor;
|
||||
GLFWjoystickfun joystick;
|
||||
GLFWapplicationclosefun application_close;
|
||||
} callbacks;
|
||||
|
||||
|
||||
// This is defined in the window API's platform.h
|
||||
_GLFW_PLATFORM_LIBRARY_WINDOW_STATE;
|
||||
// This is defined in the context API's context.h
|
||||
_GLFW_PLATFORM_LIBRARY_CONTEXT_STATE;
|
||||
_GLFW_PLATFORM_LIBRARY_CONTEXT_STATE
|
||||
// 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
|
||||
_GLFW_EGL_LIBRARY_CONTEXT_STATE;
|
||||
_GLFWlibraryEGL egl;
|
||||
// This is defined in osmesa_context.h
|
||||
_GLFW_OSMESA_LIBRARY_CONTEXT_STATE;
|
||||
_GLFWlibraryOSMesa osmesa;
|
||||
};
|
||||
|
||||
// Global state shared between compilation units of GLFW
|
||||
@@ -604,22 +640,25 @@ const char* _glfwPlatformGetVersionString(void);
|
||||
void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos);
|
||||
void _glfwPlatformSetCursorPos(_GLFWwindow* window, double xpos, double ypos);
|
||||
void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode);
|
||||
void _glfwPlatformSetRawMouseMotion(_GLFWwindow *window, bool enabled);
|
||||
bool _glfwPlatformRawMouseMotionSupported(void);
|
||||
int _glfwPlatformCreateCursor(_GLFWcursor* cursor,
|
||||
const GLFWimage* image, int xhot, int yhot, int count);
|
||||
int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape);
|
||||
int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, GLFWCursorShape shape);
|
||||
void _glfwPlatformDestroyCursor(_GLFWcursor* cursor);
|
||||
void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor);
|
||||
|
||||
const char* _glfwPlatformGetScancodeName(int scancode);
|
||||
int _glfwPlatformGetKeyScancode(int key);
|
||||
const char* _glfwPlatformGetNativeKeyName(int native_key);
|
||||
int _glfwPlatformGetNativeKeyForKey(int key);
|
||||
|
||||
void _glfwPlatformFreeMonitor(_GLFWmonitor* monitor);
|
||||
void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos);
|
||||
void _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor,
|
||||
float* xscale, float* yscale);
|
||||
void _glfwPlatformGetMonitorWorkarea(_GLFWmonitor* monitor, int* xpos, int* ypos, int *width, int *height);
|
||||
GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count);
|
||||
void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode);
|
||||
GLFWbool _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp);
|
||||
bool _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp);
|
||||
void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp);
|
||||
|
||||
void _glfwPlatformSetClipboardString(const char* string);
|
||||
@@ -629,12 +668,11 @@ void _glfwPlatformSetPrimarySelectionString(const char* string);
|
||||
const char* _glfwPlatformGetPrimarySelectionString(void);
|
||||
#endif
|
||||
|
||||
bool _glfwPlatformInitJoysticks(void);
|
||||
void _glfwPlatformTerminateJoysticks(void);
|
||||
int _glfwPlatformPollJoystick(_GLFWjoystick* js, int mode);
|
||||
void _glfwPlatformUpdateGamepadGUID(char* guid);
|
||||
|
||||
uint64_t _glfwPlatformGetTimerValue(void);
|
||||
uint64_t _glfwPlatformGetTimerFrequency(void);
|
||||
|
||||
int _glfwPlatformCreateWindow(_GLFWwindow* window,
|
||||
const _GLFWwndconfig* wndconfig,
|
||||
const _GLFWctxconfig* ctxconfig,
|
||||
@@ -651,13 +689,15 @@ void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window,
|
||||
int minwidth, int minheight,
|
||||
int maxwidth, int maxheight);
|
||||
void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window, int numer, int denom);
|
||||
void _glfwPlatformSetWindowSizeIncrements(_GLFWwindow* window, int widthincr, int heightincr);
|
||||
void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* height);
|
||||
void _glfwInputLiveResize(_GLFWwindow* window, bool started);
|
||||
void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window,
|
||||
int* left, int* top,
|
||||
int* right, int* bottom);
|
||||
void _glfwPlatformGetWindowContentScale(_GLFWwindow* window,
|
||||
float* xscale, float* yscale);
|
||||
double _glfwPlatformGetDoubleClickInterval(_GLFWwindow* window);
|
||||
monotonic_t _glfwPlatformGetDoubleClickInterval(_GLFWwindow* window);
|
||||
void _glfwPlatformIconifyWindow(_GLFWwindow* window);
|
||||
void _glfwPlatformRestoreWindow(_GLFWwindow* window);
|
||||
void _glfwPlatformMaximizeWindow(_GLFWwindow* window);
|
||||
@@ -669,24 +709,31 @@ void _glfwPlatformFocusWindow(_GLFWwindow* window);
|
||||
void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, _GLFWmonitor* monitor,
|
||||
int xpos, int ypos, int width, int height,
|
||||
int refreshRate);
|
||||
bool _glfwPlatformToggleFullscreen(_GLFWwindow *w, unsigned int flags);
|
||||
int _glfwPlatformWindowFocused(_GLFWwindow* window);
|
||||
int _glfwPlatformWindowOccluded(_GLFWwindow* window);
|
||||
int _glfwPlatformWindowIconified(_GLFWwindow* window);
|
||||
int _glfwPlatformWindowVisible(_GLFWwindow* window);
|
||||
int _glfwPlatformWindowMaximized(_GLFWwindow* window);
|
||||
int _glfwPlatformWindowHovered(_GLFWwindow* window);
|
||||
int _glfwPlatformFramebufferTransparent(_GLFWwindow* window);
|
||||
float _glfwPlatformGetWindowOpacity(_GLFWwindow* window);
|
||||
void _glfwPlatformSetWindowResizable(_GLFWwindow* window, GLFWbool enabled);
|
||||
void _glfwPlatformSetWindowDecorated(_GLFWwindow* window, GLFWbool enabled);
|
||||
void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled);
|
||||
void _glfwPlatformSetWindowResizable(_GLFWwindow* window, bool enabled);
|
||||
void _glfwPlatformSetWindowDecorated(_GLFWwindow* window, bool enabled);
|
||||
void _glfwPlatformSetWindowFloating(_GLFWwindow* window, bool enabled);
|
||||
void _glfwPlatformSetWindowMousePassthrough(_GLFWwindow* window, bool enabled);
|
||||
void _glfwPlatformSetWindowOpacity(_GLFWwindow* window, float opacity);
|
||||
void _glfwPlatformUpdateIMEState(_GLFWwindow *w, int which, int a, int b, int c, int d);
|
||||
|
||||
void _glfwPlatformPollEvents(void);
|
||||
void _glfwPlatformWaitEvents(void);
|
||||
void _glfwPlatformWaitEventsTimeout(double timeout);
|
||||
void _glfwPlatformWaitEventsTimeout(monotonic_t timeout);
|
||||
void _glfwPlatformPostEmptyEvent(void);
|
||||
|
||||
EGLenum _glfwPlatformGetEGLPlatform(EGLint** attribs);
|
||||
EGLNativeDisplayType _glfwPlatformGetEGLNativeDisplay(void);
|
||||
EGLNativeWindowType _glfwPlatformGetEGLNativeWindow(_GLFWwindow* window);
|
||||
|
||||
void _glfwPlatformGetRequiredInstanceExtensions(char** extensions);
|
||||
int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance,
|
||||
VkPhysicalDevice device,
|
||||
@@ -696,12 +743,12 @@ VkResult _glfwPlatformCreateWindowSurface(VkInstance instance,
|
||||
const VkAllocationCallbacks* allocator,
|
||||
VkSurfaceKHR* surface);
|
||||
|
||||
GLFWbool _glfwPlatformCreateTls(_GLFWtls* tls);
|
||||
bool _glfwPlatformCreateTls(_GLFWtls* tls);
|
||||
void _glfwPlatformDestroyTls(_GLFWtls* tls);
|
||||
void* _glfwPlatformGetTls(_GLFWtls* tls);
|
||||
void _glfwPlatformSetTls(_GLFWtls* tls, void* value);
|
||||
|
||||
GLFWbool _glfwPlatformCreateMutex(_GLFWmutex* mutex);
|
||||
bool _glfwPlatformCreateMutex(_GLFWmutex* mutex);
|
||||
void _glfwPlatformDestroyMutex(_GLFWmutex* mutex);
|
||||
void _glfwPlatformLockMutex(_GLFWmutex* mutex);
|
||||
void _glfwPlatformUnlockMutex(_GLFWmutex* mutex);
|
||||
@@ -711,24 +758,26 @@ void _glfwPlatformUnlockMutex(_GLFWmutex* mutex);
|
||||
////// GLFW event API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void _glfwInputWindowFocus(_GLFWwindow* window, GLFWbool focused);
|
||||
void _glfwInputWindowFocus(_GLFWwindow* window, bool focused);
|
||||
void _glfwInputWindowOcclusion(_GLFWwindow* window, bool occluded);
|
||||
void _glfwInputWindowPos(_GLFWwindow* window, int xpos, int ypos);
|
||||
void _glfwInputWindowSize(_GLFWwindow* window, int width, int height);
|
||||
void _glfwInputFramebufferSize(_GLFWwindow* window, int width, int height);
|
||||
void _glfwInputWindowContentScale(_GLFWwindow* window,
|
||||
float xscale, float yscale);
|
||||
void _glfwInputWindowIconify(_GLFWwindow* window, GLFWbool iconified);
|
||||
void _glfwInputWindowMaximize(_GLFWwindow* window, GLFWbool maximized);
|
||||
void _glfwInputWindowIconify(_GLFWwindow* window, bool iconified);
|
||||
void _glfwInputWindowMaximize(_GLFWwindow* window, bool maximized);
|
||||
void _glfwInputWindowDamage(_GLFWwindow* window);
|
||||
void _glfwInputWindowCloseRequest(_GLFWwindow* window);
|
||||
void _glfwInputWindowMonitor(_GLFWwindow* window, _GLFWmonitor* monitor);
|
||||
|
||||
void _glfwInputKeyboard(_GLFWwindow* window, int key, int scancode, int action, int mods, const char* text, int state);
|
||||
void _glfwInputScroll(_GLFWwindow* window, double xoffset, double yoffset, int flags);
|
||||
void _glfwInitializeKeyEvent(GLFWkeyevent *ev, int key, int native_key, int action, int mods);
|
||||
void _glfwInputKeyboard(_GLFWwindow *window, GLFWkeyevent *ev);
|
||||
void _glfwInputScroll(_GLFWwindow* window, double xoffset, double yoffset, int flags, int mods);
|
||||
void _glfwInputMouseClick(_GLFWwindow* window, int button, int action, int mods);
|
||||
void _glfwInputCursorPos(_GLFWwindow* window, double xpos, double ypos);
|
||||
void _glfwInputCursorEnter(_GLFWwindow* window, GLFWbool entered);
|
||||
void _glfwInputDrop(_GLFWwindow* window, int count, const char** names);
|
||||
void _glfwInputCursorEnter(_GLFWwindow* window, bool entered);
|
||||
int _glfwInputDrop(_GLFWwindow* window, const char *mime, const char *text, size_t sz);
|
||||
void _glfwInputJoystick(_GLFWjoystick* js, int event);
|
||||
void _glfwInputJoystickAxis(_GLFWjoystick* js, int axis, float value);
|
||||
void _glfwInputJoystickButton(_GLFWjoystick* js, int button, char value);
|
||||
@@ -737,25 +786,30 @@ void _glfwInputJoystickHat(_GLFWjoystick* js, int hat, char value);
|
||||
void _glfwInputMonitor(_GLFWmonitor* monitor, int action, int placement);
|
||||
void _glfwInputMonitorWindow(_GLFWmonitor* monitor, _GLFWwindow* window);
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
void _glfwInputError(int code, const char* format, ...)
|
||||
__attribute__((format(printf, 2, 3)));
|
||||
void _glfwDebug(const char* format, ...)
|
||||
__attribute__((format(printf, 1, 2)));
|
||||
#else
|
||||
void _glfwInputError(int code, const char* format, ...);
|
||||
void _glfwDebug(const char* format, ...);
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_EVENT_LOOP
|
||||
#define EVDBG(...) _glfwDebug(__VA_ARGS__)
|
||||
#else
|
||||
#define EVDBG(...)
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW internal API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
GLFWbool _glfwStringInExtensionString(const char* string, const char* extensions);
|
||||
const _GLFWfbconfig* _glfwChooseFBConfig(const _GLFWfbconfig* desired,
|
||||
const _GLFWfbconfig* alternatives,
|
||||
unsigned int count);
|
||||
GLFWbool _glfwRefreshContextAttribs(_GLFWwindow* window,
|
||||
bool _glfwStringInExtensionString(const char* string, const char* extensions);
|
||||
bool _glfwRefreshContextAttribs(_GLFWwindow* window,
|
||||
const _GLFWctxconfig* ctxconfig);
|
||||
GLFWbool _glfwIsValidContextConfig(const _GLFWctxconfig* ctxconfig);
|
||||
bool _glfwIsValidContextConfig(const _GLFWctxconfig* ctxconfig);
|
||||
|
||||
const GLFWvidmode* _glfwChooseVideoMode(_GLFWmonitor* monitor,
|
||||
const GLFWvidmode* desired);
|
||||
@@ -773,11 +827,17 @@ _GLFWjoystick* _glfwAllocJoystick(const char* name,
|
||||
int hatCount);
|
||||
void _glfwFreeJoystick(_GLFWjoystick* js);
|
||||
const char* _glfwGetKeyName(int key);
|
||||
void _glfwCenterCursorInContentArea(_GLFWwindow* window);
|
||||
|
||||
GLFWbool _glfwInitVulkan(int mode);
|
||||
bool _glfwInitVulkan(int mode);
|
||||
void _glfwTerminateVulkan(void);
|
||||
const char* _glfwGetVulkanResultString(VkResult result);
|
||||
_GLFWwindow* _glfwFocusedWindow();
|
||||
_GLFWwindow* _glfwFocusedWindow(void);
|
||||
_GLFWwindow* _glfwWindowForId(GLFWid id);
|
||||
void _glfwPlatformRunMainLoop(GLFWtickcallback, void*);
|
||||
void _glfwPlatformStopMainLoop(void);
|
||||
unsigned long long _glfwPlatformAddTimer(monotonic_t interval, bool repeats, GLFWuserdatafun callback, void *callback_data, GLFWuserdatafun free_callback);
|
||||
void _glfwPlatformUpdateTimer(unsigned long long timer_id, monotonic_t interval, bool enabled);
|
||||
void _glfwPlatformRemoveTimer(unsigned long long timer_id);
|
||||
|
||||
char* _glfw_strdup(const char* source);
|
||||
|
||||
186
glfw/linux_joystick.c
vendored
186
glfw/linux_joystick.c
vendored
@@ -1,8 +1,8 @@
|
||||
//========================================================================
|
||||
// GLFW 3.3 Linux - www.glfw.org
|
||||
// GLFW 3.4 Linux - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||
// Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
|
||||
// Copyright (c) 2006-2017 Camilla Löwy <elmindreda@glfw.org>
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
@@ -24,6 +24,8 @@
|
||||
// distribution.
|
||||
//
|
||||
//========================================================================
|
||||
// It is fine to use C99 in this file because it will not be built with VS
|
||||
//========================================================================
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
@@ -104,9 +106,7 @@ static void handleAbsEvent(_GLFWjoystick* js, int code, int value)
|
||||
//
|
||||
static void pollAbsState(_GLFWjoystick* js)
|
||||
{
|
||||
int code;
|
||||
|
||||
for (code = 0; code < ABS_CNT; code++)
|
||||
for (int code = 0; code < ABS_CNT; code++)
|
||||
{
|
||||
if (js->linjs.absMap[code] < 0)
|
||||
continue;
|
||||
@@ -124,53 +124,52 @@ static void pollAbsState(_GLFWjoystick* js)
|
||||
|
||||
// Attempt to open the specified joystick device
|
||||
//
|
||||
static GLFWbool openJoystickDevice(const char* path)
|
||||
static bool openJoystickDevice(const char* path)
|
||||
{
|
||||
int jid, code;
|
||||
char name[256] = "";
|
||||
char guid[33] = "";
|
||||
char evBits[(EV_CNT + 7) / 8] = {0};
|
||||
char keyBits[(KEY_CNT + 7) / 8] = {0};
|
||||
char absBits[(ABS_CNT + 7) / 8] = {0};
|
||||
int axisCount = 0, buttonCount = 0, hatCount = 0;
|
||||
struct input_id id;
|
||||
_GLFWjoystickLinux linjs = {0};
|
||||
_GLFWjoystick* js = NULL;
|
||||
|
||||
for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++)
|
||||
for (int jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++)
|
||||
{
|
||||
if (!_glfw.joysticks[jid].present)
|
||||
continue;
|
||||
if (strcmp(_glfw.joysticks[jid].linjs.path, path) == 0)
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
}
|
||||
|
||||
_GLFWjoystickLinux linjs = {0};
|
||||
linjs.fd = open(path, O_RDONLY | O_NONBLOCK);
|
||||
if (linjs.fd == -1)
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
|
||||
if (ioctl(linjs.fd, EVIOCGBIT(0, sizeof(evBits)), evBits) < 0 ||
|
||||
ioctl(linjs.fd, EVIOCGBIT(EV_KEY, sizeof(keyBits)), keyBits) < 0 ||
|
||||
ioctl(linjs.fd, EVIOCGBIT(EV_ABS, sizeof(absBits)), absBits) < 0 ||
|
||||
ioctl(linjs.fd, EVIOCGID, &id) < 0)
|
||||
char evBits[(EV_CNT + 7) / 8] = {0};
|
||||
char keyBits[(KEY_CNT + 7) / 8] = {0};
|
||||
char absBits[(ABS_CNT + 7) / 8] = {0};
|
||||
struct input_id id;
|
||||
|
||||
if (ioctl(linjs.fd, (int32_t)EVIOCGBIT(0, sizeof(evBits)), evBits) < 0 ||
|
||||
ioctl(linjs.fd, (int32_t)EVIOCGBIT(EV_KEY, sizeof(keyBits)), keyBits) < 0 ||
|
||||
ioctl(linjs.fd, (int32_t)EVIOCGBIT(EV_ABS, sizeof(absBits)), absBits) < 0 ||
|
||||
ioctl(linjs.fd, (int32_t)EVIOCGID, &id) < 0)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Linux: Failed to query input device: %s",
|
||||
strerror(errno));
|
||||
close(linjs.fd);
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Ensure this device supports the events expected of a joystick
|
||||
if (!isBitSet(EV_KEY, evBits) || !isBitSet(EV_ABS, evBits))
|
||||
{
|
||||
close(linjs.fd);
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ioctl(linjs.fd, EVIOCGNAME(sizeof(name)), name) < 0)
|
||||
char name[256] = "";
|
||||
|
||||
if (ioctl(linjs.fd, (int32_t)EVIOCGNAME(sizeof(name)), name) < 0)
|
||||
strncpy(name, "Unknown", sizeof(name));
|
||||
|
||||
char guid[33] = "";
|
||||
|
||||
// Generate a joystick GUID that matches the SDL 2.0.5+ one
|
||||
if (id.vendor && id.product && id.version)
|
||||
{
|
||||
@@ -189,7 +188,9 @@ static GLFWbool openJoystickDevice(const char* path)
|
||||
name[8], name[9], name[10]);
|
||||
}
|
||||
|
||||
for (code = BTN_MISC; code < KEY_CNT; code++)
|
||||
int axisCount = 0, buttonCount = 0, hatCount = 0;
|
||||
|
||||
for (int code = BTN_MISC; code < KEY_CNT; code++)
|
||||
{
|
||||
if (!isBitSet(code, keyBits))
|
||||
continue;
|
||||
@@ -198,7 +199,7 @@ static GLFWbool openJoystickDevice(const char* path)
|
||||
buttonCount++;
|
||||
}
|
||||
|
||||
for (code = 0; code < ABS_CNT; code++)
|
||||
for (int code = 0; code < ABS_CNT; code++)
|
||||
{
|
||||
linjs.absMap[code] = -1;
|
||||
if (!isBitSet(code, absBits))
|
||||
@@ -221,11 +222,12 @@ static GLFWbool openJoystickDevice(const char* path)
|
||||
}
|
||||
}
|
||||
|
||||
js = _glfwAllocJoystick(name, guid, axisCount, buttonCount, hatCount);
|
||||
_GLFWjoystick* js =
|
||||
_glfwAllocJoystick(name, guid, axisCount, buttonCount, hatCount);
|
||||
if (!js)
|
||||
{
|
||||
close(linjs.fd);
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
}
|
||||
|
||||
strncpy(linjs.path, path, sizeof(linjs.path) - 1);
|
||||
@@ -234,7 +236,7 @@ static GLFWbool openJoystickDevice(const char* path)
|
||||
pollAbsState(js);
|
||||
|
||||
_glfwInputJoystick(js, GLFW_CONNECTED);
|
||||
return GLFW_TRUE;
|
||||
return true;
|
||||
}
|
||||
|
||||
#undef isBitSet
|
||||
@@ -262,12 +264,51 @@ static int compareJoysticks(const void* fp, const void* sp)
|
||||
////// GLFW internal API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Initialize joystick interface
|
||||
//
|
||||
GLFWbool _glfwInitJoysticksLinux(void)
|
||||
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 //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool _glfwPlatformInitJoysticks(void)
|
||||
{
|
||||
DIR* dir;
|
||||
int count = 0;
|
||||
const char* dirname = "/dev/input";
|
||||
|
||||
_glfw.linjs.inotify = inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
|
||||
@@ -286,10 +327,12 @@ GLFWbool _glfwInitJoysticksLinux(void)
|
||||
if (regcomp(&_glfw.linjs.regex, "^event[0-9]\\+$", 0) != 0)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR, "Linux: Failed to compile regex");
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
}
|
||||
|
||||
dir = opendir(dirname);
|
||||
int count = 0;
|
||||
|
||||
DIR* dir = opendir(dirname);
|
||||
if (dir)
|
||||
{
|
||||
struct dirent* entry;
|
||||
@@ -314,13 +357,11 @@ GLFWbool _glfwInitJoysticksLinux(void)
|
||||
|
||||
// Continue with no joysticks if enumeration fails
|
||||
|
||||
qsort(_glfw.joysticks, count, sizeof(_GLFWjoystick), compareJoysticks);
|
||||
return GLFW_TRUE;
|
||||
qsort(_glfw.joysticks, count, sizeof(_glfw.joysticks[0]), compareJoysticks);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Close all opened joystick handles
|
||||
//
|
||||
void _glfwTerminateJoysticksLinux(void)
|
||||
void _glfwPlatformTerminateJoysticks(void)
|
||||
{
|
||||
int jid;
|
||||
|
||||
@@ -331,64 +372,17 @@ void _glfwTerminateJoysticksLinux(void)
|
||||
closeJoystick(js);
|
||||
}
|
||||
|
||||
regfree(&_glfw.linjs.regex);
|
||||
|
||||
if (_glfw.linjs.inotify > 0)
|
||||
{
|
||||
if (_glfw.linjs.watch > 0)
|
||||
inotify_rm_watch(_glfw.linjs.inotify, _glfw.linjs.watch);
|
||||
|
||||
close(_glfw.linjs.inotify);
|
||||
regfree(&_glfw.linjs.regex);
|
||||
}
|
||||
}
|
||||
|
||||
void _glfwDetectJoystickConnectionLinux(void)
|
||||
{
|
||||
ssize_t offset = 0;
|
||||
char buffer[16384];
|
||||
|
||||
if (_glfw.linjs.inotify <= 0)
|
||||
return;
|
||||
|
||||
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)
|
||||
{
|
||||
int jid;
|
||||
|
||||
for (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)
|
||||
int _glfwPlatformPollJoystick(_GLFWjoystick* js, int mode UNUSED)
|
||||
{
|
||||
// Read all queued events (non-blocking)
|
||||
for (;;)
|
||||
@@ -408,10 +402,10 @@ int _glfwPlatformPollJoystick(_GLFWjoystick* js, int mode)
|
||||
if (e.type == EV_SYN)
|
||||
{
|
||||
if (e.code == SYN_DROPPED)
|
||||
_glfw.linjs.dropped = GLFW_TRUE;
|
||||
_glfw.linjs.dropped = true;
|
||||
else if (e.code == SYN_REPORT)
|
||||
{
|
||||
_glfw.linjs.dropped = GLFW_FALSE;
|
||||
_glfw.linjs.dropped = false;
|
||||
pollAbsState(js);
|
||||
}
|
||||
}
|
||||
@@ -428,6 +422,6 @@ int _glfwPlatformPollJoystick(_GLFWjoystick* js, int mode)
|
||||
return js->present;
|
||||
}
|
||||
|
||||
void _glfwPlatformUpdateGamepadGUID(char* guid)
|
||||
void _glfwPlatformUpdateGamepadGUID(char* guid UNUSED)
|
||||
{
|
||||
}
|
||||
|
||||
10
glfw/linux_joystick.h
vendored
10
glfw/linux_joystick.h
vendored
@@ -1,5 +1,5 @@
|
||||
//========================================================================
|
||||
// GLFW 3.3 Linux - www.glfw.org
|
||||
// GLFW 3.4 Linux - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2014 Jonas Ådahl <jadahl@gmail.com>
|
||||
//
|
||||
@@ -29,7 +29,7 @@
|
||||
#include <regex.h>
|
||||
|
||||
#define _GLFW_PLATFORM_JOYSTICK_STATE _GLFWjoystickLinux linjs
|
||||
#define _GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE _GLFWlibraryLinux linjs
|
||||
#define _GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE _GLFWlibraryLinux linjs;
|
||||
|
||||
#define _GLFW_PLATFORM_MAPPING_NAME "Linux"
|
||||
|
||||
@@ -52,11 +52,7 @@ typedef struct _GLFWlibraryLinux
|
||||
int inotify;
|
||||
int watch;
|
||||
regex_t regex;
|
||||
GLFWbool dropped;
|
||||
bool dropped;
|
||||
} _GLFWlibraryLinux;
|
||||
|
||||
|
||||
GLFWbool _glfwInitJoysticksLinux(void);
|
||||
void _glfwTerminateJoysticksLinux(void);
|
||||
void _glfwDetectJoystickConnectionLinux(void);
|
||||
|
||||
|
||||
105
glfw/linux_notify.c
vendored
Normal file
105
glfw/linux_notify.c
vendored
Normal file
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* linux_notify.c
|
||||
* Copyright (C) 2019 Kovid Goyal <kovid at kovidgoyal.net>
|
||||
*
|
||||
* Distributed under terms of the GPL3 license.
|
||||
*/
|
||||
|
||||
#include "internal.h"
|
||||
#include "linux_notify.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
#define NOTIFICATIONS_SERVICE "org.freedesktop.Notifications"
|
||||
#define NOTIFICATIONS_PATH "/org/freedesktop/Notifications"
|
||||
#define NOTIFICATIONS_IFACE "org.freedesktop.Notifications"
|
||||
|
||||
static notification_id_type notification_id = 0;
|
||||
|
||||
typedef struct {
|
||||
notification_id_type next_id;
|
||||
GLFWDBusnotificationcreatedfun callback;
|
||||
void *data;
|
||||
} NotificationCreatedData;
|
||||
|
||||
static GLFWDBusnotificationactivatedfun activated_handler = NULL;
|
||||
|
||||
void
|
||||
glfw_dbus_set_user_notification_activated_handler(GLFWDBusnotificationactivatedfun handler) {
|
||||
activated_handler = handler;
|
||||
}
|
||||
|
||||
void
|
||||
notification_created(DBusMessage *msg, const char* errmsg, void *data) {
|
||||
if (errmsg) {
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR, "Notify: Failed to create notification error: %s", errmsg);
|
||||
if (data) free(data);
|
||||
return;
|
||||
}
|
||||
uint32_t notification_id;
|
||||
if (!glfw_dbus_get_args(msg, "Failed to get Notification uid", DBUS_TYPE_UINT32, ¬ification_id, DBUS_TYPE_INVALID)) return;
|
||||
NotificationCreatedData *ncd = (NotificationCreatedData*)data;
|
||||
if (ncd->callback) ncd->callback(ncd->next_id, notification_id, ncd->data);
|
||||
if (data) free(data);
|
||||
}
|
||||
|
||||
static DBusHandlerResult
|
||||
message_handler(DBusConnection *conn UNUSED, DBusMessage *msg, void *user_data UNUSED) {
|
||||
/* printf("session_bus message_handler invoked interface: %s member: %s\n", dbus_message_get_interface(msg), dbus_message_get_member(msg)); */
|
||||
if (dbus_message_is_signal(msg, NOTIFICATIONS_IFACE, "ActionInvoked")) {
|
||||
uint32_t notification_id;
|
||||
const char *action;
|
||||
if (glfw_dbus_get_args(msg, "Failed to get args from ActionInvoked notification signal",
|
||||
DBUS_TYPE_UINT32, ¬ification_id, DBUS_TYPE_STRING, &action, DBUS_TYPE_INVALID)) {
|
||||
if (activated_handler) {
|
||||
activated_handler(notification_id, action);
|
||||
return DBUS_HANDLER_RESULT_HANDLED;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
|
||||
}
|
||||
|
||||
notification_id_type
|
||||
glfw_dbus_send_user_notification(const char *app_name, const char* icon, const char *summary, const char *body, const char* action_name, int32_t timeout, GLFWDBusnotificationcreatedfun callback, void *user_data) {
|
||||
DBusConnection *session_bus = glfw_dbus_session_bus();
|
||||
static DBusConnection *added_signal_match = NULL;
|
||||
if (!session_bus) return 0;
|
||||
if (added_signal_match != session_bus) {
|
||||
dbus_bus_add_match(session_bus, "type='signal',interface='" NOTIFICATIONS_IFACE "',member='ActionInvoked'", NULL);
|
||||
dbus_connection_add_filter(session_bus, message_handler, NULL, NULL);
|
||||
added_signal_match = session_bus;
|
||||
}
|
||||
NotificationCreatedData *data = malloc(sizeof(NotificationCreatedData));
|
||||
if (!data) return 0;
|
||||
data->next_id = ++notification_id;
|
||||
data->callback = callback; data->data = user_data;
|
||||
if (!data->next_id) data->next_id = ++notification_id;
|
||||
uint32_t replaces_id = 0;
|
||||
|
||||
DBusMessage *msg = dbus_message_new_method_call(NOTIFICATIONS_SERVICE, NOTIFICATIONS_PATH, NOTIFICATIONS_IFACE, "Notify");
|
||||
if (!msg) { free(data); return 0; }
|
||||
DBusMessageIter args, array;
|
||||
dbus_message_iter_init_append(msg, &args);
|
||||
#define OOMMSG { free(data); data = NULL; dbus_message_unref(msg); _glfwInputError(GLFW_PLATFORM_ERROR, "%s", "Out of memory allocating DBUS message for notification\n"); return 0; }
|
||||
#define APPEND(type, val) { if (!dbus_message_iter_append_basic(&args, type, val)) OOMMSG }
|
||||
APPEND(DBUS_TYPE_STRING, &app_name)
|
||||
APPEND(DBUS_TYPE_UINT32, &replaces_id)
|
||||
APPEND(DBUS_TYPE_STRING, &icon)
|
||||
APPEND(DBUS_TYPE_STRING, &summary)
|
||||
APPEND(DBUS_TYPE_STRING, &body)
|
||||
if (!dbus_message_iter_open_container(&args, DBUS_TYPE_ARRAY, "s", &array)) OOMMSG;
|
||||
if (action_name) {
|
||||
static const char* default_action = "default";
|
||||
dbus_message_iter_append_basic(&array, DBUS_TYPE_STRING, &default_action);
|
||||
dbus_message_iter_append_basic(&array, DBUS_TYPE_STRING, &action_name);
|
||||
}
|
||||
if (!dbus_message_iter_close_container(&args, &array)) OOMMSG;
|
||||
if (!dbus_message_iter_open_container(&args, DBUS_TYPE_ARRAY, "{sv}", &array)) OOMMSG;
|
||||
if (!dbus_message_iter_close_container(&args, &array)) OOMMSG;
|
||||
APPEND(DBUS_TYPE_INT32, &timeout)
|
||||
#undef OOMMSG
|
||||
#undef APPEND
|
||||
if (!call_method_with_msg(session_bus, msg, 5000, notification_created, data)) return 0;
|
||||
return data->next_id;
|
||||
}
|
||||
19
glfw/linux_notify.h
vendored
Normal file
19
glfw/linux_notify.h
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Kovid Goyal <kovid at kovidgoyal.net>
|
||||
*
|
||||
* Distributed under terms of the GPL3 license.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
#include "dbus_glfw.h"
|
||||
#include "internal.h"
|
||||
|
||||
typedef unsigned long long notification_id_type;
|
||||
typedef void (*GLFWDBusnotificationcreatedfun)(notification_id_type, uint32_t, void*);
|
||||
typedef void (*GLFWDBusnotificationactivatedfun)(uint32_t, const char*);
|
||||
notification_id_type
|
||||
glfw_dbus_send_user_notification(const char *app_name, const char* icon, const char *summary, const char *body, const char *action_name, int32_t timeout, GLFWDBusnotificationcreatedfun, void*);
|
||||
void
|
||||
glfw_dbus_set_user_notification_activated_handler(GLFWDBusnotificationactivatedfun handler);
|
||||
51
glfw/main_loop.h
vendored
Normal file
51
glfw/main_loop.h
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Kovid Goyal <kovid at kovidgoyal.net>
|
||||
*
|
||||
* Distributed under terms of the GPL3 license.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "internal.h"
|
||||
#include "../kitty/monotonic.h"
|
||||
|
||||
#ifndef GLFW_LOOP_BACKEND
|
||||
#define GLFW_LOOP_BACKEND x11
|
||||
#endif
|
||||
|
||||
static bool keep_going = false;
|
||||
|
||||
|
||||
void _glfwPlatformStopMainLoop(void) {
|
||||
if (keep_going) {
|
||||
keep_going = false;
|
||||
_glfwPlatformPostEmptyEvent();
|
||||
}
|
||||
}
|
||||
|
||||
void _glfwPlatformRunMainLoop(GLFWtickcallback tick_callback, void* data) {
|
||||
keep_going = 1;
|
||||
EventLoopData *eld = &_glfw.GLFW_LOOP_BACKEND.eventLoopData;
|
||||
while(keep_going) {
|
||||
_glfwPlatformWaitEvents();
|
||||
EVDBG("--------- loop tick, wakeups_happened: %d ----------", eld->wakeup_data_read);
|
||||
if (eld->wakeup_data_read) {
|
||||
eld->wakeup_data_read = false;
|
||||
tick_callback(data);
|
||||
}
|
||||
}
|
||||
EVDBG("main loop exiting");
|
||||
}
|
||||
|
||||
unsigned long long _glfwPlatformAddTimer(monotonic_t interval, bool repeats, GLFWuserdatafreefun callback, void *callback_data, GLFWuserdatafreefun free_callback) {
|
||||
return addTimer(&_glfw.GLFW_LOOP_BACKEND.eventLoopData, "user timer", interval, 1, repeats, callback, callback_data, free_callback);
|
||||
}
|
||||
|
||||
void _glfwPlatformRemoveTimer(unsigned long long timer_id) {
|
||||
removeTimer(&_glfw.GLFW_LOOP_BACKEND.eventLoopData, timer_id);
|
||||
}
|
||||
|
||||
void _glfwPlatformUpdateTimer(unsigned long long timer_id, monotonic_t interval, bool enabled) {
|
||||
changeTimerInterval(&_glfw.GLFW_LOOP_BACKEND.eventLoopData, timer_id, interval);
|
||||
toggleTimer(&_glfw.GLFW_LOOP_BACKEND.eventLoopData, timer_id, enabled);
|
||||
}
|
||||
4
glfw/mappings.h
vendored
4
glfw/mappings.h
vendored
@@ -1,7 +1,7 @@
|
||||
//========================================================================
|
||||
// GLFW 3.3 - www.glfw.org
|
||||
// GLFW 3.4 - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
|
||||
// Copyright (c) 2006-2018 Camilla Löwy <elmindreda@glfw.org>
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
|
||||
7
glfw/memfd.h
vendored
7
glfw/memfd.h
vendored
@@ -29,8 +29,8 @@ static inline int memfd_create(const char *name, unsigned int flags) {
|
||||
#endif
|
||||
|
||||
#ifndef MFD_CLOEXEC
|
||||
#define MFD_CLOEXEC 0x0001U
|
||||
#define MFD_ALLOW_SEALING 0x0002U
|
||||
#define MFD_CLOEXEC 0x0001U
|
||||
#define MFD_ALLOW_SEALING 0x0002U
|
||||
#endif
|
||||
|
||||
#else
|
||||
@@ -39,8 +39,7 @@ static inline int memfd_create(const char *name, unsigned int flags) {
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
static inline int
|
||||
createTmpfileCloexec(char* tmpname)
|
||||
static inline int createTmpfileCloexec(char* tmpname)
|
||||
{
|
||||
int fd;
|
||||
|
||||
|
||||
55
glfw/monitor.c
vendored
55
glfw/monitor.c
vendored
@@ -1,8 +1,8 @@
|
||||
//========================================================================
|
||||
// GLFW 3.3 - www.glfw.org
|
||||
// GLFW 3.4 - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||
// Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
|
||||
// Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
@@ -24,6 +24,8 @@
|
||||
// distribution.
|
||||
//
|
||||
//========================================================================
|
||||
// Please use C89 style variable declarations in this file because VS 2010
|
||||
//========================================================================
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
@@ -54,31 +56,35 @@ static int compareVideoModes(const void* fp, const void* sp)
|
||||
if (farea != sarea)
|
||||
return farea - sarea;
|
||||
|
||||
// Then sort on width
|
||||
if (fm->width != sm->width)
|
||||
return fm->width - sm->width;
|
||||
|
||||
// Lastly sort on refresh rate
|
||||
return fm->refreshRate - sm->refreshRate;
|
||||
}
|
||||
|
||||
// Retrieves the available modes for the specified monitor
|
||||
//
|
||||
static GLFWbool refreshVideoModes(_GLFWmonitor* monitor)
|
||||
static bool refreshVideoModes(_GLFWmonitor* monitor)
|
||||
{
|
||||
int modeCount;
|
||||
GLFWvidmode* modes;
|
||||
|
||||
if (monitor->modes)
|
||||
return GLFW_TRUE;
|
||||
return true;
|
||||
|
||||
modes = _glfwPlatformGetVideoModes(monitor, &modeCount);
|
||||
if (!modes)
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
|
||||
qsort(modes, modeCount, sizeof(GLFWvidmode), compareVideoModes);
|
||||
qsort(modes, modeCount, sizeof(modes[0]), compareVideoModes);
|
||||
|
||||
free(monitor->modes);
|
||||
monitor->modes = modes;
|
||||
monitor->modeCount = modeCount;
|
||||
|
||||
return GLFW_TRUE;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -100,7 +106,7 @@ void _glfwInputMonitor(_GLFWmonitor* monitor, int action, int placement)
|
||||
{
|
||||
memmove(_glfw.monitors + 1,
|
||||
_glfw.monitors,
|
||||
(_glfw.monitorCount - 1) * sizeof(_GLFWmonitor*));
|
||||
((size_t) _glfw.monitorCount - 1) * sizeof(_GLFWmonitor*));
|
||||
_glfw.monitors[0] = monitor;
|
||||
}
|
||||
else
|
||||
@@ -127,10 +133,7 @@ void _glfwInputMonitor(_GLFWmonitor* monitor, int action, int placement)
|
||||
{
|
||||
if (_glfw.monitors[i] == monitor)
|
||||
{
|
||||
_glfw.monitorCount--;
|
||||
memmove(_glfw.monitors + i,
|
||||
_glfw.monitors + i + 1,
|
||||
(_glfw.monitorCount - i) * sizeof(_GLFWmonitor*));
|
||||
remove_i_from_array(_glfw.monitors, i, _glfw.monitorCount);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -330,6 +333,27 @@ GLFWAPI void glfwGetMonitorPos(GLFWmonitor* handle, int* xpos, int* ypos)
|
||||
_glfwPlatformGetMonitorPos(monitor, xpos, ypos);
|
||||
}
|
||||
|
||||
GLFWAPI void glfwGetMonitorWorkarea(GLFWmonitor* handle,
|
||||
int* xpos, int* ypos,
|
||||
int* width, int* height)
|
||||
{
|
||||
_GLFWmonitor* monitor = (_GLFWmonitor*) handle;
|
||||
assert(monitor != NULL);
|
||||
|
||||
if (xpos)
|
||||
*xpos = 0;
|
||||
if (ypos)
|
||||
*ypos = 0;
|
||||
if (width)
|
||||
*width = 0;
|
||||
if (height)
|
||||
*height = 0;
|
||||
|
||||
_GLFW_REQUIRE_INIT();
|
||||
|
||||
_glfwPlatformGetMonitorWorkarea(monitor, xpos, ypos, width, height);
|
||||
}
|
||||
|
||||
GLFWAPI void glfwGetMonitorPhysicalSize(GLFWmonitor* handle, int* widthMM, int* heightMM)
|
||||
{
|
||||
_GLFWmonitor* monitor = (_GLFWmonitor*) handle;
|
||||
@@ -432,7 +456,7 @@ GLFWAPI void glfwSetGamma(GLFWmonitor* handle, float gamma)
|
||||
GLFWgammaramp ramp;
|
||||
const GLFWgammaramp* original;
|
||||
assert(handle != NULL);
|
||||
assert(gamma >= 0.f);
|
||||
assert(gamma > 0.f);
|
||||
assert(gamma <= FLT_MAX);
|
||||
|
||||
_GLFW_REQUIRE_INIT();
|
||||
@@ -442,6 +466,7 @@ GLFWAPI void glfwSetGamma(GLFWmonitor* handle, float gamma)
|
||||
_glfwInputError(GLFW_INVALID_VALUE, "Invalid gamma value %f", gamma);
|
||||
return;
|
||||
}
|
||||
|
||||
original = glfwGetGammaRamp(handle);
|
||||
if (!original)
|
||||
return;
|
||||
@@ -456,10 +481,8 @@ GLFWAPI void glfwSetGamma(GLFWmonitor* handle, float gamma)
|
||||
value = i / (float) (original->size - 1);
|
||||
// Apply gamma curve
|
||||
value = powf(value, 1.f / gamma) * 65535.f + 0.5f;
|
||||
|
||||
// Clamp to value range
|
||||
if (value > 65535.f)
|
||||
value = 65535.f;
|
||||
value = fminf(value, 65535.f);
|
||||
|
||||
values[i] = (unsigned short) value;
|
||||
}
|
||||
|
||||
10
glfw/monotonic.c
vendored
Normal file
10
glfw/monotonic.c
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
/*
|
||||
* monotonic.c
|
||||
* Copyright (C) 2019 Kovid Goyal <kovid at kovidgoyal.net>
|
||||
*
|
||||
* Distributed under terms of the GPL3 license.
|
||||
*/
|
||||
|
||||
#define _POSIX_C_SOURCE 200809L
|
||||
#define MONOTONIC_IMPLEMENTATION
|
||||
#include "../kitty/monotonic.h"
|
||||
17
glfw/nsgl_context.h
vendored
17
glfw/nsgl_context.h
vendored
@@ -1,7 +1,7 @@
|
||||
//========================================================================
|
||||
// GLFW 3.3 macOS - www.glfw.org
|
||||
// GLFW 3.4 macOS - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2009-2016 Camilla Löwy <elmindreda@glfw.org>
|
||||
// Copyright (c) 2009-2019 Camilla Löwy <elmindreda@glfw.org>
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
@@ -24,16 +24,16 @@
|
||||
//
|
||||
//========================================================================
|
||||
|
||||
#define _GLFW_PLATFORM_CONTEXT_STATE _GLFWcontextNSGL nsgl
|
||||
#define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE _GLFWlibraryNSGL nsgl
|
||||
#define _GLFW_PLATFORM_CONTEXT_STATE _GLFWcontextNSGL nsgl;
|
||||
#define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE _GLFWlibraryNSGL nsgl;
|
||||
|
||||
|
||||
// NSGL-specific per-context data
|
||||
//
|
||||
typedef struct _GLFWcontextNSGL
|
||||
{
|
||||
id pixelFormat;
|
||||
id object;
|
||||
id pixelFormat;
|
||||
id object;
|
||||
|
||||
} _GLFWcontextNSGL;
|
||||
|
||||
@@ -47,10 +47,9 @@ typedef struct _GLFWlibraryNSGL
|
||||
} _GLFWlibraryNSGL;
|
||||
|
||||
|
||||
GLFWbool _glfwInitNSGL(void);
|
||||
bool _glfwInitNSGL(void);
|
||||
void _glfwTerminateNSGL(void);
|
||||
GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window,
|
||||
bool _glfwCreateContextNSGL(_GLFWwindow* window,
|
||||
const _GLFWctxconfig* ctxconfig,
|
||||
const _GLFWfbconfig* fbconfig);
|
||||
void _glfwDestroyContextNSGL(_GLFWwindow* window);
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//========================================================================
|
||||
// GLFW 3.3 macOS - www.glfw.org
|
||||
// GLFW 3.4 macOS - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2009-2016 Camilla Löwy <elmindreda@glfw.org>
|
||||
// Copyright (c) 2009-2019 Camilla Löwy <elmindreda@glfw.org>
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
@@ -23,15 +23,12 @@
|
||||
// distribution.
|
||||
//
|
||||
//========================================================================
|
||||
// It is fine to use C99 in this file because it will not be built with VS
|
||||
//========================================================================
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
|
||||
#if (MAC_OS_X_VERSION_MAX_ALLOWED < 101400)
|
||||
#define NSOpenGLContextParameterSwapInterval NSOpenGLCPSwapInterval
|
||||
#define NSOpenGLContextParameterSurfaceOpacity NSOpenGLCPSurfaceOpacity
|
||||
#endif
|
||||
|
||||
static void makeContextCurrentNSGL(_GLFWwindow* window)
|
||||
{
|
||||
if (window)
|
||||
@@ -48,19 +45,17 @@ static void swapBuffersNSGL(_GLFWwindow* window)
|
||||
[window->context.nsgl.object flushBuffer];
|
||||
}
|
||||
|
||||
static void swapIntervalNSGL(int interval)
|
||||
static void swapIntervalNSGL(int interval UNUSED)
|
||||
{
|
||||
_GLFWwindow* window = _glfwPlatformGetTls(&_glfw.contextSlot);
|
||||
|
||||
GLint sync = interval;
|
||||
[window->context.nsgl.object setValues:&sync
|
||||
forParameter:NSOpenGLContextParameterSwapInterval];
|
||||
// As of Mojave this does not work so we use CVDisplayLink instead
|
||||
_glfwInputError(GLFW_API_UNAVAILABLE,
|
||||
"NSGL: Swap intervals do not work on macOS");
|
||||
}
|
||||
|
||||
static int extensionSupportedNSGL(const char* extension)
|
||||
static int extensionSupportedNSGL(const char* extension UNUSED)
|
||||
{
|
||||
// There are no NSGL extensions
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
}
|
||||
|
||||
static GLFWglproc getProcAddressNSGL(const char* procname)
|
||||
@@ -69,16 +64,15 @@ static GLFWglproc getProcAddressNSGL(const char* procname)
|
||||
procname,
|
||||
kCFStringEncodingASCII);
|
||||
|
||||
GLFWglproc symbol = CFBundleGetFunctionPointerForName(_glfw.nsgl.framework,
|
||||
symbolName);
|
||||
GLFWglproc symbol;
|
||||
*(void **) &symbol = CFBundleGetFunctionPointerForName(_glfw.nsgl.framework,
|
||||
symbolName);
|
||||
|
||||
CFRelease(symbolName);
|
||||
|
||||
return symbol;
|
||||
}
|
||||
|
||||
// Destroy the OpenGL context
|
||||
//
|
||||
static void destroyContextNSGL(_GLFWwindow* window)
|
||||
{
|
||||
[window->context.nsgl.pixelFormat release];
|
||||
@@ -95,10 +89,10 @@ static void destroyContextNSGL(_GLFWwindow* window)
|
||||
|
||||
// Initialize OpenGL support
|
||||
//
|
||||
GLFWbool _glfwInitNSGL(void)
|
||||
bool _glfwInitNSGL(void)
|
||||
{
|
||||
if (_glfw.nsgl.framework)
|
||||
return GLFW_TRUE;
|
||||
return true;
|
||||
|
||||
_glfw.nsgl.framework =
|
||||
CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengl"));
|
||||
@@ -106,10 +100,10 @@ GLFWbool _glfwInitNSGL(void)
|
||||
{
|
||||
_glfwInputError(GLFW_API_UNAVAILABLE,
|
||||
"NSGL: Failed to locate OpenGL framework");
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
}
|
||||
|
||||
return GLFW_TRUE;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Terminate OpenGL support
|
||||
@@ -120,7 +114,7 @@ void _glfwTerminateNSGL(void)
|
||||
|
||||
// Create the OpenGL context
|
||||
//
|
||||
GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window,
|
||||
bool _glfwCreateContextNSGL(_GLFWwindow* window,
|
||||
const _GLFWctxconfig* ctxconfig,
|
||||
const _GLFWfbconfig* fbconfig)
|
||||
{
|
||||
@@ -128,7 +122,7 @@ GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window,
|
||||
{
|
||||
_glfwInputError(GLFW_API_UNAVAILABLE,
|
||||
"NSGL: OpenGL ES is not available on macOS");
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ctxconfig->major > 2)
|
||||
@@ -137,14 +131,7 @@ GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window,
|
||||
{
|
||||
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
|
||||
"NSGL: The targeted version of macOS does not support OpenGL 3.0 or 3.1 but may support 3.2 and above");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
if (!ctxconfig->forward || ctxconfig->profile != GLFW_OPENGL_CORE_PROFILE)
|
||||
{
|
||||
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
|
||||
"NSGL: The targeted version of macOS only supports forward-compatible core profile contexts for OpenGL 3.2 and above");
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -180,9 +167,7 @@ GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window,
|
||||
// Info.plist for unbundled applications
|
||||
// HACK: This assumes that NSOpenGLPixelFormat will remain
|
||||
// a straightforward wrapper of its CGL counterpart
|
||||
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1080
|
||||
addAttrib(kCGLPFASupportsAutomaticGraphicsSwitching);
|
||||
#endif /*MAC_OS_X_VERSION_MAX_ALLOWED*/
|
||||
}
|
||||
|
||||
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 101000
|
||||
@@ -247,7 +232,7 @@ GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window,
|
||||
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 101200
|
||||
_glfwInputError(GLFW_FORMAT_UNAVAILABLE,
|
||||
"NSGL: Stereo rendering is deprecated");
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
#else
|
||||
addAttrib(NSOpenGLPFAStereo);
|
||||
#endif
|
||||
@@ -283,10 +268,10 @@ GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window,
|
||||
{
|
||||
_glfwInputError(GLFW_FORMAT_UNAVAILABLE,
|
||||
"NSGL: Failed to find a suitable pixel format");
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
}
|
||||
|
||||
NSOpenGLContext* share = NULL;
|
||||
NSOpenGLContext* share = nil;
|
||||
|
||||
if (ctxconfig->share)
|
||||
share = ctxconfig->share->context.nsgl.object;
|
||||
@@ -298,15 +283,22 @@ GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window,
|
||||
{
|
||||
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
|
||||
"NSGL: Failed to create OpenGL context");
|
||||
return GLFW_FALSE;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (fbconfig->transparent)
|
||||
{
|
||||
GLint opaque = 0;
|
||||
[window->context.nsgl.object setValues:&opaque forParameter:NSOpenGLContextParameterSurfaceOpacity];
|
||||
[window->context.nsgl.object setValues:&opaque
|
||||
forParameter:NSOpenGLContextParameterSurfaceOpacity];
|
||||
}
|
||||
|
||||
[window->ns.view setWantsBestResolutionOpenGLSurface:window->ns.retina];
|
||||
|
||||
GLint interval = 0;
|
||||
[window->context.nsgl.object setValues:&interval
|
||||
forParameter:NSOpenGLContextParameterSwapInterval];
|
||||
|
||||
[window->context.nsgl.object setView:window->ns.view];
|
||||
|
||||
window->context.makeCurrent = makeContextCurrentNSGL;
|
||||
@@ -316,7 +308,7 @@ GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window,
|
||||
window->context.getProcAddress = getProcAddressNSGL;
|
||||
window->context.destroy = destroyContextNSGL;
|
||||
|
||||
return GLFW_TRUE;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -332,7 +324,7 @@ GLFWAPI id glfwGetNSGLContext(GLFWwindow* handle)
|
||||
if (window->context.client == GLFW_NO_API)
|
||||
{
|
||||
_glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
|
||||
return NULL;
|
||||
return nil;
|
||||
}
|
||||
|
||||
return window->context.nsgl.object;
|
||||
|
||||
15
glfw/null_init.c
vendored
15
glfw/null_init.c
vendored
@@ -1,8 +1,8 @@
|
||||
//========================================================================
|
||||
// GLFW 3.3 - www.glfw.org
|
||||
// GLFW 3.4 - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2016 Google Inc.
|
||||
// Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
|
||||
// Copyright (c) 2016-2017 Camilla Löwy <elmindreda@glfw.org>
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
@@ -24,9 +24,13 @@
|
||||
// distribution.
|
||||
//
|
||||
//========================================================================
|
||||
// It is fine to use C99 in this file because it will not be built with VS
|
||||
//========================================================================
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW platform API //////
|
||||
@@ -34,12 +38,14 @@
|
||||
|
||||
int _glfwPlatformInit(void)
|
||||
{
|
||||
_glfwInitTimerPOSIX();
|
||||
return GLFW_TRUE;
|
||||
_glfwPollMonitorsNull();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void _glfwPlatformTerminate(void)
|
||||
{
|
||||
free(_glfw.null.clipboardString);
|
||||
_glfwTerminateOSMesa();
|
||||
}
|
||||
|
||||
@@ -47,4 +53,3 @@ const char* _glfwPlatformGetVersionString(void)
|
||||
{
|
||||
return _GLFW_VERSION_NUMBER " null OSMesa";
|
||||
}
|
||||
|
||||
|
||||
21
glfw/null_joystick.c
vendored
21
glfw/null_joystick.c
vendored
@@ -1,7 +1,7 @@
|
||||
//========================================================================
|
||||
// GLFW 3.3 - www.glfw.org
|
||||
// GLFW 3.4 - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
|
||||
// Copyright (c) 2016-2017 Camilla Löwy <elmindreda@glfw.org>
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
@@ -23,6 +23,8 @@
|
||||
// distribution.
|
||||
//
|
||||
//========================================================================
|
||||
// It is fine to use C99 in this file because it will not be built with VS
|
||||
//========================================================================
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
@@ -31,12 +33,21 @@
|
||||
////// GLFW platform API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int _glfwPlatformPollJoystick(_GLFWjoystick* js, int mode)
|
||||
bool _glfwPlatformInitJoysticks(void)
|
||||
{
|
||||
return GLFW_FALSE;
|
||||
return true;
|
||||
}
|
||||
|
||||
void _glfwPlatformUpdateGamepadGUID(char* guid)
|
||||
void _glfwPlatformTerminateJoysticks(void)
|
||||
{
|
||||
}
|
||||
|
||||
int _glfwPlatformPollJoystick(_GLFWjoystick* js UNUSED, int mode UNUSED)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void _glfwPlatformUpdateGamepadGUID(char* guid UNUSED)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
7
glfw/null_joystick.h
vendored
7
glfw/null_joystick.h
vendored
@@ -1,7 +1,7 @@
|
||||
//========================================================================
|
||||
// GLFW 3.3 - www.glfw.org
|
||||
// GLFW 3.4 - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
|
||||
// Copyright (c) 2006-2017 Camilla Löwy <elmindreda@glfw.org>
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
@@ -25,7 +25,6 @@
|
||||
//========================================================================
|
||||
|
||||
#define _GLFW_PLATFORM_JOYSTICK_STATE int nulljs
|
||||
#define _GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE int nulljs
|
||||
#define _GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE int nulljs;
|
||||
|
||||
#define _GLFW_PLATFORM_MAPPING_NAME ""
|
||||
|
||||
|
||||
109
glfw/null_monitor.c
vendored
109
glfw/null_monitor.c
vendored
@@ -1,8 +1,8 @@
|
||||
//========================================================================
|
||||
// GLFW 3.3 - www.glfw.org
|
||||
// GLFW 3.4 - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2016 Google Inc.
|
||||
// Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
|
||||
// Copyright (c) 2016-2019 Camilla Löwy <elmindreda@glfw.org>
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
@@ -24,9 +24,42 @@
|
||||
// distribution.
|
||||
//
|
||||
//========================================================================
|
||||
// It is fine to use C99 in this file because it will not be built with VS
|
||||
//========================================================================
|
||||
|
||||
#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 //////
|
||||
@@ -34,13 +67,18 @@
|
||||
|
||||
void _glfwPlatformFreeMonitor(_GLFWmonitor* monitor)
|
||||
{
|
||||
_glfwFreeGammaArrays(&monitor->null.ramp);
|
||||
}
|
||||
|
||||
void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos)
|
||||
void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor UNUSED, int* xpos, int* ypos)
|
||||
{
|
||||
if (xpos)
|
||||
*xpos = 0;
|
||||
if (ypos)
|
||||
*ypos = 0;
|
||||
}
|
||||
|
||||
void _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor,
|
||||
void _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor UNUSED,
|
||||
float* xscale, float* yscale)
|
||||
{
|
||||
if (xscale)
|
||||
@@ -49,20 +87,73 @@ void _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor,
|
||||
*yscale = 1.f;
|
||||
}
|
||||
|
||||
GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* found)
|
||||
void _glfwPlatformGetMonitorWorkarea(_GLFWmonitor* monitor UNUSED,
|
||||
int* xpos, int* ypos,
|
||||
int* width, int* height)
|
||||
{
|
||||
return NULL;
|
||||
const GLFWvidmode mode = getVideoMode();
|
||||
|
||||
if (xpos)
|
||||
*xpos = 0;
|
||||
if (ypos)
|
||||
*ypos = 10;
|
||||
if (width)
|
||||
*width = mode.width;
|
||||
if (height)
|
||||
*height = mode.height - 10;
|
||||
}
|
||||
|
||||
void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode)
|
||||
GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor UNUSED, int* found)
|
||||
{
|
||||
GLFWvidmode* mode = calloc(1, sizeof(GLFWvidmode));
|
||||
*mode = getVideoMode();
|
||||
*found = 1;
|
||||
return mode;
|
||||
}
|
||||
|
||||
GLFWbool _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
|
||||
void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor UNUSED, GLFWvidmode* mode)
|
||||
{
|
||||
return GLFW_FALSE;
|
||||
*mode = getVideoMode();
|
||||
}
|
||||
|
||||
bool _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
|
||||
{
|
||||
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, 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);
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user