Compare commits
2760 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1ba7b5f5a3 | ||
|
|
f895b7f8cb | ||
|
|
16542e96bf | ||
|
|
3005b8b9d6 | ||
|
|
35653ef4b4 | ||
|
|
36b3582825 | ||
|
|
c17c801a31 | ||
|
|
460c353898 | ||
|
|
3fa7007e91 | ||
|
|
4cf6373203 | ||
|
|
e0b3bb1830 | ||
|
|
47ec372c30 | ||
|
|
d5366a421f | ||
|
|
3d5977669e | ||
|
|
36da668e6f | ||
|
|
052913c656 | ||
|
|
0ef055a2b2 | ||
|
|
a7bd6922e5 | ||
|
|
8d9ba4a772 | ||
|
|
222beedc2a | ||
|
|
8ba8320189 | ||
|
|
3501a2a1da | ||
|
|
819ee94a70 | ||
|
|
7e7dbc5ecf | ||
|
|
3a6bc94d25 | ||
|
|
07a4cec616 | ||
|
|
60de840d69 | ||
|
|
928167c0b2 | ||
|
|
2aac220cdb | ||
|
|
d8a74e8a3c | ||
|
|
019e6efeda | ||
|
|
a7a7216b30 | ||
|
|
ae8ca5272b | ||
|
|
06c1236cc6 | ||
|
|
4d3982c5cf | ||
|
|
a0ff625f61 | ||
|
|
b44345d78e | ||
|
|
96229becd1 | ||
|
|
b269cab0b8 | ||
|
|
0b3c8210f3 | ||
|
|
074614bc8e | ||
|
|
4ceb4cfc22 | ||
|
|
0bb08d8bdd | ||
|
|
b9e6557f72 | ||
|
|
7ed268ea2f | ||
|
|
a91b3b9487 | ||
|
|
cdf236d01b | ||
|
|
f54efb7886 | ||
|
|
0ffee56170 | ||
|
|
ab97646576 | ||
|
|
33b62dcabc | ||
|
|
39e6e91d69 | ||
|
|
dedd80c6b5 | ||
|
|
df11da74e9 | ||
|
|
9991dd6ce4 | ||
|
|
e777364f91 | ||
|
|
a32ed5ae5f | ||
|
|
db1e48848d | ||
|
|
c02fa79591 | ||
|
|
6f0a59c696 | ||
|
|
bc715d4348 | ||
|
|
55e4761302 | ||
|
|
18fe2e8dfa | ||
|
|
18a07a78b5 | ||
|
|
aa7024b264 | ||
|
|
c67ab2a6ff | ||
|
|
d15eab31da | ||
|
|
a6900443d5 | ||
|
|
235bcacc7b | ||
|
|
3e26f96744 | ||
|
|
718111582a | ||
|
|
f5cdbe53ea | ||
|
|
bf761a7189 | ||
|
|
05ee01b4dd | ||
|
|
53166d659e | ||
|
|
34aea3bca1 | ||
|
|
f26519863f | ||
|
|
a57e96500a | ||
|
|
5e27c21856 | ||
|
|
4601cd13dc | ||
|
|
ad92541ff3 | ||
|
|
3f77a2044e | ||
|
|
75e57a48e0 | ||
|
|
160fbd2071 | ||
|
|
f5743f4610 | ||
|
|
82f9aecacb | ||
|
|
be6556c884 | ||
|
|
f941ffb1fe | ||
|
|
cbdba0b6aa | ||
|
|
ce04f102a7 | ||
|
|
fc3bd2d15f | ||
|
|
a958cabf01 | ||
|
|
d0a2eab79e | ||
|
|
b835afefee | ||
|
|
d0a7be90f9 | ||
|
|
1f3550b84c | ||
|
|
939212e1d4 | ||
|
|
7db6318806 | ||
|
|
e5d9182606 | ||
|
|
d519553581 | ||
|
|
e99b1be023 | ||
|
|
e460866ebc | ||
|
|
23aea68e32 | ||
|
|
65c2cbe93a | ||
|
|
ee31ba0c76 | ||
|
|
3ed9d9a069 | ||
|
|
721e51c117 | ||
|
|
09daaf1ec3 | ||
|
|
b2d62f10d2 | ||
|
|
0d542b2f60 | ||
|
|
04fd058e0f | ||
|
|
31a0a9427e | ||
|
|
04f10ba570 | ||
|
|
34b7b2e4e8 | ||
|
|
09183772d3 | ||
|
|
3e4eca5816 | ||
|
|
30c6c4697f | ||
|
|
b650275d45 | ||
|
|
174bd5c57f | ||
|
|
ec51a219a7 | ||
|
|
cca2fb967c | ||
|
|
5b547d9b06 | ||
|
|
facb2df3f6 | ||
|
|
8395076da5 | ||
|
|
e113e0cba7 | ||
|
|
407d19c2dc | ||
|
|
382367506a | ||
|
|
bd5a85a4e7 | ||
|
|
631f97eb26 | ||
|
|
0c0ce4844c | ||
|
|
6bf290149e | ||
|
|
60fa812b60 | ||
|
|
61f3a39aa0 | ||
|
|
a6949df727 | ||
|
|
d839a31d7f | ||
|
|
1de510f46f | ||
|
|
0359bbe4be | ||
|
|
40b355e593 | ||
|
|
adf9c4fc5f | ||
|
|
ae9d049011 | ||
|
|
d24977d164 | ||
|
|
3035d64127 | ||
|
|
70c9c058e2 | ||
|
|
1d9f73adec | ||
|
|
fca95af49b | ||
|
|
62fe392041 | ||
|
|
097d11819b | ||
|
|
691286f376 | ||
|
|
c910f6c832 | ||
|
|
65f9ac32ef | ||
|
|
27f2a2e3d5 | ||
|
|
88aab20376 | ||
|
|
a045ac3bd7 | ||
|
|
722b605407 | ||
|
|
7f53745077 | ||
|
|
7f902c4c03 | ||
|
|
1205c2055f | ||
|
|
f08f0f9dbd | ||
|
|
093c05e16a | ||
|
|
787100a4dc | ||
|
|
c493583f25 | ||
|
|
b4afbe47b3 | ||
|
|
6c4aeeeadd | ||
|
|
5b01519367 | ||
|
|
c494759606 | ||
|
|
2102c48b87 | ||
|
|
c498f4e8ab | ||
|
|
05a0166ebd | ||
|
|
0484365de6 | ||
|
|
cbab3b56de | ||
|
|
715f7985c7 | ||
|
|
2637018b53 | ||
|
|
1fa66ca45d | ||
|
|
13b10f691d | ||
|
|
3fe7d91713 | ||
|
|
98864091ff | ||
|
|
7750a461aa | ||
|
|
ac98b85157 | ||
|
|
21f6c6a5a8 | ||
|
|
b8d1491b99 | ||
|
|
d9c168d824 | ||
|
|
ee7f4ee1a4 | ||
|
|
ee3ce3c7d8 | ||
|
|
a57f38dbd5 | ||
|
|
3c4cb3c35b | ||
|
|
12cfe6d1d1 | ||
|
|
c64e8fc434 | ||
|
|
15f534a8f9 | ||
|
|
8e09e809aa | ||
|
|
fec5a80b89 | ||
|
|
1d50a188c4 | ||
|
|
b0d34b136f | ||
|
|
7eb234c250 | ||
|
|
d52434c0aa | ||
|
|
efc0b830cf | ||
|
|
4a8c4c4601 | ||
|
|
e498cedf56 | ||
|
|
6c8a52875e | ||
|
|
c1397fd366 | ||
|
|
3323ddcdef | ||
|
|
1be394cda7 | ||
|
|
f292092ffc | ||
|
|
b82e74f99a | ||
|
|
9b293ad66a | ||
|
|
3a4420f2d3 | ||
|
|
1eb8d6e845 | ||
|
|
e2f97dc44a | ||
|
|
ea9af96d2b | ||
|
|
e4033d997c | ||
|
|
bc38357193 | ||
|
|
618b486fd5 | ||
|
|
1986403e42 | ||
|
|
cf51f80b79 | ||
|
|
2fe17aa889 | ||
|
|
f76c8ad30b | ||
|
|
c421d3bb59 | ||
|
|
3d862da2be | ||
|
|
10b15caad9 | ||
|
|
e08238d5a0 | ||
|
|
d0104660c8 | ||
|
|
a4c2a9ef0d | ||
|
|
ee39d7ba14 | ||
|
|
62cb035afe | ||
|
|
7a8bc6b5d2 | ||
|
|
0d86ac23bb | ||
|
|
897fd9486e | ||
|
|
39d3d093c4 | ||
|
|
3f0b52bef4 | ||
|
|
4a04f27fde | ||
|
|
5fb02c0439 | ||
|
|
edfb4ef3f1 | ||
|
|
f037923b00 | ||
|
|
424aafb514 | ||
|
|
1b64167a3e | ||
|
|
a9a86e4604 | ||
|
|
1dc7c23b2f | ||
|
|
5bdcfbc2ce | ||
|
|
74e9bf4f31 | ||
|
|
0652529839 | ||
|
|
772d6597a9 | ||
|
|
4e99194022 | ||
|
|
f0ff2f4ea7 | ||
|
|
d583c533c2 | ||
|
|
ec1f219850 | ||
|
|
21d586cc86 | ||
|
|
8f7139d48f | ||
|
|
cfb6dae04d | ||
|
|
bceac3ee0b | ||
|
|
38d6edb0ca | ||
|
|
1b41a3bcee | ||
|
|
c54f934f6e | ||
|
|
94052bb712 | ||
|
|
7eb1dcc7ee | ||
|
|
626fbe827e | ||
|
|
28c154ecf0 | ||
|
|
8176f661ea | ||
|
|
0195e7f841 | ||
|
|
141b8a1481 | ||
|
|
be3ab90cff | ||
|
|
9782f16635 | ||
|
|
6930edfd8a | ||
|
|
6b1bec6550 | ||
|
|
dac0304815 | ||
|
|
cfcf81b5fb | ||
|
|
f072a02215 | ||
|
|
5f6e21da9b | ||
|
|
b9b38a4ec1 | ||
|
|
e5a7ba4f22 | ||
|
|
1dcf3f2afb | ||
|
|
2ec84969dd | ||
|
|
a08b945124 | ||
|
|
16f712fbaa | ||
|
|
1f63ff1d41 | ||
|
|
49d8f4689f | ||
|
|
e1f993938a | ||
|
|
ab65b9b2fb | ||
|
|
f7a621f89f | ||
|
|
b808a05e5e | ||
|
|
72c37c519d | ||
|
|
af4b072b29 | ||
|
|
739ed906f0 | ||
|
|
9fd462077a | ||
|
|
cb3671343e | ||
|
|
b18b705632 | ||
|
|
9963e78636 | ||
|
|
e39635ea16 | ||
|
|
9329b2c202 | ||
|
|
791f70e5a2 | ||
|
|
8272c4a429 | ||
|
|
f0357b061e | ||
|
|
7438e0e997 | ||
|
|
cca672e536 | ||
|
|
0fa12a687d | ||
|
|
d2b900c77f | ||
|
|
21242d9144 | ||
|
|
03fd138b63 | ||
|
|
1eeaef6dbb | ||
|
|
b9a93b68c4 | ||
|
|
e3728942dc | ||
|
|
7f0674ac27 | ||
|
|
60fcf7ab3d | ||
|
|
ee82a6ff18 | ||
|
|
bac5e402b7 | ||
|
|
732108109e | ||
|
|
ab3b86d65b | ||
|
|
d4d63506e1 | ||
|
|
3ad69f8ba3 | ||
|
|
9fd50a6ac0 | ||
|
|
9b5c8a18d4 | ||
|
|
9f3112ca56 | ||
|
|
aa9de47da3 | ||
|
|
5eaeda4402 | ||
|
|
ecb03d7dba | ||
|
|
88612d3691 | ||
|
|
2c0e70a423 | ||
|
|
d6b70f10d3 | ||
|
|
40b01fb702 | ||
|
|
89222d93f4 | ||
|
|
b3db3e5732 | ||
|
|
b45161ecc3 | ||
|
|
d4fc0af7de | ||
|
|
5ef8cce1d7 | ||
|
|
c98a147f94 | ||
|
|
e9975cb7eb | ||
|
|
33f0ac83c1 | ||
|
|
3bd45966c6 | ||
|
|
1b7244f3c8 | ||
|
|
1949f3c3d5 | ||
|
|
6a51ce5dc4 | ||
|
|
c0c8e1ce5e | ||
|
|
6a3d6191bd | ||
|
|
b2aa07d29f | ||
|
|
c84fb68bf8 | ||
|
|
128b9e1cd0 | ||
|
|
bbe8bcb28d | ||
|
|
6dc9c22543 | ||
|
|
59f5781f19 | ||
|
|
d61fb9cc42 | ||
|
|
ace052ee70 | ||
|
|
1451a8ccc0 | ||
|
|
547959c1ef | ||
|
|
b1a5e98630 | ||
|
|
f3a1ee7b9f | ||
|
|
b0a39b127d | ||
|
|
e36f1157cc | ||
|
|
053b9a786c | ||
|
|
2561d937da | ||
|
|
55f457caf4 | ||
|
|
f5cc2fd8ad | ||
|
|
e630b76fac | ||
|
|
0b6948cb4f | ||
|
|
b0a2dea747 | ||
|
|
f8395e36a1 | ||
|
|
6ec58f58ce | ||
|
|
96cbfe946c | ||
|
|
ac686a47c1 | ||
|
|
e05aaf77ce | ||
|
|
6b371eb8a8 | ||
|
|
f6660a0d55 | ||
|
|
3b9f213ea2 | ||
|
|
4f05024550 | ||
|
|
4d2d9d5574 | ||
|
|
14f44e79f7 | ||
|
|
ab960ea12d | ||
|
|
d276317e3a | ||
|
|
8b3b0064a9 | ||
|
|
66b890bfd3 | ||
|
|
2454ecd586 | ||
|
|
b891f4f874 | ||
|
|
92d06b3088 | ||
|
|
3067103b18 | ||
|
|
0e248b3faa | ||
|
|
d1a76bbcd9 | ||
|
|
1d91edfb00 | ||
|
|
cf7ecd5e66 | ||
|
|
63a2ecb89c | ||
|
|
8e6b58b1db | ||
|
|
0f594ef950 | ||
|
|
0c1b76c17a | ||
|
|
1c11ba8dbd | ||
|
|
529d5b2226 | ||
|
|
9fe16867c6 | ||
|
|
1d275c6b35 | ||
|
|
d19b29ced0 | ||
|
|
bbefcb2cd2 | ||
|
|
c864cba4a2 | ||
|
|
42546f4371 | ||
|
|
ff09bdcbf1 | ||
|
|
f36a9fffa3 | ||
|
|
933cced76c | ||
|
|
c51e7d3bde | ||
|
|
d3b31224cd | ||
|
|
ec9bb2302c | ||
|
|
009ef54de7 | ||
|
|
0e0e25f986 | ||
|
|
8b02b89bd6 | ||
|
|
8ba3c4ba50 | ||
|
|
16764c79b2 | ||
|
|
96c444d041 | ||
|
|
ec1c72e9a3 | ||
|
|
f9b1f6be5c | ||
|
|
9201d27875 | ||
|
|
ecbe79e04f | ||
|
|
6e34a7559b | ||
|
|
ea8b17565d | ||
|
|
a143faaf05 | ||
|
|
acdb56ad5d | ||
|
|
1f90238b18 | ||
|
|
89b636376e | ||
|
|
59f39ae3ab | ||
|
|
a92b20f85a | ||
|
|
e71c432b7c | ||
|
|
b6a5d09d4f | ||
|
|
9235d2b8e4 | ||
|
|
605847fd75 | ||
|
|
6222273adc | ||
|
|
6a759ea7d5 | ||
|
|
d8a7114dba | ||
|
|
ab818ed89f | ||
|
|
1bb6540b64 | ||
|
|
ddd8209c45 | ||
|
|
1dc3dfe58f | ||
|
|
634d262b64 | ||
|
|
d964146f8c | ||
|
|
05b817f5f5 | ||
|
|
eb2ec1833c | ||
|
|
094ddd9333 | ||
|
|
e05d48a574 | ||
|
|
927bfcd37a | ||
|
|
42cabace47 | ||
|
|
9a1f14d05c | ||
|
|
4189aa8f14 | ||
|
|
5fa5bf8142 | ||
|
|
000c1cf306 | ||
|
|
28447d3389 | ||
|
|
ab7f3310c4 | ||
|
|
e5a720c6fa | ||
|
|
8d20dbe81d | ||
|
|
1fc666d82c | ||
|
|
1b2a1a1e77 | ||
|
|
9af3081f45 | ||
|
|
78def6e6bf | ||
|
|
b4269199b4 | ||
|
|
cb289125ab | ||
|
|
a4e3ce31dd | ||
|
|
8a725d3d3e | ||
|
|
c48fa0f078 | ||
|
|
31aa782362 | ||
|
|
892637683c | ||
|
|
1cf6f28fe8 | ||
|
|
29f9394257 | ||
|
|
8fd92df7ae | ||
|
|
374f7abb5d | ||
|
|
3d1e604a6c | ||
|
|
1ca49b9380 | ||
|
|
9bd9cf8052 | ||
|
|
ed934a0206 | ||
|
|
dc891760ec | ||
|
|
97401f843a | ||
|
|
833865cb28 | ||
|
|
02635d506e | ||
|
|
f018e1a075 | ||
|
|
c79cde43ae | ||
|
|
8a812c9d02 | ||
|
|
3df78de3f8 | ||
|
|
bd4831e2ee | ||
|
|
341a34ea9e | ||
|
|
011866a101 | ||
|
|
1486af8770 | ||
|
|
f06e04ffc5 | ||
|
|
d72098bdf8 | ||
|
|
57871e1983 | ||
|
|
21dbb0e820 | ||
|
|
007f377f16 | ||
|
|
da15477aaf | ||
|
|
4f34ad0a8d | ||
|
|
6ed9dccde2 | ||
|
|
ce2b3265be | ||
|
|
14ea69c9c7 | ||
|
|
72e2307c16 | ||
|
|
0dd3334811 | ||
|
|
5485436ea1 | ||
|
|
9e044750ce | ||
|
|
f84cb2f07a | ||
|
|
e0ff6bcc5d | ||
|
|
1695f6800c | ||
|
|
810f149501 | ||
|
|
05d51d8693 | ||
|
|
ac4c819f57 | ||
|
|
e7cc654bb4 | ||
|
|
bf37e3f77f | ||
|
|
af9f7bb0d2 | ||
|
|
0b7abf5690 | ||
|
|
490ae248f8 | ||
|
|
e552bcb0c6 | ||
|
|
2c27316c4a | ||
|
|
c49dd12855 | ||
|
|
544f97a3fe | ||
|
|
6a909e0700 | ||
|
|
40a6ad9a1f | ||
|
|
039f2b49e8 | ||
|
|
5ae2406a03 | ||
|
|
2c3235d452 | ||
|
|
d2ea71a403 | ||
|
|
feb97b2313 | ||
|
|
0b662ecb9a | ||
|
|
3d0da77c80 | ||
|
|
9918397190 | ||
|
|
b3e2562c00 | ||
|
|
255cacf912 | ||
|
|
8268f9f612 | ||
|
|
92b8798cad | ||
|
|
fbb4db8a83 | ||
|
|
19a672caf2 | ||
|
|
5a85c890ba | ||
|
|
55556aaac4 | ||
|
|
31853ee20c | ||
|
|
037bfeff82 | ||
|
|
bf1c919547 | ||
|
|
202ec17a08 | ||
|
|
98ede457a0 | ||
|
|
3c772c3576 | ||
|
|
5b1eaa741c | ||
|
|
1a1aa2d6aa | ||
|
|
6e9aecdff3 | ||
|
|
95187632bf | ||
|
|
e3e28a023c | ||
|
|
65bb71779a | ||
|
|
29dd766a67 | ||
|
|
851145e69e | ||
|
|
b2e300c440 | ||
|
|
38998a4869 | ||
|
|
21f1fd55f8 | ||
|
|
c6c6a18375 | ||
|
|
56063b283e | ||
|
|
d27e7ead49 | ||
|
|
342164ede1 | ||
|
|
1061e40b98 | ||
|
|
377115a594 | ||
|
|
e405b68da1 | ||
|
|
d875d7baed | ||
|
|
9c48e4965c | ||
|
|
8675659fcb | ||
|
|
3b226618ad | ||
|
|
6879a492dc | ||
|
|
4070255dde | ||
|
|
dd9e484336 | ||
|
|
78cda7aa74 | ||
|
|
9ced447fa3 | ||
|
|
8e665ffedc | ||
|
|
99ea6c08a7 | ||
|
|
b0bfa2b2fc | ||
|
|
3797294838 | ||
|
|
3d6995d1e6 | ||
|
|
e91eb27e56 | ||
|
|
3a4b614ae0 | ||
|
|
26a6d6bef9 | ||
|
|
dca81589a7 | ||
|
|
5b7c697dfe | ||
|
|
18d6b8a0ad | ||
|
|
cdee601137 | ||
|
|
e74c08ff39 | ||
|
|
5bfe2fb8d3 | ||
|
|
55fc5c4358 | ||
|
|
d6a603d536 | ||
|
|
5c85d915cc | ||
|
|
57f8519a52 | ||
|
|
056be45dd5 | ||
|
|
3ee22e545e | ||
|
|
db5aa36f44 | ||
|
|
cc767061cc | ||
|
|
1d22b75090 | ||
|
|
4313531432 | ||
|
|
1faddeb402 | ||
|
|
2b035739f8 | ||
|
|
aeed20087e | ||
|
|
a239f41495 | ||
|
|
b36d6967a5 | ||
|
|
7c1d13b7db | ||
|
|
3e99949db8 | ||
|
|
aa12a65a8f | ||
|
|
18804efb7e | ||
|
|
a5d27196ea | ||
|
|
5af6d88ffb | ||
|
|
472a3bc69f | ||
|
|
f0f1c911ea | ||
|
|
fcb0033d25 | ||
|
|
c8b1e76783 | ||
|
|
b50f621e61 | ||
|
|
77c4f5fecc | ||
|
|
e27ea3337a | ||
|
|
23fbf6f157 | ||
|
|
321e5081ed | ||
|
|
33cac29f87 | ||
|
|
12be438dea | ||
|
|
00092db6ad | ||
|
|
619c3a0025 | ||
|
|
f12697c897 | ||
|
|
4bf0e0ea23 | ||
|
|
c7879d06c9 | ||
|
|
05227e7dfb | ||
|
|
9805d164d0 | ||
|
|
05384c46e7 | ||
|
|
c2679eff9a | ||
|
|
3ec66c0b9f | ||
|
|
9277b80fad | ||
|
|
568a4c9b5d | ||
|
|
4de18688ca | ||
|
|
12975347ee | ||
|
|
e35c3cc913 | ||
|
|
65fef81f29 | ||
|
|
e3f60e6fa7 | ||
|
|
0c88e11cd7 | ||
|
|
d689c21283 | ||
|
|
5362d1a7a6 | ||
|
|
3b1490020d | ||
|
|
b8ba25b81f | ||
|
|
8bfdc47998 | ||
|
|
2491fafe98 | ||
|
|
b5bc466aef | ||
|
|
cfd6ea4301 | ||
|
|
2cdf41f190 | ||
|
|
9169d0aa9b | ||
|
|
05a25e3531 | ||
|
|
2852ce9a4d | ||
|
|
20f8f2c401 | ||
|
|
0995187080 | ||
|
|
d10eac1b02 | ||
|
|
2cc2f803f1 | ||
|
|
66a52ac588 | ||
|
|
32f22e0ada | ||
|
|
c037f53534 | ||
|
|
aba84581f5 | ||
|
|
82f6fbff77 | ||
|
|
d16215ab6e | ||
|
|
45b0233f60 | ||
|
|
1ce4366972 | ||
|
|
c8fc21d336 | ||
|
|
5dd3243674 | ||
|
|
815dd99f7c | ||
|
|
bf0dcb1d2e | ||
|
|
031fc10859 | ||
|
|
a644e4c31e | ||
|
|
0398dbdcbe | ||
|
|
84b2fbba28 | ||
|
|
491f233d33 | ||
|
|
5e38af6d24 | ||
|
|
4c0f68150a | ||
|
|
3f25f70783 | ||
|
|
d7007f77aa | ||
|
|
94273941ad | ||
|
|
c09542ea6a | ||
|
|
c5583d380d | ||
|
|
f820f72768 | ||
|
|
6db1f8e3e3 | ||
|
|
2aba3e249c | ||
|
|
f66db65974 | ||
|
|
5b6038db35 | ||
|
|
9a365b0968 | ||
|
|
8a0cd73821 | ||
|
|
49b065cbe7 | ||
|
|
77f651cb5d | ||
|
|
fedde51c12 | ||
|
|
f710d6906e | ||
|
|
c9a751360e | ||
|
|
ad97315925 | ||
|
|
e8f7a2b345 | ||
|
|
5bc8d05f0a | ||
|
|
3669d4135c | ||
|
|
73b870bb87 | ||
|
|
6b4217c12a | ||
|
|
8b4fe494cf | ||
|
|
35041e7709 | ||
|
|
12cbcf1c17 | ||
|
|
26f50a451e | ||
|
|
11f3d7e215 | ||
|
|
a7d533cfe5 | ||
|
|
52ec4dc21b | ||
|
|
6f7ea49008 | ||
|
|
84b99b1b3d | ||
|
|
1022d8a0ee | ||
|
|
cd6a46730a | ||
|
|
59743fd7a1 | ||
|
|
07bd371e21 | ||
|
|
fe3b10a8fb | ||
|
|
c994bc1d89 | ||
|
|
22cffef7c8 | ||
|
|
5dfb8b1d80 | ||
|
|
82f9f002bd | ||
|
|
9f51506422 | ||
|
|
2a8295d71c | ||
|
|
7214b66aa5 | ||
|
|
a7d9c63a4e | ||
|
|
61dd52b50f | ||
|
|
a157f3c5e3 | ||
|
|
fc02246373 | ||
|
|
adb8a4676c | ||
|
|
f78d05a57f | ||
|
|
301d34fecf | ||
|
|
0848816644 | ||
|
|
ba7f0132f2 | ||
|
|
561fe81d00 | ||
|
|
2db83ecf1e | ||
|
|
1b8c6b23e1 | ||
|
|
b6622b9458 | ||
|
|
d79e943844 | ||
|
|
105959d91b | ||
|
|
ea414945f2 | ||
|
|
4acc692a94 | ||
|
|
05c475e6ca | ||
|
|
c04e1aedb2 | ||
|
|
4711746f8f | ||
|
|
7a7262923b | ||
|
|
cde60b19e8 | ||
|
|
59430c1c14 | ||
|
|
e55cae6192 | ||
|
|
ed71e73ca5 | ||
|
|
9ffd0111cc | ||
|
|
93b1919a38 | ||
|
|
535606fadb | ||
|
|
7cf7d94bba | ||
|
|
136a718453 | ||
|
|
5f6c4c0f6c | ||
|
|
ddfe7797e5 | ||
|
|
fc74d22724 | ||
|
|
ca41e642fb | ||
|
|
83849ab07a | ||
|
|
02ac2336bd | ||
|
|
c094ebce07 | ||
|
|
65ed9c759c | ||
|
|
83fe2438f9 | ||
|
|
caa20aa081 | ||
|
|
fd598df1c6 | ||
|
|
0cc008e737 | ||
|
|
5dbaf9aab0 | ||
|
|
71c1432892 | ||
|
|
59ab22c0c8 | ||
|
|
668f6fa257 | ||
|
|
5701ec4082 | ||
|
|
04afe969a0 | ||
|
|
19721014d0 | ||
|
|
44b84ba295 | ||
|
|
f80f61f84f | ||
|
|
6247270011 | ||
|
|
68394cebe3 | ||
|
|
a386277df9 | ||
|
|
f88b98ccd9 | ||
|
|
eecf80469e | ||
|
|
66dd83027d | ||
|
|
a1355484a6 | ||
|
|
ca17e9b02c | ||
|
|
dd085a9297 | ||
|
|
6c72c93b02 | ||
|
|
223fe85449 | ||
|
|
365c992f80 | ||
|
|
1dd489cf0c | ||
|
|
ed0239a556 | ||
|
|
dbb94fc1ff | ||
|
|
b9dd434fab | ||
|
|
23d089b4be | ||
|
|
faa5443d43 | ||
|
|
1afa91bbb4 | ||
|
|
908823166e | ||
|
|
6845dd115e | ||
|
|
ad44e1a515 | ||
|
|
2e8d19601b | ||
|
|
f259c23695 | ||
|
|
f75957d8c0 | ||
|
|
53ae5a4f8d | ||
|
|
c76a8242e2 | ||
|
|
8a1a45b067 | ||
|
|
8f433f5ff6 | ||
|
|
97c317b735 | ||
|
|
c8e9199b03 | ||
|
|
351e1a5a15 | ||
|
|
7b1449ba46 | ||
|
|
3983953e72 | ||
|
|
84ad0604f4 | ||
|
|
c509c5eb0d | ||
|
|
d39cf5d702 | ||
|
|
2b0d8bfe46 | ||
|
|
61fc96b187 | ||
|
|
070e95b5e1 | ||
|
|
727028280a | ||
|
|
ea4a7136f0 | ||
|
|
065a2b37c7 | ||
|
|
b5e452942e | ||
|
|
4fa8cb562a | ||
|
|
429efd70ff | ||
|
|
4c636fdeca | ||
|
|
1168687923 | ||
|
|
db32079bd8 | ||
|
|
e7246fd024 | ||
|
|
1c93e2a94e | ||
|
|
e8bd6f4493 | ||
|
|
cd36e3b314 | ||
|
|
ad29d7f639 | ||
|
|
b98fca972f | ||
|
|
c63c3d2844 | ||
|
|
6c1434ab8a | ||
|
|
b6d33e2019 | ||
|
|
97bd8b127f | ||
|
|
2be45eeca3 | ||
|
|
485fe0a7fb | ||
|
|
0070e0a58a | ||
|
|
f7fe59dfbe | ||
|
|
fd731feacc | ||
|
|
61194ef1c8 | ||
|
|
dadbaf9ab1 | ||
|
|
ffdb91ffd5 | ||
|
|
2ae3157d49 | ||
|
|
1c2c98c1a4 | ||
|
|
8d446d15e8 | ||
|
|
faddcd34d2 | ||
|
|
8c7e618324 | ||
|
|
cdb1fc8602 | ||
|
|
9dc9fb2012 | ||
|
|
3ce9e1932c | ||
|
|
da6ad5df45 | ||
|
|
a9f394ce18 | ||
|
|
093921cb9a | ||
|
|
c9818e7bb1 | ||
|
|
c8bf7763b6 | ||
|
|
00446fa2c4 | ||
|
|
7cf6b8b594 | ||
|
|
088766da72 | ||
|
|
1c1b04b1d9 | ||
|
|
29734563b4 | ||
|
|
b6e330e3e7 | ||
|
|
138b4cf5da | ||
|
|
92e86a3b28 | ||
|
|
dc48e6c432 | ||
|
|
80da4d1344 | ||
|
|
e7ad2637d8 | ||
|
|
8e84b21452 | ||
|
|
5674dc5bfc | ||
|
|
1b9c5522fb | ||
|
|
71bdf73884 | ||
|
|
8d04216c2b | ||
|
|
620782aa80 | ||
|
|
bd9a4e9cd8 | ||
|
|
af6ff15ee2 | ||
|
|
bb8e0e7789 | ||
|
|
4448d2dc7f | ||
|
|
7236e0ff21 | ||
|
|
9a615efa83 | ||
|
|
f857b1afd3 | ||
|
|
5cd9af6c37 | ||
|
|
ec0edd6f45 | ||
|
|
0f82f90968 | ||
|
|
06237b85f5 | ||
|
|
d319180e88 | ||
|
|
d8f5dc958d | ||
|
|
5b31b237e3 | ||
|
|
e211589f9f | ||
|
|
cd80a85d2d | ||
|
|
b752d1ca48 | ||
|
|
091e74d618 | ||
|
|
35fb8ea1bf | ||
|
|
b6c8b4f124 | ||
|
|
9ed703384f | ||
|
|
e259fc5250 | ||
|
|
8b08182555 | ||
|
|
4e6d929e20 | ||
|
|
0d7feb0404 | ||
|
|
1dc9adebb4 | ||
|
|
d89861f601 | ||
|
|
0354e5b669 | ||
|
|
98ec3fe18f | ||
|
|
e12f5209fb | ||
|
|
77d149518c | ||
|
|
087f13f293 | ||
|
|
8d8224812d | ||
|
|
489ed6a915 | ||
|
|
98bcbf8150 | ||
|
|
1fe81872c6 | ||
|
|
fb0db2b7df | ||
|
|
28803d9a5a | ||
|
|
fba37e73e7 | ||
|
|
f8fa76d77e | ||
|
|
a3e4c74f5d | ||
|
|
0667027506 | ||
|
|
0c5c6fcbbe | ||
|
|
bf8dfa5ee3 | ||
|
|
f6d0cadcc5 | ||
|
|
611d95f0f7 | ||
|
|
bbc1430420 | ||
|
|
61f7ce4dee | ||
|
|
e4163fca6a | ||
|
|
21d7cc1a60 | ||
|
|
f82b7841c6 | ||
|
|
edda0d91bb | ||
|
|
c70200ada0 | ||
|
|
adccc8fea4 | ||
|
|
b886b4c6b2 | ||
|
|
9eb113802d | ||
|
|
dab57f3819 | ||
|
|
88d0499818 | ||
|
|
51706ed195 | ||
|
|
7332561d8e | ||
|
|
daafea7f7e | ||
|
|
5f7bc8bff2 | ||
|
|
8809b8db56 | ||
|
|
686a5f7baf | ||
|
|
020b6b582d | ||
|
|
64ed8daf59 | ||
|
|
dd20789249 | ||
|
|
6570565e2d | ||
|
|
345b3437f4 | ||
|
|
20611c7c15 | ||
|
|
8dea5b3e3e | ||
|
|
c8756612f7 | ||
|
|
9fe995c7d8 | ||
|
|
422bcfcb54 | ||
|
|
3b04776956 | ||
|
|
1ba76508de | ||
|
|
4e09a518d5 | ||
|
|
e056460f0b | ||
|
|
da166aef99 | ||
|
|
a42bc3bf8c | ||
|
|
997c244664 | ||
|
|
fe8cf46d56 | ||
|
|
df9eab279a | ||
|
|
b14c9614e0 | ||
|
|
ed44515318 | ||
|
|
523aadaa3b | ||
|
|
4f18342ea6 | ||
|
|
f36e6f0461 | ||
|
|
978dc008e2 | ||
|
|
94f1759b14 | ||
|
|
a4af0599cc | ||
|
|
de4384a420 | ||
|
|
a33ebce3c9 | ||
|
|
219d3161d9 | ||
|
|
2e07159461 | ||
|
|
23d0f5ce32 | ||
|
|
f4792a1e3d | ||
|
|
2a5ef628fa | ||
|
|
4b259dd719 | ||
|
|
c127476c4e | ||
|
|
beded75547 | ||
|
|
74a6cdb3bb | ||
|
|
ba554fb01d | ||
|
|
39c98e83da | ||
|
|
73660f7119 | ||
|
|
46b4f33850 | ||
|
|
ad8e16aac0 | ||
|
|
ae6e082419 | ||
|
|
f46d3057ba | ||
|
|
8e0e4b8fd1 | ||
|
|
76da315f81 | ||
|
|
95de39feb9 | ||
|
|
c0f790c928 | ||
|
|
6fbb953aa4 | ||
|
|
30b38e9fa0 | ||
|
|
d20e801793 | ||
|
|
fe65b346c1 | ||
|
|
c5da1c0f1b | ||
|
|
3fd2f03f11 | ||
|
|
4ad4e28a9c | ||
|
|
d3edd2e73f | ||
|
|
3d37348c2b | ||
|
|
8a3e81b7ba | ||
|
|
a29c317217 | ||
|
|
48847cdaf8 | ||
|
|
a59cda8b60 | ||
|
|
e70b5114fb | ||
|
|
d2ab7fbb36 | ||
|
|
70352ca722 | ||
|
|
be28e7bf46 | ||
|
|
6b2b8e0208 | ||
|
|
c997dc8ea7 | ||
|
|
f52afbb396 | ||
|
|
a20e7e2a6b | ||
|
|
9903b8e8db | ||
|
|
1d18f63eb5 | ||
|
|
a63682b160 | ||
|
|
812f3e60ca | ||
|
|
f8f5838ab5 | ||
|
|
07782e071a | ||
|
|
624dfdf913 | ||
|
|
a01dad8c3c | ||
|
|
b6baa99fce | ||
|
|
912b395316 | ||
|
|
b1b90d2bf7 | ||
|
|
37bd964fee | ||
|
|
fa3e173c18 | ||
|
|
2a9dc23c61 | ||
|
|
2885f54360 | ||
|
|
ac2f4c8ab6 | ||
|
|
7282d8edc1 | ||
|
|
6f2d63eb87 | ||
|
|
9cab8a2de5 | ||
|
|
709d19119d | ||
|
|
029b82807c | ||
|
|
67c0942e01 | ||
|
|
fb57653665 | ||
|
|
646a349d82 | ||
|
|
ad1109b6fe | ||
|
|
c2bd6a66d9 | ||
|
|
ba9af3df8c | ||
|
|
5d4e968f50 | ||
|
|
0e327f3d13 | ||
|
|
bb06bfa627 | ||
|
|
2a713cab60 | ||
|
|
26df57a1c7 | ||
|
|
18893f86ce | ||
|
|
8fead5ebe8 | ||
|
|
6020aadbf2 | ||
|
|
f8b6b532e0 | ||
|
|
05ec174868 | ||
|
|
3875ee021a | ||
|
|
2931afa0ae | ||
|
|
2803e45380 | ||
|
|
965dde599e | ||
|
|
229ea45d81 | ||
|
|
8ea84c97d5 | ||
|
|
7c47bd547f | ||
|
|
6ae58e6882 | ||
|
|
3bc0f90a82 | ||
|
|
2a99ef254f | ||
|
|
5bc811f26e | ||
|
|
83893d762a | ||
|
|
24bed6273b | ||
|
|
2a5b314f67 | ||
|
|
e3c9fc3fba | ||
|
|
b81700a8fd | ||
|
|
b319fd4b93 | ||
|
|
23d6995558 | ||
|
|
190612d507 | ||
|
|
cddfe425e1 | ||
|
|
bc6a03a41b | ||
|
|
e053d1f566 | ||
|
|
e429b8484c | ||
|
|
22159c5eb4 | ||
|
|
903df9972a | ||
|
|
4dcbb1f077 | ||
|
|
5158d49781 | ||
|
|
3fdf47c535 | ||
|
|
b59d1bda8b | ||
|
|
1760fb9db2 | ||
|
|
082c771fc0 | ||
|
|
7ec989d485 | ||
|
|
0f9613eb9e | ||
|
|
85a354351a | ||
|
|
24db8cef4f | ||
|
|
9908eee40c | ||
|
|
b6517758d9 | ||
|
|
029500f3ed | ||
|
|
686727a7c3 | ||
|
|
91a1d61cc6 | ||
|
|
b8e9921f3d | ||
|
|
e0ce5d5629 | ||
|
|
ed511c296c | ||
|
|
eab1fbbbb0 | ||
|
|
ee3b052a50 | ||
|
|
5b98f15d9b | ||
|
|
51d76e5a2b | ||
|
|
a6bce0b221 | ||
|
|
fb5dc8a2ba | ||
|
|
d571ee0d01 | ||
|
|
5d7ed67316 | ||
|
|
9f6c754339 | ||
|
|
2819a4ebf3 | ||
|
|
dec1203ea8 | ||
|
|
87ab0d7b18 | ||
|
|
043530409c | ||
|
|
9710282d22 | ||
|
|
5e8e141fb5 | ||
|
|
2e313fbdd2 | ||
|
|
5c3e4db05f | ||
|
|
2be2f6aa0c | ||
|
|
6d038f5cdf | ||
|
|
27feccba39 | ||
|
|
7d39d5c088 | ||
|
|
2e69b904da | ||
|
|
79dcc8c771 | ||
|
|
683e5a4754 | ||
|
|
d51a424b98 | ||
|
|
e07d216a11 | ||
|
|
b9fa8dbe42 | ||
|
|
3820c46801 | ||
|
|
b663160bc2 | ||
|
|
a65c807a4a | ||
|
|
3a1f85cb69 | ||
|
|
196bd9c22b | ||
|
|
9bf2087b55 | ||
|
|
51e589c7e6 | ||
|
|
7365ed9b05 | ||
|
|
9cb7a6b2c7 | ||
|
|
9ff7eae1af | ||
|
|
61e1b74434 | ||
|
|
324c223d54 | ||
|
|
96793a296c | ||
|
|
7b1626a38f | ||
|
|
09a3a3dafb | ||
|
|
0e21708f25 | ||
|
|
89fa2343a6 | ||
|
|
03256d8ac9 | ||
|
|
889ca77912 | ||
|
|
23ee6b3109 | ||
|
|
d133ffac25 | ||
|
|
ffc6e65392 | ||
|
|
d61086907d | ||
|
|
5b58c2892d | ||
|
|
67379c67cc | ||
|
|
4691257233 | ||
|
|
d46a8c893a | ||
|
|
577ba0b39d | ||
|
|
f761245280 | ||
|
|
f1b4e585aa | ||
|
|
255db2cb66 | ||
|
|
8b6240a067 | ||
|
|
f5c713b118 | ||
|
|
ac7596b7c5 | ||
|
|
f69ed984a4 | ||
|
|
83850b28ae | ||
|
|
5efa26a98d | ||
|
|
51d2c01bc1 | ||
|
|
be9d876997 | ||
|
|
866b53f384 | ||
|
|
de1a2f7682 | ||
|
|
86686bfac7 | ||
|
|
3f316c39d1 | ||
|
|
14459a7d18 | ||
|
|
c062b84bc6 | ||
|
|
890a68fa53 | ||
|
|
59017a6e6f | ||
|
|
06cb2cafe6 | ||
|
|
e4ed170748 | ||
|
|
f011a6c86c | ||
|
|
45fc1ace0c | ||
|
|
8d51edec17 | ||
|
|
f2afba2ef4 | ||
|
|
efcd3a5df7 | ||
|
|
2a52acdef4 | ||
|
|
eadfeeec9b | ||
|
|
f8a581129f | ||
|
|
93ff651d9e | ||
|
|
bec0f02b11 | ||
|
|
0721951c79 | ||
|
|
b37d07d31a | ||
|
|
9cacfc0c26 | ||
|
|
0b93b85cf2 | ||
|
|
f7001ea068 | ||
|
|
aa93c3fb66 | ||
|
|
166c7bf0e6 | ||
|
|
bb1374f64e | ||
|
|
053835afbe | ||
|
|
4760580d1c | ||
|
|
8fa492e0ee | ||
|
|
040ae75c77 | ||
|
|
759aaf294a | ||
|
|
9ea0de868c | ||
|
|
78002cf3ba | ||
|
|
f68f8bf9c9 | ||
|
|
54438cae3f | ||
|
|
2e693c31df | ||
|
|
0f06bf1bdb | ||
|
|
b7f4f2e898 | ||
|
|
7148ee8a0f | ||
|
|
238508fc0a | ||
|
|
84ab0f5062 | ||
|
|
cf04bdb36a | ||
|
|
d09a30d16c | ||
|
|
d54b58d2f3 | ||
|
|
0be0963dc7 | ||
|
|
61a2360df5 | ||
|
|
b3ed4e3bc2 | ||
|
|
316e7cb9f5 | ||
|
|
23851e31bf | ||
|
|
b7b64ec513 | ||
|
|
2b372373ae | ||
|
|
7a543fac86 | ||
|
|
5c4b14468c | ||
|
|
7d4d978d97 | ||
|
|
fe5b8f3aec | ||
|
|
f5abe7cbf7 | ||
|
|
bd0382830a | ||
|
|
0b99bb534f | ||
|
|
9d67198ff9 | ||
|
|
fda57a81e1 | ||
|
|
9962ac2703 | ||
|
|
edc4b91d15 | ||
|
|
92ca8ab9cc | ||
|
|
07e2d9175c | ||
|
|
c90dbb25b9 | ||
|
|
b5da109e7f | ||
|
|
aa18429a8c | ||
|
|
e578d41adb | ||
|
|
f3579e78af | ||
|
|
9c43707f40 | ||
|
|
99ff92a5a7 | ||
|
|
d866c0d202 | ||
|
|
20c42ab519 | ||
|
|
8bbc2b82d4 | ||
|
|
6929358976 | ||
|
|
82acd6b511 | ||
|
|
bb939ed4f8 | ||
|
|
cd25abc49f | ||
|
|
2e90e443ed | ||
|
|
92bb6e293a | ||
|
|
ea9b431386 | ||
|
|
23077fd6a6 | ||
|
|
5eee7ce338 | ||
|
|
784894cac3 | ||
|
|
757983b729 | ||
|
|
b6660353cd | ||
|
|
215a7689d9 | ||
|
|
dd18a1dfd8 | ||
|
|
32f16ee5f5 | ||
|
|
d4f426d2ce | ||
|
|
a6d96c9a14 | ||
|
|
bf3bfeaf69 | ||
|
|
6ce82177ea | ||
|
|
dc6efb5b37 | ||
|
|
b26d1f306d | ||
|
|
cf678d8179 | ||
|
|
8cecb22481 | ||
|
|
2504266806 | ||
|
|
e3795eb07e | ||
|
|
796ead5d75 | ||
|
|
d5907a1bf9 | ||
|
|
ddd4774169 | ||
|
|
1dc83a47cf | ||
|
|
0a8dc4be0a | ||
|
|
3d99361790 | ||
|
|
1e278938cc | ||
|
|
ba177c61bc | ||
|
|
458f10be10 | ||
|
|
c1667d9fc1 | ||
|
|
52f4e81d59 | ||
|
|
1056ab1b81 | ||
|
|
3f9d04b616 | ||
|
|
d9cc065c99 | ||
|
|
612fb3b596 | ||
|
|
532d51c411 | ||
|
|
5630c0e434 | ||
|
|
5ba8ca2745 | ||
|
|
e9ffb8d185 | ||
|
|
339a2e0800 | ||
|
|
98c04fb7da | ||
|
|
c95d1393cc | ||
|
|
1779cdd353 | ||
|
|
6a090ac740 | ||
|
|
3c7236557c | ||
|
|
83a3d99824 | ||
|
|
808750a76a | ||
|
|
32caea4197 | ||
|
|
038248f55d | ||
|
|
21b7bf6009 | ||
|
|
9dc571d8a9 | ||
|
|
805baad9cd | ||
|
|
cc910f6b79 | ||
|
|
56dd442e2c | ||
|
|
3192b61385 | ||
|
|
eef3a215a1 | ||
|
|
cb7fff6986 | ||
|
|
75b5130d96 | ||
|
|
2cf8c6aea7 | ||
|
|
5755ba72b1 | ||
|
|
785937ecfc | ||
|
|
955ead05be | ||
|
|
3830261384 | ||
|
|
662ab0df45 | ||
|
|
1ce50fb6f0 | ||
|
|
74dcf8800d | ||
|
|
e90df0ca95 | ||
|
|
49c375ae0f | ||
|
|
6c4d1a4951 | ||
|
|
f99e368831 | ||
|
|
8468ad60d5 | ||
|
|
a1ce29aab9 | ||
|
|
20b5084904 | ||
|
|
2fde0ea86b | ||
|
|
b64bceac7f | ||
|
|
a97174a350 | ||
|
|
6141c9fdda | ||
|
|
a32e010f89 | ||
|
|
4847fb52cc | ||
|
|
58e33e2512 | ||
|
|
584b59c7a1 | ||
|
|
2e657f0020 | ||
|
|
ae112294c8 | ||
|
|
8b4c7ea23f | ||
|
|
83e225a50f | ||
|
|
6256b9027a | ||
|
|
1fd84612a8 | ||
|
|
2efa83bc4d | ||
|
|
fa064bf9cf | ||
|
|
325d2bc14e | ||
|
|
90a4b4f859 | ||
|
|
ce0db16479 | ||
|
|
43ce3ce4b0 | ||
|
|
910cebeeb5 | ||
|
|
1c78633d1a | ||
|
|
530fd61125 | ||
|
|
9edfafcac2 | ||
|
|
677c47b9dd | ||
|
|
b59d7dda11 | ||
|
|
7a3534baf8 | ||
|
|
3bfcadcd81 | ||
|
|
529bb5c6a0 | ||
|
|
caf9a12b34 | ||
|
|
da8e2d3d4a | ||
|
|
582500d3e9 | ||
|
|
7926a140b8 | ||
|
|
023487a1d7 | ||
|
|
71f84b1023 | ||
|
|
ce85382c68 | ||
|
|
94d248d812 | ||
|
|
62db7639a8 | ||
|
|
80f3fe6e9f | ||
|
|
9ba2c4b397 | ||
|
|
bfa53d4b45 | ||
|
|
69f3ceb903 | ||
|
|
d0f839bbd8 | ||
|
|
48538c0e25 | ||
|
|
02ab22f08c | ||
|
|
b3b216a6dc | ||
|
|
431564c8bc | ||
|
|
57f1bbb71a | ||
|
|
faac8649e4 | ||
|
|
1e6a41186f | ||
|
|
eddee67130 | ||
|
|
9b834014e9 | ||
|
|
a467e79144 | ||
|
|
90cc785b55 | ||
|
|
09710425ab | ||
|
|
dd36727adf | ||
|
|
47b665a624 | ||
|
|
7011329761 | ||
|
|
ea24c23fde | ||
|
|
be8f2b8106 | ||
|
|
71db024a3b | ||
|
|
3790af6897 | ||
|
|
dc6ef63ddd | ||
|
|
ef762f7a2b | ||
|
|
4ed646e062 | ||
|
|
afbd843388 | ||
|
|
18c3598ef2 | ||
|
|
1c2623e609 | ||
|
|
e232863028 | ||
|
|
a89309153d | ||
|
|
fee7c8e573 | ||
|
|
1a52127c55 | ||
|
|
4920431c3a | ||
|
|
773f26b61d | ||
|
|
16e77d7329 | ||
|
|
2cec0908a5 | ||
|
|
b3ef62c188 | ||
|
|
3385f6fe67 | ||
|
|
0170bf636b | ||
|
|
b2561fd61e | ||
|
|
64b48945d4 | ||
|
|
bbfd463357 | ||
|
|
2179dab8ed | ||
|
|
801ead7f7f | ||
|
|
9e4834d58b | ||
|
|
f38e089de0 | ||
|
|
b252504306 | ||
|
|
81bcdaf48a | ||
|
|
44f654ff86 | ||
|
|
84cfa9382f | ||
|
|
c6da374aa9 | ||
|
|
d9fe0b2540 | ||
|
|
5a905dfe7f | ||
|
|
09b6d6e62b | ||
|
|
6aa26cf75f | ||
|
|
bae8915881 | ||
|
|
9c46de319e | ||
|
|
994eecadb7 | ||
|
|
f7f9ceec34 | ||
|
|
527255e3a1 | ||
|
|
0333da991d | ||
|
|
2bf8e1b1a3 | ||
|
|
ffc717717c | ||
|
|
2c8414db5d | ||
|
|
32473d7dc7 | ||
|
|
079f10eebd | ||
|
|
ae1f305a81 | ||
|
|
0b1f5209d5 | ||
|
|
fc9980903d | ||
|
|
ad87131926 | ||
|
|
4dfe1b664f | ||
|
|
d7b2ac97b5 | ||
|
|
fd9dac4ca4 | ||
|
|
8ca9348b07 | ||
|
|
5cc18fdb4b | ||
|
|
51b6b325b9 | ||
|
|
b3cc6f3802 | ||
|
|
1295094715 | ||
|
|
af85f58e3d | ||
|
|
3b34821c86 | ||
|
|
eaea0b16b5 | ||
|
|
964ffadc8e | ||
|
|
1b84064e5f | ||
|
|
dd128a99ac | ||
|
|
bc829a9712 | ||
|
|
3459c55ebf | ||
|
|
a631d950e1 | ||
|
|
f35e2d76ad | ||
|
|
8db838da9f | ||
|
|
7254a880dc | ||
|
|
a0df5b970b | ||
|
|
54ed08c24e | ||
|
|
97e1ecabdc | ||
|
|
e716f6d35e | ||
|
|
c7506496da | ||
|
|
1e3d3df9b8 | ||
|
|
ed75ad0d41 | ||
|
|
fd6159c0b4 | ||
|
|
976c322b83 | ||
|
|
28c1935800 | ||
|
|
1edf1524f8 | ||
|
|
0dfe101c0f | ||
|
|
a571821f73 | ||
|
|
f8e6f87984 | ||
|
|
c7338bca6f | ||
|
|
15f07f57bf | ||
|
|
ec989a45b5 | ||
|
|
e8286c50b2 | ||
|
|
bfbbe3db14 | ||
|
|
6214a87522 | ||
|
|
743ff719c8 | ||
|
|
b491eacb9c | ||
|
|
5bfc89e13f | ||
|
|
52d2b7b09e | ||
|
|
19e59d9575 | ||
|
|
6fe4baf1de | ||
|
|
bc21ec7551 | ||
|
|
aad4a1fd6a | ||
|
|
721595ef04 | ||
|
|
139838c717 | ||
|
|
c93238d8c9 | ||
|
|
5ee1fbe07d | ||
|
|
ee1287211d | ||
|
|
94e8be6b1c | ||
|
|
053ba7f082 | ||
|
|
e8f3f00792 | ||
|
|
740a89b77f | ||
|
|
1fe936dbbc | ||
|
|
11e85ac703 | ||
|
|
4cb99be8e6 | ||
|
|
8cf9fd3cdb | ||
|
|
b22950bb0a | ||
|
|
f87d62571b | ||
|
|
42afc56b65 | ||
|
|
10c3c7c41f | ||
|
|
e236539e3a | ||
|
|
1fc605cbc0 | ||
|
|
1e4963e727 | ||
|
|
95384d437a | ||
|
|
e44910212c | ||
|
|
36b8802f43 | ||
|
|
a6b0554edc | ||
|
|
c1df5eac57 | ||
|
|
68bf1be8d0 | ||
|
|
d5edea3c7f | ||
|
|
eb580f5ead | ||
|
|
c99588082b | ||
|
|
96d241e9f3 | ||
|
|
8f423c6d8f | ||
|
|
f25ecedcab | ||
|
|
2913c1aedc | ||
|
|
5a15f7e8ad | ||
|
|
e6cb64baa5 | ||
|
|
537023ef5a | ||
|
|
70125e0de5 | ||
|
|
8c5646b81b | ||
|
|
bd741365cb | ||
|
|
efd9843920 | ||
|
|
0bb8ec61e5 | ||
|
|
6a51096304 | ||
|
|
807c8f9005 | ||
|
|
9c21610215 | ||
|
|
97b4256ba4 | ||
|
|
e4b643fdaf | ||
|
|
0bda7b3679 | ||
|
|
51e3e9997c | ||
|
|
9f52d427e5 | ||
|
|
ad706f9924 | ||
|
|
57cf789c75 | ||
|
|
62174fdbcc | ||
|
|
dff7ddea39 | ||
|
|
0c3257b6b9 | ||
|
|
4bbf5c0bc9 | ||
|
|
b0820f6e13 | ||
|
|
b0f5d8dfdc | ||
|
|
67e0d3723a | ||
|
|
a36f4a4670 | ||
|
|
dab852c412 | ||
|
|
193ac6cd81 | ||
|
|
34ca8419bb | ||
|
|
6094aabe26 | ||
|
|
19648257f2 | ||
|
|
3363a9459b | ||
|
|
4d92f4871a | ||
|
|
f0d4ad16d2 | ||
|
|
2cc8402458 | ||
|
|
1c79320133 | ||
|
|
8b099d969f | ||
|
|
61157e8763 | ||
|
|
f97d078f81 | ||
|
|
a14cf81422 | ||
|
|
feeba9b5f5 | ||
|
|
b1b76ca250 | ||
|
|
e119ed0daa | ||
|
|
8c18486836 | ||
|
|
b6ed3951bc | ||
|
|
ea178ea689 | ||
|
|
973bbf3f8a | ||
|
|
3068846d8f | ||
|
|
194454715f | ||
|
|
ac02e053ee | ||
|
|
75db360929 | ||
|
|
f9141120aa | ||
|
|
d19f9e5b96 | ||
|
|
213a223861 | ||
|
|
ef9a24932f | ||
|
|
bf5b0070c1 | ||
|
|
2ab6f57159 | ||
|
|
77d46630d7 | ||
|
|
b78612aebd | ||
|
|
0f63d1bfa7 | ||
|
|
66a897cc80 | ||
|
|
3828511051 | ||
|
|
226a89c184 | ||
|
|
e3b4919c17 | ||
|
|
168bc58635 | ||
|
|
f4f0b8fd5f | ||
|
|
13c034c613 | ||
|
|
35f1658f4a | ||
|
|
328f22adab | ||
|
|
22cf67b407 | ||
|
|
0c7d51dd9d | ||
|
|
fa87ce72a8 | ||
|
|
ff2e5b3966 | ||
|
|
96c93fa252 | ||
|
|
e830b7edf7 | ||
|
|
9c874f6685 | ||
|
|
b8ab15bea8 | ||
|
|
6c7247f726 | ||
|
|
7674aa4e7c | ||
|
|
ebe97bf492 | ||
|
|
fbe4d036d8 | ||
|
|
c572b8bb1a | ||
|
|
59a5e23466 | ||
|
|
b9857f9499 | ||
|
|
b667e3a577 | ||
|
|
240b1475c7 | ||
|
|
3f24e5b571 | ||
|
|
fc7ec1d3f7 | ||
|
|
452ff02b15 | ||
|
|
c2cb43cc07 | ||
|
|
6736fd3835 | ||
|
|
a1bd69a9c2 | ||
|
|
561e63ee2d | ||
|
|
647b95631f | ||
|
|
aa518b2520 | ||
|
|
51c0f01539 | ||
|
|
cc9a19b303 | ||
|
|
2ee9844c2b | ||
|
|
4c53a74fa9 | ||
|
|
9b0ffdbf5a | ||
|
|
2777b89e45 | ||
|
|
7f90430414 | ||
|
|
ee4e56edf9 | ||
|
|
93c83d03c0 | ||
|
|
855b3de473 | ||
|
|
a9be05c885 | ||
|
|
9f3dfc27da | ||
|
|
4b4f6bc928 | ||
|
|
273735f9dc | ||
|
|
b95e0fb80e | ||
|
|
6ad21fc98f | ||
|
|
bff9b03935 | ||
|
|
edf9413356 | ||
|
|
c74f4a8165 | ||
|
|
8201cd3288 | ||
|
|
1603310b86 | ||
|
|
627b91ffba | ||
|
|
9ad65f2e1d | ||
|
|
a6a606ff3d | ||
|
|
63317f9c78 | ||
|
|
46d9dfb614 | ||
|
|
be3b33af06 | ||
|
|
04e1b8b1ae | ||
|
|
213768b6e0 | ||
|
|
aff1abdb26 | ||
|
|
44a413df81 | ||
|
|
4f12c91fff | ||
|
|
b6188bf436 | ||
|
|
b9a14e0e4a | ||
|
|
6882c23f43 | ||
|
|
80301d465b | ||
|
|
32632264ee | ||
|
|
409bd37db5 | ||
|
|
5fd4bc965f | ||
|
|
e86e5ce1d8 | ||
|
|
5faa649452 | ||
|
|
2ddc7e8c80 | ||
|
|
ed700ff830 | ||
|
|
33ed873997 | ||
|
|
9125c00f96 | ||
|
|
73fe3293be | ||
|
|
804c4fbe19 | ||
|
|
d6c82ba21c | ||
|
|
67308f2ca1 | ||
|
|
4a17a946fb | ||
|
|
1ae7ae4a1d | ||
|
|
404ca23de3 | ||
|
|
d385952fef | ||
|
|
f03cac8a9d | ||
|
|
4b501fd694 | ||
|
|
872d39eb2c | ||
|
|
0341cae922 | ||
|
|
5357a9a1cc | ||
|
|
3695538a11 | ||
|
|
7780d52930 | ||
|
|
6a23b4ee47 | ||
|
|
f48b770036 | ||
|
|
81b5d2c4f2 | ||
|
|
d43d6ab0a9 | ||
|
|
5a4e883360 | ||
|
|
eb93cd4048 | ||
|
|
d83e3fddb0 | ||
|
|
80ca25e879 | ||
|
|
c86b34aacd | ||
|
|
8da426039b | ||
|
|
9184e9a28f | ||
|
|
578d537d5f | ||
|
|
236c92b2b4 | ||
|
|
66a46279f4 | ||
|
|
eb35edbe20 | ||
|
|
7cf2404331 | ||
|
|
9ccc6bf835 | ||
|
|
025a46bb35 | ||
|
|
677e8a1ae9 | ||
|
|
03702772d3 | ||
|
|
3cd744b247 | ||
|
|
88523b2692 | ||
|
|
dcb39eb210 | ||
|
|
102823809b | ||
|
|
23f2b29069 | ||
|
|
7b33a87725 | ||
|
|
6dde573ed9 | ||
|
|
566e641be1 | ||
|
|
08d5448523 | ||
|
|
c11a20f1ec | ||
|
|
e5b9bd2e5a | ||
|
|
6ad49bd7fb | ||
|
|
5d082d8d5a | ||
|
|
977575da73 | ||
|
|
bced6f31b1 | ||
|
|
6bf04e22cc | ||
|
|
2f9784809d | ||
|
|
3e85497c2c | ||
|
|
3b551a1dee | ||
|
|
d2fdb1c1eb | ||
|
|
db92af68e9 | ||
|
|
815087460c | ||
|
|
b4cb9d7c4d | ||
|
|
c6d10c6a23 | ||
|
|
464c7a80e2 | ||
|
|
4f56cce727 | ||
|
|
7dea6e0ef4 | ||
|
|
8c143db381 | ||
|
|
0cea6d5a1b | ||
|
|
eff881f4bb | ||
|
|
c64fd1760c | ||
|
|
9e361700d2 | ||
|
|
1f976644bf | ||
|
|
f3cb68ee40 | ||
|
|
85a3da057f | ||
|
|
c551384369 | ||
|
|
ce230b071b | ||
|
|
13d5f04ad9 | ||
|
|
3b861de3d2 | ||
|
|
1ef010689d | ||
|
|
3523ab283f | ||
|
|
5b2a9b101d | ||
|
|
fdcfcfa1b9 | ||
|
|
88e9c21a3b | ||
|
|
973352a98d | ||
|
|
f06f871dfc | ||
|
|
e03c713294 | ||
|
|
aa107956f9 | ||
|
|
d725578e1b | ||
|
|
239eb8202b | ||
|
|
58d7439719 | ||
|
|
cc145ec3dd | ||
|
|
847ce37160 | ||
|
|
0305009766 | ||
|
|
fe1b056371 | ||
|
|
0c4804db79 | ||
|
|
f7e84df332 | ||
|
|
bd654d22f4 | ||
|
|
115de36599 | ||
|
|
b01c3483de | ||
|
|
db7f566a0c | ||
|
|
9f806e76e7 | ||
|
|
12bdd4dddd | ||
|
|
72a1eb237d | ||
|
|
6a89289907 | ||
|
|
7ed835cf13 | ||
|
|
4621ff41d9 | ||
|
|
60e17d5224 | ||
|
|
1e2f7c705d | ||
|
|
1ebf0b95c4 | ||
|
|
c5acd94456 | ||
|
|
448ffe01c3 | ||
|
|
5c882f3290 | ||
|
|
70a4720bf9 | ||
|
|
c8aee8c881 | ||
|
|
c2ad0607b8 | ||
|
|
d1282b9f55 | ||
|
|
11ee317884 | ||
|
|
e69de2f968 | ||
|
|
2f4f3e3331 | ||
|
|
020f8a2047 | ||
|
|
b8faba2a16 | ||
|
|
0fcce6ec58 | ||
|
|
15f5ea92b8 | ||
|
|
2bbb5d25eb | ||
|
|
8d94285a5d | ||
|
|
eed11361c5 | ||
|
|
b759f96f96 | ||
|
|
df3342d121 | ||
|
|
862ed40c44 | ||
|
|
8018024cb7 | ||
|
|
c8d5f232b3 | ||
|
|
d48b76508b | ||
|
|
2d62e10a7e | ||
|
|
0b3a5a7d45 | ||
|
|
076658a1e8 | ||
|
|
be1a05b322 | ||
|
|
945613555a | ||
|
|
5f75becc5a | ||
|
|
51ac78f74d | ||
|
|
3cce9b1c38 | ||
|
|
8a9ee6f3f5 | ||
|
|
d3059c09e0 | ||
|
|
1f093b4ff2 | ||
|
|
50470b5747 | ||
|
|
304f21e79d | ||
|
|
cb04deef63 | ||
|
|
ddb2e41352 | ||
|
|
a6700c951a | ||
|
|
684a2e05f4 | ||
|
|
c7e1a12eb6 | ||
|
|
ce7be5a05e | ||
|
|
433640de84 | ||
|
|
7f19424f2d | ||
|
|
b9d0ec0d4c | ||
|
|
869abc4d5c | ||
|
|
872118fcbe | ||
|
|
da0309545e | ||
|
|
54b802f1e6 | ||
|
|
d097403a12 | ||
|
|
c81a8216dc | ||
|
|
95683c658b | ||
|
|
d25c0d42bc | ||
|
|
77f0328f4f | ||
|
|
a1b4f7c92d | ||
|
|
47704f24c1 | ||
|
|
e0ef563885 | ||
|
|
2e570e21a0 | ||
|
|
a962a28b36 | ||
|
|
898395253b | ||
|
|
346a9f68b1 | ||
|
|
dbf8eb773c | ||
|
|
47ed1a4dca | ||
|
|
4c566ee37f | ||
|
|
a29b424477 | ||
|
|
56a30a014c | ||
|
|
abdc149f65 | ||
|
|
005c4bf29e | ||
|
|
c86c166448 | ||
|
|
0999ce159e | ||
|
|
98d8ab2953 | ||
|
|
5407fa72b4 | ||
|
|
e332522a61 | ||
|
|
ee27f23862 | ||
|
|
b1853ca966 | ||
|
|
ed2e83654f | ||
|
|
ec6dcd53b5 | ||
|
|
0b6fe99611 | ||
|
|
03847b15f6 | ||
|
|
8d7515bd9b | ||
|
|
e4b839742c | ||
|
|
f3cdf4194a | ||
|
|
ef6f4c2fbf | ||
|
|
9cda51b5a8 | ||
|
|
b8093d6b83 | ||
|
|
ffedc5d170 | ||
|
|
f223cd4b56 | ||
|
|
111c7fa57c | ||
|
|
e630abfe7f | ||
|
|
11b17c09ce | ||
|
|
466d96c167 | ||
|
|
c90223e4c8 | ||
|
|
01324a7ad2 | ||
|
|
122ad8a1f8 | ||
|
|
138bfcf2a8 | ||
|
|
c95418a947 | ||
|
|
b191727567 | ||
|
|
c17c6cae4c | ||
|
|
ed9b332da5 | ||
|
|
e8441ce697 | ||
|
|
f2d00589d8 | ||
|
|
e81ba3b207 | ||
|
|
27cd303a05 | ||
|
|
52ecdfe3a9 | ||
|
|
70f71e8ada | ||
|
|
d12063daad | ||
|
|
b9798c74d4 | ||
|
|
c12bce3d2f | ||
|
|
73b501c961 | ||
|
|
08079ad889 | ||
|
|
b4509e341a | ||
|
|
08ee77d11c | ||
|
|
868c1d634b | ||
|
|
ccc67b66c4 | ||
|
|
a0702f4a97 | ||
|
|
cada4a8ca8 | ||
|
|
af69f714b1 | ||
|
|
9c135f9f4c | ||
|
|
d1df5ad4e2 | ||
|
|
6352f585e8 | ||
|
|
fe3bb92b54 | ||
|
|
59243355f6 | ||
|
|
fd49d17591 | ||
|
|
1d9b36996a | ||
|
|
0cac74d39a | ||
|
|
fb41ecb2e5 | ||
|
|
0296d1f9a2 | ||
|
|
b51100195a | ||
|
|
b86e0ef669 | ||
|
|
86e33f739c | ||
|
|
259dcf376c | ||
|
|
466155fd24 | ||
|
|
452fd71fea | ||
|
|
da8944b551 | ||
|
|
5e2587920a | ||
|
|
7fb48dc04c | ||
|
|
b8e477c6eb | ||
|
|
a3b85883f8 | ||
|
|
e1c553e7b2 | ||
|
|
be6151730d | ||
|
|
444d9536a7 | ||
|
|
ffff343e3d | ||
|
|
f85c050235 | ||
|
|
fe214f43cb | ||
|
|
d9b0b5c08f | ||
|
|
a561697f04 | ||
|
|
bbc140e020 | ||
|
|
2bcbcfff44 | ||
|
|
1fb81d2265 | ||
|
|
3b4a242e26 | ||
|
|
b8937bc151 | ||
|
|
b3de442116 | ||
|
|
fb797d7735 | ||
|
|
982a9320c5 | ||
|
|
47dec2c2e9 | ||
|
|
eb8f4e0b3c | ||
|
|
85fcd51ea3 | ||
|
|
9ec6cf721f | ||
|
|
bcd4c64b8a | ||
|
|
3b0d8ec500 | ||
|
|
73ce2ccb47 | ||
|
|
a5078afd1e | ||
|
|
32a6dd2aa1 | ||
|
|
02884c5045 | ||
|
|
25d7668b70 | ||
|
|
2ff39c1578 | ||
|
|
a11d6466c6 | ||
|
|
df56080303 | ||
|
|
4d1eb1f729 | ||
|
|
ec06dd7460 | ||
|
|
163ce2a066 | ||
|
|
058c1bec10 | ||
|
|
ba40bf5e6f | ||
|
|
d457abdee4 | ||
|
|
3773aaa8a1 | ||
|
|
cfc99baac4 | ||
|
|
b6be6ee1e7 | ||
|
|
dfd8a69cf2 | ||
|
|
9307486254 | ||
|
|
6a627cca9e | ||
|
|
480f4bf44e | ||
|
|
b5b2f11b18 | ||
|
|
ee232fb08c | ||
|
|
ef7dcbf365 | ||
|
|
3e511d217b | ||
|
|
b08f4ab593 | ||
|
|
fa1ae39480 | ||
|
|
96483a0e92 | ||
|
|
7deb68de61 | ||
|
|
bf09c33b99 | ||
|
|
9e5882c9fb | ||
|
|
c5d17934e4 | ||
|
|
c8c1a3618c | ||
|
|
593b4c5a46 | ||
|
|
d7ea28f8e7 | ||
|
|
c4bcda80e9 | ||
|
|
528573ac80 | ||
|
|
dba067d875 | ||
|
|
5a5d27077c | ||
|
|
c145dfc832 | ||
|
|
407431adc8 | ||
|
|
8e3b5ddb0b | ||
|
|
e1b77f0a59 | ||
|
|
81a465f7bc | ||
|
|
0bec6ea15d | ||
|
|
2b988b01c6 | ||
|
|
ab604fb149 | ||
|
|
d344c391fd | ||
|
|
449c1ba5d7 | ||
|
|
12340e4c60 | ||
|
|
95aad91a49 | ||
|
|
c3f5b20ca7 | ||
|
|
f8c7a7a690 | ||
|
|
c5649df971 | ||
|
|
9cedefb50c | ||
|
|
96f8f8c79d | ||
|
|
889d5b07a6 | ||
|
|
82d17c8a59 | ||
|
|
7ba3aa0c6f | ||
|
|
598f08e222 | ||
|
|
625798220a | ||
|
|
2f06c0f721 | ||
|
|
0ec793e8bc | ||
|
|
e30f88d382 | ||
|
|
49be779982 | ||
|
|
2ac8ad39c9 | ||
|
|
e11a50ae83 | ||
|
|
eecd0c8d9a | ||
|
|
974950e7de | ||
|
|
47446975ac | ||
|
|
c69145b6bc | ||
|
|
141a08ec7c | ||
|
|
f0003f223a | ||
|
|
a4fe97c88c | ||
|
|
cc23515a35 | ||
|
|
8d2a720fb9 | ||
|
|
9ed980a511 | ||
|
|
1365eafce5 | ||
|
|
07b70f8c95 | ||
|
|
f16bf2a136 | ||
|
|
0f2bcfabb3 | ||
|
|
d3e8c616b0 | ||
|
|
99888996a0 | ||
|
|
4c94e16936 | ||
|
|
235f3940f2 | ||
|
|
e86c2f2000 | ||
|
|
65b212fa1b | ||
|
|
4b0ff03868 | ||
|
|
8961eaaa9d | ||
|
|
356722b9a6 | ||
|
|
89e5ae28bb | ||
|
|
b40e1e6492 | ||
|
|
4dc6918b13 | ||
|
|
1d45a831ef | ||
|
|
32920fee5b | ||
|
|
121de41930 | ||
|
|
a553107da8 | ||
|
|
8cad6ae9d6 | ||
|
|
ed60e7cf19 | ||
|
|
a9db9f8874 | ||
|
|
b9b2570369 | ||
|
|
c4f61de3fe | ||
|
|
523c9ff0d1 | ||
|
|
a02fd8411a | ||
|
|
98d8d6b915 | ||
|
|
2b87e1f601 | ||
|
|
084fb23930 | ||
|
|
244840255b | ||
|
|
94c11af7c8 | ||
|
|
26e6716f67 | ||
|
|
aef8b4ae67 | ||
|
|
a97ba08cbb | ||
|
|
ddc327b772 | ||
|
|
a70f6405ac | ||
|
|
bf0ad30d17 | ||
|
|
6fbe52acf4 | ||
|
|
9fccc38382 | ||
|
|
339c0d2980 | ||
|
|
336857a106 | ||
|
|
d01e5f72fc | ||
|
|
5c6be7f637 | ||
|
|
088087df73 | ||
|
|
0bd093ec2e | ||
|
|
4613e161ce | ||
|
|
dad9444db0 | ||
|
|
dd0080d3ce | ||
|
|
6b9303ba7d | ||
|
|
eb32423fb6 | ||
|
|
9bb2a05a9b | ||
|
|
653fc0dd7e | ||
|
|
cee6ef9941 | ||
|
|
67a37f1f41 | ||
|
|
604e82fd65 | ||
|
|
5f4e003bed | ||
|
|
53e9f35c1f | ||
|
|
c56a2ed055 | ||
|
|
e5d411b80d | ||
|
|
98e93cb4bd | ||
|
|
f5040532c5 | ||
|
|
447a2fe8cf | ||
|
|
a14defbab7 | ||
|
|
3592f82e4f | ||
|
|
4edfa9f4fd | ||
|
|
51fe1e4dab | ||
|
|
2df9f3500c | ||
|
|
289cfe7584 | ||
|
|
b603d7abb7 | ||
|
|
3437433ed4 | ||
|
|
cccacfdf7c | ||
|
|
c6fa0503af | ||
|
|
579933ac27 | ||
|
|
541f389a06 | ||
|
|
d2654db6f0 | ||
|
|
c2b2833a37 | ||
|
|
b0fffad0c2 | ||
|
|
774956053a | ||
|
|
5c582f7639 | ||
|
|
ccc0433fa1 | ||
|
|
43bf056f09 | ||
|
|
1d7b650fd0 | ||
|
|
fefe6c9024 | ||
|
|
b58e900806 | ||
|
|
ec58777d01 | ||
|
|
7a0b649cbd | ||
|
|
e15bc71930 | ||
|
|
6d02e884d8 | ||
|
|
6d7546aa8c | ||
|
|
ace91f04af | ||
|
|
934d21ac30 | ||
|
|
79d8c04b00 | ||
|
|
6c838bbc28 | ||
|
|
0277be5856 | ||
|
|
71dcf13edf | ||
|
|
bc0a77ee31 | ||
|
|
758d315b8e | ||
|
|
3ec64a17f8 | ||
|
|
dc7d705c87 | ||
|
|
6c98b676bb | ||
|
|
dd6108de5b | ||
|
|
aa1b94aed0 | ||
|
|
75e1b30fc1 | ||
|
|
a8bca1c119 | ||
|
|
d05ea312ef | ||
|
|
e72f153a66 | ||
|
|
da8bf5adc7 | ||
|
|
ce0e5a893f | ||
|
|
c8b7b49d56 | ||
|
|
9842a47f85 | ||
|
|
1db4286a12 | ||
|
|
4234a9d963 | ||
|
|
6da465d7d7 | ||
|
|
a1cb01b3b2 | ||
|
|
6920d37042 | ||
|
|
1dcdf9534b | ||
|
|
f9c21b1cb3 | ||
|
|
58be99a27e | ||
|
|
ae06879193 | ||
|
|
f121773276 | ||
|
|
4726bcd210 | ||
|
|
891942494f | ||
|
|
0b8e8bff16 | ||
|
|
898e87aa7b | ||
|
|
d153794c05 | ||
|
|
742c60f37f | ||
|
|
81143e0c7e | ||
|
|
7f610f3b4e | ||
|
|
4ba17df570 | ||
|
|
00a73e4d12 | ||
|
|
6501ee45b6 | ||
|
|
b0bee2f1f3 | ||
|
|
5a044c0320 | ||
|
|
6a2f964123 | ||
|
|
0518cabef6 | ||
|
|
7d7d82a68d | ||
|
|
0c4bb6a0d6 | ||
|
|
f25d2ea540 | ||
|
|
38a5e76c50 | ||
|
|
d873d11202 | ||
|
|
729395c887 | ||
|
|
5007a82ea6 | ||
|
|
83e114d211 | ||
|
|
0d92ea72e1 | ||
|
|
646e8dab0a | ||
|
|
8fc9f97c12 | ||
|
|
3643a78b18 | ||
|
|
8431eef970 | ||
|
|
e8798b5bf2 | ||
|
|
9bef53459f | ||
|
|
c2f008672c | ||
|
|
216a66ec4c | ||
|
|
c1a1b06fe7 | ||
|
|
802524a17a | ||
|
|
ea4edaaddd | ||
|
|
7941ac1810 | ||
|
|
de6967df0d | ||
|
|
ceef207812 | ||
|
|
7ed272e971 | ||
|
|
6362499fc2 | ||
|
|
ff528604dd | ||
|
|
505ae90fd7 | ||
|
|
1f9acf99b0 | ||
|
|
5392ceea7d | ||
|
|
ba1883c1de | ||
|
|
3a81b186b0 | ||
|
|
204b6fa3e8 | ||
|
|
f3c99546d7 | ||
|
|
f137ea7094 | ||
|
|
88df0890ae | ||
|
|
aaf593d2df | ||
|
|
a614fe615f | ||
|
|
3cb74a25ba | ||
|
|
c0114d5e4e | ||
|
|
e90aaa8470 | ||
|
|
c762f6199b | ||
|
|
7119c04c81 | ||
|
|
18dde7b26c | ||
|
|
013fd31493 | ||
|
|
490310a9f1 | ||
|
|
d900811a7b | ||
|
|
b06a09c01a | ||
|
|
81f14edb49 | ||
|
|
d39ba72591 | ||
|
|
f04fbde6ca | ||
|
|
d9ff3bce72 | ||
|
|
21ed07d7ce | ||
|
|
6cbd1d1727 | ||
|
|
27701351e1 | ||
|
|
6370dccb1a | ||
|
|
cc77d06ec7 | ||
|
|
04a61d0e21 | ||
|
|
96f85b187e | ||
|
|
27a1f27e59 | ||
|
|
4098b33bb7 | ||
|
|
657d0c4e2d | ||
|
|
b0663c1a3c | ||
|
|
20ff9ff977 | ||
|
|
ed6049b4be | ||
|
|
76d6d5f94b | ||
|
|
d8629a2d5b | ||
|
|
0652fa1696 | ||
|
|
a5e6ab2bee | ||
|
|
b5d105186c | ||
|
|
e274b809e2 | ||
|
|
a2fdea1a98 | ||
|
|
855d91d9dd | ||
|
|
8a049039ef | ||
|
|
4bea6b7ad9 | ||
|
|
5b0e2311e9 | ||
|
|
25c6735a5f | ||
|
|
1356bcbb9a | ||
|
|
c841106902 | ||
|
|
91963095d0 | ||
|
|
692bdd3ad5 | ||
|
|
e6f758b986 | ||
|
|
89d5387a52 | ||
|
|
2b9034759a | ||
|
|
b4d824e165 | ||
|
|
39bc0cd8c5 | ||
|
|
a2b2e767c1 | ||
|
|
da2d334b7a | ||
|
|
05363ba501 | ||
|
|
e43a26d64c | ||
|
|
c5c8a18c99 | ||
|
|
2f5b110c41 | ||
|
|
2443d76ac3 | ||
|
|
8b54df31ef | ||
|
|
4e7b957cc7 | ||
|
|
b1424cc4c7 | ||
|
|
be7d0e2016 | ||
|
|
7e8d509fdd | ||
|
|
8672a29503 | ||
|
|
32a1886b31 | ||
|
|
70bfe8589f | ||
|
|
4f3d71d4ee | ||
|
|
0df0fd6a0b | ||
|
|
2b9198866a | ||
|
|
6350652009 | ||
|
|
d239db8492 | ||
|
|
bdb6723564 | ||
|
|
d6bf5aa011 | ||
|
|
b5c4fbb42b | ||
|
|
1276bd6f5d | ||
|
|
be6e41c400 | ||
|
|
a9e26952e9 | ||
|
|
348cdf5d5d | ||
|
|
a527cc88f3 | ||
|
|
17cfd98545 | ||
|
|
09c723380c | ||
|
|
ff35bd61a8 | ||
|
|
eb5fe234f4 | ||
|
|
113494b4c6 | ||
|
|
b7e8bd2faf | ||
|
|
aaf94b61ed | ||
|
|
9a1b85081e | ||
|
|
626847f2f5 | ||
|
|
6b8d38e4b9 | ||
|
|
227d21184a | ||
|
|
f947c2eecb | ||
|
|
6a42a510bf | ||
|
|
efc8b898f8 | ||
|
|
e8a1ada5bf | ||
|
|
73b6cc433b | ||
|
|
4f6084c9f2 | ||
|
|
6c9615df0d | ||
|
|
073c330800 | ||
|
|
e558880e8f | ||
|
|
d4e5bc4141 | ||
|
|
7f3c808e66 | ||
|
|
9322b210ff | ||
|
|
3d7e8e3e84 | ||
|
|
40d80c7833 | ||
|
|
e908484491 | ||
|
|
25913f77e0 | ||
|
|
66803e6873 | ||
|
|
40722f42d3 | ||
|
|
192b16e9ff | ||
|
|
02dc637ed0 | ||
|
|
2aa29f1873 | ||
|
|
199d5b34a4 | ||
|
|
48b98c583e | ||
|
|
090ee5b846 | ||
|
|
55db07c79f | ||
|
|
75e84a4519 | ||
|
|
e679fa9a1c | ||
|
|
6f0922d5e3 | ||
|
|
4663133871 | ||
|
|
3f8b2184a6 | ||
|
|
2f7e517b5b | ||
|
|
f2e8877032 | ||
|
|
555409ea73 | ||
|
|
30baf81858 | ||
|
|
76a591e7d1 | ||
|
|
57d16a02c0 | ||
|
|
5c55502946 | ||
|
|
ef7fa507fb | ||
|
|
1ceefde2d0 | ||
|
|
94eaaae4a6 | ||
|
|
3cce238b2b | ||
|
|
f9b52249d1 | ||
|
|
f396fe59ca | ||
|
|
b4b6968e07 | ||
|
|
747f7b076d | ||
|
|
3f9f5ae076 | ||
|
|
2058682d1f | ||
|
|
201ac973e3 | ||
|
|
df87c051bd | ||
|
|
f76077a45c | ||
|
|
836e9d98b4 | ||
|
|
d5088a3e5b | ||
|
|
3a344d86fe | ||
|
|
6a65f23f98 | ||
|
|
9e284442e8 | ||
|
|
135358423c | ||
|
|
31173245f8 | ||
|
|
ad5a276ddb | ||
|
|
4bc852e615 | ||
|
|
d4e493727e | ||
|
|
8d3ec7451b | ||
|
|
652e1084bc | ||
|
|
a9d31541c1 | ||
|
|
480645877a | ||
|
|
600bff73d6 | ||
|
|
1c9612bd55 | ||
|
|
259e01e879 | ||
|
|
240c9b5d8b | ||
|
|
689227dce4 | ||
|
|
a4e7985fb0 | ||
|
|
9bd231c4f9 | ||
|
|
7bf8b3c3c1 | ||
|
|
57a6d53a45 | ||
|
|
49aeae4aad | ||
|
|
664975b707 | ||
|
|
c3ab6ff780 | ||
|
|
6ad7260871 | ||
|
|
e8f72c90f3 | ||
|
|
75244b1416 | ||
|
|
952f0ad98c | ||
|
|
c726a15ed4 | ||
|
|
5d6af442c1 | ||
|
|
596a392e68 | ||
|
|
46bb482e96 | ||
|
|
e9bc64205e | ||
|
|
8f05f752af | ||
|
|
124a41643f | ||
|
|
138a37ccac | ||
|
|
e1650d5df7 | ||
|
|
3f615666df | ||
|
|
96a9d64bcb | ||
|
|
bd09e2ebf1 | ||
|
|
ad040271b9 | ||
|
|
ead73c8209 | ||
|
|
b032130a20 | ||
|
|
c5837d4577 | ||
|
|
1a8d9314fe | ||
|
|
9ccf9636ce | ||
|
|
e56042c41a | ||
|
|
72626279c2 | ||
|
|
acc43ce9dc | ||
|
|
c87dcdbe3c | ||
|
|
aec1612de2 | ||
|
|
7c488888a0 | ||
|
|
6d960e4130 | ||
|
|
3cbc20005b | ||
|
|
e2a8115328 | ||
|
|
28ae99ed37 | ||
|
|
e5898ad4b0 | ||
|
|
b722bc809c | ||
|
|
710d00674a | ||
|
|
9078ca975e | ||
|
|
4f98d10caa | ||
|
|
9e5dbb45d4 | ||
|
|
5e5065715e | ||
|
|
8be7679a38 | ||
|
|
6297c9a719 | ||
|
|
933621b038 | ||
|
|
c31e608ff9 | ||
|
|
671bcafee5 | ||
|
|
c01f009e42 | ||
|
|
dbd7ec5b27 | ||
|
|
898136dbdc | ||
|
|
ef91f9dc8f | ||
|
|
bfd7675639 | ||
|
|
b644d4620a | ||
|
|
03dd6e0490 | ||
|
|
dfca991173 | ||
|
|
13c4c605b3 | ||
|
|
8e5c4b6f7a | ||
|
|
d0d769f26b | ||
|
|
558b208edd | ||
|
|
35acb1497a | ||
|
|
8cd1f76d2b | ||
|
|
f0ee728b94 | ||
|
|
b4a96428f3 | ||
|
|
7d6d8efc26 | ||
|
|
f3ee3784f7 | ||
|
|
7da08d37d2 | ||
|
|
23c2bdb6f0 | ||
|
|
7736629bc4 | ||
|
|
204bd97198 | ||
|
|
2786976c63 | ||
|
|
7567f96a34 | ||
|
|
cf33ef8666 | ||
|
|
9860ed544f | ||
|
|
9601ed79f1 | ||
|
|
e5b5fb2773 | ||
|
|
01fb9436dd | ||
|
|
df1e06ec2c | ||
|
|
c973a7326e | ||
|
|
9facc5f7d3 | ||
|
|
66bce4b8cd | ||
|
|
c567acb4e5 | ||
|
|
8418cc04c1 | ||
|
|
e52818d54c | ||
|
|
15e03f74f4 | ||
|
|
56c2e0c26a | ||
|
|
83de392b39 | ||
|
|
3c89f80603 | ||
|
|
8e64895c23 | ||
|
|
967e65e150 | ||
|
|
9f5d731d8d | ||
|
|
ef312a3d1c | ||
|
|
705298737a | ||
|
|
a7b95f73be | ||
|
|
a9ed44eecc | ||
|
|
b8d9629ee4 | ||
|
|
5b24d51fcd | ||
|
|
e832524bfc | ||
|
|
a783325464 | ||
|
|
af99c172fe | ||
|
|
b5b9a7ba6d | ||
|
|
2909fddaa2 | ||
|
|
7863857b2c | ||
|
|
b28cec3236 | ||
|
|
55498b5a44 | ||
|
|
8d03d7216f | ||
|
|
7ddaa70498 | ||
|
|
150ffab72d | ||
|
|
cda385b37c | ||
|
|
28146a4e9c | ||
|
|
0ad9149ca8 | ||
|
|
f9972bc33c | ||
|
|
e6cff1e9b6 | ||
|
|
c64527c333 | ||
|
|
9cfc19e010 | ||
|
|
af971af4ca | ||
|
|
3471887817 | ||
|
|
cd88505ca7 | ||
|
|
3ca45ab241 | ||
|
|
564f19d248 | ||
|
|
5622efb710 | ||
|
|
a857a35348 | ||
|
|
93ca469d85 | ||
|
|
1e01c2a07c | ||
|
|
efaee69486 | ||
|
|
558e4af3c6 | ||
|
|
8490457cab | ||
|
|
6585c11808 | ||
|
|
142cba54b3 | ||
|
|
19b065b6a4 | ||
|
|
826a64c8dc | ||
|
|
14103db2ee | ||
|
|
51d037fb70 | ||
|
|
b433380e1d | ||
|
|
df4df76d24 | ||
|
|
2d0c6a43c5 | ||
|
|
0307497e06 | ||
|
|
bc1de92534 | ||
|
|
37feb65204 | ||
|
|
9cd146fe3e | ||
|
|
7b1576d960 | ||
|
|
6361da9e0b | ||
|
|
50a1bf528c | ||
|
|
2ddbac073a | ||
|
|
33f48e8268 | ||
|
|
ee581ebdf4 | ||
|
|
81879db2db | ||
|
|
3675c27268 | ||
|
|
a92b3c605f | ||
|
|
85ed5c1515 | ||
|
|
b7a5c064c2 | ||
|
|
34084e7ab5 | ||
|
|
728f33700a | ||
|
|
43ebddc28f | ||
|
|
c5e989bc94 | ||
|
|
a4d71bcf5c | ||
|
|
ddbe0703a3 | ||
|
|
b2c7272af1 | ||
|
|
0423c55dc1 | ||
|
|
0b656246fd | ||
|
|
28430a4104 | ||
|
|
f0a9f32d0a | ||
|
|
44c897a61a | ||
|
|
b5af266b87 | ||
|
|
9989363ecd | ||
|
|
53ea5c678d | ||
|
|
464291bbb1 | ||
|
|
ed3427f349 | ||
|
|
21accfe114 | ||
|
|
ee0a539e01 | ||
|
|
d236955dfb | ||
|
|
32a11d9d21 | ||
|
|
43c4c71abd | ||
|
|
b9ac13c379 | ||
|
|
11bb21e8a4 | ||
|
|
4bfe7e1069 | ||
|
|
4feaf13556 | ||
|
|
a27004da35 | ||
|
|
cf6894d74f | ||
|
|
a921180224 | ||
|
|
7e4948be10 | ||
|
|
04a45babfb | ||
|
|
1c1d0a4e91 | ||
|
|
271b623f82 | ||
|
|
88d896e745 | ||
|
|
745b6222c2 | ||
|
|
42329e5d46 | ||
|
|
240c683504 | ||
|
|
c683725434 | ||
|
|
f3cd0a4966 | ||
|
|
573dd8c99e | ||
|
|
6d8b59cb61 | ||
|
|
c41ede4d20 | ||
|
|
13ac050bf8 | ||
|
|
6e4b977128 | ||
|
|
e6df82b255 | ||
|
|
943a1575ad | ||
|
|
2e0cbb88bb | ||
|
|
8e379df24f | ||
|
|
ccf5391b45 | ||
|
|
ca5eb4feb5 | ||
|
|
c1cb4df9d2 | ||
|
|
367ffb602c | ||
|
|
4e8ade53d8 | ||
|
|
bc8a8d83fc | ||
|
|
7f6befe4f9 | ||
|
|
86893db46b | ||
|
|
3c3eeb1835 | ||
|
|
3a883ad436 | ||
|
|
cc8271b766 | ||
|
|
1246032b67 | ||
|
|
9eea178890 | ||
|
|
44f456089b | ||
|
|
2fff6e1cb9 | ||
|
|
ff6c366b8a | ||
|
|
6701d52e26 | ||
|
|
11e147c718 | ||
|
|
634cd53454 | ||
|
|
084f31292b | ||
|
|
1e37041b50 | ||
|
|
2a24199c90 | ||
|
|
5905216f96 | ||
|
|
3ddf963c5c | ||
|
|
778c3c075a | ||
|
|
d2b3052918 | ||
|
|
8ce2794a8a | ||
|
|
c1dc4d0575 | ||
|
|
9c184c794a | ||
|
|
d3f2620caf | ||
|
|
a1c9c90fc8 | ||
|
|
83f4b6e391 | ||
|
|
cc9ed734cf | ||
|
|
98daddc39a | ||
|
|
408c719c5f | ||
|
|
5caea75115 | ||
|
|
19bd068599 | ||
|
|
2490199e52 | ||
|
|
726a6370ad | ||
|
|
00b8db26fc | ||
|
|
544c402c9f | ||
|
|
9bea1001f9 | ||
|
|
63882e1fdc | ||
|
|
5103381c27 | ||
|
|
56e55ddbc3 | ||
|
|
a261e1f57d | ||
|
|
5ceec08d32 | ||
|
|
92d53daf22 | ||
|
|
99acc4adcb | ||
|
|
827d086c54 | ||
|
|
fb820faf11 | ||
|
|
0aecae288f | ||
|
|
3274327fe7 | ||
|
|
f97127f587 | ||
|
|
b8c34c3ee2 | ||
|
|
4ae3abb3cb | ||
|
|
5c1747b2c8 | ||
|
|
2611678855 | ||
|
|
746a20a11d | ||
|
|
3072eac222 | ||
|
|
a4580f2126 | ||
|
|
4a27793651 | ||
|
|
5ed4b29e4b | ||
|
|
b8678871df | ||
|
|
457bf8c289 | ||
|
|
dd8be35922 | ||
|
|
b4d1cfea50 | ||
|
|
7113d5c293 | ||
|
|
bc97cfa024 | ||
|
|
382daacb73 | ||
|
|
aa526db772 | ||
|
|
1f9510ab9e | ||
|
|
b8acb9b133 | ||
|
|
51231b7eb2 | ||
|
|
029ff84f09 | ||
|
|
f5dbe36cf3 | ||
|
|
906937149e | ||
|
|
f324d8ec4f | ||
|
|
2089d2bfdf | ||
|
|
281cb50780 | ||
|
|
012b209a56 | ||
|
|
c0593d9f1f | ||
|
|
f655112bda | ||
|
|
c4680aae2c | ||
|
|
a8d5ad2c1a | ||
|
|
333eb3534a | ||
|
|
1a42356f68 | ||
|
|
1197549e5b | ||
|
|
d2749f5ccc | ||
|
|
6379b3f898 | ||
|
|
c97afd7b44 | ||
|
|
9b9003ded0 | ||
|
|
5550c7a95f | ||
|
|
fe7f3233ba | ||
|
|
a52f0939df | ||
|
|
ff3ddfd369 | ||
|
|
161161f840 | ||
|
|
b0e1c74fdd | ||
|
|
1bd46b0636 | ||
|
|
5e676090fa | ||
|
|
4d31624a69 | ||
|
|
c9695efd18 | ||
|
|
7dc51d7d9e | ||
|
|
d5d812ccfe | ||
|
|
af02b735e7 | ||
|
|
52ab534e22 | ||
|
|
895eedeb9b | ||
|
|
5972a37550 | ||
|
|
079054f798 | ||
|
|
914f7ddbd5 | ||
|
|
5357876128 | ||
|
|
b20367b888 | ||
|
|
6698712b44 | ||
|
|
21b799905d | ||
|
|
02870d7221 | ||
|
|
d4991424f9 | ||
|
|
1684bda1e9 | ||
|
|
e8b5a72c96 | ||
|
|
7f180ad3d9 | ||
|
|
94c4c00859 | ||
|
|
1308bbac2d | ||
|
|
76890a2b71 | ||
|
|
2c8f3b6d98 | ||
|
|
0e46994d0a | ||
|
|
44650c5723 | ||
|
|
234bb07b67 | ||
|
|
fea79878fa | ||
|
|
0365828a5b | ||
|
|
fa30a95b46 | ||
|
|
f44d56b116 | ||
|
|
6127d2d122 | ||
|
|
4feff2e2da | ||
|
|
8624dbac2c | ||
|
|
4c0cf93562 | ||
|
|
d12573a67d | ||
|
|
d7b433f6b7 | ||
|
|
b1168f6c6c | ||
|
|
91e263cabb | ||
|
|
ed15f2f97e | ||
|
|
6689595277 | ||
|
|
34f946fd98 | ||
|
|
a5bec84554 | ||
|
|
0fae3e1b10 | ||
|
|
a56e1296fd | ||
|
|
acdeaaeda5 | ||
|
|
a44e3a3a50 | ||
|
|
db40445572 | ||
|
|
1d888c9194 | ||
|
|
b50eaa9cbb | ||
|
|
fe764ab6b6 | ||
|
|
bab4680828 | ||
|
|
564010c7cd | ||
|
|
052fd46ff9 | ||
|
|
4fd8c7cfaa | ||
|
|
37f0cf86d0 | ||
|
|
0cbd3a2820 | ||
|
|
af3c89d79f | ||
|
|
a1d75eb00d | ||
|
|
6176607ac4 | ||
|
|
40254625d9 | ||
|
|
29b16d0856 | ||
|
|
ff72b1f96f | ||
|
|
a429bcbb22 | ||
|
|
3c7305b93c | ||
|
|
f9b1a71edd | ||
|
|
2de0c82f18 | ||
|
|
cdb12f2049 | ||
|
|
ca310fc2f2 | ||
|
|
273210cb97 | ||
|
|
b957ef441c | ||
|
|
31775c8b50 | ||
|
|
8199802b44 | ||
|
|
941c553172 | ||
|
|
8ee1c851a1 | ||
|
|
4ce9f550ac | ||
|
|
7041616837 | ||
|
|
6a3c812470 | ||
|
|
778b090467 | ||
|
|
a922b4c789 | ||
|
|
e43bf891e4 | ||
|
|
fa8203ff31 | ||
|
|
212207d667 | ||
|
|
95a3c51a4b | ||
|
|
697a7b78b3 | ||
|
|
58644e2b37 | ||
|
|
ddcd4daede | ||
|
|
678bd97e1f | ||
|
|
2eb4bf7a1d | ||
|
|
e0e517d6ec | ||
|
|
b6679ff7b5 | ||
|
|
de80003103 | ||
|
|
2b0596c7f9 | ||
|
|
3d15a1d786 | ||
|
|
1fcb865202 | ||
|
|
1c56de5605 | ||
|
|
adbce71fb4 | ||
|
|
00e3ea8c08 | ||
|
|
36432c8616 | ||
|
|
03e0b9de04 | ||
|
|
4364163ceb | ||
|
|
ffd9ec653d | ||
|
|
ee3c3e4cb4 | ||
|
|
277c46908d | ||
|
|
8e27c80e1f | ||
|
|
afa767c3a8 | ||
|
|
67ec04fba3 | ||
|
|
f35bf7f1ba | ||
|
|
4fdb55e260 | ||
|
|
be06669e8f | ||
|
|
313253cd95 | ||
|
|
8c16be2ccd | ||
|
|
e1b276786b | ||
|
|
05f5a05c20 | ||
|
|
7e79aac275 | ||
|
|
0a21819e16 | ||
|
|
fe3e51a00d | ||
|
|
21874339f1 | ||
|
|
4f22fcdaac | ||
|
|
0424d665d5 | ||
|
|
0bbea6812e | ||
|
|
101a50b0ff | ||
|
|
a9f3a698d2 | ||
|
|
5117a2c17a | ||
|
|
ebce1d7c61 | ||
|
|
e4668c1aff | ||
|
|
2519c49c02 | ||
|
|
9e512ff58a | ||
|
|
ed50595aca | ||
|
|
9d62d087e0 | ||
|
|
6b933e33f5 | ||
|
|
a86931f401 | ||
|
|
fc4e1595e8 | ||
|
|
b36c3f3425 | ||
|
|
e427fd1233 | ||
|
|
dd3af45043 | ||
|
|
304d42d4c2 | ||
|
|
abca9280e7 | ||
|
|
9a103f3979 | ||
|
|
270dde7020 | ||
|
|
11de18e737 | ||
|
|
62db44c71e | ||
|
|
3d5c65eaea | ||
|
|
ea298f95f2 | ||
|
|
2f21e0e341 | ||
|
|
ae62d36a4a | ||
|
|
76e3101d9b | ||
|
|
c3442545a8 | ||
|
|
3a9b0faa06 | ||
|
|
4989b1f8bb | ||
|
|
348fe4ada4 | ||
|
|
bbc6b2d86a | ||
|
|
b4d4ed718f | ||
|
|
836724709e | ||
|
|
96d2567815 | ||
|
|
419f43ceed | ||
|
|
47851ebb1b | ||
|
|
24a4fbd987 | ||
|
|
8047743882 | ||
|
|
e9b5963610 | ||
|
|
a1d4630a25 | ||
|
|
fafd710ce3 | ||
|
|
a79bb3add2 | ||
|
|
b3a718b1e4 | ||
|
|
952aa7ad4a | ||
|
|
149d606154 | ||
|
|
ad21c7ed0f | ||
|
|
38d2839206 | ||
|
|
24d0bb8bd5 | ||
|
|
08f336769f | ||
|
|
5525d4db49 | ||
|
|
448ba26257 | ||
|
|
1d1138ca31 | ||
|
|
357a415386 | ||
|
|
a65856ec98 | ||
|
|
83855e16ce | ||
|
|
ccf66fc621 | ||
|
|
c27b597951 | ||
|
|
85dbae1de4 | ||
|
|
cd1ba334c1 | ||
|
|
1cff4f9d29 | ||
|
|
d180601711 | ||
|
|
01d0e7474f |
13
.gitattributes
vendored
Normal file
13
.gitattributes
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
kitty/wcwidth-std.h linguist-generated=true
|
||||
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/rgb.py linguist-generated=true
|
||||
kitty/gl-wrapper.* linguist-generated=true
|
||||
kitty/khrplatform.h linguist-generated=true
|
||||
kitty/glfw-wrapper.* linguist-generated=true
|
||||
glfw/*.c linguist-vendored=true
|
||||
glfw/*.h linguist-vendored=true
|
||||
kittens/unicode_input/names.h linguist-generated=true
|
||||
19
.gitignore
vendored
19
.gitignore
vendored
@@ -1,10 +1,19 @@
|
||||
*.js
|
||||
*.pyj-cached
|
||||
*.so
|
||||
.build-cache
|
||||
*.pyc
|
||||
*.pyo
|
||||
tags
|
||||
build
|
||||
README.html
|
||||
linux-package
|
||||
kitty.app
|
||||
logo/*.iconset
|
||||
test-launcher
|
||||
compile_commands.json
|
||||
glad/out
|
||||
asan-launcher
|
||||
asan-launcher.dSYM
|
||||
kitty-profile
|
||||
dev
|
||||
__pycache__
|
||||
glfw/wayland-*-client-protocol.[ch]
|
||||
docs/_build
|
||||
docs/generated
|
||||
.DS_Store
|
||||
|
||||
118
.travis.yml
118
.travis.yml
@@ -1,23 +1,45 @@
|
||||
git:
|
||||
depth: false
|
||||
matrix:
|
||||
fast_finish: true
|
||||
include:
|
||||
- os: linux
|
||||
dist: trusty
|
||||
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:
|
||||
- libxi-dev
|
||||
- libxrandr-dev
|
||||
- libxinerama-dev
|
||||
- libxcursor-dev
|
||||
- libxcb-xkb-dev
|
||||
- libdbus-1-dev
|
||||
|
||||
- os: linux
|
||||
dist: trusty
|
||||
group: beta
|
||||
sudo: false
|
||||
env:
|
||||
- CC=gcc SANITIZE_ARG=--sanitize
|
||||
- CC=gcc CFLAGS=-funsigned-char SANITIZE_ARG=--sanitize
|
||||
language: python
|
||||
python: "3.5"
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- libfontconfig1-dev
|
||||
- libglew-dev
|
||||
- libharfbuzz-dev
|
||||
- libxi-dev
|
||||
- libxrandr-dev
|
||||
- libxinerama-dev
|
||||
- libxcursor-dev
|
||||
- libxcb-xkb-dev
|
||||
- libpng-dev
|
||||
- libdbus-1-dev
|
||||
- python3-pil
|
||||
|
||||
- os: linux
|
||||
dist: trusty
|
||||
@@ -31,43 +53,52 @@ matrix:
|
||||
apt:
|
||||
packages:
|
||||
- libfontconfig1-dev
|
||||
- libglew-dev
|
||||
- libharfbuzz-dev
|
||||
- libxi-dev
|
||||
- libxrandr-dev
|
||||
- libxinerama-dev
|
||||
- libxcursor-dev
|
||||
- libxcb-xkb-dev
|
||||
- libpng-dev
|
||||
- libdbus-1-dev
|
||||
- python3-pil
|
||||
|
||||
- os: linux
|
||||
dist: trusty
|
||||
group: beta
|
||||
sudo: false
|
||||
env:
|
||||
- RUN_FLAKE=1 BUILD_PKG=1
|
||||
- RUN_FLAKE=1 BUILD_PKG=linux-package
|
||||
language: python
|
||||
python: "3.5"
|
||||
python: "3.6"
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- libfontconfig1-dev
|
||||
- libglew-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
|
||||
env: USE_BREW=1 BUILD_PKG=1
|
||||
# Disabled because harfbuzz is currently broken in brew
|
||||
# - os: osx
|
||||
# language: generic
|
||||
# env: USE_BREW=1 BUILD_PKG=osx-bundle
|
||||
|
||||
env:
|
||||
global:
|
||||
- PYTHON=python3
|
||||
- PKG_CONFIG_PATH=$HOME/glfw/lib/pkgconfig:$PKG_CONFIG_PATH
|
||||
- LD_LIBRARY_PATH=$HOME/glfw/lib:$LD_LIBRARY_PATH
|
||||
- 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: |
|
||||
@@ -76,22 +107,44 @@ install: |
|
||||
if [[ "$TRAVIS_OS_NAME" == 'osx' ]]; then
|
||||
if [[ "$USE_BREW" == "1" ]]; then
|
||||
brew update;
|
||||
brew install python3;
|
||||
brew install glfw;
|
||||
# brew upgrade python;
|
||||
brew install harfbuzz --without-graphite2 --without-icu4c --without-freetype;
|
||||
brew install imagemagick
|
||||
brew install optipng
|
||||
brew install librsvg
|
||||
logo/make.py
|
||||
else
|
||||
mkdir -p $SW;
|
||||
curl https://download.calibre-ebook.com/travis/kitty/osx.tar.xz | tar xJ -C $SW;
|
||||
fi
|
||||
else
|
||||
wget -O glfw-3.2.1.zip https://github.com/glfw/glfw/archive/3.2.1.zip
|
||||
unzip -q glfw-3.2.1.zip
|
||||
cd glfw-3.2.1
|
||||
cmake -DBUILD_SHARED_LIBS=ON -DGLFW_BUILD_EXAMPLES=OFF -DGLFW_BUILD_TESTS=OFF -DGLFW_BUILD_DOCS=OFF -DCMAKE_INSTALL_PREFIX=$HOME/glfw
|
||||
make
|
||||
make install
|
||||
cd ..
|
||||
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 glfw3
|
||||
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`
|
||||
@@ -99,11 +152,20 @@ install: |
|
||||
set +e
|
||||
|
||||
before_script:
|
||||
- echo $LD_LIBRARY_PATH
|
||||
- $PYTHON setup.py build --debug $SANITIZE_ARG;
|
||||
- if [[ "$TRAVIS_OS_NAME" != 'osx' ]]; then ldd ./test-launcher `which $PYTHON`; fi
|
||||
- echo LD_LIBRARY_PATH=$LD_LIBRARY_PATH PKG_CONFIG_PATH=$PKG_CONFIG_PATH
|
||||
- $PYTHON setup.py build --debug --verbose $SANITIZE_ARG;
|
||||
|
||||
script:
|
||||
- ./test-launcher
|
||||
- if [[ "$RUN_FLAKE" == "1" ]]; then flake8 --count .; fi
|
||||
- if [[ "$BUILD_PKG" == "1" ]]; then $PYTHON setup.py linux-package; fi
|
||||
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
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
# vim:fileencoding=utf-8
|
||||
# License: GPL v3 Copyright: %YEAR%, %USER% <%MAIL%>
|
||||
|
||||
%HERE%
|
||||
1
CHANGELOG.rst
Normal file
1
CHANGELOG.rst
Normal file
@@ -0,0 +1 @@
|
||||
See https://sw.kovidgoyal.net/kitty/changelog.html
|
||||
25
CONTRIBUTING.md
Normal file
25
CONTRIBUTING.md
Normal file
@@ -0,0 +1,25 @@
|
||||
### Reporting bugs
|
||||
|
||||
Please first search existing bug reports (especially closed ones) for a report
|
||||
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
|
||||
config to reproduce the issue with).
|
||||
|
||||
|
||||
### Contributing code
|
||||
|
||||
Install [the dependencies](https://sw.kovidgoyal.net/kitty/build.html#dependencies)
|
||||
using your favorite package manager. Build and run kitty [from
|
||||
source](https://sw.kovidgoyal.net/kitty/build.html#install-and-run-from-source).
|
||||
|
||||
Make a fork, submit your Pull Request. If it's a large/controversial change, open an issue
|
||||
beforehand to discuss it, so that you don't waste your time making a pull
|
||||
request that gets rejected.
|
||||
|
||||
If the code you are submitting is reasonably easily testable, please contribute
|
||||
tests as well (see the `kitty_tests/` sub-directory for existing tests, which
|
||||
can be run with `./test.py`).
|
||||
|
||||
That's it.
|
||||
7
INSTALL.md
Normal file
7
INSTALL.md
Normal file
@@ -0,0 +1,7 @@
|
||||
To build from source:
|
||||
|
||||
https://sw.kovidgoyal.net/kitty/build.html
|
||||
|
||||
Pre-built binaries:
|
||||
|
||||
https://sw.kovidgoyal.net/kitty/binary.html
|
||||
44
Makefile
44
Makefile
@@ -1,5 +1,45 @@
|
||||
ifdef V
|
||||
VVAL=--verbose
|
||||
endif
|
||||
ifdef VERBOSE
|
||||
VVAL=--verbose
|
||||
endif
|
||||
|
||||
all:
|
||||
python3 setup.py
|
||||
python3 setup.py $(VVAL)
|
||||
|
||||
test:
|
||||
python3 setup.py test
|
||||
python3 setup.py $(VVAL) test
|
||||
|
||||
clean:
|
||||
python3 setup.py $(VVAL) clean
|
||||
|
||||
# A debug build
|
||||
debug:
|
||||
python3 setup.py build $(VVAL) --debug
|
||||
|
||||
# Build with the ASAN and UBSAN sanitizers
|
||||
asan:
|
||||
python3 setup.py build $(VVAL) --debug --sanitize
|
||||
|
||||
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
|
||||
python3 setup.py kitty.app $(VVAL)
|
||||
|
||||
man:
|
||||
$(MAKE) FAIL_WARN=$(FAIL_WARN) -C docs man
|
||||
|
||||
html:
|
||||
$(MAKE) FAIL_WARN=$(FAIL_WARN) -C docs html
|
||||
|
||||
linkcheck:
|
||||
$(MAKE) FAIL_WARN=$(FAIL_WARN) -C docs linkcheck
|
||||
|
||||
docs: man html
|
||||
|
||||
327
README.asciidoc
327
README.asciidoc
@@ -1,326 +1,5 @@
|
||||
= kitty - A terminal emulator
|
||||
:toc:
|
||||
:toc-placement!:
|
||||
// START_SHORTCUT_BLOCK
|
||||
:sc_close_tab: pass:quotes[`ctrl+shift+q`]
|
||||
:sc_close_window: pass:quotes[`ctrl+shift+w`]
|
||||
:sc_copy_to_clipboard: pass:quotes[`ctrl+shift+c`]
|
||||
:sc_eighth_window: pass:quotes[`ctrl+shift+8`]
|
||||
:sc_fifth_window: pass:quotes[`ctrl+shift+5`]
|
||||
:sc_first_window: pass:quotes[`ctrl+shift+1`]
|
||||
:sc_fourth_window: pass:quotes[`ctrl+shift+4`]
|
||||
:sc_move_tab_backward: pass:quotes[`ctrl+shift+,`]
|
||||
:sc_move_tab_forward: pass:quotes[`ctrl+shift+.`]
|
||||
:sc_move_window_backward: pass:quotes[`ctrl+shift+b`]
|
||||
:sc_move_window_forward: pass:quotes[`ctrl+shift+f`]
|
||||
:sc_move_window_to_top: pass:quotes[`ctrl+shift+``]
|
||||
:sc_new_tab: pass:quotes[`ctrl+shift+t`]
|
||||
:sc_new_window: pass:quotes[`ctrl+shift+enter`]
|
||||
:sc_next_layout: pass:quotes[`ctrl+shift+l`]
|
||||
:sc_next_tab: pass:quotes[`ctrl+shift+right`]
|
||||
:sc_next_window: pass:quotes[`ctrl+shift+]`]
|
||||
:sc_ninth_window: pass:quotes[`ctrl+shift+9`]
|
||||
:sc_paste_from_clipboard: pass:quotes[`ctrl+shift+v`]
|
||||
:sc_paste_from_selection: pass:quotes[`ctrl+shift+s` or `shift+insert`]
|
||||
:sc_previous_tab: pass:quotes[`ctrl+shift+left`]
|
||||
:sc_previous_window: pass:quotes[`ctrl+shift+[`]
|
||||
:sc_scroll_end: pass:quotes[`ctrl+shift+end`]
|
||||
:sc_scroll_home: pass:quotes[`ctrl+shift+home`]
|
||||
:sc_scroll_line_down: pass:quotes[`ctrl+shift+down` or `ctrl+shift+j`]
|
||||
:sc_scroll_line_up: pass:quotes[`ctrl+shift+up` or `ctrl+shift+k`]
|
||||
:sc_scroll_page_down: pass:quotes[`ctrl+shift+page_down`]
|
||||
:sc_scroll_page_up: pass:quotes[`ctrl+shift+page_up`]
|
||||
:sc_second_window: pass:quotes[`ctrl+shift+2`]
|
||||
:sc_seventh_window: pass:quotes[`ctrl+shift+7`]
|
||||
:sc_show_scrollback: pass:quotes[`ctrl+shift+h`]
|
||||
:sc_sixth_window: pass:quotes[`ctrl+shift+6`]
|
||||
:sc_tenth_window: pass:quotes[`ctrl+shift+0`]
|
||||
:sc_third_window: pass:quotes[`ctrl+shift+3`]
|
||||
// END_SHORTCUT_BLOCK
|
||||
= kitty - the fast, featureful, GPU based, terminal emulator
|
||||
|
||||
See https://sw.kovidgoyal.net/kitty
|
||||
|
||||
++++
|
||||
<img align="left" role="left" src="logo/kitty.png?raw=true"/>
|
||||
++++
|
||||
image::https://travis-ci.org/kovidgoyal/kitty.svg?branch=master[Build status, link=https://travis-ci.org/kovidgoyal/kitty]
|
||||
|
||||
== Major Features
|
||||
|
||||
* Supports tiling multiple terminal windows side by side in different
|
||||
layouts without needing to use an extra program like tmux
|
||||
|
||||
* Supports all modern terminal features: unicode, true-color, mouse
|
||||
protocol, focus tracking, bracketed paste and so on.
|
||||
|
||||
* Allows you to view the scrollback buffer in a separate window
|
||||
using your favorite pager program such as less
|
||||
|
||||
* Support startup sessions which allow you to specify the window/tab layout,
|
||||
working directories and programs to run on startup.
|
||||
|
||||
* Easily hackable (UI layer written in python, inner loops in C for
|
||||
speed). Less than ten thousand lines of code.
|
||||
|
||||
* Uses OpenGL for rendering, offloads rendering work to the GPU for lower system load.
|
||||
|
||||
* Cross-platform support: kitty currently works on Linux and macOS, but because it
|
||||
uses only OpenGL for rendering, it should be trivial to port to
|
||||
other platforms.
|
||||
|
||||
image::screenshot.png?raw=true[Screenshot, showing three programs in the "Tall" layout]
|
||||
|
||||
toc::[]
|
||||
|
||||
|
||||
== Installation
|
||||
|
||||
kitty is designed to run from source, for easy hackability. Make sure
|
||||
the following dependencies are installed first.
|
||||
|
||||
=== Dependencies
|
||||
|
||||
* python >= 3.5
|
||||
* glfw >= 3.2
|
||||
* glew >= 2.0 (not needed on macOS)
|
||||
* fontconfig (not needed on macOS)
|
||||
* xdpyinfo and xsel (only on X11 based systems)
|
||||
* gcc or clang (required only for building)
|
||||
* pkg-config (required only for building)
|
||||
|
||||
=== Install and run from source
|
||||
|
||||
....
|
||||
git clone https://github.com/kovidgoyal/kitty && cd kitty
|
||||
....
|
||||
|
||||
Now build the C parts of kitty with the following command:
|
||||
|
||||
....
|
||||
python3 setup.py build
|
||||
....
|
||||
|
||||
You can run kitty, as:
|
||||
|
||||
....
|
||||
python3 /path/to/kitty/folder
|
||||
....
|
||||
|
||||
=== Linux packages
|
||||
|
||||
* Arch linux: AUR git package https://aur.archlinux.org/packages/kitty-git/
|
||||
|
||||
|
||||
=== macOS packages
|
||||
|
||||
kitty is available as a macOS `dmg` file for easy installation from the
|
||||
link:../../releases[releases page]. You can also run kitty directly from
|
||||
source using the above install from source instructions, after installing its
|
||||
two dependencies (`python >= 3.5` and `glfw >= 3.2` using http://brew.sh/[brew]
|
||||
or a similar package manager)
|
||||
|
||||
|
||||
== Design philosophy
|
||||
|
||||
kitty is designed for power keyboard users. To that end all its controls
|
||||
work with the keyboard (although it fully supports mouse interactions as
|
||||
well). Its configuration is a simple, human editable, single file for
|
||||
easy reproducability (I like to store config files in source control).
|
||||
|
||||
The code in kitty is designed to be simple, modular and hackable. It is
|
||||
written in a mix of C (for performance sensitive parts) and Python (for
|
||||
easy hackability of the UI). It does not depend on any large and complex
|
||||
UI toolkit, using only OpenGL for rendering everything.
|
||||
|
||||
Finally, kitty is designed from the ground up to support all modern
|
||||
terminal features, such as unicode, true color, bold/italic fonts, text
|
||||
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.
|
||||
|
||||
== Tabs and Windows
|
||||
|
||||
kitty is capable of running multiple programs organized into tabs and
|
||||
windows. The top level of organization is the _Tab_. Each tab consists
|
||||
of one or more _windows_. The windows can be arranged in multiple
|
||||
different layouts, like windows are organized in a tiling window
|
||||
manager. The keyboard controls (which are all customizable) for tabs and
|
||||
windows are:
|
||||
|
||||
[[scrolling-shortcuts]]
|
||||
[options="header"]
|
||||
|
||||
=== 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}
|
||||
|
||||
|===
|
||||
|
||||
[options="header"]
|
||||
|
||||
=== Tabs
|
||||
|
||||
|===
|
||||
|Action |Shortcut
|
||||
|
||||
|New tab | {sc_new_tab}
|
||||
|Close tab | {sc_close_tab}
|
||||
|Next tab | {sc_next_tab}
|
||||
|Previous tab | {sc_previous_tab}
|
||||
|Next layout | {sc_next_layout}
|
||||
|Move tab forward | {sc_move_tab_forward}
|
||||
|Move tab backward | {sc_move_tab_backward}
|
||||
|
||||
|===
|
||||
|
||||
|
||||
[options="header"]
|
||||
|
||||
=== Windows
|
||||
|
||||
|===
|
||||
|Action |Shortcut
|
||||
|
||||
|New window | {sc_new_window}
|
||||
|Close window | {sc_close_window}
|
||||
|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 (windows are counted clockwise from the top left corner) | {sc_first_window}, {sc_second_window} ... {sc_tenth_window}
|
||||
|
||||
|===
|
||||
|
||||
|
||||
== The scrollback buffer
|
||||
|
||||
kitty supports scrolling back to view history, just like most terminals. You
|
||||
can use either the <<scrolling-shortcuts,keyboard shortcuts>> or the mouse
|
||||
scroll wheel to do so. However, kitty has an extra, neat feature. Sometimes you
|
||||
need to explore the scrollback buffer in more detail, maybe search for some
|
||||
text or refer to it side-by-side while typing in a follow-up command. kitty
|
||||
allows you to do this by pressing the {sc_show_scrollback} key-combination,
|
||||
which will open the scrollback buffer in a new window, using your favorite
|
||||
pager program (which is `less` by default). You can then explore the scrollback
|
||||
buffer using whatever program you normally use. Colors and text formatting are
|
||||
preserved.
|
||||
|
||||
|
||||
== Miscellaneous features
|
||||
|
||||
You can double click to select a word and triple click to select a line. You can also
|
||||
hold down `ctrl+shift` and click on a URL to open it in a browser.
|
||||
|
||||
|
||||
== Layouts
|
||||
|
||||
Currently, there are two 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.
|
||||
|
||||
You can switch between layouts using the {sc_next_layout} key combination.
|
||||
|
||||
Writing a new layout only requires about thirty lines of code, so if there is
|
||||
some layout you want, take a look at link:kitty/layout.py[layout.py] and submit
|
||||
a pull request!
|
||||
|
||||
|
||||
== Configuration
|
||||
|
||||
kitty is highly customizable, everything from keyboard shortcuts, to
|
||||
painting frames-per-second. See the heavily commented
|
||||
link:kitty/kitty.conf[default config file]. By default kitty looks for a
|
||||
config file in the OS config directory (usually
|
||||
`~/.config/kitty/kitty.conf` on Linux and
|
||||
`~/Library/Preferences/kitty/kitty.conf` on macOS) but you can pass a specific
|
||||
path via the `--config` option.
|
||||
|
||||
== Startup Sessions
|
||||
|
||||
You can control the tabs, window layout, working directory, startup
|
||||
programs, etc. by creating a "session" file and using the `--session`
|
||||
command line flag. For example:
|
||||
|
||||
....
|
||||
# Set the window layout for the current tab
|
||||
layout tall
|
||||
# Set the working directory for the current tab
|
||||
cd ~
|
||||
# Create a window and run the specified command in it
|
||||
launch zsh
|
||||
launch vim
|
||||
launch irssi --profile x
|
||||
|
||||
# Create a new tab (the part after new_tab is the optional tab name which will
|
||||
# be displayed in the tab bar, if omitted, the title of the active window will
|
||||
# be used instead)
|
||||
new_tab my tab
|
||||
cd ~/somewhere
|
||||
# Set the layouts allowed in this tab
|
||||
enabled_layouts tall, stack
|
||||
# Set the current layout
|
||||
layout stack
|
||||
launch zsh
|
||||
# Make the current window the active (focused) window
|
||||
focus
|
||||
launch emacs
|
||||
....
|
||||
|
||||
== Protocol Extensions
|
||||
|
||||
kitty has a few extensions to the xterm protocol, to enable advanced features,
|
||||
see link:protocol-extensions.asciidoc[Protocol Extensions].
|
||||
|
||||
|
||||
== Font control
|
||||
|
||||
kitty has extremely flexible and powerful font selection features. You can
|
||||
specify individual families for the regular, bold, italic and bold+italic
|
||||
fonts. You can even specify specific font families for specific ranges of
|
||||
unicode characters. This allows precise control over text rendering. It can
|
||||
come in handy for applications like powerline, without the need to use patched
|
||||
fonts. See the various font related configuration directives in the
|
||||
link:kitty/kitty.conf[config file].
|
||||
|
||||
== Note for Linux/macOS packagers
|
||||
|
||||
While kitty does use python, it is not a traditional python package, so please do not install it in site-packages.
|
||||
Instead run,
|
||||
|
||||
```
|
||||
python3 setup.py linux-package
|
||||
```
|
||||
|
||||
This will install kitty into the directory `linux-package`. You can run kitty
|
||||
with `linux-package/bin/kitty`. All the files needed to run kitty will be in
|
||||
`linux-package/lib/kitty`. The terminfo file will be installed into
|
||||
`linux-package/share/terminfo`. Simply copy these files into `/usr` to install
|
||||
kitty. In other words, `linux-package` is the staging area into which kitty is
|
||||
installed. You can choose a different staging area, by passing the `--prefix`
|
||||
argument to `setup.py`.
|
||||
|
||||
You should probably split kitty into two packages, `kitty-terminfo` that
|
||||
installs the terminfo file and `kitty` that installs the main program.
|
||||
This allows users to install the terminfo file on servers into which they ssh,
|
||||
without needing to install all of kitty.
|
||||
|
||||
This applies to creating packages for kitty for macOS package managers such as
|
||||
brew or MacPorts as well.
|
||||
|
||||
== Resources on terminal behavior
|
||||
|
||||
http://invisible-island.net/xterm/ctlseqs/ctlseqs.html
|
||||
|
||||
https://en.wikipedia.org/wiki/C0_and_C1_control_codes
|
||||
|
||||
http://vt100.net/
|
||||
|
||||
114
__main__.py
114
__main__.py
@@ -2,6 +2,116 @@
|
||||
# vim:fileencoding=utf-8
|
||||
# License: GPL v3 Copyright: 2015, Kovid Goyal <kovid at kovidgoyal.net>
|
||||
|
||||
import sys
|
||||
import os
|
||||
|
||||
from kitty.main import main
|
||||
main()
|
||||
|
||||
def icat(args):
|
||||
from kittens.runner import run_kitten
|
||||
sys.argv = args
|
||||
run_kitten('icat')
|
||||
|
||||
|
||||
def list_fonts(args):
|
||||
from kitty.fonts.list import main
|
||||
main(args)
|
||||
|
||||
|
||||
def remote_control(args):
|
||||
from kitty.remote_control import main
|
||||
main(args)
|
||||
|
||||
|
||||
def runpy(args):
|
||||
sys.argv = ['kitty'] + args[2:]
|
||||
exec(args[1])
|
||||
|
||||
|
||||
def hold(args):
|
||||
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 launch(args):
|
||||
import runpy
|
||||
sys.argv = args[1:]
|
||||
exe = args[1]
|
||||
if exe.startswith(':'):
|
||||
import shutil
|
||||
exe = shutil.which(exe[1:])
|
||||
if not exe:
|
||||
raise SystemExit('{} not found in PATH'.format(args[1][1:]))
|
||||
runpy.run_path(exe, run_name='__main__')
|
||||
|
||||
|
||||
def run_kitten(args):
|
||||
try:
|
||||
kitten = args[1]
|
||||
except IndexError:
|
||||
from kittens.runner import list_kittens
|
||||
list_kittens()
|
||||
raise SystemExit(1)
|
||||
sys.argv = args[1:]
|
||||
from kittens.runner import run_kitten
|
||||
run_kitten(kitten)
|
||||
|
||||
|
||||
def namespaced(args):
|
||||
func = namespaced_entry_points[args[1]]
|
||||
func(args[1:])
|
||||
|
||||
|
||||
entry_points = {
|
||||
# These two are here for backwards compat
|
||||
'icat': icat,
|
||||
'list-fonts': list_fonts,
|
||||
'runpy': runpy,
|
||||
'launch': launch,
|
||||
'kitten': run_kitten,
|
||||
|
||||
'@': remote_control,
|
||||
'+': namespaced,
|
||||
}
|
||||
namespaced_entry_points = {k: v for k, v in entry_points.items() if k[0] not in '+@'}
|
||||
namespaced_entry_points['hold'] = hold
|
||||
namespaced_entry_points['complete'] = complete
|
||||
|
||||
|
||||
def setup_openssl_environment():
|
||||
# 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
|
||||
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'
|
||||
elif os.path.isdir('/etc/ssl/certs'):
|
||||
os.environ['SSL_CERT_DIR'] = '/etc/ssl/certs'
|
||||
|
||||
|
||||
def main():
|
||||
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]
|
||||
func = entry_points.get(first_arg)
|
||||
if func is None:
|
||||
if first_arg.startswith('@'):
|
||||
remote_control(['@', first_arg[1:]] + sys.argv[2:])
|
||||
elif first_arg.startswith('+'):
|
||||
namespaced(['+', first_arg[1:]] + sys.argv[2:])
|
||||
else:
|
||||
from kitty.main import main
|
||||
main()
|
||||
else:
|
||||
func(sys.argv[1:])
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
19
asan-launcher.c
Normal file
19
asan-launcher.c
Normal file
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
@@ -15,7 +15,7 @@ with open('terminfo/kitty.terminfo', 'w') as f:
|
||||
f.write(generate_terminfo())
|
||||
|
||||
os.environ['TERMINFO'] = os.path.join(base, 'terminfo')
|
||||
subprocess.check_call(['tic', 'terminfo/kitty.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')
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
#!/bin/bash
|
||||
cloc --exclude-list-file <(echo -e 'kitty/wcwidth9.h\nkitty/unicode-data.h\nkitty/gl.h\nkitty/glfw.c\nkitty/glfw.h\nkitty/charsets.c\nkitty/key_encoding.py\nkitty/rgb.py') kitty
|
||||
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
|
||||
|
||||
20
docs/Makefile
Normal file
20
docs/Makefile
Normal file
@@ -0,0 +1,20 @@
|
||||
# Minimal makefile for Sphinx documentation
|
||||
#
|
||||
|
||||
# You can set these variables from the command line.
|
||||
SPHINXOPTS = -T $(FAIL_WARN)
|
||||
SPHINXBUILD = python3 .. +launch :sphinx-build
|
||||
SPHINXPROJ = kitty
|
||||
SOURCEDIR = .
|
||||
BUILDDIR = _build
|
||||
|
||||
# Put it first so that "make" without argument is like "make help".
|
||||
help:
|
||||
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||
|
||||
.PHONY: help Makefile
|
||||
|
||||
# Catch-all target: route all unknown targets to Sphinx using the new
|
||||
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
|
||||
%: Makefile
|
||||
$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||
120
docs/_static/custom.css
vendored
Normal file
120
docs/_static/custom.css
vendored
Normal file
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* custom.css
|
||||
* Copyright (C) 2018 Kovid Goyal
|
||||
*
|
||||
* Distributed under terms of the MIT license.
|
||||
*/
|
||||
|
||||
.float-left-img {
|
||||
float: left;
|
||||
margin-right: 1em;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
.float-right-img { float: right; margin-left: 1em; margin-bottom: 1em }
|
||||
|
||||
.half-with-img { max-width: 50% }
|
||||
|
||||
.fit-img { max-width: 95% }
|
||||
|
||||
div.body p, div.body dd, div.body li, div.body blockquote {
|
||||
text-align: justify;
|
||||
}
|
||||
|
||||
pre {
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
pre.pre {
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
a[href], input[type="submit"] { cursor: pointer; }
|
||||
|
||||
img[style] {
|
||||
/* Used for :scale: images to have them render properly but still popup when clicked */
|
||||
width: auto !important;
|
||||
height: auto !important;
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none !important;
|
||||
border-bottom: none !important;
|
||||
}
|
||||
|
||||
body div.document {
|
||||
margin-top: 1ex;
|
||||
}
|
||||
|
||||
.major-features li {
|
||||
margin-top: 0.75ex;
|
||||
margin-bottom: 0.75ex;
|
||||
}
|
||||
|
||||
.support-form input[type=submit] {
|
||||
border-radius: 6px;
|
||||
box-shadow: rgb(255, 246, 175) 0px 1px 0px 0px;
|
||||
background: linear-gradient(rgb(255, 236, 100) 5%, rgb(255, 171, 35) 100%) rgb(255, 236, 100);
|
||||
border: 1px solid rgb(255, 170, 34);
|
||||
display: inline-block;
|
||||
color: rgb(51, 51, 51);
|
||||
font-family: Arial;
|
||||
font-size: 15px;
|
||||
font-weight: bold;
|
||||
padding: 6px 24px;
|
||||
text-decoration: none;
|
||||
text-shadow: rgb(255, 238, 102) 0px 1px 0px;
|
||||
}
|
||||
|
||||
.support-form input[type=submit]:hover {
|
||||
background: linear-gradient(rgb(255, 171, 35) 5%, rgb(255, 236, 100) 100%) rgb(255, 171, 35);
|
||||
}
|
||||
|
||||
.support-form input[type=submit]:focus {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
|
||||
div.sphinxsidebar {
|
||||
font-size: inherit;
|
||||
line-height: inherit;
|
||||
}
|
||||
|
||||
#sidebartoc li {
|
||||
margin-top: 0.75ex;
|
||||
margin-bottom: 0.75ex;
|
||||
}
|
||||
|
||||
#sidebartoc ul {
|
||||
list-style: none !important;
|
||||
}
|
||||
|
||||
#sidebartoc a[href]:hover {
|
||||
color: red;
|
||||
}
|
||||
|
||||
|
||||
.green {
|
||||
color: green;
|
||||
}
|
||||
|
||||
.cyan {
|
||||
color: blue;
|
||||
}
|
||||
|
||||
.env {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.italic {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.bold {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: larger;
|
||||
font-weight: bold
|
||||
}
|
||||
13
docs/_templates/layout.html
vendored
Normal file
13
docs/_templates/layout.html
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
{% 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 -->
|
||||
{{ super() }}
|
||||
{% endblock %}
|
||||
6
docs/_templates/localtoc.html
vendored
Normal file
6
docs/_templates/localtoc.html
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
{%- if display_toc %}
|
||||
<div> </div>
|
||||
<div id="sidebartoc">
|
||||
{{ toc }}
|
||||
</div>
|
||||
{%- endif %}
|
||||
22
docs/_templates/searchbox.html
vendored
Normal file
22
docs/_templates/searchbox.html
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
{#
|
||||
basic/searchbox.html
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Sphinx sidebar template: quick search box.
|
||||
|
||||
:copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
#}
|
||||
{%- if pagename != "search" and builder != "singlehtml" %}
|
||||
<div id="searchbox" style="display: none" role="search">
|
||||
<div class="searchformwrapper">
|
||||
<form class="search" action="{{ pathto('search') }}" method="get">
|
||||
<input type="text" name="q" placeholder="{{ _('Search') }}" />
|
||||
<input type="submit" value="{{ _('Go') }}" style="cursor: pointer" />
|
||||
<input type="hidden" name="check_keywords" value="yes" />
|
||||
<input type="hidden" name="area" value="default" />
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/javascript">$('#searchbox').show(0);</script>
|
||||
{%- endif %}
|
||||
7
docs/_templates/support.html
vendored
Normal file
7
docs/_templates/support.html
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
{% if pagename != "support" %}
|
||||
<div id="support" style="text-align: center">
|
||||
<form class="support-form" action="{{ pathto('support') }}" title="{{ _('Donate to support kitty development') }}">
|
||||
<input type="submit" value="{{ _('Support kitty') }}">
|
||||
</form>
|
||||
</div>
|
||||
{% endif %}
|
||||
91
docs/binary.rst
Normal file
91
docs/binary.rst
Normal file
@@ -0,0 +1,91 @@
|
||||
kitty - Binary install
|
||||
========================
|
||||
|
||||
.. |ins| replace:: curl -L :literal:`https://sw.kovidgoyal.net/kitty/installer.sh` | sh /dev/stdin
|
||||
|
||||
.. highlight:: sh
|
||||
|
||||
You can install pre-built binaries of |kitty| if you are on macOS or Linux using
|
||||
the following simple command:
|
||||
|
||||
.. parsed-literal::
|
||||
:class: pre
|
||||
|
||||
|ins|
|
||||
|
||||
|
||||
The binaries will be installed in the standard location for your OS,
|
||||
:file:`/Applications/kitty.app` on macOS and :file:`~/.local/kitty.app` on
|
||||
Linux. The installer only touches files in that directory. To update kitty,
|
||||
simply re-run the command.
|
||||
|
||||
|
||||
Manually installing
|
||||
---------------------
|
||||
|
||||
If something goes wrong or you simply do not want to run the installer, you can
|
||||
manually download and install |kitty| from the `GitHub releases page
|
||||
<https://github.com/kovidgoyal/kitty/releases>`_. If you are on macOS, download
|
||||
the :file:`.dmg` and install as normal. If you are on Linux, download the tarball
|
||||
and extract it into a directory. The |kitty| executable will be in the
|
||||
:file:`bin` sub-directory.
|
||||
|
||||
Desktop integration on Linux
|
||||
--------------------------------
|
||||
|
||||
If you want the kitty icon to appear in the taskbar and an entry for it to be
|
||||
present in the menus, you will need to install the :file:`kitty.desktop` file.
|
||||
The details of the following procedure may need to be adjusted for your
|
||||
particular desktop, but it should work for most major desktop environments.
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
# Create a symbolic link to add kitty to PATH (assuming ~/.local/bin is in
|
||||
# your PATH)
|
||||
ln -s ~/.local/kitty.app/bin/kitty ~/.local/bin/
|
||||
# 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
|
||||
|
||||
|
||||
|
||||
Customizing the installation
|
||||
--------------------------------
|
||||
|
||||
* You can specify a different install location, with ``dest``:
|
||||
|
||||
.. parsed-literal::
|
||||
:class: pre
|
||||
|
||||
|ins| \\
|
||||
dest=/some/other/location
|
||||
|
||||
* You can tell the installer not to launch |kitty| after installing it with
|
||||
``launch=n``:
|
||||
|
||||
.. parsed-literal::
|
||||
:class: pre
|
||||
|
||||
|ins| \\
|
||||
launch=n
|
||||
|
||||
* You can use a previously downloaded dmg/tarball, with ``installer``:
|
||||
|
||||
.. parsed-literal::
|
||||
:class: pre
|
||||
|
||||
|ins| \\
|
||||
installer=/path/to/dmg or tarball
|
||||
|
||||
Uninstalling
|
||||
----------------
|
||||
|
||||
All the installer does is copy the kitty files into the install directory. To
|
||||
uninstall, simply delete that directory.
|
||||
|
||||
|
||||
Building from source
|
||||
------------------------
|
||||
|
||||
|kitty| is easy to build from source, follow the :doc:`instructions <build>`.
|
||||
113
docs/build.rst
Normal file
113
docs/build.rst
Normal file
@@ -0,0 +1,113 @@
|
||||
Building kitty from source
|
||||
==============================
|
||||
|
||||
.. image:: https://travis-ci.org/kovidgoyal/kitty.svg?branch=master
|
||||
:alt: Build status
|
||||
:target: https://travis-ci.org/kovidgoyal/kitty
|
||||
|
||||
|
||||
|kitty| is designed to run from source, for easy hackability. Make sure
|
||||
the following dependencies are installed first.
|
||||
|
||||
Dependencies
|
||||
----------------
|
||||
|
||||
Run-time dependencies:
|
||||
|
||||
* python >= 3.5
|
||||
* harfbuzz >= 1.5.0
|
||||
* zlib
|
||||
* libpng
|
||||
* freetype (not needed on macOS)
|
||||
* fontconfig (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``)
|
||||
|
||||
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``.
|
||||
if they are not already installed by your distro.
|
||||
|
||||
Install and run from source
|
||||
------------------------------
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
git clone https://github.com/kovidgoyal/kitty && cd kitty
|
||||
|
||||
Now build the native code parts of |kitty| with the following command::
|
||||
|
||||
make
|
||||
|
||||
You can run |kitty|, as::
|
||||
|
||||
python3 .
|
||||
|
||||
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
|
||||
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::
|
||||
|
||||
make app
|
||||
|
||||
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 for Linux/macOS packagers
|
||||
----------------------------------
|
||||
|
||||
The released |kitty| source code is available as a `tarball`_ from
|
||||
`the GitHub releases page <https://github.com/kovidgoyal/kitty/releases>`_.
|
||||
|
||||
While |kitty| does use python, it is not a traditional python package, so please
|
||||
do not install it in site-packages.
|
||||
Instead run::
|
||||
|
||||
python3 setup.py linux-package
|
||||
|
||||
This will install |kitty| into the directory :file:`linux-package`. You can run |kitty|
|
||||
with :file:`linux-package/bin/kitty`. All the files needed to run kitty will be in
|
||||
:file:`linux-package/lib/kitty`. The terminfo file will be installed into
|
||||
:file:`linux-package/share/terminfo`. Simply copy these files into :file:`/usr` to install
|
||||
|kitty|. In other words, :file:`linux-package` is the staging area into which |kitty| is
|
||||
installed. You can choose a different staging area, by passing the ``--prefix``
|
||||
argument to :file:`setup.py`.
|
||||
|
||||
You should probably split |kitty| into two packages, :file:`kitty-terminfo` that
|
||||
installs the terminfo file and :file:`kitty` that installs the main program.
|
||||
This allows users to install the terminfo file on servers into which they ssh,
|
||||
without needing to install all of |kitty|.
|
||||
|
||||
.. note::
|
||||
You need a couple of extra dependencies to build linux-package.
|
||||
:file:`tic` to compile terminfo files, usually found in the
|
||||
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/>`_.
|
||||
|
||||
This applies to creating packages for |kitty| for macOS package managers such as
|
||||
brew or MacPorts as well.
|
||||
1054
docs/changelog.rst
Normal file
1054
docs/changelog.rst
Normal file
File diff suppressed because it is too large
Load Diff
538
docs/conf.py
Normal file
538
docs/conf.py
Normal file
@@ -0,0 +1,538 @@
|
||||
# -*- coding: 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
|
||||
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
from functools import partial
|
||||
|
||||
from docutils import nodes
|
||||
from docutils.parsers.rst.roles import set_classes
|
||||
from pygments.lexer import RegexLexer, bygroups
|
||||
from pygments.token import (
|
||||
Comment, Keyword, Literal, Name, Number, String, Whitespace
|
||||
)
|
||||
from sphinx import addnodes
|
||||
from sphinx.util.logging import getLogger
|
||||
|
||||
from kitty.constants import str_version
|
||||
|
||||
# config {{{
|
||||
# -- Project information -----------------------------------------------------
|
||||
|
||||
project = 'kitty'
|
||||
copyright = '2018, Kovid Goyal'
|
||||
author = 'Kovid Goyal'
|
||||
building_man_pages = 'man' in sys.argv
|
||||
|
||||
# The short X.Y version
|
||||
version = str_version
|
||||
# The full version, including alpha/beta/rc tags
|
||||
release = str_version
|
||||
logger = getLogger(__name__)
|
||||
|
||||
|
||||
# -- General configuration ---------------------------------------------------
|
||||
|
||||
# If your documentation needs a minimal Sphinx version, state it here.
|
||||
#
|
||||
needs_sphinx = '1.7'
|
||||
|
||||
# Add any Sphinx extension module names here, as strings. They can be
|
||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||
# ones.
|
||||
extensions = [
|
||||
'sphinx.ext.ifconfig',
|
||||
'sphinx.ext.viewcode',
|
||||
'sphinx.ext.githubpages',
|
||||
]
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['_templates']
|
||||
|
||||
# The suffix(es) of source filenames.
|
||||
# You can specify multiple suffix as a list of string:
|
||||
#
|
||||
# source_suffix = ['.rst', '.md']
|
||||
source_suffix = '.rst'
|
||||
|
||||
# The master toctree document.
|
||||
master_doc = 'index'
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
#
|
||||
# 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
|
||||
|
||||
# List of patterns, relative to source directory, that match files and
|
||||
# directories to ignore when looking for source files.
|
||||
# This pattern also affects html_static_path and html_extra_path .
|
||||
exclude_patterns = [
|
||||
'_build', 'Thumbs.db', '.DS_Store',
|
||||
'generated/cli-*.rst', 'generated/conf-*.rst'
|
||||
]
|
||||
|
||||
# The name of the Pygments (syntax highlighting) style to use.
|
||||
pygments_style = 'sphinx'
|
||||
|
||||
rst_prolog = '''
|
||||
.. |kitty| replace:: *kitty*
|
||||
.. |version| replace:: VERSION
|
||||
.. _tarball: https://github.com/kovidgoyal/kitty/releases/download/vVERSION/kitty-VERSION.tar.xz
|
||||
.. role:: green
|
||||
.. role:: italic
|
||||
.. role:: bold
|
||||
.. role:: cyan
|
||||
.. role:: title
|
||||
.. role:: env
|
||||
|
||||
'''.replace('VERSION', str_version)
|
||||
|
||||
|
||||
# -- Options for HTML output -------------------------------------------------
|
||||
|
||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||
# a list of builtin themes.
|
||||
#
|
||||
html_theme = 'alabaster'
|
||||
|
||||
# Theme options are theme-specific and customize the look and feel of a theme
|
||||
# further. For a list of options available for each theme, see the
|
||||
# documentation.
|
||||
#
|
||||
html_theme_options = {
|
||||
'logo': 'kitty.png',
|
||||
'show_powered_by': False,
|
||||
'fixed_sidebar': True,
|
||||
'sidebar_collapse': True,
|
||||
'github_button': False,
|
||||
'github_banner': True,
|
||||
'github_user': 'kovidgoyal',
|
||||
'github_repo': 'kitty',
|
||||
# increase contrast of link color with text color
|
||||
'link': '#00587d',
|
||||
'link_hover': 'green',
|
||||
}
|
||||
|
||||
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
html_static_path = ['_static', '../logo/kitty.png']
|
||||
html_context = {
|
||||
'css_files': ['_static/custom.css']
|
||||
}
|
||||
html_favicon = '../logo/kitty.png'
|
||||
|
||||
# Custom sidebar templates, must be a dictionary that maps document names
|
||||
# to template names.
|
||||
#
|
||||
# The default sidebars (for documents that don't match any pattern) are
|
||||
# defined by theme itself. Builtin themes are using these templates by
|
||||
# default: ``['localtoc.html', 'relations.html', 'sourcelink.html',
|
||||
# 'searchbox.html']``.
|
||||
#
|
||||
html_sidebars = {
|
||||
'**': [
|
||||
'about.html',
|
||||
'support.html',
|
||||
'searchbox.html',
|
||||
'localtoc.html',
|
||||
'relations.html',
|
||||
]
|
||||
}
|
||||
html_show_sourcelink = False
|
||||
|
||||
|
||||
# -- Options for manual page output ------------------------------------------
|
||||
|
||||
# One entry per manual page. List of tuples
|
||||
# (source start file, name, description, authors, manual section).
|
||||
man_pages = [
|
||||
('invocation', 'kitty', 'kitty Documentation',
|
||||
[author], 1)
|
||||
]
|
||||
|
||||
|
||||
# -- Options for Texinfo output ----------------------------------------------
|
||||
|
||||
# Grouping the document tree into Texinfo files. List of tuples
|
||||
# (source start file, target name, title, author,
|
||||
# dir menu entry, description, category)
|
||||
texinfo_documents = [
|
||||
(master_doc, 'kitty', 'kitty Documentation',
|
||||
author, 'kitty', 'A cross-platform, fast, feature full, GPU based terminal emulator',
|
||||
'Miscellaneous'),
|
||||
]
|
||||
# }}}
|
||||
|
||||
|
||||
# GitHub linking inlne roles {{{
|
||||
|
||||
def num_role(which, name, rawtext, text, lineno, inliner, options={}, content=[]):
|
||||
' Link to a github issue '
|
||||
try:
|
||||
issue_num = int(text)
|
||||
if issue_num <= 0:
|
||||
raise ValueError
|
||||
except ValueError:
|
||||
msg = inliner.reporter.error(
|
||||
'GitHub issue number must be a number greater than or equal to 1; '
|
||||
'"%s" is invalid.' % text, line=lineno)
|
||||
prb = inliner.problematic(rawtext, rawtext, msg)
|
||||
return [prb], [msg]
|
||||
url = f'https://github.com/kovidgoyal/kitty/{which}/{issue_num}'
|
||||
set_classes(options)
|
||||
node = nodes.reference(rawtext, f'#{issue_num}', refuri=url, **options)
|
||||
return [node], []
|
||||
|
||||
|
||||
def commit_role(name, rawtext, text, lineno, inliner, options={}, content=[]):
|
||||
' 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()
|
||||
except Exception:
|
||||
msg = inliner.reporter.error(
|
||||
f'GitHub commit id "{text}" not recognized.', line=lineno)
|
||||
prb = inliner.problematic(rawtext, rawtext, msg)
|
||||
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()
|
||||
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)
|
||||
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
|
||||
subtree = subtree[bl]
|
||||
# for li in subtree.traverse(nodes.list_item):
|
||||
# modify_li(li)
|
||||
# subtree['ids'] = [ID]
|
||||
return app.builder.render_partial(subtree)['fragment']
|
||||
|
||||
|
||||
def add_html_context(app, pagename, templatename, context, *args):
|
||||
if 'toc' in context:
|
||||
context['toc'] = create_toc(app, pagename) or context['toc']
|
||||
# }}}
|
||||
|
||||
|
||||
# CLI docs {{{
|
||||
def write_cli_docs(all_kitten_names):
|
||||
from kitty.cli import option_spec_as_rst
|
||||
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
|
||||
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]
|
||||
p(f'.. _at_{func.name}:\n')
|
||||
p('kitty @', func.name + '\n' + '-' * 120)
|
||||
p('.. program::', 'kitty @', func.name)
|
||||
p('\n\n' + as_rst(*cli_params_for(func)))
|
||||
from kittens.runner import get_kitten_cli_docs
|
||||
for kitten in all_kitten_names:
|
||||
data = get_kitten_cli_docs(kitten)
|
||||
if data:
|
||||
with open(f'generated/cli-kitten-{kitten}.rst', 'w') as f:
|
||||
p = partial(print, file=f)
|
||||
p('.. program::', f'kitty +kitten {kitten}')
|
||||
p('\n\n' + option_spec_as_rst(
|
||||
data['options'], message=data['help_text'], usage=data['usage'], appname=f'kitty +kitten {kitten}',
|
||||
heading_char='^'))
|
||||
|
||||
# }}}
|
||||
|
||||
|
||||
# config file docs {{{
|
||||
|
||||
class ConfLexer(RegexLexer):
|
||||
name = 'Conf'
|
||||
aliases = ['conf']
|
||||
filenames = ['*.conf']
|
||||
|
||||
tokens = {
|
||||
'root': [
|
||||
(r'#.*?$', Comment.Single),
|
||||
(r'\s+$', Whitespace),
|
||||
(r'\s+', Whitespace),
|
||||
(r'(include)(\s+)(.+?)$', bygroups(Comment.Preproc, Whitespace, Name.Namespace)),
|
||||
(r'(map)(\s+)(\S+)(\s+)', bygroups(
|
||||
Keyword.Declaration, Whitespace, String, Whitespace), 'action'),
|
||||
(r'(symbol_map)(\s+)(\S+)(\s+)(.+?)$', bygroups(
|
||||
Keyword.Declaration, Whitespace, String, Whitespace, Literal)),
|
||||
(r'([a-zA-Z_0-9]+)(\s+)', bygroups(
|
||||
Name.Variable, Whitespace), 'args'),
|
||||
],
|
||||
'action': [
|
||||
(r'[a-z_0-9]+$', Name.Function, 'root'),
|
||||
(r'[a-z_0-9]+', Name.Function, 'args'),
|
||||
],
|
||||
'args': [
|
||||
(r'\s+', Whitespace, 'args'),
|
||||
(r'\b(yes|no)\b$', Number.Bin, 'root'),
|
||||
(r'\b(yes|no)\b', Number.Bin, 'args'),
|
||||
(r'[+-]?[0-9]+\s*$', Number.Integer, 'root'),
|
||||
(r'[+-]?[0-9.]+\s*$', Number.Float, 'root'),
|
||||
(r'[+-]?[0-9]+', Number.Integer, 'args'),
|
||||
(r'[+-]?[0-9.]+', Number.Float, 'args'),
|
||||
(r'#[a-fA-F0-9]{3,6}\s*$', String, 'root'),
|
||||
(r'#[a-fA-F0-9]{3,6}\s*', String, 'args'),
|
||||
(r'.+', String, 'root'),
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
class SessionLexer(RegexLexer):
|
||||
name = 'Session'
|
||||
aliases = ['session']
|
||||
filenames = ['*.session']
|
||||
|
||||
tokens = {
|
||||
'root': [
|
||||
(r'#.*?$', Comment.Single),
|
||||
(r'[a-z][a-z0-9_]+', Name.Function, 'args'),
|
||||
],
|
||||
'args': [
|
||||
(r'.*?$', Literal, 'root'),
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
def link_role(name, rawtext, text, lineno, inliner, options={}, content=[]):
|
||||
m = re.match(r'(.+)\s+<(.+?)>', text)
|
||||
if m is None:
|
||||
msg = inliner.reporter.error(f'link "{text}" not recognized', line=lineno)
|
||||
prb = inliner.problematic(rawtext, rawtext, msg)
|
||||
return [prb], [msg]
|
||||
text, url = m.group(1, 2)
|
||||
set_classes(options)
|
||||
node = nodes.reference(rawtext, text, refuri=url, **options)
|
||||
return [node], []
|
||||
|
||||
|
||||
def expand_opt_references(conf_name, text):
|
||||
conf_name += '.'
|
||||
|
||||
def expand(m):
|
||||
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 re.sub(r':opt:`(.+?)`', expand, text)
|
||||
|
||||
|
||||
opt_aliases = {}
|
||||
shortcut_slugs = {}
|
||||
|
||||
|
||||
def parse_opt_node(env, sig, signode):
|
||||
"""Transform an option description into RST nodes."""
|
||||
count = 0
|
||||
firstname = ''
|
||||
for potential_option in sig.split(', '):
|
||||
optname = potential_option.strip()
|
||||
if count:
|
||||
signode += addnodes.desc_addname(', ', ', ')
|
||||
text = optname.split('.', 1)[-1]
|
||||
signode += addnodes.desc_name(text, text)
|
||||
if not count:
|
||||
firstname = optname
|
||||
signode['allnames'] = [optname]
|
||||
else:
|
||||
signode['allnames'].append(optname)
|
||||
opt_aliases[optname] = firstname
|
||||
count += 1
|
||||
if not firstname:
|
||||
raise ValueError('{} is not a valid opt'.format(sig))
|
||||
return firstname
|
||||
|
||||
|
||||
def parse_shortcut_node(env, sig, signode):
|
||||
"""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
|
||||
ans = ['.. default-domain:: conf', '']
|
||||
a = ans.append
|
||||
current_group = None
|
||||
all_options = list(all_options)
|
||||
kitty_mod = 'kitty_mod'
|
||||
|
||||
def render_group(group):
|
||||
a('')
|
||||
a(f'.. _conf-{conf_name}-{group.name}:')
|
||||
a('')
|
||||
a(group.short_text)
|
||||
heading_level = '+' if '.' in group.name else '^'
|
||||
a(heading_level * (len(group.short_text) + 20))
|
||||
a('')
|
||||
if group.start_text:
|
||||
a(group.start_text)
|
||||
a('')
|
||||
|
||||
def handle_group_end(group):
|
||||
if group.end_text:
|
||||
a(''), a(current_group.end_text)
|
||||
|
||||
def handle_group(new_group, new_group_is_shortcut=False):
|
||||
nonlocal current_group
|
||||
if new_group is not current_group:
|
||||
if current_group:
|
||||
handle_group_end(current_group)
|
||||
current_group = new_group
|
||||
render_group(current_group)
|
||||
|
||||
def handle_option(i, opt):
|
||||
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))
|
||||
a('.. opt:: ' + ', '.join(conf_name + '.' + mo.name for mo in mopts))
|
||||
a('.. code-block:: conf')
|
||||
a('')
|
||||
sz = max(len(x.name) for x in mopts)
|
||||
for mo in mopts:
|
||||
a((' {:%ds} {}' % sz).format(mo.name, mo.defval_as_string))
|
||||
a('')
|
||||
if opt.long_text:
|
||||
a(expand_opt_references(conf_name, opt.long_text))
|
||||
a('')
|
||||
|
||||
def handle_shortcuts(shortcuts):
|
||||
sc = shortcuts[0]
|
||||
handle_group(sc.group, True)
|
||||
sc_text = f'{conf_name}.{sc.short_text}'
|
||||
a('.. shortcut:: ' + sc_text)
|
||||
shortcuts = [s for s in shortcuts if s.add_to_default]
|
||||
shortcut_slugs[f'{conf_name}.{sc.name}'] = (sc_text, sc.key.replace('kitty_mod', kitty_mod))
|
||||
if shortcuts:
|
||||
a('.. code-block:: conf')
|
||||
a('')
|
||||
for x in shortcuts:
|
||||
if x.add_to_default:
|
||||
a(' map {} {}'.format(x.key.replace('kitty_mod', kitty_mod), x.action_def))
|
||||
a('')
|
||||
if sc.long_text:
|
||||
a(expand_opt_references(conf_name, sc.long_text))
|
||||
a('')
|
||||
|
||||
for i, opt in enumerate(all_options):
|
||||
if isinstance(opt, Option):
|
||||
handle_option(i, opt)
|
||||
else:
|
||||
handle_shortcuts(opt)
|
||||
|
||||
if current_group:
|
||||
handle_group_end(current_group)
|
||||
return '\n'.join(ans)
|
||||
|
||||
|
||||
def process_opt_link(env, refnode, has_explicit_title, title, target):
|
||||
conf_name, opt = target.partition('.')[::2]
|
||||
if not opt:
|
||||
conf_name, opt = 'kitty', conf_name
|
||||
full_name = conf_name + '.' + opt
|
||||
return title, opt_aliases.get(full_name, full_name)
|
||||
|
||||
|
||||
def process_shortcut_link(env, refnode, has_explicit_title, title, target):
|
||||
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]
|
||||
except KeyError:
|
||||
logger.warning('Unknown shortcut: {}'.format(target), location=refnode)
|
||||
return title, target
|
||||
|
||||
|
||||
def write_conf_docs(app, all_kitten_names):
|
||||
app.add_lexer('conf', ConfLexer())
|
||||
app.add_object_type(
|
||||
'opt', 'opt',
|
||||
indextemplate="pair: %s; Config Setting",
|
||||
parse_node=parse_opt_node,
|
||||
)
|
||||
# Warn about opt references that could not be resolved
|
||||
opt_role = app.registry.domain_roles['std']['opt']
|
||||
opt_role.warn_dangling = True
|
||||
opt_role.process_link = process_opt_link
|
||||
|
||||
app.add_object_type(
|
||||
'shortcut', 'sc',
|
||||
indextemplate="pair: %s; Keyboard Shortcut",
|
||||
parse_node=parse_shortcut_node,
|
||||
)
|
||||
sc_role = app.registry.domain_roles['std']['sc']
|
||||
sc_role.warn_dangling = True
|
||||
sc_role.process_link = process_shortcut_link
|
||||
|
||||
def generate_default_config(all_options, name):
|
||||
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)
|
||||
f.write(render_conf(name, all_options.values()))
|
||||
|
||||
conf_name = re.sub(r'^kitten-', '', name) + '.conf'
|
||||
with open(f'generated/conf/{conf_name}', 'w', encoding='utf-8') as f:
|
||||
text = '\n'.join(as_conf_file(all_options.values()))
|
||||
print(text, file=f)
|
||||
|
||||
from kitty.config_data import all_options
|
||||
generate_default_config(all_options, 'kitty')
|
||||
|
||||
from kittens.runner import get_kitten_conf_docs
|
||||
for kitten in all_kitten_names:
|
||||
all_options = get_kitten_conf_docs(kitten)
|
||||
if all_options:
|
||||
generate_default_config(all_options, f'kitten-{kitten}')
|
||||
# }}}
|
||||
|
||||
|
||||
def setup(app):
|
||||
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())
|
||||
app.add_role('link', link_role)
|
||||
app.add_role('iss', partial(num_role, 'issues'))
|
||||
app.add_role('pull', partial(num_role, 'pull'))
|
||||
app.add_role('commit', commit_role)
|
||||
app.connect('html-page-context', add_html_context)
|
||||
40
docs/conf.rst
Normal file
40
docs/conf.rst
Normal file
@@ -0,0 +1,40 @@
|
||||
:tocdepth: 2
|
||||
|
||||
Configuring kitty
|
||||
===============================
|
||||
|
||||
.. highlight:: conf
|
||||
|
||||
|kitty| is highly customizable, everything from keyboard shortcuts, to painting
|
||||
frames-per-second. See below for an overview of all customization
|
||||
possibilities.
|
||||
|
||||
You can open the config file within kitty by pressing :sc:`edit_config_file`.
|
||||
You can also display the current configuration by running ``kitty
|
||||
--debug-config``.
|
||||
|
||||
.. _confloc:
|
||||
|
||||
|kitty| looks for a config file in the OS config directories (usually
|
||||
:file:`~/.config/kitty/kitty.conf`) but you can pass a specific path via the
|
||||
:option:`kitty --config` option or use the ``KITTY_CONFIG_DIRECTORY``
|
||||
environment variable. See the :option:`kitty --config` option for full details.
|
||||
|
||||
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
|
||||
expanded, so :code:`${USER}.conf` becomes :file:`name.conf` if
|
||||
:code:`USER=name`. For example::
|
||||
|
||||
include other.conf
|
||||
|
||||
|
||||
.. include:: /generated/conf-kitty.rst
|
||||
|
||||
|
||||
Sample kitty.conf
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
You can download a sample :file:`kitty.conf` file with all default settings and
|
||||
comments describing each setting by clicking: :download:`sample kitty.conf
|
||||
</generated/conf/kitty.conf>`.
|
||||
106
docs/faq.rst
Normal file
106
docs/faq.rst
Normal file
@@ -0,0 +1,106 @@
|
||||
Frequently Asked Questions
|
||||
==============================
|
||||
|
||||
.. highlight:: sh
|
||||
|
||||
.. contents::
|
||||
|
||||
Some special symbols are rendered small/truncated in kitty?
|
||||
-----------------------------------------------------------------
|
||||
|
||||
The number of cells a unicode character takes up are controlled by the unicode
|
||||
standard. All characters are rendered in a single cell unless the unicode
|
||||
standard says they should be rendered in two cells. When a symbol does not fit,
|
||||
it will either be rescaled to be smaller or truncated (depending on how much
|
||||
extra space it needs). This is often different from other terminals which just
|
||||
let the character overflow into neighboring cells, which is fine if the
|
||||
neighboring cell is empty, but looks terrible if it is not.
|
||||
|
||||
Some programs, like powerline, vim with fancy gutter symbols/status-bar, etc.
|
||||
misuse unicode characters from the private use area to represent symbols. Often
|
||||
these symbols are square and should be rendered in two cells. However, since
|
||||
private use area symbols all have their width set to one in the unicode
|
||||
standard, |kitty| renders them either smaller or truncated. The exception is if
|
||||
these characters are followed by a space or empty cell in which case kitty
|
||||
makes use of the extra cell to render them in two cells.
|
||||
|
||||
|
||||
Using a color theme with a background color does not work well in vim?
|
||||
-----------------------------------------------------------------------
|
||||
|
||||
First make sure you have not changed the TERM environment variable, it should
|
||||
be ``xterm-kitty``. vim uses *background color erase* even if the terminfo file
|
||||
does not contain the ``bce`` capability. This is a bug in vim. You can work around
|
||||
it by adding the following to your vimrc::
|
||||
|
||||
let &t_ut=''
|
||||
|
||||
See :ref:`here <ext_styles>` for why |kitty| does not support background color erase.
|
||||
|
||||
|
||||
I get errors about the terminal being unknown or opening the terminal failing when SSHing into a different computer?
|
||||
-----------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
This happens because the |kitty| terminfo files are not available on the server.
|
||||
You can ssh in using the following command which will automatically copy the
|
||||
terminfo files to the server::
|
||||
|
||||
kitty +kitten ssh myserver
|
||||
|
||||
If for some reason that does not work (typically because the server is using a
|
||||
a non POSIX compliant shell), you can use the following one-liner instead (it
|
||||
is slower as it needs to ssh into the server twice, but will work with most
|
||||
servers)::
|
||||
|
||||
infocmp xterm-kitty | ssh myserver tic -x -o \~/.terminfo /dev/stdin
|
||||
|
||||
Really, the correct solution for this is to convince the OpenSSH maintainers to
|
||||
have ssh do this automatically when connecting to a server, so that all
|
||||
terminals work transparently.
|
||||
|
||||
|
||||
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`.
|
||||
|
||||
|
||||
How do I specify command line options for kitty on macOS?
|
||||
---------------------------------------------------------------
|
||||
|
||||
Apple does not want you to use command line options with GUI applications. To
|
||||
workaround that limitation, |kitty| will read command line options from the file
|
||||
:file:`<kitty config dir>/macos-launch-services-cmdline` when it is launched
|
||||
from the GUI, i.e. by clicking the |kitty| application icon or using ``open -a kitty``.
|
||||
Note that this file is *only read* when running via the GUI.
|
||||
|
||||
You can, of course, also run |kitty| from a terminal with command line options, using:
|
||||
:file:`/Applications/kitty.app/Contents/MacOS/kitty`.
|
||||
|
||||
And within |kitty| itself, you can always run |kitty| using just `kitty` as it
|
||||
cleverly adds itself to the ``PATH``.
|
||||
|
||||
|
||||
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::
|
||||
|
||||
fc-list : family spacing | grep spacing=100
|
||||
|
||||
|
||||
How can I assign a single global shortcut to bring up the kitty terminal?
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
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>`_.
|
||||
439
docs/graphics-protocol.rst
Normal file
439
docs/graphics-protocol.rst
Normal file
@@ -0,0 +1,439 @@
|
||||
:tocdepth: 3
|
||||
|
||||
The terminal graphics protocol
|
||||
==================================
|
||||
|
||||
The goal of this specification is to create a flexible and performant protocol
|
||||
that allows the program running in the terminal, hereafter called the *client*,
|
||||
to render arbitrary pixel (raster) graphics to the screen of the terminal
|
||||
emulator. The major design goals are
|
||||
|
||||
* Should not require terminal emulators to understand image formats.
|
||||
* Should allow specifying graphics to be drawn at individual pixel positions.
|
||||
* The graphics should integrate with the text, in particular it should be possible to draw graphics
|
||||
below as well as above the text, with alpha blending. The graphics should also scroll with the text, automatically.
|
||||
* Should use optimizations when the client is running on the same computer as the terminal emulator.
|
||||
|
||||
For some discussion regarding the design choices, see `#33
|
||||
<https://github.com/kovidgoyal/kitty/issues/33>`_.
|
||||
|
||||
To see a quick demo, inside a |kitty| terminal run::
|
||||
|
||||
kitty +kitten icat path/to/some/image.png
|
||||
|
||||
You can also see a screenshot with more sophisticated features such as
|
||||
alpha-blending and text over graphics.
|
||||
|
||||
.. image:: https://user-images.githubusercontent.com/1308621/31647475-1188ab66-b326-11e7-8d26-24b937f1c3e8.png
|
||||
:alt: Demo of graphics rendering in kitty
|
||||
:align: center
|
||||
|
||||
Some programs that use the kitty graphics protocol:
|
||||
|
||||
* `termpdf <https://github.com/dsanson/termpdf>`_ - 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
|
||||
* `neofetch <https://github.com/dylanaraps/neofetch>`_ - A command line system
|
||||
information tool
|
||||
|
||||
|
||||
.. contents::
|
||||
|
||||
|
||||
Getting the window size
|
||||
-------------------------
|
||||
|
||||
In order to know what size of images to display and how to position them, the
|
||||
client must be able to get the window size in pixels and the number of cells
|
||||
per row and column. This can be done by using the ``TIOCGWINSZ`` ioctl. Some
|
||||
code to demonstrate its use
|
||||
|
||||
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);
|
||||
|
||||
In Python:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import array, fcntl, 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))
|
||||
|
||||
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.
|
||||
|
||||
A minimal example
|
||||
------------------
|
||||
|
||||
Some minimal python code to display PNG images in kitty, using the most basic
|
||||
features of the graphics protocol:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import sys
|
||||
from base64 import standard_b64encode
|
||||
|
||||
def serialize_gr_command(cmd, payload=None):
|
||||
cmd = ','.join('{}={}'.format(k, v) for k, v in cmd.items())
|
||||
ans = []
|
||||
w = ans.append
|
||||
w(b'\033_G'), w(cmd.encode('ascii'))
|
||||
if payload:
|
||||
w(b';')
|
||||
w(payload)
|
||||
w(b'\033\\')
|
||||
return b''.join(ans)
|
||||
|
||||
def write_chunked(cmd, data):
|
||||
data = standard_b64encode(data)
|
||||
while data:
|
||||
chunk, data = data[:4096], data[4096:]
|
||||
m = 1 if data else 0
|
||||
cmd['m'] = m
|
||||
sys.stdout.buffer.write(serialize_gr_command(cmd, chunk))
|
||||
sys.stdout.flush()
|
||||
cmd.clear()
|
||||
|
||||
write_chunked({'a': 'T', 'f': 100}, open(sys.argv[-1], 'rb').read())
|
||||
|
||||
|
||||
Save this script as :file:`png.py`, then you can use it to display any PNG
|
||||
file in kitty as::
|
||||
|
||||
python png.py file.png
|
||||
|
||||
|
||||
The graphics escape code
|
||||
---------------------------
|
||||
|
||||
All graphics escape codes are of the form::
|
||||
|
||||
<ESC>_G<control data>;<payload><ESC>\
|
||||
|
||||
This is a so-called *Application Programming Command (APC)*. Most terminal
|
||||
emulators ignore APC codes, making it safe to use.
|
||||
|
||||
The control data is a comma-separated list of ``key=value`` pairs. The payload
|
||||
is arbitrary binary data, base64-encoded to prevent interoperation problems
|
||||
with legacy terminals that get confused by control codes within an APC code.
|
||||
The meaning of the payload is interpreted based on the control data.
|
||||
|
||||
The first step is to transmit the actual image data.
|
||||
|
||||
Transferring pixel data
|
||||
--------------------------
|
||||
|
||||
The first consideration when transferring data between the client and the
|
||||
terminal emulator is the format in which to do so. Since there is a vast and
|
||||
growing number of image formats in existence, it does not make sense to have
|
||||
every terminal emulator implement support for them. Instead, the client should
|
||||
send simple pixel data to the terminal emulator. The obvious downside to this
|
||||
is performance, especially when the client is running on a remote machine.
|
||||
Techniques for remedying this limitation are discussed later. The terminal
|
||||
emulator must understand pixel data in three formats, 24-bit RGB, 32-bit RGBA and
|
||||
PNG. This is specified using the ``f`` key in the control data. ``f=32`` (which is the
|
||||
default) indicates 32-bit RGBA data and ``f=24`` indicates 24-bit RGB data and ``f=100``
|
||||
indicates PNG data. The PNG format is supported for convenience and a compact way
|
||||
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::
|
||||
|
||||
<ESC>_Gf=24,s=10,v=20;<payload><ESC>\
|
||||
|
||||
Here the width and height are specified using the ``s`` and ``v`` keys respectively. Since
|
||||
``f=24`` there are three bytes per pixel and therefore the pixel data must be ``3 * 10 * 20 = 600``
|
||||
bytes.
|
||||
|
||||
PNG data
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
In this format any PNG image can be transmitted directly. For example::
|
||||
|
||||
<ESC>_Gf=100;<payload><ESC>\
|
||||
|
||||
|
||||
The PNG format is specified using the ``f=100`` key. The width and height of
|
||||
the image will be read from the PNG data itself. Note that if you use both PNG and
|
||||
compression, then you must provide the ``S`` key with the size of the PNG data.
|
||||
|
||||
|
||||
Compression
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
The client can send compressed image data to the terminal emulator, by specifying the
|
||||
``o`` key. Currently, only zlib based deflate compression is supported, which is specified using
|
||||
``o=z``. For example::
|
||||
|
||||
<ESC>_Gf=24,s=10,v=20,o=z;<payload><ESC>\
|
||||
|
||||
This is the same as the example from the RGB data section, except that the
|
||||
payload is now compressed using deflate. The terminal emulator will decompress
|
||||
it before rendering. You can specify compression for any format. The terminal
|
||||
emulator will decompress before interpreting the pixel data.
|
||||
|
||||
|
||||
The transmission medium
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The transmission medium is specified using the ``t`` key. The ``t`` key defaults to ``d``
|
||||
and can take the values:
|
||||
|
||||
================== ============
|
||||
Value of `t` Meaning
|
||||
================== ============
|
||||
``d`` Direct (the data is transmitted within the escape code itself)
|
||||
``f`` A simple file
|
||||
``t`` A temporary file, the terminal emulator will delete the file after reading the pixel data
|
||||
``s`` A `POSIX shared memory object <http://man7.org/linux/man-pages/man7/shm_overview.7.html>`_.
|
||||
The terminal emulator will delete it after reading the pixel data
|
||||
================== ============
|
||||
|
||||
Local client
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
First let us consider the local client techniques (files and shared memory). Some examples::
|
||||
|
||||
<ESC>_Gf=100,t=f;<encoded /path/to/file.png><ESC>\
|
||||
|
||||
Here we tell the terminal emulator to read PNG data from the specified file of
|
||||
the specified size::
|
||||
|
||||
<ESC>_Gs=10,v=2,t=s,o=z;<encoded /some-shared-memory-name><ESC>\
|
||||
|
||||
Here we tell the terminal emulator to read compressed image data from
|
||||
the specified shared memory object.
|
||||
|
||||
The client can also specify a size and offset to tell the terminal emulator
|
||||
to only read a part of the specified file. The is done using the ``S`` and ``O``
|
||||
keys respectively. For example::
|
||||
|
||||
<ESC>_Gs=10,v=2,t=s,S=80,O=10;<encoded /some-shared-memory-name><ESC>\
|
||||
|
||||
This tells the terminal emulator to read ``80`` bytes starting from the offset ``10``
|
||||
inside the specified shared memory buffer.
|
||||
|
||||
|
||||
Remote client
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
Remote clients, those that are unable to use the filesystem/shared memory to
|
||||
transmit data, must send the pixel data directly using escape codes. Since
|
||||
escape codes are of limited maximum length, the data will need to be chunked up
|
||||
for transfer. This is done using the ``m`` key. The pixel data must first be
|
||||
base64 encoded then chunked up into chunks no larger than ``4096`` bytes. The client
|
||||
then sends the graphics escape code as usual, with the addition of an ``m`` key that
|
||||
must have the value ``1`` for all but the last chunk, where it must be ``0``. For example,
|
||||
if the data is split into three chunks, the client would send the following
|
||||
sequence of escape codes to the terminal emulator::
|
||||
|
||||
<ESC>_Gs=100,v=30,m=1;<encoded pixel data first chunk><ESC>\
|
||||
<ESC>_Gm=1;<encoded pixel data second chunk><ESC>\
|
||||
<ESC>_Gm=0;<encoded pixel data last chunk><ESC>\
|
||||
|
||||
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.
|
||||
|
||||
|
||||
Detecting 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
|
||||
(which can be an arbitrary positive integer up to 4294967295, it must not be zero).
|
||||
If it does so, the terminal emulator will reply after trying to load the image, saying
|
||||
whether loading was successful or not. For example::
|
||||
|
||||
<ESC>_Gi=31,s=10,v=2,t=s;<encoded /some-shared-memory-name><ESC>\
|
||||
|
||||
to which the terminal emulator will reply (after trying to load the data)::
|
||||
|
||||
<ESC>_Gi=31;error message or OK<ESC>\
|
||||
|
||||
Here the ``i`` value will be the same as was sent by the client in the original
|
||||
request. The message data will be a ASCII encoded string containing only
|
||||
printable characters and spaces. The string will be ``OK`` if reading the pixel
|
||||
data succeeded or an error message.
|
||||
|
||||
Sometimes, using an id is not appropriate, for example, if you do not want to
|
||||
replace a previously sent image with the same id, or if you are sending a dummy
|
||||
image and do not want it stored by the terminal emulator. In that case, you can
|
||||
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.
|
||||
|
||||
|
||||
Display images on screen
|
||||
-----------------------------
|
||||
|
||||
Every transmitted image can be displayed an arbitrary number of times on the
|
||||
screen, in different locations, using different parts of the source image, as
|
||||
needed. You can either simultaneously transmit and display an image using the
|
||||
action ``a=T``, or first transmit the image with a id, such as ``i=10`` and then display
|
||||
it with ``a=p,i=10`` which will display the previously transmitted image at the current
|
||||
cursor position. When specifying an image id, the terminal emulator will reply with an
|
||||
acknowledgement code, which will be either::
|
||||
|
||||
<ESC>_Gi=<id>;OK<ESC>\
|
||||
|
||||
when the image referred to by id was found, or::
|
||||
|
||||
<ESC>_Gi=<id>;ENOENT:<some detailed error msg><ESC>\
|
||||
|
||||
when the image with the specified id was not found. This is similar to the
|
||||
scheme described above for querying available transmission media, except that
|
||||
here we are querying if the image with the specified id is available or needs to
|
||||
be re-transmitted.
|
||||
|
||||
Controlling displayed image layout
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The image is rendered at the current cursor position, from the upper left corner of
|
||||
the current cell. You can also specify extra ``X=3`` and ``Y=4`` pixel offsets to display from
|
||||
a different origin within the cell. Note that the offsets must be smaller that the size of the cell.
|
||||
|
||||
By default, the entire image will be displayed (images wider than the available
|
||||
width will be truncated on the right edge). You can choose a source rectangle (in pixels)
|
||||
as the part of the image to display. This is done with the keys: ``x, y, w, h`` which specify
|
||||
the top-left corner, width and height of the source rectangle.
|
||||
|
||||
You can also ask the terminal emulator to display the image in a specified rectangle
|
||||
(num of columns / num of lines), using the control codes ``c,r``. ``c`` is the number of columns
|
||||
and `r` the number of rows. The image will be scaled (enlarged/shrunk) as needed to fit
|
||||
the specified area. Note that if you specify a start cell offset via the ``X,Y`` keys, it is not
|
||||
added to the number of rows/columns.
|
||||
|
||||
Finally, you can specify the image *z-index*, i.e. the vertical stacking order. Images
|
||||
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.
|
||||
|
||||
Deleting images
|
||||
---------------------
|
||||
|
||||
Images can be deleted by using the delete action ``a=d``. If specified without any
|
||||
other keys, it will delete all images visible on screen. To delete specific images,
|
||||
use the `d` key as described in the table below. Note that each value of d has
|
||||
both a lowercase and an uppercase variant. The lowercase variant only deletes the
|
||||
images without necessarily freeing up the stored image data, so that the images can be
|
||||
re-displayed without needing to resend the data. The uppercase variants will delete
|
||||
the image data as well, provided that the image is not referenced elsewhere, such as in the
|
||||
scrollback buffer. The values of the ``x`` and ``y`` keys are the same as cursor positions (i.e.
|
||||
``x=1, y=1`` is the top left cell).
|
||||
|
||||
================= ============
|
||||
Value of ``d`` Meaning
|
||||
================= ============
|
||||
``a`` or ``A`` Delete all images visible on screen
|
||||
``i`` or ``I`` Delete all images with the specified id, specified using the ``i`` key.
|
||||
``c`` or ``C`` Delete all images that intersect with the current cursor position.
|
||||
``p`` or ``P`` Delete all images that intersect a specific cell, the cell is specified using the ``x`` and ``y`` keys
|
||||
``q`` or ``Q`` Delete all images that intersect a specific cell having a specific z-index. The cell and z-index is specified using the ``x``, ``y`` and ``z`` keys.
|
||||
``x`` or ``X`` Delete all images that intersect the specified column, specified using the ``x`` key.
|
||||
``y`` or ``Y`` Delete all images that intersect the specified row, specified using the ``y`` key.
|
||||
``z`` or ``Z`` Delete all images that have the specified z-index, specified using the ``z`` key.
|
||||
================= ============
|
||||
|
||||
|
||||
|
||||
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)
|
||||
|
||||
Image persistence and storage quotas
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
In order to avoid *Denial-of-Service* attacks, terminal emulators should have a
|
||||
maximum storage quota for image data. It should allow at least a few full
|
||||
screen images. For example the quota in kitty is 320MB per buffer. When adding
|
||||
a new image, if the total size exceeds the quota, the terminal emulator should
|
||||
delete older images to make space for the new one.
|
||||
|
||||
|
||||
Control data reference
|
||||
---------------------------
|
||||
|
||||
The table below shows all the control data keys as well as what values they can
|
||||
take, and the default value they take when missing. All integers are 32-bit.
|
||||
|
||||
======= ==================== ========= =================
|
||||
Key Value Default Description
|
||||
======= ==================== ========= =================
|
||||
``a`` Single character. ``t`` The overall action this graphics command is performing.
|
||||
``(t, T, q, p, d)``
|
||||
**Keys for image transmission**
|
||||
-----------------------------------------------------------
|
||||
``f`` Positive integer. ``32`` The format in which the image data is sent.
|
||||
``(24, 32, 100)``.
|
||||
``t`` Single character. ``d`` The transmission medium used.
|
||||
``(d, f, t, s)``.
|
||||
``s`` Positive integer. ``0`` The width of the image being sent.
|
||||
``v`` Positive integer. ``0`` The height of the image being sent.
|
||||
``S`` Positive integer. ``0`` The size of data to read from a file.
|
||||
``O`` Positive integer. ``0`` The offset from which to read data from a file.
|
||||
``i`` Positive integer.
|
||||
``(0 - 4294967295)`` ``0`` The image id
|
||||
``o`` Single character. ``null`` The type of data compression.
|
||||
``only z``
|
||||
``m`` zero or one ``0`` Whether there is more chunked data available.
|
||||
**Keys for image display**
|
||||
-----------------------------------------------------------
|
||||
``x`` Positive integer ``0`` The left edge (in pixels) of the image area to display
|
||||
``y`` Positive integer ``0`` The top edge (in pixels) of the image area to display
|
||||
``w`` Positive integer ``0`` The width (in pixels) of the image area to display. By default, the entire width is used.
|
||||
``h`` Positive integer ``0`` The height (in pixels) of the image area to display. By default, the entire height is used
|
||||
``X`` Positive integer ``0`` The x-offset within the first cell at which to start displaying the image
|
||||
``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
|
||||
**Keys for deleting images**
|
||||
-----------------------------------------------------------
|
||||
``d`` Single character. ``a`` What to delete.
|
||||
``(a, A, c, C, i,
|
||||
I, p, P, q, Q, x, X,
|
||||
y, Y, z, Z)``.
|
||||
======= ==================== ========= =================
|
||||
|
||||
|
||||
Interaction with other terminal actions
|
||||
--------------------------------------------
|
||||
|
||||
When resetting the terminal, all images that are visible on the screen must be
|
||||
cleared. When switching from the main screen to the alternate screen buffer
|
||||
(1049 private mode) all images in the alternate screen must be cleared, just as
|
||||
all text is cleared. The clear screen escape code (usually ``<ESC>[2J``) should
|
||||
also clear all images. This is so that the clear command works.
|
||||
|
||||
The other commands to erase text must have no effect on graphics.
|
||||
The dedicated delete graphics commands must be used for those.
|
||||
|
||||
When scrolling the screen (such as when using index cursor movement commands,
|
||||
or scrolling through the history buffer), images must be scrolled along with
|
||||
text. When page margins are defined and the index commands are used, only
|
||||
images that are entirely within the page area (between the margins) must be
|
||||
scrolled. When scrolling them would cause them to extend outside the page area,
|
||||
they must be clipped.
|
||||
443
docs/index.rst
Normal file
443
docs/index.rst
Normal file
@@ -0,0 +1,443 @@
|
||||
:tocdepth: 2
|
||||
|
||||
==========================================================
|
||||
kitty - the fast, featureful, GPU based terminal emulator
|
||||
==========================================================
|
||||
|
||||
.. container:: major-features
|
||||
|
||||
* Offloads rendering to the GPU for :doc:`lower system load <performance>` and
|
||||
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>`.
|
||||
|
||||
* Supports tiling multiple terminal windows side by side in different
|
||||
:ref:`layouts <layouts>` without needing to use an extra program like tmux
|
||||
|
||||
* Can be :doc:`controlled from scripts or the shell prompt <remote-control>`,
|
||||
even over SSH.
|
||||
|
||||
* Has a framework for :ref:`kittens`, small terminal programs that can be used to
|
||||
extend |kitty|'s functionality. For example, they are used for
|
||||
:doc:`Unicode input <kittens/unicode-input>`, :doc:`Hints <kittens/hints>` and
|
||||
:doc:`Side-by-side diff <kittens/diff>`.
|
||||
|
||||
* Supports :ref:`startup sessions <sessions>` which allow you to specify
|
||||
the window/tab layout, working directories and programs to run on startup.
|
||||
|
||||
* Cross-platform: |kitty| works on Linux and macOS, but because it uses only
|
||||
OpenGL for rendering, it should be trivial to port to other Unix-like platforms.
|
||||
|
||||
* Allows you to open :ref:`the scrollback buffer <scrollback>` in a
|
||||
separate window using arbitrary programs of your choice. This is useful for
|
||||
browsing the history comfortably in a pager or editor.
|
||||
|
||||
|
||||
.. 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
|
||||
|
||||
|
||||
.. _quickstart:
|
||||
|
||||
Quickstart
|
||||
--------------
|
||||
|
||||
Pre-built binaries of |kitty| are available for both macOS and Linux.
|
||||
See the :doc:`binary install instructions </binary>`. You can also
|
||||
:doc:`build from source </build>`.
|
||||
|
||||
If you are on Linux, you can also use your distribution's |kitty| package.
|
||||
|kitty| packages are available for:
|
||||
`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>`_.
|
||||
|
||||
See :doc:`Configuring kitty <conf>` for help on configuring |kitty| and
|
||||
:doc:`Invocation <invocation>` for the command line arguments |kitty| supports.
|
||||
|
||||
|
||||
.. contents::
|
||||
|
||||
|
||||
Design philosophy
|
||||
-------------------
|
||||
|
||||
|kitty| is designed for power keyboard users. To that end all its controls
|
||||
work with the keyboard (although it fully supports mouse interactions as
|
||||
well). Its configuration is a simple, human editable, single file for
|
||||
easy reproducibility (I like to store configuration in source control).
|
||||
|
||||
The code in |kitty| is designed to be simple, modular and hackable. It is
|
||||
written in a mix of C (for performance sensitive parts) and Python (for
|
||||
easy hackability of the UI). It does not depend on any large and complex
|
||||
UI toolkit, using only OpenGL for rendering everything.
|
||||
|
||||
Finally, |kitty| is designed from the ground up to support all modern
|
||||
terminal features, such as unicode, true color, bold/italic fonts, text
|
||||
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.
|
||||
|
||||
Tabs and Windows
|
||||
-------------------
|
||||
|
||||
|kitty| is capable of running multiple programs organized into tabs and
|
||||
windows. The top level of organization is the *Tab*. Each tab consists
|
||||
of one or more *windows*. The windows can be arranged in multiple
|
||||
different layouts, like windows are organized in a tiling window
|
||||
manager. The keyboard controls (which are all customizable) for tabs and
|
||||
windows are:
|
||||
|
||||
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`
|
||||
======================== =======================
|
||||
|
||||
Tabs
|
||||
~~~~~~~~~~~
|
||||
|
||||
======================== =======================
|
||||
Action Shortcut
|
||||
======================== =======================
|
||||
New tab :sc:`new_tab`
|
||||
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)
|
||||
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`
|
||||
======================== =======================
|
||||
|
||||
|
||||
Windows
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
======================== =======================
|
||||
Action Shortcut
|
||||
======================== =======================
|
||||
New window :sc:`new_window`
|
||||
New OS window :sc:`new_os_window` (also :kbd:`⌘+n` on macOS)
|
||||
Close window :sc:`close_window`
|
||||
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`
|
||||
(clockwise from the top-left)
|
||||
======================== =======================
|
||||
|
||||
Additionally, you can define shortcuts in :file:`kitty.conf` to focus neighboring
|
||||
windows and move windows around (similar to window movement in vim)::
|
||||
|
||||
map ctrl+left neighboring_window left
|
||||
map shift+left move_window right
|
||||
map ctrl+down neighboring_window down
|
||||
map shift+down move_window up
|
||||
...
|
||||
|
||||
You can also define a shortcut to switch to the previously active window::
|
||||
|
||||
map ctrl+p nth_window -1
|
||||
|
||||
``nth_window`` will focus the nth window for positive numbers and the
|
||||
previously active windows for negative numbers.
|
||||
|
||||
|
||||
Other keyboard shortcuts
|
||||
----------------------------------
|
||||
|
||||
================================== =======================
|
||||
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
|
||||
Input unicode character :sc:`input_unicode_character`
|
||||
Click URL using the keyboard :sc:`open_url`
|
||||
Reset the terminal :sc:`reset_terminal`
|
||||
Pass current selection to program :sc:`pass_selection_to_program`
|
||||
Edit |kitty| config file :sc:`edit_config_file`
|
||||
Open a |kitty| shell :sc:`kitty_shell`
|
||||
Increase background opacity :sc:`increase_background_opacity`
|
||||
Decrease background opacity :sc:`decrease_background_opacity`
|
||||
Full background opacity :sc:`full_background_opacity`
|
||||
Reset background opacity :sc:`reset_background_opacity`
|
||||
================================== =======================
|
||||
|
||||
|
||||
.. _layouts:
|
||||
|
||||
Layouts
|
||||
----------
|
||||
|
||||
A layout is an arrangement of multiple *windows*. You can create a new window
|
||||
using the :sc:`new_window` key combination.
|
||||
|
||||
Currently, there are five 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
|
||||
* **Grid** -- All windows are shown in a grid
|
||||
* **Horizontal** -- All windows are shown side-by-side
|
||||
* **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.
|
||||
|
||||
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.
|
||||
|
||||
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!
|
||||
|
||||
.. _kittens:
|
||||
|
||||
Kittens
|
||||
------------------
|
||||
|
||||
|kitty| has a framework for easily creating terminal programs that make use of
|
||||
its advanced features. These programs are called kittens. They are used both
|
||||
to add features to |kitty| itself and to create useful standalone programs.
|
||||
Some prominent kittens:
|
||||
|
||||
:doc:`icat <kittens/icat>`
|
||||
Display images in the terminal
|
||||
|
||||
|
||||
:doc:`diff <kittens/diff>`
|
||||
A fast, side-by-side diff for the terminal with syntax highlighting and
|
||||
images
|
||||
|
||||
|
||||
:doc:`Unicode Input <kittens/unicode-input>`
|
||||
Easily input arbitrary unicode characters in |kitty| by name or hex code.
|
||||
|
||||
|
||||
:doc:`Hints <kittens/hints>`
|
||||
Select and open/paste/insert arbitrary text snippets such as URLs,
|
||||
filenames, words, lines, etc from the terminal screen.
|
||||
|
||||
|
||||
:doc:`Panel <kittens/panel>`
|
||||
Draw a GPU accelerated dock panel on your desktop showing the output
|
||||
from an arbitrary terminal program.
|
||||
|
||||
:doc:`Clipboard <kittens/clipboard>`
|
||||
Copy/paste to the clipboard from shell scripts, even over SSH.
|
||||
|
||||
You can also :doc:`Learn to create your own kittens <kittens/custom>`.
|
||||
|
||||
|
||||
Configuring kitty
|
||||
-------------------
|
||||
|
||||
|kitty| is highly configurable, everything from keyboard shortcuts to
|
||||
painting frames-per-second. For details and a sample :file:`kitty.conf`,
|
||||
see the :doc:`configuration docs <conf>`.
|
||||
|
||||
|
||||
Remote control
|
||||
------------------
|
||||
|
||||
|kitty| has a very powerful system that allows you to control it from the
|
||||
:doc:`shell prompt, even over SSH <remote-control>`. You can change colors,
|
||||
fonts, open new windows, tabs, set their titles, change window layout, get text
|
||||
from one window and send text to another, etc, etc. The possibilities are
|
||||
endless. See the :doc:`tutorial <remote-control>` to get started.
|
||||
|
||||
.. _sessions:
|
||||
|
||||
Startup Sessions
|
||||
------------------
|
||||
|
||||
You can control the tabs, window layout, working directory, startup programs,
|
||||
etc. by creating a "session" file and using the :option:`kitty --session`
|
||||
command line flag or the :opt:`startup_session` option in :file:`kitty.conf`.
|
||||
For example:
|
||||
|
||||
.. code-block:: session
|
||||
|
||||
# Set the window layout for the current tab
|
||||
layout tall
|
||||
# Set the working directory for windows in the current tab
|
||||
cd ~
|
||||
# Create a window and run the specified command in it
|
||||
launch zsh
|
||||
# Create a window with some environment variables set and run
|
||||
# vim in it
|
||||
launch env FOO=BAR vim
|
||||
# Set the title for the next window
|
||||
title Chat with x
|
||||
launch irssi --profile x
|
||||
|
||||
# Create a new tab (the part after new_tab is the optional tab
|
||||
# name which will be displayed in the tab bar, if omitted, the
|
||||
# title of the active window will be used instead)
|
||||
new_tab my tab
|
||||
cd ~/somewhere
|
||||
# Set the layouts allowed in this tab
|
||||
enabled_layouts tall, stack
|
||||
# Set the current layout
|
||||
layout stack
|
||||
launch zsh
|
||||
# Make the current window the active (focused) window
|
||||
focus
|
||||
launch emacs
|
||||
|
||||
|
||||
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+alt` and drag with the mouse to select in
|
||||
columns
|
||||
|
||||
|
||||
Font control
|
||||
-----------------
|
||||
|
||||
|kitty| has extremely flexible and powerful font selection features. You can
|
||||
specify individual families for the regular, bold, italic and bold+italic
|
||||
fonts. You can even specify specific font families for specific ranges of
|
||||
unicode characters. This allows precise control over text rendering. It can
|
||||
come in handy for applications like powerline, without the need to use patched
|
||||
fonts. See the various font related configuration directives in
|
||||
:ref:`conf-kitty-fonts`.
|
||||
|
||||
|
||||
.. _scrollback:
|
||||
|
||||
The scrollback buffer
|
||||
-----------------------
|
||||
|
||||
|kitty| supports scrolling back to view history, just like most terminals. You
|
||||
can use either keyboard shortcuts or the mouse scroll wheel to do so. However,
|
||||
|kitty| has an extra, neat feature. Sometimes you need to explore the
|
||||
scrollback buffer in more detail, maybe search for some text or refer to it
|
||||
side-by-side while typing in a follow-up command. |kitty| allows you to do this
|
||||
by pressing the :sc:`show_scrollback` key-combination, which will open the
|
||||
scrollback buffer in your favorite pager program (which is ``less`` by default).
|
||||
Colors and text formatting are preserved. You can explore the scrollback buffer
|
||||
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
|
||||
|
||||
Would open the scrollback buffer in a new window when you press the :kbd:`F1`
|
||||
key. See :sc:`show_scrollback` for details.
|
||||
|
||||
If you wish to store very large amounts of scrollback to view using the piping or
|
||||
:sc:`show_scrollback` features, you can use the :opt:`scrollback_pager_history_size`
|
||||
option.
|
||||
|
||||
Frequently Asked Questions
|
||||
---------------------------------
|
||||
|
||||
The list of Frequently Asked Questions (*FAQ*) is :doc:`available here <faq>`.
|
||||
|
||||
.. _completion:
|
||||
|
||||
Completion for kitty
|
||||
---------------------------------
|
||||
|
||||
|kitty| comes with completion for the ``kitty`` command for popular shells.
|
||||
|
||||
|
||||
bash
|
||||
~~~~~~~~
|
||||
|
||||
Add the following to your :file:`~/.bashrc`
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
source <(kitty + complete setup bash)
|
||||
|
||||
|
||||
zsh
|
||||
~~~~~~~~~
|
||||
|
||||
Add the following to your :file:`~/.zshrc`
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
autoload -Uz compinit
|
||||
compinit
|
||||
# Completion for kitty
|
||||
kitty + complete setup zsh | source /dev/stdin
|
||||
|
||||
The important thing above is to make sure the call to |kitty| to load the zsh
|
||||
completions happens after the call to :file:`compinit`.
|
||||
|
||||
|
||||
fish
|
||||
~~~~~~~~
|
||||
|
||||
Add the following to your :file:`~/.config/fish/config.fish`
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
kitty + complete setup fish | source
|
||||
|
||||
|
||||
Changelog
|
||||
------------------
|
||||
|
||||
See :doc:`changelog`.
|
||||
|
||||
.. toctree::
|
||||
:hidden:
|
||||
:glob:
|
||||
|
||||
*
|
||||
kittens/*
|
||||
241
docs/installer.py
Normal file
241
docs/installer.py
Normal file
@@ -0,0 +1,241 @@
|
||||
#!/usr/bin/env python
|
||||
# vim:fileencoding=utf-8
|
||||
# License: GPL v3 Copyright: 2018, Kovid Goyal <kovid at kovidgoyal.net>
|
||||
|
||||
from __future__ import (
|
||||
absolute_import, division, print_function, unicode_literals
|
||||
)
|
||||
|
||||
import atexit
|
||||
import json
|
||||
import os
|
||||
import platform
|
||||
import re
|
||||
import shlex
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
|
||||
py3 = sys.version_info[0] > 2
|
||||
is64bit = platform.architecture()[0] == '64bit'
|
||||
is_macos = 'darwin' in sys.platform.lower()
|
||||
|
||||
try:
|
||||
__file__
|
||||
from_file = True
|
||||
except NameError:
|
||||
from_file = False
|
||||
|
||||
if py3:
|
||||
unicode = str
|
||||
raw_input = input
|
||||
import urllib.request as urllib
|
||||
|
||||
def encode_for_subprocess(x):
|
||||
return x
|
||||
else:
|
||||
from future_builtins import map
|
||||
import urllib2 as urllib
|
||||
|
||||
def encode_for_subprocess(x):
|
||||
if isinstance(x, unicode):
|
||||
x = x.encode('utf-8')
|
||||
return x
|
||||
|
||||
|
||||
def run(*args):
|
||||
if len(args) == 1:
|
||||
args = shlex.split(args[0])
|
||||
args = list(map(encode_for_subprocess, args))
|
||||
ret = subprocess.Popen(args).wait()
|
||||
if ret != 0:
|
||||
raise SystemExit(ret)
|
||||
|
||||
|
||||
class Reporter: # {{{
|
||||
|
||||
def __init__(self, fname):
|
||||
self.fname = fname
|
||||
self.last_percent = 0
|
||||
|
||||
def __call__(self, blocks, block_size, total_size):
|
||||
percent = (blocks*block_size)/float(total_size)
|
||||
report = '\rDownloaded {:.1%} '.format(percent)
|
||||
if percent - self.last_percent > 0.05:
|
||||
self.last_percent = percent
|
||||
print(report, end='')
|
||||
sys.stdout.flush()
|
||||
# }}}
|
||||
|
||||
|
||||
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')
|
||||
data = json.loads(res)
|
||||
html_url = data['html_url'].replace('/tag/', '/download/').rstrip('/')
|
||||
for asset in data.get('assets', ()):
|
||||
name = asset['name']
|
||||
if is_macos:
|
||||
if name.endswith('.dmg'):
|
||||
return html_url + '/' + name, asset['size']
|
||||
else:
|
||||
if name.endswith('.txz'):
|
||||
if is64bit:
|
||||
if name.endswith('-x86_64.txz'):
|
||||
return html_url + '/' + name, asset['size']
|
||||
else:
|
||||
if name.endswith('-i686.txz'):
|
||||
return html_url + '/' + name, asset['size']
|
||||
raise SystemExit('Failed to find the installer package on github')
|
||||
|
||||
|
||||
def do_download(url, size, dest):
|
||||
print('Will download and install', os.path.basename(dest))
|
||||
reporter = Reporter(os.path.basename(dest))
|
||||
|
||||
# Get content length and check if range is supported
|
||||
rq = urllib.urlopen(url)
|
||||
headers = rq.info()
|
||||
sent_size = int(headers['content-length'])
|
||||
if sent_size != size:
|
||||
raise SystemExit('Failed to download from {} Content-Length ({}) != {}'.format(url, sent_size, size))
|
||||
with open(dest, 'wb') as f:
|
||||
while f.tell() < size:
|
||||
raw = rq.read(8192)
|
||||
if not raw:
|
||||
break
|
||||
f.write(raw)
|
||||
reporter(f.tell(), 1, size)
|
||||
rq.close()
|
||||
if os.path.getsize(dest) < size:
|
||||
raise SystemExit('Download failed, try again later')
|
||||
print('\rDownloaded {} bytes'.format(os.path.getsize(dest)))
|
||||
|
||||
|
||||
def clean_cache(cache, fname):
|
||||
for x in os.listdir(cache):
|
||||
if fname not in x:
|
||||
os.remove(os.path.join(cache, x))
|
||||
|
||||
|
||||
def download_installer(url, size):
|
||||
fname = url.rpartition('/')[-1]
|
||||
tdir = tempfile.gettempdir()
|
||||
cache = os.path.join(tdir, 'kitty-installer-cache')
|
||||
if not os.path.exists(cache):
|
||||
os.makedirs(cache)
|
||||
clean_cache(cache, fname)
|
||||
dest = os.path.join(cache, fname)
|
||||
if os.path.exists(dest) and os.path.getsize(dest) == size:
|
||||
print('Using previously downloaded', fname)
|
||||
return dest
|
||||
if os.path.exists(dest):
|
||||
os.remove(dest)
|
||||
do_download(url, size, dest)
|
||||
return dest
|
||||
|
||||
|
||||
def macos_install(dmg, dest='/Applications', launch=True):
|
||||
mp = tempfile.mkdtemp()
|
||||
atexit.register(shutil.rmtree, mp)
|
||||
run('hdiutil', 'attach', dmg, '-mountpoint', mp)
|
||||
try:
|
||||
os.chdir(mp)
|
||||
app = 'kitty.app'
|
||||
d = os.path.join(dest, app)
|
||||
if os.path.exists(d):
|
||||
shutil.rmtree(d)
|
||||
dest = os.path.join(dest, app)
|
||||
run('ditto', '-v', app, dest)
|
||||
print('Successfully installed kitty into', dest)
|
||||
if launch:
|
||||
run('open', dest)
|
||||
finally:
|
||||
os.chdir('/')
|
||||
run('hdiutil', 'detach', mp)
|
||||
|
||||
|
||||
def linux_install(installer, dest=os.path.expanduser('~/.local'), launch=True):
|
||||
dest = os.path.join(dest, 'kitty.app')
|
||||
if os.path.exists(dest):
|
||||
shutil.rmtree(dest)
|
||||
os.makedirs(dest)
|
||||
print('Extracting tarball...')
|
||||
run('tar', '-C', dest, '-xJof', installer)
|
||||
print('kitty successfully installed to', dest)
|
||||
kitty = os.path.join(dest, 'bin', 'kitty')
|
||||
print('Use', kitty, 'to run kitty')
|
||||
if launch:
|
||||
run(kitty, '--detach')
|
||||
|
||||
|
||||
def main(dest=None, launch=True, installer=None):
|
||||
if not dest:
|
||||
if is_macos:
|
||||
dest = '/Applications'
|
||||
else:
|
||||
dest = os.path.expanduser('~/.local')
|
||||
machine = os.uname()[4]
|
||||
if machine and machine.lower().startswith('arm'):
|
||||
raise SystemExit(
|
||||
'You are running on an ARM system. The kitty binaries are only'
|
||||
' available for x86 systems. You will have to build from'
|
||||
' source.')
|
||||
if not installer:
|
||||
url, size = get_latest_release_data()
|
||||
installer = download_installer(url, size)
|
||||
else:
|
||||
installer = os.path.abspath(installer)
|
||||
if not os.access(installer, os.R_OK):
|
||||
raise SystemExit('Could not read from: {}'.format(installer))
|
||||
if is_macos:
|
||||
macos_install(installer, dest=dest, launch=launch)
|
||||
else:
|
||||
linux_install(installer, dest=dest, launch=launch)
|
||||
|
||||
|
||||
def script_launch():
|
||||
# To test: python3 -c "import runpy; runpy.run_path('installer.py', run_name='script_launch')"
|
||||
def path(x):
|
||||
return os.path.expandvars(os.path.expanduser(x))
|
||||
|
||||
def to_bool(x):
|
||||
return x.lower() in {'y', 'yes', '1', 'true'}
|
||||
|
||||
type_map = {x: path for x in 'dest installer'.split()}
|
||||
type_map['launch'] = to_bool
|
||||
kwargs = {}
|
||||
|
||||
for arg in sys.argv[1:]:
|
||||
if arg:
|
||||
m = re.match('([a-z_]+)=(.+)', arg)
|
||||
if m is None:
|
||||
raise SystemExit('Unrecognized command line argument: ' + arg)
|
||||
k = m.group(1)
|
||||
if k not in type_map:
|
||||
raise SystemExit('Unrecognized command line argument: ' + arg)
|
||||
kwargs[k] = type_map[k](m.group(2))
|
||||
main(**kwargs)
|
||||
|
||||
|
||||
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')
|
||||
wrapper = sys.argv[-1]
|
||||
with open(wrapper, 'r+b') as f:
|
||||
raw = f.read().decode('utf-8')
|
||||
nraw = re.sub(r'^# HEREDOC_START.+^# HEREDOC_END', lambda m: '# HEREDOC_START\n{}\n# HEREDOC_END'.format(src), raw, flags=re.MULTILINE | re.DOTALL)
|
||||
if 'update_intaller_wrapper()' not in nraw:
|
||||
raise SystemExit('regex substitute of HEREDOC failed')
|
||||
f.seek(0), f.truncate()
|
||||
f.write(nraw.encode('utf-8'))
|
||||
|
||||
|
||||
if __name__ == '__main__' and from_file:
|
||||
main()
|
||||
elif __name__ == 'update_wrapper':
|
||||
update_intaller_wrapper()
|
||||
elif __name__ == 'script_launch':
|
||||
script_launch()
|
||||
30
docs/installer.sh
Normal file
30
docs/installer.sh
Normal file
@@ -0,0 +1,30 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# installer.sh
|
||||
# Copyright (C) 2018 Kovid Goyal <kovid at kovidgoyal.net>
|
||||
#
|
||||
# Distributed under terms of the GPLv3 license.
|
||||
#
|
||||
|
||||
python=$(command -v python3)
|
||||
if [ -z "$python" ]; then
|
||||
python=$(command -v python2)
|
||||
fi
|
||||
if [ -z "$python" ]; then
|
||||
python=$(command -v python2.7)
|
||||
fi
|
||||
if [ -z "$python" ]; then
|
||||
python=$(command -v python)
|
||||
fi
|
||||
if [ -z "$python" ]; then
|
||||
python=python
|
||||
fi
|
||||
|
||||
echo Using python executable: $python
|
||||
|
||||
$python -c "import sys; script_launch=lambda:sys.exit('Download of installer failed!'); exec(sys.stdin.read()); script_launch()" "$@" <<'INSTALLER_HEREDOC'
|
||||
# {{{
|
||||
# HEREDOC_START
|
||||
# HEREDOC_END
|
||||
# }}}
|
||||
INSTALLER_HEREDOC
|
||||
6
docs/invocation.rst
Normal file
6
docs/invocation.rst
Normal file
@@ -0,0 +1,6 @@
|
||||
The kitty command line interface
|
||||
====================================
|
||||
|
||||
.. program:: kitty
|
||||
|
||||
.. include:: generated/cli-kitty.rst
|
||||
128
docs/key-encoding.rst
Normal file
128
docs/key-encoding.rst
Normal file
@@ -0,0 +1,128 @@
|
||||
Key encoding for extended keyboard protocol
|
||||
===============================================
|
||||
|
||||
See :ref:`extended-key-protocol` for more information and `this table in JSON
|
||||
format <https://github.com/kovidgoyal/kitty/blob/master/key_encoding.json>`_.
|
||||
|
||||
===================== ======================
|
||||
Name Encoded representation
|
||||
0 ``G``
|
||||
1 ``H``
|
||||
2 ``I``
|
||||
3 ``J``
|
||||
4 ``K``
|
||||
5 ``L``
|
||||
6 ``M``
|
||||
7 ``N``
|
||||
8 ``O``
|
||||
9 ``P``
|
||||
A ``S``
|
||||
APOSTROPHE ``B``
|
||||
B ``T``
|
||||
BACKSLASH ``t``
|
||||
BACKSPACE ``1``
|
||||
C ``U``
|
||||
CAPS LOCK ``:``
|
||||
COMMA ``C``
|
||||
D ``V``
|
||||
DELETE ``3``
|
||||
DOWN ``6``
|
||||
E ``W``
|
||||
END ``-``
|
||||
ENTER ``z``
|
||||
EQUAL ``R``
|
||||
ESCAPE ``y``
|
||||
F ``X``
|
||||
F1 ``/``
|
||||
F10 ``]``
|
||||
F11 ``{``
|
||||
F12 ``}``
|
||||
F13 ``@``
|
||||
F14 ``%``
|
||||
F15 ``$``
|
||||
F16 ``#``
|
||||
F17 ``BA``
|
||||
F18 ``BB``
|
||||
F19 ``BC``
|
||||
F2 ``*``
|
||||
F20 ``BD``
|
||||
F21 ``BE``
|
||||
F22 ``BF``
|
||||
F23 ``BG``
|
||||
F24 ``BH``
|
||||
F25 ``BI``
|
||||
F3 ``?``
|
||||
F4 ``&``
|
||||
F5 ``<``
|
||||
F6 ``>``
|
||||
F7 ``(``
|
||||
F8 ``)``
|
||||
F9 ``[``
|
||||
G ``Y``
|
||||
GRAVE ACCENT ``v``
|
||||
H ``Z``
|
||||
HOME ``.``
|
||||
I ``a``
|
||||
INSERT ``2``
|
||||
J ``b``
|
||||
K ``c``
|
||||
KP 0 ``BJ``
|
||||
KP 1 ``BK``
|
||||
KP 2 ``BL``
|
||||
KP 3 ``BM``
|
||||
KP 4 ``BN``
|
||||
KP 5 ``BO``
|
||||
KP 6 ``BP``
|
||||
KP 7 ``BQ``
|
||||
KP 8 ``BR``
|
||||
KP 9 ``BS``
|
||||
KP ADD ``BX``
|
||||
KP DECIMAL ``BT``
|
||||
KP DIVIDE ``BU``
|
||||
KP ENTER ``BY``
|
||||
KP EQUAL ``BZ``
|
||||
KP MULTIPLY ``BV``
|
||||
KP SUBTRACT ``BW``
|
||||
L ``d``
|
||||
LEFT ``5``
|
||||
LEFT ALT ``Bc``
|
||||
LEFT BRACKET ``s``
|
||||
LEFT CONTROL ``Bb``
|
||||
LEFT SHIFT ``Ba``
|
||||
LEFT SUPER ``Bd``
|
||||
M ``e``
|
||||
MINUS ``D``
|
||||
N ``f``
|
||||
NUM LOCK ``=``
|
||||
O ``g``
|
||||
P ``h``
|
||||
PAGE DOWN ``9``
|
||||
PAGE UP ``8``
|
||||
PAUSE ``!``
|
||||
PERIOD ``E``
|
||||
PRINT SCREEN ``^``
|
||||
Q ``i``
|
||||
R ``j``
|
||||
RIGHT ``4``
|
||||
RIGHT ALT ``Bg``
|
||||
RIGHT BRACKET ``u``
|
||||
RIGHT CONTROL ``Bf``
|
||||
RIGHT SHIFT ``Be``
|
||||
RIGHT SUPER ``Bh``
|
||||
S ``k``
|
||||
SCROLL LOCK ``+``
|
||||
SEMICOLON ``Q``
|
||||
SLASH ``F``
|
||||
SPACE ``A``
|
||||
T ``l``
|
||||
TAB ``0``
|
||||
U ``m``
|
||||
UP ``7``
|
||||
V ``n``
|
||||
W ``o``
|
||||
WORLD 1 ``w``
|
||||
WORLD 2 ``x``
|
||||
X ``p``
|
||||
Y ``q``
|
||||
Z ``r``
|
||||
===================== ======================
|
||||
27
docs/kittens/clipboard.rst
Normal file
27
docs/kittens/clipboard.rst
Normal file
@@ -0,0 +1,27 @@
|
||||
clipboard - copy/paste to the system clipboard
|
||||
==================================================
|
||||
|
||||
.. highlight:: sh
|
||||
|
||||
|
||||
The ``clipboard`` kitten can be used to read or write to the system clipboard
|
||||
from the shell. It even works over SSH. Using it is as simple as::
|
||||
|
||||
echo hooray | kitty +kitten clipboard
|
||||
|
||||
All text received on :file:`stdin` is copied to the clipboard.
|
||||
|
||||
To get text from the clipboard you have to enable reading of the clipboard
|
||||
in :opt:`clipboard_control` in :file:`kitty.conf`. Once you do that, you can
|
||||
use::
|
||||
|
||||
kitty +kitten clipboard --get-clipboard
|
||||
|
||||
|
||||
.. program:: kitty +kitten clipboard
|
||||
|
||||
|
||||
Command Line Interface
|
||||
--------------------------
|
||||
|
||||
.. include:: /generated/cli-kitten-clipboard.rst
|
||||
122
docs/kittens/custom.rst
Normal file
122
docs/kittens/custom.rst
Normal file
@@ -0,0 +1,122 @@
|
||||
Custom kittens
|
||||
=================
|
||||
|
||||
You can easily create your own kittens to extend kitty. They are just
|
||||
terminal programs written in Python. When launching a kitten, kitty will
|
||||
open an overlay window over the current window and optionally pass the
|
||||
contents of the current window/scrollback to the kitten over its :file:`STDIN`.
|
||||
The kitten can then perform whatever actions it likes, just as a normal
|
||||
terminal program. After execution of the kitten is complete, it has access
|
||||
to the running kitty instance so it can perform arbitrary actions
|
||||
such as closing windows, pasting text, etc.
|
||||
|
||||
Let's see a simple example of creating a kitten. It will ask the user for some
|
||||
input and paste it into the terminal window.
|
||||
|
||||
Create a file in the kitty config folder, :file:`~/.config/kitty/mykitten.py`
|
||||
(you might need to adjust the path to wherever the kitty config folder is on
|
||||
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 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)
|
||||
|
||||
|
||||
Now in :file:`kitty.conf` add the lines::
|
||||
|
||||
map ctrl+k kitten mykitten.py
|
||||
|
||||
|
||||
Start kitty and press :kbd:`ctrl+k` and you should see the kitten running.
|
||||
The best way to develop your own kittens is to modify one of the built in
|
||||
kittens. Look in the kittens sub-directory of the kitty source code for those.
|
||||
|
||||
|
||||
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
|
||||
|
||||
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.
|
||||
|
||||
|
||||
Passing the contents of the screen to the kitten
|
||||
---------------------------------------------------
|
||||
|
||||
If you would like your kitten to have access to the contents of the screen
|
||||
and/or the scrollback buffer, you just need to add an annotation to the ``handle_result()``
|
||||
function, telling kitty what kind of input your kitten would like. For example:
|
||||
|
||||
.. code-block:: py
|
||||
|
||||
def handle_result(...):
|
||||
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``.
|
||||
|
||||
|
||||
Using kittens to script kitty, without any terminal UI
|
||||
-----------------------------------------------------------
|
||||
|
||||
If you would like your kitten to script kitty, without bothering to write a
|
||||
terminal program, you can tell the kittens system to run the
|
||||
``handle_result()`` function without first running the ``main()`` function.
|
||||
|
||||
For example, here is a kitten that "zooms/unzooms" the current terminal window
|
||||
by switching to the stack layout or back to the previous layout.
|
||||
|
||||
Create a file in the kitty config folder, :file:`~/.config/kitty/zoom_toggle.py`
|
||||
|
||||
.. code-block:: py
|
||||
|
||||
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
|
||||
|
||||
|
||||
Now in kitty.conf add::
|
||||
|
||||
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
|
||||
layout, by simply adding the line::
|
||||
|
||||
boss.toggle_fullscreen()
|
||||
|
||||
|
||||
to the ``handle_result()`` function, above.
|
||||
157
docs/kittens/diff.rst
Normal file
157
docs/kittens/diff.rst
Normal file
@@ -0,0 +1,157 @@
|
||||
kitty-diff - A fast side-by-side diff tool with syntax highlighting and images
|
||||
================================================================================
|
||||
|
||||
.. highlight:: sh
|
||||
|
||||
Major Features
|
||||
-----------------
|
||||
|
||||
.. container:: major-features
|
||||
|
||||
* Displays diffs side-by-side in the kitty terminal
|
||||
|
||||
* Does syntax highlighting of the displayed diffs, asynchronously, for maximum
|
||||
speed
|
||||
|
||||
* Displays images as well as text diffs, even over SSH
|
||||
|
||||
* Does recursive directory diffing
|
||||
|
||||
|
||||
.. figure:: ../screenshots/diff.png
|
||||
:alt: Screenshot, showing a sample diff
|
||||
:align: center
|
||||
:scale: 100%
|
||||
|
||||
Screenshot, showing a sample diff
|
||||
|
||||
.. contents::
|
||||
|
||||
|
||||
Installation
|
||||
---------------
|
||||
|
||||
Simply :ref:`install kitty <quickstart>`. You also need
|
||||
to have either the `git <https://git-scm.com/>`_ program or the ``diff`` program
|
||||
installed. Additionally, for syntax highlighting to work,
|
||||
`pygments <http://pygments.org/>`_ must be installed (note that pygments is
|
||||
included in the macOS kitty app).
|
||||
|
||||
|
||||
Usage
|
||||
--------
|
||||
|
||||
In the kitty terminal, run::
|
||||
|
||||
kitty +kitten diff file1 file2
|
||||
|
||||
to see the diff between file1 and file2.
|
||||
|
||||
Create an alias in your shell's startup file to shorten the command, for example:
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
alias d="kitty +kitten diff"
|
||||
|
||||
Now all you need to do to diff two files is::
|
||||
|
||||
d file1 file2
|
||||
|
||||
You can also pass directories instead of files to see the recursive diff of the
|
||||
directory contents.
|
||||
|
||||
|
||||
Keyboard controls
|
||||
----------------------
|
||||
|
||||
========================= ===========================
|
||||
Action Shortcut
|
||||
========================= ===========================
|
||||
Quit :kbd:`q, Ctrl+c, Esc`
|
||||
Scroll line up :kbd:`k, up`
|
||||
Scroll line down :kbd:`j, down`
|
||||
Scroll page up :kbd:`PgUp`
|
||||
Scroll page down :kbd:`PgDn`
|
||||
Scroll to top :kbd:`Home`
|
||||
Scroll to bottom :kbd:`End`
|
||||
Scroll to next page :kbd:`Space, PgDn`
|
||||
Scroll to previous page :kbd:`PgUp`
|
||||
Scroll to next change :kbd:`n`
|
||||
Scroll to previous change :kbd:`p`
|
||||
Increase lines of context :kbd:`+`
|
||||
Decrease lines of context :kbd:`-`
|
||||
All lines of context :kbd:`a`
|
||||
Restore default context :kbd:`=`
|
||||
Search forwards :kbd:`/`
|
||||
Search backwards :kbd:`?`
|
||||
Clear search :kbd:`Esc`
|
||||
Scroll to next match :kbd:`>, .`
|
||||
Scroll to previous match :kbd:`<, ,`
|
||||
========================= ===========================
|
||||
|
||||
|
||||
Integrating with git
|
||||
-----------------------
|
||||
|
||||
Add the following to `~/.gitconfig`:
|
||||
|
||||
.. code-block:: ini
|
||||
|
||||
[diff]
|
||||
tool = kitty
|
||||
guitool = kitty.gui
|
||||
[difftool]
|
||||
prompt = false
|
||||
trustExitCode = true
|
||||
[difftool "kitty"]
|
||||
cmd = kitty +kitten diff $LOCAL $REMOTE
|
||||
[difftool "kitty.gui"]
|
||||
cmd = kitty kitty +kitten diff $LOCAL $REMOTE
|
||||
|
||||
Now to use kitty-diff to view git diffs, you can simply do::
|
||||
|
||||
git difftool --no-symlinks --dir-diff
|
||||
|
||||
Once again, creating an alias for this command is useful.
|
||||
|
||||
|
||||
Why does this work only in kitty?
|
||||
----------------------------------------
|
||||
|
||||
The diff kitten makes use of various features that are :doc:`kitty only
|
||||
</protocol-extensions>`, such as the :doc:`kitty graphics protocol
|
||||
</graphics-protocol>`, the :ref:`extended keyboard protocol
|
||||
<extended-key-protocol>`, etc. It also leverages terminal program
|
||||
infrastructure I created for all of kitty's other kittens to reduce the amount
|
||||
of code needed (the entire implementation is under 2000 lines of code).
|
||||
|
||||
And fundamentally, it's kitty only because I wrote it for myself, and I am
|
||||
highly unlikely to use any other terminals :)
|
||||
|
||||
|
||||
|
||||
Configuration
|
||||
------------------------
|
||||
|
||||
You can configure the colors used, keyboard shortcuts, the diff implementation,
|
||||
the default lines of context, etc. by creating a :file:`diff.conf` file in
|
||||
your :ref:`kitty config folder <confloc>`. See below for the supported
|
||||
configuration directives.
|
||||
|
||||
|
||||
.. include:: /generated/conf-kitten-diff.rst
|
||||
|
||||
|
||||
Command Line Interface
|
||||
-------------------------
|
||||
|
||||
.. include:: /generated/cli-kitten-diff.rst
|
||||
|
||||
|
||||
|
||||
Sample diff.conf
|
||||
-----------------
|
||||
|
||||
You can download a sample :file:`diff.conf` file with all default settings and
|
||||
comments describing each setting by clicking: :download:`sample diff.conf
|
||||
</generated/conf/diff.conf>`.
|
||||
29
docs/kittens/hints.rst
Normal file
29
docs/kittens/hints.rst
Normal file
@@ -0,0 +1,29 @@
|
||||
Hints
|
||||
==========
|
||||
|
||||
|kitty| has a *hints mode* to select and act on arbitrary text snippets currently
|
||||
visible on the screen. For example, you can press :sc:`open_url`
|
||||
to choose any URL visible on the screen and then open it using your system
|
||||
browser.
|
||||
|
||||
.. figure:: ../screenshots/hints_mode.png
|
||||
:alt: URL hints mode
|
||||
:align: center
|
||||
:scale: 100%
|
||||
|
||||
URL hints mode
|
||||
|
||||
Similarly, you can press :sc:`insert_selected_path` to
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
Command Line Interface
|
||||
-------------------------
|
||||
|
||||
.. include:: ../generated/cli-kitten-hints.rst
|
||||
35
docs/kittens/icat.rst
Normal file
35
docs/kittens/icat.rst
Normal file
@@ -0,0 +1,35 @@
|
||||
icat - Display images in the terminal
|
||||
========================================
|
||||
|
||||
The ``icat`` kitten can be used to display arbitrary images in the |kitty|
|
||||
terminal. Using it is as simple as::
|
||||
|
||||
kitty +kitten icat image.jpeg
|
||||
|
||||
It supports all image types supported by `ImageMagick
|
||||
<https://www.imagemagick.org>`_. It even works over SSH. For details, see
|
||||
the :doc:`kitty graphics protocol </graphics-protocol>`.
|
||||
|
||||
You might want to create an alias in your shell's configuration files::
|
||||
|
||||
alias icat="kitty +kitten icat"
|
||||
|
||||
Then you can simply use ``icat image.png`` to view images.
|
||||
|
||||
.. note::
|
||||
|
||||
`ImageMagick <https://www.imagemagick.org>`_ must be installed for ``icat`` to
|
||||
work.
|
||||
|
||||
|
||||
.. program:: kitty +kitten icat
|
||||
|
||||
|
||||
The ``icat`` kitten has various command line arguments to allow it to be used
|
||||
from inside other programs to display images. In particular, :option:`--place`,
|
||||
:option:`--detect-support` and :option:`--print-window-size`.
|
||||
|
||||
Command Line Interface
|
||||
--------------------------
|
||||
|
||||
.. include:: /generated/cli-kitten-icat.rst
|
||||
43
docs/kittens/panel.rst
Normal file
43
docs/kittens/panel.rst
Normal file
@@ -0,0 +1,43 @@
|
||||
Draw a GPU accelerated dock panel on your desktop
|
||||
====================================================================================================
|
||||
|
||||
.. highlight:: sh
|
||||
|
||||
|
||||
You can use this kitten to draw a GPU accelerated panel on the edge
|
||||
of your screen, that shows the output from an arbitrary terminal program.
|
||||
|
||||
It is useful for showing status information or notifications on your desktop
|
||||
using terminal programs instead of GUI toolkits.
|
||||
|
||||
|
||||
.. figure:: ../screenshots/panel.png
|
||||
:alt: Screenshot, showing a sample panel
|
||||
:align: center
|
||||
:scale: 100%
|
||||
|
||||
Screenshot, showing a sample panel
|
||||
|
||||
|
||||
The screenshot above shows a sample panel that displays the current desktop and
|
||||
window title as well as miscellaneous system information such as network
|
||||
activity, CPU load, date/time, etc.
|
||||
|
||||
.. note::
|
||||
|
||||
This kitten currently only works on X11 desktops
|
||||
|
||||
Using this kitten is simple, for example::
|
||||
|
||||
kitty +kitten panel sh -c 'printf "\n\n\nHello, world."; sleep 5s'
|
||||
|
||||
This will show ``Hello, world.`` at the top edge of your screen for five
|
||||
seconds. Here the terminal program we are running is ``sh`` with a script to
|
||||
print out ``Hello, world!``. You can make the terminal program as complex as
|
||||
you like, as demonstrated in the screenshot above.
|
||||
|
||||
|
||||
Command Line Interface
|
||||
-------------------------
|
||||
|
||||
.. include:: ../generated/cli-kitten-panel.rst
|
||||
22
docs/kittens/unicode-input.rst
Normal file
22
docs/kittens/unicode-input.rst
Normal file
@@ -0,0 +1,22 @@
|
||||
Unicode input
|
||||
================
|
||||
|
||||
You can input unicode characters by name, hex code, recently used and even an editable favorites list.
|
||||
Press :sc:`input_unicode_character` to start the unicode input widget, shown below.
|
||||
|
||||
.. figure:: ../screenshots/unicode.png
|
||||
:alt: A screenshot of the unicode input widget
|
||||
:align: center
|
||||
:scale: 100%
|
||||
|
||||
A screenshot of the unicode input widget
|
||||
|
||||
In :guilabel:`Code` mode, you enter a unicode character by typing in the hex code for the
|
||||
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.
|
||||
|
||||
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.
|
||||
59
docs/performance.rst
Normal file
59
docs/performance.rst
Normal file
@@ -0,0 +1,59 @@
|
||||
|kitty| Performance
|
||||
===================
|
||||
|
||||
The main goals for |kitty| performance are user perceived latency while typing
|
||||
and "smoothness" while scrolling as well as CPU usage. |kitty| tries hard to find
|
||||
an optimum balance for these. To that end it keeps a cache of each rendered
|
||||
glyph in video RAM so that font rendering is not a bottleneck. Interaction
|
||||
with child programs takes place in a separate thread from rendering, to improve
|
||||
smoothness.
|
||||
|
||||
There are two parameters you can tune to adjust the performance. :opt:`repaint_delay`
|
||||
and :opt:`input_delay`. These control the artificial delays introduced into the
|
||||
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.
|
||||
|
||||
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
|
||||
measured using htop. The measurements are taken at the same font and window
|
||||
size for all terminals on a ``Intel(R) Core(TM) i7-4820K CPU @ 3.70GHz`` CPU
|
||||
with a ``Advanced Micro Devices, Inc. [AMD/ATI] Cape Verde XT [Radeon HD
|
||||
7770/8760 / R7 250X]`` GPU.
|
||||
|
||||
============== =========================
|
||||
Terminal CPU usage (X + terminal)
|
||||
============== =========================
|
||||
|kitty| 6 - 8%
|
||||
xterm 5 - 7% (but scrolling was extremely janky)
|
||||
termite 10 - 13%
|
||||
urxvt 12 - 14%
|
||||
gnome-terminal 15 - 17%
|
||||
konsole 29 - 31%
|
||||
============== =========================
|
||||
|
||||
|
||||
As you can see, |kitty| uses much less CPU than all terminals, except xterm, but
|
||||
its scrolling "smoothness" is much better than that of xterm (at least to my,
|
||||
admittedly biased, eyes).
|
||||
|
||||
|
||||
.. _perf-cat:
|
||||
|
||||
.. note::
|
||||
|
||||
Some people have asked why kitty does not perform better than terminal XXX in
|
||||
the test of sinking large amounts of data, such as catting a large text
|
||||
file. The answer is because this is not a goal for kitty. kitty
|
||||
deliberately throttles input parsing and output rendering to minimize
|
||||
resource usage while still being able to sink output faster than any real
|
||||
world program can produce it. Reducing CPU usage, and hence battery drain
|
||||
while achieving instant response times and smooth scrolling to a human eye
|
||||
is a far more important goal.
|
||||
88
docs/pipe.rst
Normal file
88
docs/pipe.rst
Normal file
@@ -0,0 +1,88 @@
|
||||
Working with the screen and history buffer contents
|
||||
======================================================
|
||||
|
||||
|
||||
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
|
||||
can be displayed in a kitty window or overlay.
|
||||
|
||||
For example, the following in :file:`kitty.conf` will open the scrollback
|
||||
buffer in less in an overlay window, when you press :kbd:`F1`::
|
||||
|
||||
map f1 pipe @ansi overlay less +G -R
|
||||
|
||||
The syntax of the ``pipe`` function is::
|
||||
|
||||
pipe <input placeholder> <destination window type> <command line to run>
|
||||
|
||||
|
||||
The piping environment
|
||||
--------------------------
|
||||
|
||||
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.
|
||||
|
||||
You can choose where to run the pipe program:
|
||||
|
||||
``overlay``
|
||||
An overlay window over the current kitty window
|
||||
|
||||
``window``
|
||||
A new kitty window
|
||||
|
||||
``os_window``
|
||||
A new top-level window
|
||||
|
||||
``tab``
|
||||
A new window in a new tab
|
||||
|
||||
``none``
|
||||
Run it in the background
|
||||
|
||||
|
||||
Input placeholders
|
||||
--------------------
|
||||
|
||||
There are various different kinds of placeholders
|
||||
|
||||
``@text``
|
||||
Plain text, current screen + scrollback buffer
|
||||
|
||||
``@ansi``
|
||||
Text with formatting, current screen + scrollback buffer
|
||||
|
||||
``@screen``
|
||||
Plain text, only current screen
|
||||
|
||||
``@ansi_screen``
|
||||
Text with formatting, only current screen
|
||||
|
||||
``@alternate``
|
||||
Plain text, secondary screen. The secondary screen is the screen not currently displayed. For
|
||||
example if you run a fullscreen terminal application, the secondary screen will
|
||||
be the screen you return to when quitting the application.
|
||||
|
||||
``@ansi_alternate``
|
||||
Text with formatting, secondary screen.
|
||||
|
||||
``@alternate_scrollback``
|
||||
Plain text, secondary screen + scrollback, if any.
|
||||
|
||||
``@ansi_alternate_scrollback``
|
||||
Text with formatting, secondary screen + scrollback, if any.
|
||||
|
||||
``none``
|
||||
No input
|
||||
|
||||
|
||||
You can also add the suffix ``_wrap`` to the placeholder, in which case kitty
|
||||
will insert the carriage return at every line wrap location (where long lines
|
||||
are wrapped at screen edges). This is useful if you want to pipe to program
|
||||
that wants to duplicate the screen layout of the screen.
|
||||
210
docs/protocol-extensions.rst
Normal file
210
docs/protocol-extensions.rst
Normal file
@@ -0,0 +1,210 @@
|
||||
Extensions to the xterm protocol
|
||||
===================================
|
||||
|
||||
|kitty| has a few extensions to the xterm protocol, to enable advanced features.
|
||||
These are typically in the form of new or re-purposed escape codes. While these
|
||||
extensions are currently |kitty| specific, it would be nice to get some of them
|
||||
adopted more broadly, to push the state of terminal emulators forward.
|
||||
|
||||
The goal of these extensions is to be as small and unobtrusive as possible,
|
||||
while filling in some gaps in the existing xterm protocol. In particular, one
|
||||
of the goals of this specification is explicitly not to "re-imagine" the tty.
|
||||
The tty should remain what it is -- a device for efficiently processing text
|
||||
received as a simple byte stream. Another objective is to only move the minimum
|
||||
possible amount of extra functionality into the terminal program itself. This
|
||||
is to make it as easy to implement these protocol extensions as possible,
|
||||
thereby hopefully encouraging their widespread adoption.
|
||||
|
||||
If you wish to discuss these extensions, propose additions/changes to them
|
||||
please do so by opening issues in the github bug tracker.
|
||||
|
||||
.. contents::
|
||||
|
||||
Colored and styled underlines
|
||||
-------------------------------
|
||||
|
||||
|kitty| supports colored and styled (wavy) underlines. This is of particular
|
||||
use in terminal editors such as vim and emacs to display red, wavy underlines
|
||||
under mis-spelled words and/or syntax errors. This is done by re-purposing some
|
||||
SGR escape codes that are not used in modern terminals (`CSI codes
|
||||
<https://en.wikipedia.org/wiki/ANSI_escape_code#CSI_sequences>`_)
|
||||
|
||||
To set the underline style::
|
||||
|
||||
<ESC>[4:0m # this is no underline
|
||||
<ESC>[4:1m # this is a straight underline
|
||||
<ESC>[4:2m # this is a double underline
|
||||
<ESC>[4:3m # this is a curly underline
|
||||
<ESC>[4:4m # this is a dotted underline (not implemented in kitty)
|
||||
<ESC>[4:5m # this is a dashed underline (not implemented in kitty)
|
||||
<ESC>[4m # this is a straight underline (for backwards compat)
|
||||
<ESC>[24m # this is no underline (for backwards compat)
|
||||
|
||||
To set the underline color (this is reserved and as far as I can tell not actually used for anything)::
|
||||
|
||||
<ESC>[58...m
|
||||
|
||||
This works exactly like the codes ``38, 48`` that are used to set foreground and
|
||||
background color respectively.
|
||||
|
||||
To reset the underline color (also previously reserved and unused)::
|
||||
|
||||
<ESC>[59m
|
||||
|
||||
To detect support for this feature in a terminal emulator, query the terminfo database
|
||||
for the ``Su`` boolean capability.
|
||||
|
||||
Graphics rendering
|
||||
---------------------
|
||||
|
||||
See :doc:`/graphics-protocol` for a description
|
||||
of this protocol to enable drawing of arbitrary raster images in the terminal.
|
||||
|
||||
|
||||
.. _extended-key-protocol:
|
||||
|
||||
Keyboard handling
|
||||
-------------------
|
||||
|
||||
There are various problems with the current state of keyboard handling. They
|
||||
include:
|
||||
|
||||
* No way to use modifiers other than ``Ctrl`` and ``Alt``
|
||||
|
||||
* No way to reliably use multiple modifier keys, other than, ``Shift+Alt``.
|
||||
|
||||
* No way to handle different types of keyboard events, such as press, release or repeat
|
||||
|
||||
* No reliable way to distinguish single ``Esc`` keypresses from the start of a
|
||||
escape sequence. Currently, client programs use fragile timing related hacks
|
||||
for this, leading to bugs, for example:
|
||||
`neovim #2035 <https://github.com/neovim/neovim/issues/2035>`_.
|
||||
|
||||
There are already two distinct keyboard handling modes, *normal mode* and
|
||||
*application mode*. These modes generate different escape sequences for the
|
||||
various special keys (arrow keys, function keys, home/end etc.) Most terminals
|
||||
start out in normal mode, however, most shell programs like ``bash`` switch them to
|
||||
application mode. We propose adding a third mode, named *full mode* that addresses
|
||||
the shortcomings listed above.
|
||||
|
||||
Switching to the new *full mode* is accomplished using the standard private
|
||||
mode DECSET escape sequence::
|
||||
|
||||
<ESC>[?2017h
|
||||
|
||||
and to leave *full mode*, use DECRST::
|
||||
|
||||
<ESC>[?2017l
|
||||
|
||||
The number ``2017`` above is not used for any existing modes, as far as I know.
|
||||
Client programs can query if the terminal emulator is in *full mode* by using
|
||||
the standard `DECRQM <https://vt100.net/docs/vt510-rm/DECRQM.html>`_ escape sequence.
|
||||
|
||||
The new mode works as follows:
|
||||
|
||||
* All printable key presses without modifier keys are sent just as in the
|
||||
*normal mode*. This means all printable ASCII characters and in addition,
|
||||
``Enter``, ``Space`` and ``Backspace``. Also any unicode characters generated by
|
||||
platform specific extended input modes, such as using the ``AltGr`` key. This
|
||||
is done so that client programs that are not aware of this mode can still
|
||||
handle basic text entry, so if a *full mode* using program crashes and does
|
||||
not reset, the user can still issue a ``reset`` command in the shell to restore
|
||||
normal key handling. Note that this includes pressing the ``Shift`` modifier
|
||||
and printable keys. Note that this means there are no repeat and release
|
||||
events for these keys and also for the left and right shift keys.
|
||||
|
||||
* For non printable keys and key combinations including one or more modifiers,
|
||||
an escape sequence encoding the key event is sent. For details on the
|
||||
escape sequence, see below.
|
||||
|
||||
The escape sequence encodes the following properties:
|
||||
|
||||
* Type of event: ``press,repeat,release``
|
||||
* Modifiers pressed at the time of the event
|
||||
* The actual key being pressed
|
||||
|
||||
Schematically::
|
||||
|
||||
<ESC>_K<type><modifiers><key><ESC>\
|
||||
|
||||
Where ``<type>`` is one of ``p`` -- press, ``r`` -- release and ``t`` -- repeat.
|
||||
Modifiers is a bitmask represented as a single base64 digit. Shift -- ``0x1``,
|
||||
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>`.
|
||||
|
||||
For example::
|
||||
|
||||
<ESC>_KpGp<ESC>\ is <Ctrl>+<Alt>+x (press)
|
||||
<ESC>_KrP8<ESC>\ is <Ctrl>+<Alt>+<Shift>+<Super>+PageUp (release)
|
||||
|
||||
This encoding means each key event is represented by 8 or 9 printable ascii
|
||||
only bytes, for maximum robustness.
|
||||
|
||||
Support for this mode is indicated by the ``fullkbd`` boolean capability
|
||||
in the terminfo database, in case querying for it via DECQRM is inconvenient.
|
||||
|
||||
.. _ext_styles:
|
||||
|
||||
Setting text styles/colors in arbitrary regions of the screen
|
||||
------------------------------------------------------------------
|
||||
|
||||
There already exists an escape code to set *some* text attributes in arbitrary
|
||||
regions of the screen, `DECCARA
|
||||
<https://vt100.net/docs/vt510-rm/DECCARA.html>`_. However, it is limited to
|
||||
only a few attributes. |kitty| extends this to work with *all* SGR attributes.
|
||||
So, for example, this can be used to set the background color in an arbitrary
|
||||
region of the screen.
|
||||
|
||||
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>`_
|
||||
for a summary of problems with *bce*.
|
||||
|
||||
For example, to set the background color to blue in a
|
||||
rectangular region of the screen from (3, 4) to (10, 11), you use::
|
||||
|
||||
<ESC>[2*x<ESC>[4;3;11;10;44$r<ESC>[*x
|
||||
|
||||
|
||||
Saving and restoring the default foreground/background/selection/cursor colors
|
||||
---------------------------------------------------------------------------------
|
||||
|
||||
It is often useful for a full screen application with its own color themes
|
||||
to set the default foreground, background, selection and cursor colors. This
|
||||
allows for various performance optimizations when drawing the screen. The
|
||||
problem is that if the user previously used the escape codes to change these
|
||||
colors herself, then running the full screen application will lose her
|
||||
changes even after it exits. To avoid this, kitty introduces a new pair of
|
||||
*OSC* escape codes to push and pop the current color values from a stack::
|
||||
|
||||
<ESC>]30001<ESC>\ # push onto stack
|
||||
<ESC>]30101<ESC>\ # pop from stack
|
||||
|
||||
These escape codes save/restore the so called *dynamic colors*, default
|
||||
background, default foreground, selection background, selection foreground and
|
||||
cursor color.
|
||||
|
||||
|
||||
Pasting to clipboard
|
||||
----------------------
|
||||
|
||||
|kitty| implements the OSC 52 escape code protocol to get/set the clipboard
|
||||
contents (controlled via the :opt:`clipboard_control` setting). There is one
|
||||
difference in kitty's implementation compared to some other terminal emulators.
|
||||
|kitty| allows sending arbitrary amounts of text to the clipboard. It does so
|
||||
by modifying the protocol slightly. Successive OSC 52 escape codes to set the
|
||||
clipboard will concatenate, so::
|
||||
|
||||
<ESC>]52;c;<payload1><ESC>\
|
||||
<ESC>]52;c;<payload2><ESC>\
|
||||
|
||||
will result in the clipboard having the contents ``payload1 + payload2``. To
|
||||
send a new string to the clipboard send an OSC 52 sequence with an invalid payload
|
||||
first, for example::
|
||||
|
||||
<ESC>]52;c;!<ESC>\
|
||||
|
||||
Here ``!`` is not valid base64 encoded text, so it clears the clipboard.
|
||||
138
docs/remote-control.rst
Normal file
138
docs/remote-control.rst
Normal file
@@ -0,0 +1,138 @@
|
||||
:tocdepth: 2
|
||||
|
||||
Controlling kitty from scripts or the shell
|
||||
==============================================
|
||||
|
||||
.. highlight:: sh
|
||||
|
||||
Tutorial
|
||||
----------
|
||||
|
||||
|kitty| can be controlled from scripts or the shell prompt. You can open new
|
||||
windows, send arbitrary text input to any window, name windows and tabs, etc.
|
||||
Let's walk through a few examples of controlling |kitty|.
|
||||
|
||||
Start by running |kitty| as::
|
||||
|
||||
kitty -o allow_remote_control=yes -o enabled_layouts=tall
|
||||
|
||||
In order for control to work, :opt:`allow_remote_control` must be enabled in
|
||||
:file:`kitty.conf`. Here we turn it on explicitly at the command line.
|
||||
|
||||
Now, in the new |kitty| window, enter the command::
|
||||
|
||||
kitty @ new-window --title Output --keep-focus cat
|
||||
|
||||
This will open a new window, running the ``cat`` program that will appear next
|
||||
to the current window.
|
||||
|
||||
Let's send some text to this new window::
|
||||
|
||||
kitty @ send-text --match cmdline:cat Hello, World
|
||||
|
||||
This will make ``Hello, World`` show up in the window running the ``cat`` program.
|
||||
The :option:`kitty @ send-text --match` option is very powerful, it allows selecting windows by their
|
||||
titles, the command line of the program running in the window, the working
|
||||
directory of the program running in the window, etc. See ``kitty @ send-text
|
||||
--help`` for details.
|
||||
|
||||
More usefully, you can pipe the output of a command running in one window to
|
||||
another window, for example::
|
||||
|
||||
ls | kitty @ send-text --match title:Output --stdin
|
||||
|
||||
This will show the output of ls in the output window instead of the current
|
||||
window. You can use this technique to, for example, show the output of running
|
||||
``make`` in your editor in a different window. The possibilities are endless.
|
||||
|
||||
You can even have things you type show up in a different window. Run::
|
||||
|
||||
kitty @ send-text --match title:Output --stdin
|
||||
|
||||
And type some text, it will show up in the output window, instead of the current
|
||||
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
|
||||
|
||||
This will open a new tab running the bash shell with the title "My Tab".
|
||||
We can change the title of the tab with::
|
||||
|
||||
kitty @ set-tab-title --match title:My New Title
|
||||
|
||||
Let's change the title of the current tab::
|
||||
|
||||
kitty @ set-tab-title Master Tab
|
||||
|
||||
Now lets switch to the newly opened tab::
|
||||
|
||||
kitty @ focus-tab --match title:New
|
||||
|
||||
Similarly, to focus the previously opened output window (which will also switch
|
||||
back to the old tab, automatically)::
|
||||
|
||||
kitty @ focus-window --match title:Output
|
||||
|
||||
You can get a listing of available tabs and windows, by running::
|
||||
|
||||
kitty @ ls
|
||||
|
||||
This outputs a tree of data in JSON format. The top level of the tree is all
|
||||
operating system kitty windows. Each OS window has an id and a list of tabs.
|
||||
Each tab has its own id, a title and a list of windows. Each window has an id,
|
||||
title, current working directory, process id (PID) and command-line of the
|
||||
process running in the window. You can use this information with :option:`kitty @ focus-window --match`
|
||||
to control individual windows.
|
||||
|
||||
As you can see, it is very easy to control |kitty| using the
|
||||
``kitty @`` messaging system. This tutorial touches only the
|
||||
surface of what is possible. See ``kitty @ --help`` for more details.
|
||||
|
||||
Note that in the example's above, ``kitty @`` messaging works only when run inside a |kitty| window,
|
||||
not anywhere. But, within a |kitty| window it even works over SSH. If you want to control
|
||||
|kitty| from programs/scripts not running inside a |kitty| window, you have to implement a couple of
|
||||
extra steps. First start |kitty| as::
|
||||
|
||||
kitty -o allow_remote_control=yes --listen-on unix:/tmp/mykitty
|
||||
|
||||
The :option:`kitty --listen-on` option tells |kitty| to listen for control messages at the
|
||||
specified path. See ``kitty --help`` for details. Now you can control this
|
||||
instance of |kitty| using the :option:`kitty @ --to` command line argument to ``kitty @``. For example::
|
||||
|
||||
kitty @ --to unix:/tmp/mykitty ls
|
||||
|
||||
|
||||
Note that if all you want to do is run a single |kitty| "daemon" and have subsequent
|
||||
|kitty| invocations appear as new top-level windows, you can use the simpler :option:`kitty --single-instance`
|
||||
option, see ``kitty --help`` for that.
|
||||
|
||||
The builtin kitty shell
|
||||
--------------------------
|
||||
|
||||
You can explore the |kitty| command language more easily using the builtin |kitty|
|
||||
shell. Run ``kitty @`` with no arguments and you will be dropped into the |kitty|
|
||||
shell with completion for |kitty| command names and options.
|
||||
|
||||
You can even open the |kitty| shell inside a running |kitty| using a simple
|
||||
keyboard shortcut (:sc:`kitty_shell` by default). This has the added
|
||||
advantage that you don't need to use ``allow_remote_control`` to make it work.
|
||||
|
||||
|
||||
Allowing only some windows to control kitty
|
||||
----------------------------------------------
|
||||
|
||||
If you do not want to allow all programs running in |kitty| to control it, you can selectively
|
||||
enable remote control for only some |kitty| windows. Simply create a shortcut
|
||||
such as::
|
||||
|
||||
map ctrl+k new_window @ 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
|
||||
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.
|
||||
|
||||
|
||||
.. include:: generated/cli-kitty-at.rst
|
||||
BIN
docs/screenshots/diff.png
Normal file
BIN
docs/screenshots/diff.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 131 KiB |
BIN
docs/screenshots/hints_mode.png
Normal file
BIN
docs/screenshots/hints_mode.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 62 KiB |
BIN
docs/screenshots/panel.png
Normal file
BIN
docs/screenshots/panel.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 1.2 MiB After Width: | Height: | Size: 1.2 MiB |
BIN
docs/screenshots/unicode.png
Normal file
BIN
docs/screenshots/unicode.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 88 KiB |
69
docs/support.html
Normal file
69
docs/support.html
Normal file
@@ -0,0 +1,69 @@
|
||||
<style>
|
||||
.support-button {
|
||||
border-radius: 6px;
|
||||
box-shadow: rgb(255, 246, 175) 0px 1px 0px 0px;
|
||||
display: inline-block;
|
||||
cursor: pointer;
|
||||
color: rgb(51, 51, 51);
|
||||
font-size: inherit;
|
||||
font-family: Arial;
|
||||
font-weight: bold;
|
||||
padding: 8px 24px;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.support-button:hover {
|
||||
transform: scale(1.5);
|
||||
}
|
||||
|
||||
.support-button {
|
||||
outline: 0;
|
||||
}
|
||||
.support-button:visited {
|
||||
color: rgb(51, 51, 51);
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
#support-buttons > div {
|
||||
margin-top: 3ex;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#paypal input[type=submit] {
|
||||
background: linear-gradient(rgb(255, 236, 100) 5%, rgb(255, 171, 35) 100%) rgb(255, 236, 100);
|
||||
border: 1px solid rgb(255, 171, 35);
|
||||
}
|
||||
|
||||
#liberapay a {
|
||||
background: linear-gradient(rgb(92, 184, 92) 5%, rgb(62, 142, 62) 100%) rgb(92, 184, 92);
|
||||
border: 1px solid rgb(62, 142, 62);
|
||||
color: rgb(51, 51, 51);
|
||||
}
|
||||
|
||||
#patreon a {
|
||||
background: linear-gradient(rgb(11, 100, 163) 5%, rgb(5, 45, 73) 100%) rgb(11, 100, 163);
|
||||
border: 1px solid rgb(5, 45, 73);
|
||||
color: #eee;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div id="support-buttons">
|
||||
<div id="patreon">
|
||||
<a class="support-button" href="https://www.patreon.com/bePatron?u=917933">Patronage via Patreon</a>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<form id="paypal" action="https://www.paypal.com/cgi-bin/webscr" method="post" title="Contribute to support calibre development">
|
||||
<input type="hidden" name="cmd" value="_s-xclick" />
|
||||
<input type="hidden" name="hosted_button_id" value="FEELASHWEL5HS" />
|
||||
<input class="support-button" type="submit" name="submit" value="One time support via PayPal" />
|
||||
<img alt="" border="0" src="https://www.paypalobjects.com/en_GB/i/scr/pixel.gif" width="1" height="1" />
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div id="liberapay">
|
||||
<a class="support-button" href="https://liberapay.com/kovidgoyal/donate">Patronage via Liberapay</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
23
docs/support.rst
Normal file
23
docs/support.rst
Normal file
@@ -0,0 +1,23 @@
|
||||
Support kitty development
|
||||
===========================
|
||||
|
||||
My goal with |kitty| is to move the stagnant terminal ecosystem forward. To that
|
||||
end kitty has many foundational features, such as: :doc:`image support
|
||||
<graphics-protocol>`, :doc:`superlative performance <performance>`,
|
||||
:doc:`various enhancements to the terminal protocol <protocol-extensions>`,
|
||||
etc. These features allow the development of rich terminal applications, such
|
||||
as :doc:`Side-by-side diff <kittens/diff>` and :doc:`Unicode input
|
||||
<kittens/unicode-input>`.
|
||||
|
||||
If you wish to support this mission and see the terminal ecosystem evolve,
|
||||
consider donating so that I can devote more time to |kitty| development.
|
||||
I have personally written `almost all kitty code
|
||||
<https://github.com/kovidgoyal/kitty/graphs/contributors>`_.
|
||||
|
||||
You can choose to make either a one-time payment via PayPal or become a
|
||||
*patron* of kitty development via the Patreon or Liberapay services
|
||||
below:
|
||||
|
||||
|
||||
.. raw:: html
|
||||
:file: support.html
|
||||
264
gen-apc-parsers.py
Executable file
264
gen-apc-parsers.py
Executable file
@@ -0,0 +1,264 @@
|
||||
#!/usr/bin/env python
|
||||
# vim:fileencoding=utf-8
|
||||
# License: GPLv3 Copyright: 2018, Kovid Goyal <kovid at kovidgoyal.net>
|
||||
|
||||
import subprocess
|
||||
from collections import defaultdict
|
||||
|
||||
|
||||
def resolve_keys(keymap):
|
||||
ans = defaultdict(list)
|
||||
for ch, (attr, atype) in keymap.items():
|
||||
if atype not in ('int', 'uint'):
|
||||
atype = 'flag'
|
||||
ans[atype].append(ch)
|
||||
return ans
|
||||
|
||||
|
||||
def enum(keymap):
|
||||
lines = []
|
||||
for ch, (attr, atype) in keymap.items():
|
||||
lines.append(f"{attr}='{ch}'")
|
||||
return '''
|
||||
enum KEYS {{
|
||||
{}
|
||||
}};
|
||||
'''.format(',\n'.join(lines))
|
||||
|
||||
|
||||
def parse_key(keymap):
|
||||
lines = []
|
||||
for attr, atype in keymap.values():
|
||||
vs = atype.upper() if 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):
|
||||
lines = []
|
||||
for ch in type_map['flag']:
|
||||
attr, allowed_values = keymap[ch]
|
||||
q = ' && '.join(f"g.{attr} != '{x}'" for x in allowed_values)
|
||||
lines.append(f'''
|
||||
case {attr}: {{
|
||||
g.{attr} = screen->parser_buf[pos++] & 0xff;
|
||||
if ({q}) {{
|
||||
REPORT_ERROR("Malformed {command_class} control block, unknown flag value for {attr}: 0x%x", g.{attr});
|
||||
return;
|
||||
}};
|
||||
}}
|
||||
break;
|
||||
''')
|
||||
return ' \n'.join(lines)
|
||||
|
||||
|
||||
def parse_number(keymap):
|
||||
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):
|
||||
flag_fmt, flag_attrs = [], []
|
||||
cv = {'flag': 'c', 'int': 'i', 'uint': 'I'}[atype]
|
||||
for ch in type_map[atype]:
|
||||
flag_fmt.append('s' + cv)
|
||||
attr = keymap[ch][0]
|
||||
flag_attrs.append(f'"{attr}", {conv}g.{attr}')
|
||||
return ' '.join(flag_fmt), ', '.join(flag_attrs)
|
||||
|
||||
flag_fmt, flag_attrs = group('flag', '')
|
||||
int_fmt, int_attrs = group('int', '(int)')
|
||||
uint_fmt, uint_attrs = group('uint', '(unsigned int)')
|
||||
|
||||
fmt = f'{flag_fmt} {uint_fmt} {int_fmt}'
|
||||
if payload_allowed:
|
||||
ans = [f'REPORT_VA_COMMAND("s {{{fmt} sI}} y#", "{report_name}",']
|
||||
else:
|
||||
ans = [f'REPORT_VA_COMMAND("s {{{fmt}}}", "{report_name}",']
|
||||
ans.append(',\n '.join((flag_attrs, uint_attrs, int_attrs)))
|
||||
if payload_allowed:
|
||||
ans.append(', "payload_sz", g.payload_sz, payload, g.payload_sz')
|
||||
ans.append(');')
|
||||
return '\n'.join(ans)
|
||||
|
||||
|
||||
def generate(function_name, callback_name, report_name, keymap, command_class, initial_key='a', payload_allowed=True):
|
||||
type_map = resolve_keys(keymap)
|
||||
keys_enum = enum(keymap)
|
||||
handle_key = parse_key(keymap)
|
||||
flag_keys = parse_flag(keymap, type_map, command_class)
|
||||
int_keys, uint_keys = parse_number(keymap)
|
||||
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'
|
||||
parr = 'static uint8_t payload[4096];'
|
||||
payload_case = f'''
|
||||
case PAYLOAD: {{
|
||||
sz = screen->parser_buf_pos - pos;
|
||||
const char *err = base64_decode(screen->parser_buf + pos, sz, payload, sizeof(payload), &g.payload_sz);
|
||||
if (err != NULL) {{ REPORT_ERROR("Failed to parse {command_class} command payload with error: %s", err); return; }}
|
||||
pos = screen->parser_buf_pos;
|
||||
}}
|
||||
break;
|
||||
'''
|
||||
callback = f'{callback_name}(screen, &g, payload)'
|
||||
else:
|
||||
payload_after_value = payload = parr = payload_case = ''
|
||||
callback = f'{callback_name}(screen, &g)'
|
||||
|
||||
return f'''
|
||||
static inline void
|
||||
{function_name}(Screen *screen, PyObject UNUSED *dump_callback) {{
|
||||
unsigned int pos = 1;
|
||||
enum PARSER_STATES {{ KEY, EQUAL, UINT, INT, FLAG, AFTER_VALUE {payload} }};
|
||||
enum PARSER_STATES state = KEY, value_state = FLAG;
|
||||
static {command_class} g;
|
||||
unsigned int i, code;
|
||||
uint64_t lcode;
|
||||
bool is_negative;
|
||||
memset(&g, 0, sizeof(g));
|
||||
size_t sz;
|
||||
{parr}
|
||||
{keys_enum}
|
||||
enum KEYS key = '{initial_key}';
|
||||
|
||||
while (pos < screen->parser_buf_pos) {{
|
||||
switch(state) {{
|
||||
case KEY:
|
||||
key = screen->parser_buf[pos++];
|
||||
state = EQUAL;
|
||||
switch(key) {{
|
||||
{handle_key}
|
||||
default:
|
||||
REPORT_ERROR("Malformed {command_class} control block, invalid key character: 0x%x", key);
|
||||
return;
|
||||
}}
|
||||
break;
|
||||
|
||||
case EQUAL:
|
||||
if (screen->parser_buf[pos++] != '=') {{
|
||||
REPORT_ERROR("Malformed {command_class} control block, no = after key, found: 0x%x instead", screen->parser_buf[pos-1]);
|
||||
return;
|
||||
}}
|
||||
state = value_state;
|
||||
break;
|
||||
|
||||
case FLAG:
|
||||
switch(key) {{
|
||||
{flag_keys}
|
||||
default:
|
||||
break;
|
||||
}}
|
||||
state = AFTER_VALUE;
|
||||
break;
|
||||
|
||||
case INT:
|
||||
#define READ_UINT \\
|
||||
for (i = pos; i < MIN(screen->parser_buf_pos, pos + 10); i++) {{ \\
|
||||
if (screen->parser_buf[i] < '0' || screen->parser_buf[i] > '9') break; \\
|
||||
}} \\
|
||||
if (i == pos) {{ REPORT_ERROR("Malformed {command_class} control block, expecting an integer value for key: %c", key & 0xFF); return; }} \\
|
||||
lcode = utoi(screen->parser_buf + pos, i - pos); pos = i; \\
|
||||
if (lcode > UINT32_MAX) {{ REPORT_ERROR("Malformed {command_class} control block, number is too large"); return; }} \\
|
||||
code = lcode;
|
||||
|
||||
is_negative = false;
|
||||
if(screen->parser_buf[pos] == '-') {{ is_negative = true; pos++; }}
|
||||
#define I(x) case x: g.x = is_negative ? 0 - (int32_t)code : (int32_t)code; break
|
||||
READ_UINT;
|
||||
switch(key) {{
|
||||
{int_keys};
|
||||
default: break;
|
||||
}}
|
||||
state = AFTER_VALUE;
|
||||
break;
|
||||
#undef I
|
||||
case UINT:
|
||||
READ_UINT;
|
||||
#define U(x) case x: g.x = code; break
|
||||
switch(key) {{
|
||||
{uint_keys};
|
||||
default: break;
|
||||
}}
|
||||
state = AFTER_VALUE;
|
||||
break;
|
||||
#undef U
|
||||
#undef READ_UINT
|
||||
|
||||
case AFTER_VALUE:
|
||||
switch (screen->parser_buf[pos++]) {{
|
||||
default:
|
||||
REPORT_ERROR("Malformed {command_class} control block, expecting a comma or semi-colon after a value, found: 0x%x",
|
||||
screen->parser_buf[pos - 1]);
|
||||
return;
|
||||
case ',':
|
||||
state = KEY;
|
||||
break;
|
||||
{payload_after_value}
|
||||
}}
|
||||
break;
|
||||
|
||||
{payload_case}
|
||||
|
||||
}} // end switch
|
||||
}} // end while
|
||||
|
||||
switch(state) {{
|
||||
case EQUAL:
|
||||
REPORT_ERROR("Malformed {command_class} control block, no = after key"); return;
|
||||
case INT:
|
||||
case UINT:
|
||||
REPORT_ERROR("Malformed {command_class} control block, expecting an integer value"); return;
|
||||
case FLAG:
|
||||
REPORT_ERROR("Malformed {command_class} control block, expecting a flag value"); return;
|
||||
default:
|
||||
break;
|
||||
}}
|
||||
|
||||
{report_cmd}
|
||||
|
||||
{callback};
|
||||
}}
|
||||
'''
|
||||
|
||||
|
||||
def write_header(text, path):
|
||||
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)
|
||||
print(text, file=f)
|
||||
subprocess.check_call(['clang-format', '-i', path])
|
||||
|
||||
|
||||
def graphics_parser():
|
||||
flag = frozenset
|
||||
keymap = {
|
||||
'a': ('action', flag('tTqpd')),
|
||||
'd': ('delete_action', flag('aAiIcCpPqQxXyYzZ')),
|
||||
't': ('transmission_type', flag('dfts')),
|
||||
'o': ('compressed', flag('z')),
|
||||
'f': ('format', 'uint'),
|
||||
'm': ('more', 'uint'),
|
||||
'i': ('id', 'uint'),
|
||||
'w': ('width', 'uint'),
|
||||
'h': ('height', 'uint'),
|
||||
'x': ('x_offset', 'uint'),
|
||||
'y': ('y_offset', 'uint'),
|
||||
'v': ('data_height', 'uint'),
|
||||
's': ('data_width', 'uint'),
|
||||
'S': ('data_sz', 'uint'),
|
||||
'O': ('data_offset', 'uint'),
|
||||
'c': ('num_cells', 'uint'),
|
||||
'r': ('num_lines', 'uint'),
|
||||
'X': ('cell_x_offset', 'uint'),
|
||||
'Y': ('cell_y_offset', 'uint'),
|
||||
'z': ('z_index', 'int'),
|
||||
}
|
||||
text = generate('parse_graphics_code', 'screen_handle_graphics_command', 'graphics_command', keymap, 'GraphicsCommand')
|
||||
write_header(text, 'kitty/parse-graphics-command.h')
|
||||
|
||||
|
||||
graphics_parser()
|
||||
440
gen-wcwidth.py
Executable file
440
gen-wcwidth.py
Executable file
@@ -0,0 +1,440 @@
|
||||
#!/usr/bin/env python3
|
||||
# vim:fileencoding=utf-8
|
||||
# License: GPL v3 Copyright: 2017, Kovid Goyal <kovid at kovidgoyal.net>
|
||||
|
||||
import os
|
||||
import sys
|
||||
from collections import defaultdict
|
||||
from contextlib import contextmanager
|
||||
from datetime import date
|
||||
from functools import partial
|
||||
from html.entities import html5
|
||||
from itertools import groupby
|
||||
from operator import itemgetter
|
||||
from urllib.request import urlopen
|
||||
|
||||
os.chdir(os.path.dirname(os.path.abspath(__file__)))
|
||||
|
||||
non_characters = frozenset(range(0xfffe, 0x10ffff, 0x10000))
|
||||
non_characters |= frozenset(range(0xffff, 0x10ffff + 1, 0x10000))
|
||||
non_characters |= frozenset(range(0xfdd0, 0xfdf0))
|
||||
if len(non_characters) != 66:
|
||||
raise SystemExit('non_characters table incorrect')
|
||||
emoji_skin_tone_modifiers = frozenset(range(0x1f3fb, 0x1F3FF + 1))
|
||||
|
||||
|
||||
def get_data(fname, folder='UCD'):
|
||||
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()
|
||||
else:
|
||||
data = urlopen(url).read()
|
||||
open(local, 'wb').write(data)
|
||||
for line in data.decode('utf-8').splitlines():
|
||||
line = line.strip()
|
||||
if line and not line.startswith('#'):
|
||||
yield line
|
||||
|
||||
|
||||
# Map of class names to set of codepoints in class
|
||||
class_maps = {}
|
||||
name_map = {}
|
||||
word_search_map = defaultdict(set)
|
||||
zwj = 0x200d
|
||||
marks = set(emoji_skin_tone_modifiers) | {zwj}
|
||||
not_assigned = set(range(0, sys.maxunicode))
|
||||
|
||||
|
||||
def parse_ucd():
|
||||
|
||||
def add_word(w, c):
|
||||
if c <= 32 or c == 127 or 128 <= c <= 159:
|
||||
return
|
||||
if len(w) > 1:
|
||||
word_search_map[w.lower()].add(c)
|
||||
|
||||
first = None
|
||||
for word, c in html5.items():
|
||||
if len(c) == 1:
|
||||
add_word(word.rstrip(';'), ord(c))
|
||||
word_search_map['nnbsp'].add(0x202f)
|
||||
for line in get_data('ucd/UnicodeData.txt'):
|
||||
parts = [x.strip() for x in line.split(';')]
|
||||
codepoint = int(parts[0], 16)
|
||||
name = parts[1] or parts[10]
|
||||
if name == '<control>':
|
||||
name = parts[10]
|
||||
if name:
|
||||
name_map[codepoint] = name
|
||||
for word in name.lower().split():
|
||||
add_word(word, codepoint)
|
||||
category = parts[2]
|
||||
s = class_maps.setdefault(category, set())
|
||||
desc = parts[1]
|
||||
codepoints = (codepoint,)
|
||||
if first is None:
|
||||
if desc.endswith(', First>'):
|
||||
first = codepoint
|
||||
continue
|
||||
else:
|
||||
codepoints = range(first, codepoint + 1)
|
||||
first = None
|
||||
for codepoint in codepoints:
|
||||
s.add(codepoint)
|
||||
not_assigned.discard(codepoint)
|
||||
if category.startswith('M'):
|
||||
marks.add(codepoint)
|
||||
|
||||
# Some common synonyms
|
||||
word_search_map['bee'] |= word_search_map['honeybee']
|
||||
word_search_map['lambda'] |= word_search_map['lamda']
|
||||
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()
|
||||
if '..' in spec:
|
||||
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
|
||||
|
||||
|
||||
all_emoji = set()
|
||||
emoji_categories = {}
|
||||
emoji_presentation_bases = set()
|
||||
|
||||
|
||||
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('#'):
|
||||
continue
|
||||
base = int(base, 16)
|
||||
if var.upper() == 'FE0F':
|
||||
emoji_presentation_bases.add(base)
|
||||
|
||||
|
||||
doublewidth, ambiguous = set(), set()
|
||||
|
||||
|
||||
def parse_eaw():
|
||||
global doublewidth, ambiguous
|
||||
seen = set()
|
||||
for line in get_data('ucd/EastAsianWidth.txt'):
|
||||
chars, eaw = split_two(line)
|
||||
if eaw == 'A':
|
||||
ambiguous |= chars
|
||||
seen |= chars
|
||||
elif eaw == 'W' or eaw == 'F':
|
||||
doublewidth |= chars
|
||||
seen |= chars
|
||||
doublewidth |= set(range(0x3400, 0x4DBF + 1)) - seen
|
||||
doublewidth |= set(range(0x4E00, 0x9FFF + 1)) - seen
|
||||
doublewidth |= set(range(0xF900, 0xFAFF + 1)) - seen
|
||||
doublewidth |= set(range(0x20000, 0x2FFFD + 1)) - seen
|
||||
doublewidth |= set(range(0x30000, 0x3FFFD + 1)) - seen
|
||||
|
||||
|
||||
def get_ranges(items):
|
||||
items.sort()
|
||||
for k, g in groupby(enumerate(items), lambda m: m[0]-m[1]):
|
||||
group = tuple(map(itemgetter(1), g))
|
||||
a, b = group[0], group[-1]
|
||||
if a == b:
|
||||
yield a
|
||||
else:
|
||||
yield a, b
|
||||
|
||||
|
||||
def write_case(spec, p):
|
||||
if isinstance(spec, tuple):
|
||||
p('\t\tcase 0x{:x} ... 0x{:x}:'.format(*spec))
|
||||
else:
|
||||
p('\t\tcase 0x{:x}:'.format(spec))
|
||||
|
||||
|
||||
@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 gen_emoji():
|
||||
with create_header('kitty/emoji.h') as p:
|
||||
p('static inline bool\nis_emoji(char_type code) {')
|
||||
p('\tswitch(code) {')
|
||||
for spec in get_ranges(list(all_emoji)):
|
||||
write_case(spec, p)
|
||||
p('\t\t\treturn true;')
|
||||
p('\t\tdefault: return false;')
|
||||
p('\t}')
|
||||
p('\treturn false;\n}')
|
||||
p('static inline bool\nis_emoji_modifier(char_type code) {')
|
||||
p('\tswitch(code) {')
|
||||
for spec in get_ranges(list(emoji_categories['Emoji_Modifier'])):
|
||||
write_case(spec, p)
|
||||
p('\t\t\treturn true;')
|
||||
p('\t\tdefault: return false;')
|
||||
p('\t}')
|
||||
p('\treturn false;\n}')
|
||||
|
||||
|
||||
def category_test(name, p, classes, comment, static=False, extra_chars=frozenset(), exclude=frozenset()):
|
||||
static = 'static inline ' if static else ''
|
||||
chars = 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)' + ' {{' '{')
|
||||
p('\tswitch(code) {')
|
||||
for spec in get_ranges(list(chars)):
|
||||
write_case(spec, p)
|
||||
p(f'\t\t\treturn true;')
|
||||
p('\t} // }}}\n')
|
||||
p('\treturn false;\n}\n')
|
||||
|
||||
|
||||
def codepoint_to_mark_map(p, mark_map):
|
||||
p('\tswitch(c) { // {{{')
|
||||
rmap = {c: m for m, c in enumerate(mark_map)}
|
||||
for spec in get_ranges(mark_map):
|
||||
if isinstance(spec, tuple):
|
||||
s = rmap[spec[0]]
|
||||
cases = ' '.join(f'case {i}:' for i in range(spec[0], spec[1]+1))
|
||||
p(f'\t\t{cases} return {s} + c - {spec[0]};')
|
||||
else:
|
||||
p(f'\t\tcase {spec}: return {rmap[spec]};')
|
||||
p('default: return 0;')
|
||||
p('\t} // }}}')
|
||||
return rmap
|
||||
|
||||
|
||||
def classes_to_regex(classes, exclude=''):
|
||||
chars = set()
|
||||
for c in classes:
|
||||
chars |= class_maps[c]
|
||||
for c in map(ord, exclude):
|
||||
chars.discard(c)
|
||||
|
||||
def as_string(codepoint):
|
||||
if codepoint < 256:
|
||||
return r'\x{:02x}'.format(codepoint)
|
||||
if codepoint <= 0xffff:
|
||||
return r'\u{:04x}'.format(codepoint)
|
||||
return r'\U{:08x}'.format(codepoint)
|
||||
|
||||
for spec in get_ranges(list(chars)):
|
||||
if isinstance(spec, tuple):
|
||||
yield '{}-{}'.format(*map(as_string, (spec[0], spec[1])))
|
||||
else:
|
||||
yield as_string(spec)
|
||||
|
||||
|
||||
def gen_ucd():
|
||||
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"')
|
||||
category_test(
|
||||
'is_combining_char', p,
|
||||
{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}
|
||||
)
|
||||
category_test(
|
||||
'is_ignored_char', p, 'Cc Cf Cs'.split(),
|
||||
'Control characters and non-characters', extra_chars=non_characters, exclude={zwj})
|
||||
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)')
|
||||
mark_map = [0] + list(sorted(marks))
|
||||
p('char_type codepoint_for_mark(combining_type m) {')
|
||||
p(f'\tstatic char_type map[{len(mark_map)}] =', '{', ', '.join(map(str, mark_map)), '}; // {{{ mapping }}}')
|
||||
p('\tif (m < arraysz(map)) return map[m];')
|
||||
p('\treturn 0;')
|
||||
p('}\n')
|
||||
p('combining_type mark_for_codepoint(char_type c) {')
|
||||
rmap = codepoint_to_mark_map(p, mark_map)
|
||||
p('}\n')
|
||||
if rmap[0xfe0e] != 1281:
|
||||
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]
|
||||
))
|
||||
with open('kittens/hints/url_regex.py', 'w') as f:
|
||||
f.write("url_delimiters = '{}' # noqa".format(''.join(classes_to_regex(cz, exclude='\n'))))
|
||||
|
||||
|
||||
def gen_names():
|
||||
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)}
|
||||
# Mapping of mark to codepoint name
|
||||
p(f'static const char* name_map[{len(mark_to_cp)}] = {{' ' // {{{')
|
||||
for cp in mark_to_cp:
|
||||
w = name_map[cp].replace('"', '\\"')
|
||||
p(f'\t"{w}",')
|
||||
p("}; // }}}\n")
|
||||
|
||||
# Mapping of mark to codepoint
|
||||
p(f'static const char_type mark_to_cp[{len(mark_to_cp)}] = {{' ' // {{{')
|
||||
p(', '.join(map(str, mark_to_cp)))
|
||||
p('}; // }}}\n')
|
||||
|
||||
# Function to get mark number for codepoint
|
||||
p('static char_type mark_for_codepoint(char_type c) {')
|
||||
codepoint_to_mark_map(p, mark_to_cp)
|
||||
p('}\n')
|
||||
p('static inline const char* name_for_codepoint(char_type cp) {')
|
||||
p('\tchar_type m = mark_for_codepoint(cp); if (m == 0) return NULL;')
|
||||
p('\treturn name_map[m];')
|
||||
p('}\n')
|
||||
|
||||
# Array of all words
|
||||
word_map = tuple(sorted(word_search_map))
|
||||
word_rmap = {w: i for i, w in enumerate(word_map)}
|
||||
p(f'static const char* all_words_map[{len(word_map)}] = {{' ' // {{{')
|
||||
cwords = (w.replace('"', '\\"') for w in word_map)
|
||||
p(', '.join(f'"{w}"' for w in cwords))
|
||||
p('}; // }}}\n')
|
||||
|
||||
# Array of sets of marks for each word
|
||||
word_to_marks = {word_rmap[w]: frozenset(map(cp_to_mark.__getitem__, cps)) for w, cps in word_search_map.items()}
|
||||
all_mark_groups = frozenset(word_to_marks.values())
|
||||
array = [0]
|
||||
mg_to_offset = {}
|
||||
for mg in all_mark_groups:
|
||||
mg_to_offset[mg] = len(array)
|
||||
array.append(len(mg))
|
||||
array.extend(sorted(mg))
|
||||
p(f'static const char_type mark_groups[{len(array)}] = {{' ' // {{{')
|
||||
p(', '.join(map(str, array)))
|
||||
p('}; // }}}\n')
|
||||
offsets_array = []
|
||||
for wi, w in enumerate(word_map):
|
||||
mg = word_to_marks[wi]
|
||||
offsets_array.append(mg_to_offset[mg])
|
||||
p(f'static const char_type mark_to_offset[{len(offsets_array)}] = {{' ' // {{{')
|
||||
p(', '.join(map(str, offsets_array)))
|
||||
p('}; // }}}\n')
|
||||
|
||||
# The trie
|
||||
p(f'typedef struct {{ uint32_t children_offset; uint32_t match_offset; }} word_trie;\n')
|
||||
all_trie_nodes = []
|
||||
|
||||
class TrieNode:
|
||||
|
||||
def __init__(self):
|
||||
self.match_offset = 0
|
||||
self.children_offset = 0
|
||||
self.children = {}
|
||||
|
||||
def add_letter(self, letter):
|
||||
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):
|
||||
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):
|
||||
parent = root
|
||||
for letter in map(ord, word):
|
||||
idx = parent.add_letter(letter)
|
||||
parent = all_trie_nodes[idx]
|
||||
parent.match_offset = offsets_array[word_idx]
|
||||
|
||||
for i, word in enumerate(word_map):
|
||||
add_word(i, word)
|
||||
children_array = [0]
|
||||
for node in all_trie_nodes:
|
||||
if node.children:
|
||||
node.children_offset = len(children_array)
|
||||
children_array.append(len(node.children))
|
||||
for letter, child_offset in node.children.items():
|
||||
children_array.append((child_offset << 8) | (letter & 0xff))
|
||||
|
||||
p(f'static const word_trie all_trie_nodes[{len(all_trie_nodes)}] = {{' ' // {{{')
|
||||
p(',\n'.join(map(str, all_trie_nodes)))
|
||||
p('\n}; // }}}\n')
|
||||
p(f'static const uint32_t children_array[{len(children_array)}] = {{' ' // {{{')
|
||||
p(', '.join(map(str, children_array)))
|
||||
p('}; // }}}\n')
|
||||
|
||||
|
||||
def gen_wcwidth():
|
||||
seen = set()
|
||||
|
||||
def add(p, comment, chars_, ret):
|
||||
chars = chars_ - seen
|
||||
seen.update(chars)
|
||||
p(f'\t\t// {comment} ({len(chars)} codepoints)' + ' {{' '{')
|
||||
for spec in get_ranges(list(chars)):
|
||||
write_case(spec, p)
|
||||
p(f'\t\t\treturn {ret};')
|
||||
p('\t\t// }}}\n')
|
||||
|
||||
with create_header('kitty/wcwidth-std.h') as p:
|
||||
p('static int\nwcwidth_std(int32_t code) {')
|
||||
p('\tswitch(code) {')
|
||||
|
||||
non_printing = class_maps['Cc'] | class_maps['Cf'] | class_maps['Cs']
|
||||
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, '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, 'Not assigned in the unicode character database', not_assigned, -4)
|
||||
|
||||
p('\t\tdefault: return 1;')
|
||||
p('\t}')
|
||||
p('\treturn 1;\n}')
|
||||
|
||||
p('static bool\nis_emoji_presentation_base(uint32_t code) {')
|
||||
p('\tswitch(code) {')
|
||||
for spec in get_ranges(list(emoji_presentation_bases)):
|
||||
write_case(spec, p)
|
||||
p('\t\t\treturn true;')
|
||||
p('\t\tdefault: return false;')
|
||||
p('\t}')
|
||||
p('\treturn 1;\n}')
|
||||
|
||||
|
||||
parse_ucd()
|
||||
parse_emoji()
|
||||
parse_eaw()
|
||||
gen_ucd()
|
||||
gen_wcwidth()
|
||||
gen_emoji()
|
||||
gen_names()
|
||||
@@ -1,57 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
# vim:fileencoding=utf-8
|
||||
# License: GPL v3 Copyright: 2016, Kovid Goyal <kovid at kovidgoyal.net>
|
||||
|
||||
import unicodedata
|
||||
import itertools
|
||||
import sys
|
||||
|
||||
IGNORED_CATEGORIES = ('Cc', 'Cf', 'Cs')
|
||||
|
||||
|
||||
def ranges(i):
|
||||
for a, b in itertools.groupby(enumerate(i), lambda r: r[1] - r[0]):
|
||||
b = list(b)
|
||||
yield b[0][1], b[-1][1]
|
||||
|
||||
|
||||
def generate_data(chars):
|
||||
points, cranges = [], []
|
||||
for l, r in ranges(chars):
|
||||
if l == r:
|
||||
points.append(l)
|
||||
else:
|
||||
cranges.append((l, r))
|
||||
return points, cranges
|
||||
|
||||
|
||||
def generate_predicate(name, chars):
|
||||
points, cranges = generate_data(chars)
|
||||
cranges = ['(0x%x %s ch && ch <= 0x%x)' % (l, '<' if l == 0 else '<=', r) for l, r in cranges]
|
||||
points = ['(ch == 0x%x)' % p for p in points]
|
||||
return '''
|
||||
static inline bool %s(uint32_t ch) {
|
||||
return %s || %s;
|
||||
}
|
||||
''' % (name, '||'.join(cranges), '||'.join(points))
|
||||
|
||||
|
||||
def main():
|
||||
combining_chars = []
|
||||
igchars = []
|
||||
for c in map(chr, range(sys.maxunicode + 1)):
|
||||
if unicodedata.category(c) in IGNORED_CATEGORIES:
|
||||
igchars.append(ord(c))
|
||||
if unicodedata.combining(c):
|
||||
combining_chars.append(ord(c))
|
||||
|
||||
cc = generate_predicate('is_combining_char', combining_chars)
|
||||
ig = generate_predicate('is_ignored_char', igchars)
|
||||
with open('kitty/unicode-data.h', 'w') as f:
|
||||
print('#pragma once', file=f)
|
||||
print(cc, file=f)
|
||||
print(ig, file=f)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
67
glad/generate.py
Executable file
67
glad/generate.py
Executable file
@@ -0,0 +1,67 @@
|
||||
#!/usr/bin/env python3
|
||||
# vim:fileencoding=utf-8
|
||||
# License: GPL v3 Copyright: 2017, Kovid Goyal <kovid at kovidgoyal.net>
|
||||
|
||||
import os
|
||||
import re
|
||||
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'
|
||||
)
|
||||
|
||||
|
||||
def clean(x):
|
||||
if os.path.exists(x):
|
||||
shutil.rmtree(x)
|
||||
|
||||
|
||||
def regenerate():
|
||||
clean('out')
|
||||
|
||||
subprocess.check_call(
|
||||
shlex.split(cmdline.format(dest='out', generator='c-debug'))
|
||||
)
|
||||
|
||||
|
||||
def strip_trailing_whitespace(c):
|
||||
return re.sub(r'\s+$', '', c, flags=re.MULTILINE) + '\n'
|
||||
|
||||
|
||||
def export():
|
||||
c = open('out/src/glad.c', 'rb').read().decode('utf-8')
|
||||
functions = []
|
||||
|
||||
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))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
os.chdir(os.path.dirname(os.path.abspath(__file__)))
|
||||
regenerate()
|
||||
export()
|
||||
314
glfw/backend_utils.c
vendored
Normal file
314
glfw/backend_utils.c
vendored
Normal file
@@ -0,0 +1,314 @@
|
||||
/*
|
||||
* backend_utils.c
|
||||
* Copyright (C) 2018 Kovid Goyal <kovid at kovidgoyal.net>
|
||||
*
|
||||
* Distributed under terms of the GPL3 license.
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include "backend_utils.h"
|
||||
#include "internal.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <float.h>
|
||||
#include <time.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef __NetBSD__
|
||||
#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++) {
|
||||
Watch *w = eld->watches + i;
|
||||
eld->fds[i].fd = w->fd;
|
||||
eld->fds[i].events = w->enabled ? w->events : 0;
|
||||
}
|
||||
}
|
||||
|
||||
static id_type watch_counter = 0;
|
||||
|
||||
id_type
|
||||
addWatch(EventLoopData *eld, const char* name, int fd, int events, int enabled, watch_callback_func cb, void *cb_data) {
|
||||
if (eld->watches_count >= sizeof(eld->watches)/sizeof(eld->watches[0])) {
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR, "Too many watches added");
|
||||
return 0;
|
||||
}
|
||||
Watch *w = eld->watches + eld->watches_count++;
|
||||
w->name = name;
|
||||
w->fd = fd; w->events = events; w->enabled = enabled;
|
||||
w->callback = cb;
|
||||
w->callback_data = cb_data;
|
||||
w->id = ++watch_counter;
|
||||
update_fds(eld);
|
||||
return w->id;
|
||||
}
|
||||
|
||||
#define removeX(which, item_id, update_func) {\
|
||||
for (nfds_t i = 0; i < eld->which##_count; i++) { \
|
||||
if (eld->which[i].id == item_id) { \
|
||||
eld->which##_count--; \
|
||||
if (i < eld->which##_count) { \
|
||||
memmove(eld->which + i, eld->which + i + 1, sizeof(eld->which[0]) * (eld->which##_count - i)); \
|
||||
} \
|
||||
update_func(eld); break; \
|
||||
}}}
|
||||
|
||||
void
|
||||
removeWatch(EventLoopData *eld, id_type watch_id) {
|
||||
removeX(watches, watch_id, update_fds);
|
||||
}
|
||||
|
||||
void
|
||||
toggleWatch(EventLoopData *eld, id_type watch_id, int enabled) {
|
||||
for (nfds_t i = 0; i < eld->watches_count; i++) {
|
||||
if (eld->watches[i].id == watch_id) {
|
||||
if (eld->watches[i].enabled != enabled) {
|
||||
eld->watches[i].enabled = enabled;
|
||||
update_fds(eld);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static id_type timer_counter = 0;
|
||||
|
||||
static int
|
||||
compare_timers(const void *a_, const void *b_) {
|
||||
const Timer *a = (const Timer*)a_, *b = (const Timer*)b_;
|
||||
return (a->trigger_at > b->trigger_at) ? 1 : (a->trigger_at < b->trigger_at) ? -1 : 0;
|
||||
}
|
||||
|
||||
static inline void
|
||||
update_timers(EventLoopData *eld) {
|
||||
if (eld->timers_count > 1) qsort(eld->timers, eld->timers_count, sizeof(eld->timers[0]), compare_timers);
|
||||
}
|
||||
|
||||
id_type
|
||||
addTimer(EventLoopData *eld, const char *name, double interval, int enabled, timer_callback_func cb, void *cb_data) {
|
||||
if (eld->timers_count >= sizeof(eld->timers)/sizeof(eld->timers[0])) {
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR, "Too many timers added");
|
||||
return 0;
|
||||
}
|
||||
Timer *t = eld->timers + eld->timers_count++;
|
||||
t->interval = interval;
|
||||
t->name = name;
|
||||
t->trigger_at = enabled ? monotonic() + interval : DBL_MAX;
|
||||
t->callback = cb;
|
||||
t->callback_data = cb_data;
|
||||
t->id = ++timer_counter;
|
||||
update_timers(eld);
|
||||
return t->id;
|
||||
}
|
||||
|
||||
void
|
||||
removeTimer(EventLoopData *eld, id_type timer_id) {
|
||||
removeX(timers, timer_id, update_timers);
|
||||
}
|
||||
|
||||
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;
|
||||
if (trigger_at != eld->timers[i].trigger_at) {
|
||||
eld->timers[i].trigger_at = trigger_at;
|
||||
update_timers(eld);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
changeTimerInterval(EventLoopData *eld, id_type timer_id, double interval) {
|
||||
for (nfds_t i = 0; i < eld->timers_count; i++) {
|
||||
if (eld->timers[i].id == timer_id) {
|
||||
eld->timers[i].interval = interval;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
double
|
||||
prepareForPoll(EventLoopData *eld, double 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 (timeout < 0 || now + timeout > next_repeat_at) {
|
||||
timeout = next_repeat_at <= now ? 0 : next_repeat_at - now;
|
||||
}
|
||||
return timeout;
|
||||
}
|
||||
|
||||
int
|
||||
pollWithTimeout(struct pollfd *fds, nfds_t nfds, double timeout) {
|
||||
const long seconds = (long) timeout;
|
||||
const long nanoseconds = (long) ((timeout - seconds) * 1e9);
|
||||
struct timespec tv = { seconds, nanoseconds };
|
||||
return ppoll(fds, nfds, &tv, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
dispatchEvents(EventLoopData *eld) {
|
||||
for (nfds_t i = 0; i < eld->watches_count; i++) {
|
||||
Watch *ww = eld->watches + i;
|
||||
struct pollfd *pfd = eld->fds + i;
|
||||
if (pfd->revents & ww->events) {
|
||||
ww->ready = 1;
|
||||
if (ww->callback) ww->callback(ww->fd, pfd->revents, ww->callback_data);
|
||||
} else ww->ready = 0;
|
||||
}
|
||||
}
|
||||
|
||||
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])];
|
||||
unsigned num_dispatches = 0;
|
||||
double 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;
|
||||
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 (num_dispatches) update_timers(eld);
|
||||
return num_dispatches;
|
||||
}
|
||||
|
||||
static void
|
||||
drain_wakeup_fd(int fd, int events, void* data) {
|
||||
static char drain_buf[64];
|
||||
while(read(fd, drain_buf, sizeof(drain_buf)) < 0 && errno == EINTR);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
pollForEvents(EventLoopData *eld, double timeout) {
|
||||
int read_ok = 0;
|
||||
timeout = prepareForPoll(eld, timeout);
|
||||
int result;
|
||||
double end_time = monotonic() + timeout;
|
||||
|
||||
while(1) {
|
||||
if (timeout >= 0) {
|
||||
errno = 0;
|
||||
result = pollWithTimeout(eld->fds, eld->watches_count, timeout);
|
||||
int saved_errno = errno;
|
||||
dispatchTimers(eld);
|
||||
if (result > 0) {
|
||||
dispatchEvents(eld);
|
||||
read_ok = eld->watches[0].ready;
|
||||
break;
|
||||
}
|
||||
timeout = end_time - monotonic();
|
||||
if (timeout <= 0) break;
|
||||
if (result < 0 && (saved_errno == EINTR || saved_errno == EAGAIN)) continue;
|
||||
break;
|
||||
} else {
|
||||
errno = 0;
|
||||
result = poll(eld->fds, eld->watches_count, -1);
|
||||
int saved_errno = errno;
|
||||
dispatchTimers(eld);
|
||||
if (result > 0) {
|
||||
dispatchEvents(eld);
|
||||
read_ok = eld->watches[0].ready;
|
||||
}
|
||||
if (result < 0 && (saved_errno == EINTR || saved_errno == EAGAIN)) continue;
|
||||
break;
|
||||
}
|
||||
}
|
||||
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++;
|
||||
}
|
||||
}
|
||||
|
||||
return paths;
|
||||
}
|
||||
74
glfw/backend_utils.h
vendored
Normal file
74
glfw/backend_utils.h
vendored
Normal file
@@ -0,0 +1,74 @@
|
||||
//========================================================================
|
||||
// GLFW 3.3 Wayland - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2014 Jonas Ådahl <jadahl@gmail.com>
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
//========================================================================
|
||||
|
||||
#pragma once
|
||||
#include <poll.h>
|
||||
#include <unistd.h>
|
||||
|
||||
typedef unsigned long long id_type;
|
||||
typedef void(*watch_callback_func)(int, int, void*);
|
||||
typedef void(*timer_callback_func)(id_type, void*);
|
||||
|
||||
typedef struct {
|
||||
int fd, events, enabled, ready;
|
||||
watch_callback_func callback;
|
||||
void *callback_data;
|
||||
id_type id;
|
||||
const char *name;
|
||||
} Watch;
|
||||
|
||||
typedef struct {
|
||||
id_type id;
|
||||
double interval, trigger_at;
|
||||
timer_callback_func callback;
|
||||
void *callback_data;
|
||||
const char *name;
|
||||
} Timer;
|
||||
|
||||
|
||||
typedef struct {
|
||||
struct pollfd fds[32];
|
||||
int wakeupFds[2];
|
||||
nfds_t watches_count, timers_count;
|
||||
Watch watches[32];
|
||||
Timer timers[128];
|
||||
} EventLoopData;
|
||||
|
||||
|
||||
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);
|
||||
void removeTimer(EventLoopData *eld, id_type timer_id);
|
||||
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);
|
||||
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);
|
||||
376
glfw/cocoa_init.m
Normal file
376
glfw/cocoa_init.m
Normal file
@@ -0,0 +1,376 @@
|
||||
//========================================================================
|
||||
// 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 <sys/param.h> // For MAXPATHLEN
|
||||
|
||||
|
||||
// Change to our application bundle's resources directory, if present
|
||||
//
|
||||
static void changeToResourcesDirectory(void)
|
||||
{
|
||||
char resourcesPath[MAXPATHLEN];
|
||||
|
||||
CFBundleRef bundle = CFBundleGetMainBundle();
|
||||
if (!bundle)
|
||||
return;
|
||||
|
||||
CFURLRef resourcesURL = CFBundleCopyResourcesDirectoryURL(bundle);
|
||||
|
||||
CFStringRef last = CFURLCopyLastPathComponent(resourcesURL);
|
||||
if (CFStringCompare(CFSTR("Resources"), last, 0) != kCFCompareEqualTo)
|
||||
{
|
||||
CFRelease(last);
|
||||
CFRelease(resourcesURL);
|
||||
return;
|
||||
}
|
||||
|
||||
CFRelease(last);
|
||||
|
||||
if (!CFURLGetFileSystemRepresentation(resourcesURL,
|
||||
true,
|
||||
(UInt8*) resourcesPath,
|
||||
MAXPATHLEN))
|
||||
{
|
||||
CFRelease(resourcesURL);
|
||||
return;
|
||||
}
|
||||
|
||||
CFRelease(resourcesURL);
|
||||
|
||||
chdir(resourcesPath);
|
||||
}
|
||||
|
||||
// Create key code translation tables
|
||||
//
|
||||
static void createKeyTables(void)
|
||||
{
|
||||
int scancode;
|
||||
|
||||
memset(_glfw.ns.keycodes, -1, sizeof(_glfw.ns.keycodes));
|
||||
memset(_glfw.ns.scancodes, -1, sizeof(_glfw.ns.scancodes));
|
||||
|
||||
_glfw.ns.keycodes[0x1D] = GLFW_KEY_0;
|
||||
_glfw.ns.keycodes[0x12] = GLFW_KEY_1;
|
||||
_glfw.ns.keycodes[0x13] = GLFW_KEY_2;
|
||||
_glfw.ns.keycodes[0x14] = GLFW_KEY_3;
|
||||
_glfw.ns.keycodes[0x15] = GLFW_KEY_4;
|
||||
_glfw.ns.keycodes[0x17] = GLFW_KEY_5;
|
||||
_glfw.ns.keycodes[0x16] = GLFW_KEY_6;
|
||||
_glfw.ns.keycodes[0x1A] = GLFW_KEY_7;
|
||||
_glfw.ns.keycodes[0x1C] = GLFW_KEY_8;
|
||||
_glfw.ns.keycodes[0x19] = GLFW_KEY_9;
|
||||
_glfw.ns.keycodes[0x00] = GLFW_KEY_A;
|
||||
_glfw.ns.keycodes[0x0B] = GLFW_KEY_B;
|
||||
_glfw.ns.keycodes[0x08] = GLFW_KEY_C;
|
||||
_glfw.ns.keycodes[0x02] = GLFW_KEY_D;
|
||||
_glfw.ns.keycodes[0x0E] = GLFW_KEY_E;
|
||||
_glfw.ns.keycodes[0x03] = GLFW_KEY_F;
|
||||
_glfw.ns.keycodes[0x05] = GLFW_KEY_G;
|
||||
_glfw.ns.keycodes[0x04] = GLFW_KEY_H;
|
||||
_glfw.ns.keycodes[0x22] = GLFW_KEY_I;
|
||||
_glfw.ns.keycodes[0x26] = GLFW_KEY_J;
|
||||
_glfw.ns.keycodes[0x28] = GLFW_KEY_K;
|
||||
_glfw.ns.keycodes[0x25] = GLFW_KEY_L;
|
||||
_glfw.ns.keycodes[0x2E] = GLFW_KEY_M;
|
||||
_glfw.ns.keycodes[0x2D] = GLFW_KEY_N;
|
||||
_glfw.ns.keycodes[0x1F] = GLFW_KEY_O;
|
||||
_glfw.ns.keycodes[0x23] = GLFW_KEY_P;
|
||||
_glfw.ns.keycodes[0x0C] = GLFW_KEY_Q;
|
||||
_glfw.ns.keycodes[0x0F] = GLFW_KEY_R;
|
||||
_glfw.ns.keycodes[0x01] = GLFW_KEY_S;
|
||||
_glfw.ns.keycodes[0x11] = GLFW_KEY_T;
|
||||
_glfw.ns.keycodes[0x20] = GLFW_KEY_U;
|
||||
_glfw.ns.keycodes[0x09] = GLFW_KEY_V;
|
||||
_glfw.ns.keycodes[0x0D] = GLFW_KEY_W;
|
||||
_glfw.ns.keycodes[0x07] = GLFW_KEY_X;
|
||||
_glfw.ns.keycodes[0x10] = GLFW_KEY_Y;
|
||||
_glfw.ns.keycodes[0x06] = GLFW_KEY_Z;
|
||||
|
||||
_glfw.ns.keycodes[0x27] = GLFW_KEY_APOSTROPHE;
|
||||
_glfw.ns.keycodes[0x2A] = GLFW_KEY_BACKSLASH;
|
||||
_glfw.ns.keycodes[0x2B] = GLFW_KEY_COMMA;
|
||||
_glfw.ns.keycodes[0x18] = GLFW_KEY_EQUAL;
|
||||
_glfw.ns.keycodes[0x32] = GLFW_KEY_GRAVE_ACCENT;
|
||||
_glfw.ns.keycodes[0x21] = GLFW_KEY_LEFT_BRACKET;
|
||||
_glfw.ns.keycodes[0x1B] = GLFW_KEY_MINUS;
|
||||
_glfw.ns.keycodes[0x2F] = GLFW_KEY_PERIOD;
|
||||
_glfw.ns.keycodes[0x1E] = GLFW_KEY_RIGHT_BRACKET;
|
||||
_glfw.ns.keycodes[0x29] = GLFW_KEY_SEMICOLON;
|
||||
_glfw.ns.keycodes[0x2C] = GLFW_KEY_SLASH;
|
||||
_glfw.ns.keycodes[0x0A] = GLFW_KEY_WORLD_1;
|
||||
|
||||
_glfw.ns.keycodes[0x33] = GLFW_KEY_BACKSPACE;
|
||||
_glfw.ns.keycodes[0x39] = GLFW_KEY_CAPS_LOCK;
|
||||
_glfw.ns.keycodes[0x75] = GLFW_KEY_DELETE;
|
||||
_glfw.ns.keycodes[0x7D] = GLFW_KEY_DOWN;
|
||||
_glfw.ns.keycodes[0x77] = GLFW_KEY_END;
|
||||
_glfw.ns.keycodes[0x24] = GLFW_KEY_ENTER;
|
||||
_glfw.ns.keycodes[0x35] = GLFW_KEY_ESCAPE;
|
||||
_glfw.ns.keycodes[0x7A] = GLFW_KEY_F1;
|
||||
_glfw.ns.keycodes[0x78] = GLFW_KEY_F2;
|
||||
_glfw.ns.keycodes[0x63] = GLFW_KEY_F3;
|
||||
_glfw.ns.keycodes[0x76] = GLFW_KEY_F4;
|
||||
_glfw.ns.keycodes[0x60] = GLFW_KEY_F5;
|
||||
_glfw.ns.keycodes[0x61] = GLFW_KEY_F6;
|
||||
_glfw.ns.keycodes[0x62] = GLFW_KEY_F7;
|
||||
_glfw.ns.keycodes[0x64] = GLFW_KEY_F8;
|
||||
_glfw.ns.keycodes[0x65] = GLFW_KEY_F9;
|
||||
_glfw.ns.keycodes[0x6D] = GLFW_KEY_F10;
|
||||
_glfw.ns.keycodes[0x67] = GLFW_KEY_F11;
|
||||
_glfw.ns.keycodes[0x6F] = GLFW_KEY_F12;
|
||||
_glfw.ns.keycodes[0x69] = GLFW_KEY_F13;
|
||||
_glfw.ns.keycodes[0x6B] = GLFW_KEY_F14;
|
||||
_glfw.ns.keycodes[0x71] = GLFW_KEY_F15;
|
||||
_glfw.ns.keycodes[0x6A] = GLFW_KEY_F16;
|
||||
_glfw.ns.keycodes[0x40] = GLFW_KEY_F17;
|
||||
_glfw.ns.keycodes[0x4F] = GLFW_KEY_F18;
|
||||
_glfw.ns.keycodes[0x50] = GLFW_KEY_F19;
|
||||
_glfw.ns.keycodes[0x5A] = GLFW_KEY_F20;
|
||||
_glfw.ns.keycodes[0x73] = GLFW_KEY_HOME;
|
||||
_glfw.ns.keycodes[0x72] = GLFW_KEY_INSERT;
|
||||
_glfw.ns.keycodes[0x7B] = GLFW_KEY_LEFT;
|
||||
_glfw.ns.keycodes[0x3A] = GLFW_KEY_LEFT_ALT;
|
||||
_glfw.ns.keycodes[0x3B] = GLFW_KEY_LEFT_CONTROL;
|
||||
_glfw.ns.keycodes[0x38] = GLFW_KEY_LEFT_SHIFT;
|
||||
_glfw.ns.keycodes[0x37] = GLFW_KEY_LEFT_SUPER;
|
||||
_glfw.ns.keycodes[0x6E] = GLFW_KEY_MENU;
|
||||
_glfw.ns.keycodes[0x47] = GLFW_KEY_NUM_LOCK;
|
||||
_glfw.ns.keycodes[0x79] = GLFW_KEY_PAGE_DOWN;
|
||||
_glfw.ns.keycodes[0x74] = GLFW_KEY_PAGE_UP;
|
||||
_glfw.ns.keycodes[0x7C] = GLFW_KEY_RIGHT;
|
||||
_glfw.ns.keycodes[0x3D] = GLFW_KEY_RIGHT_ALT;
|
||||
_glfw.ns.keycodes[0x3E] = GLFW_KEY_RIGHT_CONTROL;
|
||||
_glfw.ns.keycodes[0x3C] = GLFW_KEY_RIGHT_SHIFT;
|
||||
_glfw.ns.keycodes[0x36] = GLFW_KEY_RIGHT_SUPER;
|
||||
_glfw.ns.keycodes[0x31] = GLFW_KEY_SPACE;
|
||||
_glfw.ns.keycodes[0x30] = GLFW_KEY_TAB;
|
||||
_glfw.ns.keycodes[0x7E] = GLFW_KEY_UP;
|
||||
|
||||
_glfw.ns.keycodes[0x52] = GLFW_KEY_KP_0;
|
||||
_glfw.ns.keycodes[0x53] = GLFW_KEY_KP_1;
|
||||
_glfw.ns.keycodes[0x54] = GLFW_KEY_KP_2;
|
||||
_glfw.ns.keycodes[0x55] = GLFW_KEY_KP_3;
|
||||
_glfw.ns.keycodes[0x56] = GLFW_KEY_KP_4;
|
||||
_glfw.ns.keycodes[0x57] = GLFW_KEY_KP_5;
|
||||
_glfw.ns.keycodes[0x58] = GLFW_KEY_KP_6;
|
||||
_glfw.ns.keycodes[0x59] = GLFW_KEY_KP_7;
|
||||
_glfw.ns.keycodes[0x5B] = GLFW_KEY_KP_8;
|
||||
_glfw.ns.keycodes[0x5C] = GLFW_KEY_KP_9;
|
||||
_glfw.ns.keycodes[0x45] = GLFW_KEY_KP_ADD;
|
||||
_glfw.ns.keycodes[0x41] = GLFW_KEY_KP_DECIMAL;
|
||||
_glfw.ns.keycodes[0x4B] = GLFW_KEY_KP_DIVIDE;
|
||||
_glfw.ns.keycodes[0x4C] = GLFW_KEY_KP_ENTER;
|
||||
_glfw.ns.keycodes[0x51] = GLFW_KEY_KP_EQUAL;
|
||||
_glfw.ns.keycodes[0x43] = GLFW_KEY_KP_MULTIPLY;
|
||||
_glfw.ns.keycodes[0x4E] = GLFW_KEY_KP_SUBTRACT;
|
||||
|
||||
for (scancode = 0; scancode < 256; scancode++)
|
||||
{
|
||||
// Store the reverse translation for faster key name lookup
|
||||
if (_glfw.ns.keycodes[scancode] >= 0)
|
||||
_glfw.ns.scancodes[_glfw.ns.keycodes[scancode]] = scancode;
|
||||
}
|
||||
}
|
||||
|
||||
// Retrieve Unicode data for the current keyboard layout
|
||||
//
|
||||
static GLFWbool updateUnicodeDataNS(void)
|
||||
{
|
||||
if (_glfw.ns.inputSource)
|
||||
{
|
||||
CFRelease(_glfw.ns.inputSource);
|
||||
_glfw.ns.inputSource = NULL;
|
||||
_glfw.ns.unicodeData = nil;
|
||||
}
|
||||
|
||||
for (_GLFWwindow *window = _glfw.windowListHead; window; window = window->next)
|
||||
window->ns.deadKeyState = 0;
|
||||
|
||||
_glfw.ns.inputSource = TISCopyCurrentKeyboardLayoutInputSource();
|
||||
if (!_glfw.ns.inputSource)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Cocoa: Failed to retrieve keyboard layout input source");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
_glfw.ns.unicodeData =
|
||||
TISGetInputSourceProperty(_glfw.ns.inputSource,
|
||||
kTISPropertyUnicodeKeyLayoutData);
|
||||
if (!_glfw.ns.unicodeData)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Cocoa: Failed to retrieve keyboard layout Unicode data");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
// Load HIToolbox.framework and the TIS symbols we need from it
|
||||
//
|
||||
static GLFWbool initializeTIS(void)
|
||||
{
|
||||
// This works only because Cocoa has already loaded it properly
|
||||
_glfw.ns.tis.bundle =
|
||||
CFBundleGetBundleWithIdentifier(CFSTR("com.apple.HIToolbox"));
|
||||
if (!_glfw.ns.tis.bundle)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Cocoa: Failed to load HIToolbox.framework");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
CFStringRef* kPropertyUnicodeKeyLayoutData =
|
||||
CFBundleGetDataPointerForName(_glfw.ns.tis.bundle,
|
||||
CFSTR("kTISPropertyUnicodeKeyLayoutData"));
|
||||
_glfw.ns.tis.CopyCurrentKeyboardLayoutInputSource =
|
||||
CFBundleGetFunctionPointerForName(_glfw.ns.tis.bundle,
|
||||
CFSTR("TISCopyCurrentKeyboardLayoutInputSource"));
|
||||
_glfw.ns.tis.GetInputSourceProperty =
|
||||
CFBundleGetFunctionPointerForName(_glfw.ns.tis.bundle,
|
||||
CFSTR("TISGetInputSourceProperty"));
|
||||
_glfw.ns.tis.GetKbdType =
|
||||
CFBundleGetFunctionPointerForName(_glfw.ns.tis.bundle,
|
||||
CFSTR("LMGetKbdType"));
|
||||
|
||||
if (!kPropertyUnicodeKeyLayoutData ||
|
||||
!TISCopyCurrentKeyboardLayoutInputSource ||
|
||||
!TISGetInputSourceProperty ||
|
||||
!LMGetKbdType)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Cocoa: Failed to load TIS API symbols");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
_glfw.ns.tis.kPropertyUnicodeKeyLayoutData =
|
||||
*kPropertyUnicodeKeyLayoutData;
|
||||
|
||||
return updateUnicodeDataNS();
|
||||
}
|
||||
|
||||
@interface GLFWLayoutListener : NSObject
|
||||
@end
|
||||
|
||||
@implementation GLFWLayoutListener
|
||||
|
||||
- (void)selectedKeyboardInputSourceChanged:(NSObject* )object
|
||||
{
|
||||
updateUnicodeDataNS();
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW platform API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int _glfwPlatformInit(void)
|
||||
{
|
||||
_glfw.ns.autoreleasePool = [[NSAutoreleasePool alloc] init];
|
||||
|
||||
if (_glfw.hints.init.ns.chdir)
|
||||
changeToResourcesDirectory();
|
||||
|
||||
_glfw.ns.listener = [[GLFWLayoutListener alloc] init];
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
addObserver:_glfw.ns.listener
|
||||
selector:@selector(selectedKeyboardInputSourceChanged:)
|
||||
name:NSTextInputContextKeyboardSelectionDidChangeNotification
|
||||
object:nil];
|
||||
|
||||
createKeyTables();
|
||||
|
||||
_glfw.ns.eventSource = CGEventSourceCreate(kCGEventSourceStateHIDSystemState);
|
||||
if (!_glfw.ns.eventSource)
|
||||
return GLFW_FALSE;
|
||||
|
||||
CGEventSourceSetLocalEventsSuppressionInterval(_glfw.ns.eventSource, 0.0);
|
||||
|
||||
if (!initializeTIS())
|
||||
return GLFW_FALSE;
|
||||
|
||||
_glfwInitTimerNS();
|
||||
_glfwInitJoysticksNS();
|
||||
|
||||
_glfwPollMonitorsNS();
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
void _glfwPlatformTerminate(void)
|
||||
{
|
||||
if (_glfw.ns.inputSource)
|
||||
{
|
||||
CFRelease(_glfw.ns.inputSource);
|
||||
_glfw.ns.inputSource = NULL;
|
||||
_glfw.ns.unicodeData = nil;
|
||||
}
|
||||
|
||||
if (_glfw.ns.eventSource)
|
||||
{
|
||||
CFRelease(_glfw.ns.eventSource);
|
||||
_glfw.ns.eventSource = NULL;
|
||||
}
|
||||
|
||||
if (_glfw.ns.delegate)
|
||||
{
|
||||
[NSApp setDelegate:nil];
|
||||
[_glfw.ns.delegate release];
|
||||
_glfw.ns.delegate = nil;
|
||||
}
|
||||
|
||||
if (_glfw.ns.listener)
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
removeObserver:_glfw.ns.listener
|
||||
name:NSTextInputContextKeyboardSelectionDidChangeNotification
|
||||
object:nil];
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
removeObserver:_glfw.ns.listener];
|
||||
[_glfw.ns.listener release];
|
||||
_glfw.ns.listener = nil;
|
||||
}
|
||||
|
||||
free(_glfw.ns.clipboardString);
|
||||
|
||||
_glfwTerminateNSGL();
|
||||
_glfwTerminateJoysticksNS();
|
||||
|
||||
[_glfw.ns.autoreleasePool release];
|
||||
_glfw.ns.autoreleasePool = nil;
|
||||
}
|
||||
|
||||
const char* _glfwPlatformGetVersionString(void)
|
||||
{
|
||||
return _GLFW_VERSION_NUMBER " Cocoa NSGL"
|
||||
#if defined(_GLFW_BUILD_DLL)
|
||||
" dynamic"
|
||||
#endif
|
||||
;
|
||||
}
|
||||
50
glfw/cocoa_joystick.h
vendored
Normal file
50
glfw/cocoa_joystick.h
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
//========================================================================
|
||||
// GLFW 3.3 Cocoa - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2006-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 <IOKit/IOKitLib.h>
|
||||
#include <IOKit/IOCFPlugIn.h>
|
||||
#include <IOKit/hid/IOHIDLib.h>
|
||||
#include <IOKit/hid/IOHIDKeys.h>
|
||||
|
||||
#define _GLFW_PLATFORM_JOYSTICK_STATE _GLFWjoystickNS ns
|
||||
#define _GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE
|
||||
|
||||
#define _GLFW_PLATFORM_MAPPING_NAME "Mac OS X"
|
||||
|
||||
// Cocoa-specific per-joystick data
|
||||
//
|
||||
typedef struct _GLFWjoystickNS
|
||||
{
|
||||
IOHIDDeviceRef device;
|
||||
CFMutableArrayRef axes;
|
||||
CFMutableArrayRef buttons;
|
||||
CFMutableArrayRef hats;
|
||||
} _GLFWjoystickNS;
|
||||
|
||||
|
||||
void _glfwInitJoysticksNS(void);
|
||||
void _glfwTerminateJoysticksNS(void);
|
||||
|
||||
462
glfw/cocoa_joystick.m
Normal file
462
glfw/cocoa_joystick.m
Normal file
@@ -0,0 +1,462 @@
|
||||
//========================================================================
|
||||
// GLFW 3.3 Cocoa - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2009-2016 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
|
||||
// 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 <unistd.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <mach/mach.h>
|
||||
#include <mach/mach_error.h>
|
||||
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#include <Kernel/IOKit/hidsystem/IOHIDUsageTables.h>
|
||||
|
||||
|
||||
// Joystick element information
|
||||
//
|
||||
typedef struct _GLFWjoyelementNS
|
||||
{
|
||||
IOHIDElementRef native;
|
||||
uint32_t usage;
|
||||
int index;
|
||||
long minimum;
|
||||
long maximum;
|
||||
|
||||
} _GLFWjoyelementNS;
|
||||
|
||||
|
||||
// Returns the value of the specified element of the specified joystick
|
||||
//
|
||||
static long getElementValue(_GLFWjoystick* js, _GLFWjoyelementNS* element)
|
||||
{
|
||||
IOHIDValueRef valueRef;
|
||||
long value = 0;
|
||||
|
||||
if (js->ns.device)
|
||||
{
|
||||
if (IOHIDDeviceGetValue(js->ns.device,
|
||||
element->native,
|
||||
&valueRef) == kIOReturnSuccess)
|
||||
{
|
||||
value = IOHIDValueGetIntegerValue(valueRef);
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
// Comparison function for matching the SDL element order
|
||||
//
|
||||
static CFComparisonResult compareElements(const void* fp,
|
||||
const void* sp,
|
||||
void* user)
|
||||
{
|
||||
const _GLFWjoyelementNS* fe = fp;
|
||||
const _GLFWjoyelementNS* se = sp;
|
||||
if (fe->usage < se->usage)
|
||||
return kCFCompareLessThan;
|
||||
if (fe->usage > se->usage)
|
||||
return kCFCompareGreaterThan;
|
||||
if (fe->index < se->index)
|
||||
return kCFCompareLessThan;
|
||||
if (fe->index > se->index)
|
||||
return kCFCompareGreaterThan;
|
||||
return kCFCompareEqualTo;
|
||||
}
|
||||
|
||||
// Removes the specified joystick
|
||||
//
|
||||
static void closeJoystick(_GLFWjoystick* js)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!js->present)
|
||||
return;
|
||||
|
||||
for (i = 0; i < CFArrayGetCount(js->ns.axes); i++)
|
||||
free((void*) CFArrayGetValueAtIndex(js->ns.axes, i));
|
||||
CFRelease(js->ns.axes);
|
||||
|
||||
for (i = 0; i < CFArrayGetCount(js->ns.buttons); i++)
|
||||
free((void*) CFArrayGetValueAtIndex(js->ns.buttons, i));
|
||||
CFRelease(js->ns.buttons);
|
||||
|
||||
for (i = 0; i < CFArrayGetCount(js->ns.hats); i++)
|
||||
free((void*) CFArrayGetValueAtIndex(js->ns.hats, i));
|
||||
CFRelease(js->ns.hats);
|
||||
|
||||
_glfwFreeJoystick(js);
|
||||
_glfwInputJoystick(js, GLFW_DISCONNECTED);
|
||||
}
|
||||
|
||||
// Callback for user-initiated joystick addition
|
||||
//
|
||||
static void matchCallback(void* context,
|
||||
IOReturn result,
|
||||
void* sender,
|
||||
IOHIDDeviceRef device)
|
||||
{
|
||||
int jid;
|
||||
char name[256];
|
||||
char guid[33];
|
||||
CFIndex i;
|
||||
CFTypeRef property;
|
||||
uint32_t vendor = 0, product = 0, version = 0;
|
||||
_GLFWjoystick* js;
|
||||
CFMutableArrayRef axes, buttons, hats;
|
||||
|
||||
for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++)
|
||||
{
|
||||
if (_glfw.joysticks[jid].ns.device == device)
|
||||
return;
|
||||
}
|
||||
|
||||
axes = CFArrayCreateMutable(NULL, 0, NULL);
|
||||
buttons = CFArrayCreateMutable(NULL, 0, NULL);
|
||||
hats = CFArrayCreateMutable(NULL, 0, NULL);
|
||||
|
||||
property = IOHIDDeviceGetProperty(device, CFSTR(kIOHIDProductKey));
|
||||
if (property)
|
||||
{
|
||||
CFStringGetCString(property,
|
||||
name,
|
||||
sizeof(name),
|
||||
kCFStringEncodingUTF8);
|
||||
}
|
||||
else
|
||||
strncpy(name, "Unknown", sizeof(name));
|
||||
|
||||
property = IOHIDDeviceGetProperty(device, CFSTR(kIOHIDVendorIDKey));
|
||||
if (property)
|
||||
CFNumberGetValue(property, kCFNumberSInt32Type, &vendor);
|
||||
|
||||
property = IOHIDDeviceGetProperty(device, CFSTR(kIOHIDProductIDKey));
|
||||
if (property)
|
||||
CFNumberGetValue(property, kCFNumberSInt32Type, &product);
|
||||
|
||||
property = IOHIDDeviceGetProperty(device, CFSTR(kIOHIDVersionNumberKey));
|
||||
if (property)
|
||||
CFNumberGetValue(property, kCFNumberSInt32Type, &version);
|
||||
|
||||
// Generate a joystick GUID that matches the SDL 2.0.5+ one
|
||||
if (vendor && product)
|
||||
{
|
||||
sprintf(guid, "03000000%02x%02x0000%02x%02x0000%02x%02x0000",
|
||||
(uint8_t) vendor, (uint8_t) (vendor >> 8),
|
||||
(uint8_t) product, (uint8_t) (product >> 8),
|
||||
(uint8_t) version, (uint8_t) (version >> 8));
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(guid, "05000000%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x00",
|
||||
name[0], name[1], name[2], name[3],
|
||||
name[4], name[5], name[6], name[7],
|
||||
name[8], name[9], name[10]);
|
||||
}
|
||||
|
||||
CFArrayRef elements =
|
||||
IOHIDDeviceCopyMatchingElements(device, NULL, kIOHIDOptionsTypeNone);
|
||||
|
||||
for (i = 0; i < CFArrayGetCount(elements); i++)
|
||||
{
|
||||
IOHIDElementRef native = (IOHIDElementRef)
|
||||
CFArrayGetValueAtIndex(elements, i);
|
||||
if (CFGetTypeID(native) != IOHIDElementGetTypeID())
|
||||
continue;
|
||||
|
||||
const IOHIDElementType type = IOHIDElementGetType(native);
|
||||
if ((type != kIOHIDElementTypeInput_Axis) &&
|
||||
(type != kIOHIDElementTypeInput_Button) &&
|
||||
(type != kIOHIDElementTypeInput_Misc))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
CFMutableArrayRef target = NULL;
|
||||
|
||||
const uint32_t usage = IOHIDElementGetUsage(native);
|
||||
const uint32_t page = IOHIDElementGetUsagePage(native);
|
||||
if (page == kHIDPage_GenericDesktop)
|
||||
{
|
||||
switch (usage)
|
||||
{
|
||||
case kHIDUsage_GD_X:
|
||||
case kHIDUsage_GD_Y:
|
||||
case kHIDUsage_GD_Z:
|
||||
case kHIDUsage_GD_Rx:
|
||||
case kHIDUsage_GD_Ry:
|
||||
case kHIDUsage_GD_Rz:
|
||||
case kHIDUsage_GD_Slider:
|
||||
case kHIDUsage_GD_Dial:
|
||||
case kHIDUsage_GD_Wheel:
|
||||
target = axes;
|
||||
break;
|
||||
case kHIDUsage_GD_Hatswitch:
|
||||
target = hats;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (page == kHIDPage_Button)
|
||||
target = buttons;
|
||||
|
||||
if (target)
|
||||
{
|
||||
_GLFWjoyelementNS* element = calloc(1, sizeof(_GLFWjoyelementNS));
|
||||
element->native = native;
|
||||
element->usage = usage;
|
||||
element->index = (int) CFArrayGetCount(target);
|
||||
element->minimum = IOHIDElementGetLogicalMin(native);
|
||||
element->maximum = IOHIDElementGetLogicalMax(native);
|
||||
CFArrayAppendValue(target, element);
|
||||
}
|
||||
}
|
||||
|
||||
CFRelease(elements);
|
||||
|
||||
CFArraySortValues(axes, CFRangeMake(0, CFArrayGetCount(axes)),
|
||||
compareElements, NULL);
|
||||
CFArraySortValues(buttons, CFRangeMake(0, CFArrayGetCount(buttons)),
|
||||
compareElements, NULL);
|
||||
CFArraySortValues(hats, CFRangeMake(0, CFArrayGetCount(hats)),
|
||||
compareElements, NULL);
|
||||
|
||||
js = _glfwAllocJoystick(name, guid,
|
||||
(int) CFArrayGetCount(axes),
|
||||
(int) CFArrayGetCount(buttons),
|
||||
(int) CFArrayGetCount(hats));
|
||||
|
||||
js->ns.device = device;
|
||||
js->ns.axes = axes;
|
||||
js->ns.buttons = buttons;
|
||||
js->ns.hats = hats;
|
||||
|
||||
_glfwInputJoystick(js, GLFW_CONNECTED);
|
||||
}
|
||||
|
||||
// Callback for user-initiated joystick removal
|
||||
//
|
||||
static void removeCallback(void* context,
|
||||
IOReturn result,
|
||||
void* sender,
|
||||
IOHIDDeviceRef device)
|
||||
{
|
||||
int jid;
|
||||
|
||||
for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++)
|
||||
{
|
||||
if (_glfw.joysticks[jid].ns.device == device)
|
||||
{
|
||||
closeJoystick(_glfw.joysticks + jid);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW internal API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Initialize joystick interface
|
||||
//
|
||||
void _glfwInitJoysticksNS(void)
|
||||
{
|
||||
CFMutableArrayRef matching;
|
||||
const long usages[] =
|
||||
{
|
||||
kHIDUsage_GD_Joystick,
|
||||
kHIDUsage_GD_GamePad,
|
||||
kHIDUsage_GD_MultiAxisController
|
||||
};
|
||||
|
||||
_glfw.ns.hidManager = IOHIDManagerCreate(kCFAllocatorDefault,
|
||||
kIOHIDOptionsTypeNone);
|
||||
|
||||
matching = CFArrayCreateMutable(kCFAllocatorDefault,
|
||||
0,
|
||||
&kCFTypeArrayCallBacks);
|
||||
if (!matching)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR, "Cocoa: Failed to create array");
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < sizeof(usages) / sizeof(long); i++)
|
||||
{
|
||||
const long page = kHIDPage_GenericDesktop;
|
||||
|
||||
CFMutableDictionaryRef dict =
|
||||
CFDictionaryCreateMutable(kCFAllocatorDefault,
|
||||
0,
|
||||
&kCFTypeDictionaryKeyCallBacks,
|
||||
&kCFTypeDictionaryValueCallBacks);
|
||||
if (!dict)
|
||||
continue;
|
||||
|
||||
CFNumberRef pageRef = CFNumberCreate(kCFAllocatorDefault,
|
||||
kCFNumberLongType,
|
||||
&page);
|
||||
CFNumberRef usageRef = CFNumberCreate(kCFAllocatorDefault,
|
||||
kCFNumberLongType,
|
||||
&usages[i]);
|
||||
if (pageRef && usageRef)
|
||||
{
|
||||
CFDictionarySetValue(dict,
|
||||
CFSTR(kIOHIDDeviceUsagePageKey),
|
||||
pageRef);
|
||||
CFDictionarySetValue(dict,
|
||||
CFSTR(kIOHIDDeviceUsageKey),
|
||||
usageRef);
|
||||
CFArrayAppendValue(matching, dict);
|
||||
}
|
||||
|
||||
if (pageRef)
|
||||
CFRelease(pageRef);
|
||||
if (usageRef)
|
||||
CFRelease(usageRef);
|
||||
|
||||
CFRelease(dict);
|
||||
}
|
||||
|
||||
IOHIDManagerSetDeviceMatchingMultiple(_glfw.ns.hidManager, matching);
|
||||
CFRelease(matching);
|
||||
|
||||
IOHIDManagerRegisterDeviceMatchingCallback(_glfw.ns.hidManager,
|
||||
&matchCallback, NULL);
|
||||
IOHIDManagerRegisterDeviceRemovalCallback(_glfw.ns.hidManager,
|
||||
&removeCallback, NULL);
|
||||
IOHIDManagerScheduleWithRunLoop(_glfw.ns.hidManager,
|
||||
CFRunLoopGetMain(),
|
||||
kCFRunLoopDefaultMode);
|
||||
IOHIDManagerOpen(_glfw.ns.hidManager, kIOHIDOptionsTypeNone);
|
||||
|
||||
// Execute the run loop once in order to register any initially-attached
|
||||
// joysticks
|
||||
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, false);
|
||||
}
|
||||
|
||||
// Close all opened joystick handles
|
||||
//
|
||||
void _glfwTerminateJoysticksNS(void)
|
||||
{
|
||||
int jid;
|
||||
|
||||
for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++)
|
||||
closeJoystick(_glfw.joysticks + jid);
|
||||
|
||||
CFRelease(_glfw.ns.hidManager);
|
||||
_glfw.ns.hidManager = NULL;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW platform API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int _glfwPlatformPollJoystick(_GLFWjoystick* js, int mode)
|
||||
{
|
||||
if (mode & _GLFW_POLL_AXES)
|
||||
{
|
||||
CFIndex i;
|
||||
|
||||
for (i = 0; i < CFArrayGetCount(js->ns.axes); i++)
|
||||
{
|
||||
_GLFWjoyelementNS* axis = (_GLFWjoyelementNS*)
|
||||
CFArrayGetValueAtIndex(js->ns.axes, i);
|
||||
|
||||
const long raw = getElementValue(js, axis);
|
||||
// Perform auto calibration
|
||||
if (raw < axis->minimum)
|
||||
axis->minimum = raw;
|
||||
if (raw > axis->maximum)
|
||||
axis->maximum = raw;
|
||||
|
||||
const long delta = axis->maximum - axis->minimum;
|
||||
if (delta == 0)
|
||||
_glfwInputJoystickAxis(js, (int) i, 0.f);
|
||||
else
|
||||
{
|
||||
const float value = (2.f * (raw - axis->minimum) / delta) - 1.f;
|
||||
_glfwInputJoystickAxis(js, (int) i, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mode & _GLFW_POLL_BUTTONS)
|
||||
{
|
||||
CFIndex i;
|
||||
|
||||
for (i = 0; i < CFArrayGetCount(js->ns.buttons); i++)
|
||||
{
|
||||
_GLFWjoyelementNS* button = (_GLFWjoyelementNS*)
|
||||
CFArrayGetValueAtIndex(js->ns.buttons, i);
|
||||
const char value = getElementValue(js, button) - button->minimum;
|
||||
_glfwInputJoystickButton(js, (int) i, value);
|
||||
}
|
||||
|
||||
for (i = 0; i < CFArrayGetCount(js->ns.hats); i++)
|
||||
{
|
||||
const int states[9] =
|
||||
{
|
||||
GLFW_HAT_UP,
|
||||
GLFW_HAT_RIGHT_UP,
|
||||
GLFW_HAT_RIGHT,
|
||||
GLFW_HAT_RIGHT_DOWN,
|
||||
GLFW_HAT_DOWN,
|
||||
GLFW_HAT_LEFT_DOWN,
|
||||
GLFW_HAT_LEFT,
|
||||
GLFW_HAT_LEFT_UP,
|
||||
GLFW_HAT_CENTERED
|
||||
};
|
||||
|
||||
_GLFWjoyelementNS* hat = (_GLFWjoyelementNS*)
|
||||
CFArrayGetValueAtIndex(js->ns.hats, i);
|
||||
long state = getElementValue(js, hat) - hat->minimum;
|
||||
if (state < 0 || state > 8)
|
||||
state = 8;
|
||||
|
||||
_glfwInputJoystickHat(js, (int) i, states[state]);
|
||||
}
|
||||
}
|
||||
|
||||
return js->present;
|
||||
}
|
||||
|
||||
void _glfwPlatformUpdateGamepadGUID(char* guid)
|
||||
{
|
||||
if ((strncmp(guid + 4, "000000000000", 12) == 0) &&
|
||||
(strncmp(guid + 20, "000000000000", 12) == 0))
|
||||
{
|
||||
char original[33];
|
||||
strcpy(original, guid);
|
||||
sprintf(guid, "03000000%.4s0000%.4s000000000000",
|
||||
original, original + 16);
|
||||
}
|
||||
}
|
||||
|
||||
526
glfw/cocoa_monitor.m
Normal file
526
glfw/cocoa_monitor.m
Normal file
@@ -0,0 +1,526 @@
|
||||
//========================================================================
|
||||
// GLFW 3.3 macOS - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||
// Copyright (c) 2006-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 <stdlib.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include <IOKit/graphics/IOGraphicsLib.h>
|
||||
#include <CoreVideo/CVBase.h>
|
||||
#include <CoreVideo/CVDisplayLink.h>
|
||||
#include <ApplicationServices/ApplicationServices.h>
|
||||
|
||||
|
||||
// Get the name of the specified display, or NULL
|
||||
//
|
||||
static char* getDisplayName(CGDirectDisplayID displayID)
|
||||
{
|
||||
io_iterator_t it;
|
||||
io_service_t service;
|
||||
CFDictionaryRef info;
|
||||
|
||||
if (IOServiceGetMatchingServices(kIOMasterPortDefault,
|
||||
IOServiceMatching("IODisplayConnect"),
|
||||
&it) != 0)
|
||||
{
|
||||
// This may happen if a desktop Mac is running headless
|
||||
return NULL;
|
||||
}
|
||||
|
||||
while ((service = IOIteratorNext(it)) != 0)
|
||||
{
|
||||
info = IODisplayCreateInfoDictionary(service,
|
||||
kIODisplayOnlyPreferredName);
|
||||
|
||||
CFNumberRef vendorIDRef =
|
||||
CFDictionaryGetValue(info, CFSTR(kDisplayVendorID));
|
||||
CFNumberRef productIDRef =
|
||||
CFDictionaryGetValue(info, CFSTR(kDisplayProductID));
|
||||
if (!vendorIDRef || !productIDRef)
|
||||
{
|
||||
CFRelease(info);
|
||||
continue;
|
||||
}
|
||||
|
||||
unsigned int vendorID, productID;
|
||||
CFNumberGetValue(vendorIDRef, kCFNumberIntType, &vendorID);
|
||||
CFNumberGetValue(productIDRef, kCFNumberIntType, &productID);
|
||||
|
||||
if (CGDisplayVendorNumber(displayID) == vendorID &&
|
||||
CGDisplayModelNumber(displayID) == productID)
|
||||
{
|
||||
// Info dictionary is used and freed below
|
||||
break;
|
||||
}
|
||||
|
||||
CFRelease(info);
|
||||
}
|
||||
|
||||
IOObjectRelease(it);
|
||||
|
||||
if (!service)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Cocoa: Failed to find service port for display");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
CFDictionaryRef names =
|
||||
CFDictionaryGetValue(info, CFSTR(kDisplayProductName));
|
||||
|
||||
CFStringRef nameRef;
|
||||
|
||||
if (!names || !CFDictionaryGetValueIfPresent(names, CFSTR("en_US"),
|
||||
(const void**) &nameRef))
|
||||
{
|
||||
// This may happen if a desktop Mac is running headless
|
||||
CFRelease(info);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const CFIndex size =
|
||||
CFStringGetMaximumSizeForEncoding(CFStringGetLength(nameRef),
|
||||
kCFStringEncodingUTF8);
|
||||
char* name = calloc(size + 1, 1);
|
||||
CFStringGetCString(nameRef, name, size, kCFStringEncodingUTF8);
|
||||
|
||||
CFRelease(info);
|
||||
return name;
|
||||
}
|
||||
|
||||
// Check whether the display mode should be included in enumeration
|
||||
//
|
||||
static GLFWbool modeIsGood(CGDisplayModeRef mode)
|
||||
{
|
||||
uint32_t flags = CGDisplayModeGetIOFlags(mode);
|
||||
|
||||
if (!(flags & kDisplayModeValidFlag) || !(flags & kDisplayModeSafeFlag))
|
||||
return GLFW_FALSE;
|
||||
if (flags & kDisplayModeInterlacedFlag)
|
||||
return GLFW_FALSE;
|
||||
if (flags & kDisplayModeStretchedFlag)
|
||||
return GLFW_FALSE;
|
||||
|
||||
#if MAC_OS_X_VERSION_MAX_ALLOWED <= 101100
|
||||
CFStringRef format = CGDisplayModeCopyPixelEncoding(mode);
|
||||
if (CFStringCompare(format, CFSTR(IO16BitDirectPixels), 0) &&
|
||||
CFStringCompare(format, CFSTR(IO32BitDirectPixels), 0))
|
||||
{
|
||||
CFRelease(format);
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
CFRelease(format);
|
||||
#endif /* MAC_OS_X_VERSION_MAX_ALLOWED */
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
// Convert Core Graphics display mode to GLFW video mode
|
||||
//
|
||||
static GLFWvidmode vidmodeFromCGDisplayMode(CGDisplayModeRef mode,
|
||||
CVDisplayLinkRef link)
|
||||
{
|
||||
GLFWvidmode result;
|
||||
result.width = (int) CGDisplayModeGetWidth(mode);
|
||||
result.height = (int) CGDisplayModeGetHeight(mode);
|
||||
result.refreshRate = (int) CGDisplayModeGetRefreshRate(mode);
|
||||
|
||||
if (result.refreshRate == 0)
|
||||
{
|
||||
const CVTime time = CVDisplayLinkGetNominalOutputVideoRefreshPeriod(link);
|
||||
if (!(time.flags & kCVTimeIsIndefinite))
|
||||
result.refreshRate = (int) (time.timeScale / (double) time.timeValue);
|
||||
}
|
||||
|
||||
#if MAC_OS_X_VERSION_MAX_ALLOWED <= 101100
|
||||
CFStringRef format = CGDisplayModeCopyPixelEncoding(mode);
|
||||
if (CFStringCompare(format, CFSTR(IO16BitDirectPixels), 0) == 0)
|
||||
{
|
||||
result.redBits = 5;
|
||||
result.greenBits = 5;
|
||||
result.blueBits = 5;
|
||||
}
|
||||
else
|
||||
#endif /* MAC_OS_X_VERSION_MAX_ALLOWED */
|
||||
{
|
||||
result.redBits = 8;
|
||||
result.greenBits = 8;
|
||||
result.blueBits = 8;
|
||||
}
|
||||
|
||||
#if MAC_OS_X_VERSION_MAX_ALLOWED <= 101100
|
||||
CFRelease(format);
|
||||
#endif /* MAC_OS_X_VERSION_MAX_ALLOWED */
|
||||
return result;
|
||||
}
|
||||
|
||||
// Starts reservation for display fading
|
||||
//
|
||||
static CGDisplayFadeReservationToken beginFadeReservation(void)
|
||||
{
|
||||
CGDisplayFadeReservationToken token = kCGDisplayFadeReservationInvalidToken;
|
||||
|
||||
if (CGAcquireDisplayFadeReservation(5, &token) == kCGErrorSuccess)
|
||||
{
|
||||
CGDisplayFade(token, 0.3,
|
||||
kCGDisplayBlendNormal,
|
||||
kCGDisplayBlendSolidColor,
|
||||
0.0, 0.0, 0.0,
|
||||
TRUE);
|
||||
}
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
// Ends reservation for display fading
|
||||
//
|
||||
static void endFadeReservation(CGDisplayFadeReservationToken token)
|
||||
{
|
||||
if (token != kCGDisplayFadeReservationInvalidToken)
|
||||
{
|
||||
CGDisplayFade(token, 0.5,
|
||||
kCGDisplayBlendSolidColor,
|
||||
kCGDisplayBlendNormal,
|
||||
0.0, 0.0, 0.0,
|
||||
FALSE);
|
||||
CGReleaseDisplayFadeReservation(token);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW internal API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Poll for changes in the set of connected monitors
|
||||
//
|
||||
void _glfwPollMonitorsNS(void)
|
||||
{
|
||||
uint32_t i, j, displayCount, disconnectedCount;
|
||||
CGDirectDisplayID* displays;
|
||||
_GLFWmonitor** disconnected = NULL;
|
||||
|
||||
CGGetOnlineDisplayList(0, NULL, &displayCount);
|
||||
displays = calloc(displayCount, sizeof(CGDirectDisplayID));
|
||||
CGGetOnlineDisplayList(displayCount, displays, &displayCount);
|
||||
|
||||
for (i = 0; i < _glfw.monitorCount; i++)
|
||||
_glfw.monitors[i]->ns.screen = nil;
|
||||
|
||||
disconnectedCount = _glfw.monitorCount;
|
||||
if (disconnectedCount)
|
||||
{
|
||||
disconnected = calloc(_glfw.monitorCount, sizeof(_GLFWmonitor*));
|
||||
memcpy(disconnected,
|
||||
_glfw.monitors,
|
||||
_glfw.monitorCount * sizeof(_GLFWmonitor*));
|
||||
}
|
||||
|
||||
for (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
|
||||
if (disconnected[j] && disconnected[j]->ns.unitNumber == unitNumber)
|
||||
{
|
||||
disconnected[j] = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const CGSize size = CGDisplayScreenSize(displays[i]);
|
||||
char* name = getDisplayName(displays[i]);
|
||||
if (!name)
|
||||
name = _glfw_strdup("Unknown");
|
||||
|
||||
monitor = _glfwAllocMonitor(name, size.width, size.height);
|
||||
monitor->ns.displayID = displays[i];
|
||||
monitor->ns.unitNumber = unitNumber;
|
||||
|
||||
free(name);
|
||||
|
||||
_glfwInputMonitor(monitor, GLFW_CONNECTED, _GLFW_INSERT_LAST);
|
||||
}
|
||||
|
||||
for (i = 0; i < disconnectedCount; i++)
|
||||
{
|
||||
if (disconnected[i])
|
||||
_glfwInputMonitor(disconnected[i], GLFW_DISCONNECTED, 0);
|
||||
}
|
||||
|
||||
free(disconnected);
|
||||
free(displays);
|
||||
}
|
||||
|
||||
// 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);
|
||||
if (_glfwCompareVideoModes(¤t, best) == 0)
|
||||
return;
|
||||
|
||||
CVDisplayLinkCreateWithCGDisplay(monitor->ns.displayID, &link);
|
||||
|
||||
modes = CGDisplayCopyAllDisplayModes(monitor->ns.displayID, NULL);
|
||||
count = CFArrayGetCount(modes);
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
CGDisplayModeRef dm = (CGDisplayModeRef) CFArrayGetValueAtIndex(modes, i);
|
||||
if (!modeIsGood(dm))
|
||||
continue;
|
||||
|
||||
const GLFWvidmode mode = vidmodeFromCGDisplayMode(dm, link);
|
||||
if (_glfwCompareVideoModes(best, &mode) == 0)
|
||||
{
|
||||
native = dm;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (native)
|
||||
{
|
||||
if (monitor->ns.previousMode == NULL)
|
||||
monitor->ns.previousMode = CGDisplayCopyDisplayMode(monitor->ns.displayID);
|
||||
|
||||
CGDisplayFadeReservationToken token = beginFadeReservation();
|
||||
CGDisplaySetDisplayMode(monitor->ns.displayID, native, NULL);
|
||||
endFadeReservation(token);
|
||||
}
|
||||
|
||||
CFRelease(modes);
|
||||
CVDisplayLinkRelease(link);
|
||||
}
|
||||
|
||||
// Restore the previously saved (original) video mode
|
||||
//
|
||||
void _glfwRestoreVideoModeNS(_GLFWmonitor* monitor)
|
||||
{
|
||||
if (monitor->ns.previousMode)
|
||||
{
|
||||
CGDisplayFadeReservationToken token = beginFadeReservation();
|
||||
CGDisplaySetDisplayMode(monitor->ns.displayID,
|
||||
monitor->ns.previousMode, NULL);
|
||||
endFadeReservation(token);
|
||||
|
||||
CGDisplayModeRelease(monitor->ns.previousMode);
|
||||
monitor->ns.previousMode = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW platform API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void _glfwPlatformFreeMonitor(_GLFWmonitor* monitor)
|
||||
{
|
||||
}
|
||||
|
||||
void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos)
|
||||
{
|
||||
const CGRect bounds = CGDisplayBounds(monitor->ns.displayID);
|
||||
|
||||
if (xpos)
|
||||
*xpos = (int) bounds.origin.x;
|
||||
if (ypos)
|
||||
*ypos = (int) bounds.origin.y;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
const NSRect points = [monitor->ns.screen frame];
|
||||
const NSRect pixels = [monitor->ns.screen convertRectToBacking:points];
|
||||
|
||||
if (xscale)
|
||||
*xscale = (float) (pixels.size.width / points.size.width);
|
||||
if (yscale)
|
||||
*yscale = (float) (pixels.size.height / points.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);
|
||||
|
||||
modes = CGDisplayCopyAllDisplayModes(monitor->ns.displayID, NULL);
|
||||
found = CFArrayGetCount(modes);
|
||||
result = calloc(found, sizeof(GLFWvidmode));
|
||||
|
||||
for (i = 0; i < found; i++)
|
||||
{
|
||||
CGDisplayModeRef dm = (CGDisplayModeRef) CFArrayGetValueAtIndex(modes, i);
|
||||
if (!modeIsGood(dm))
|
||||
continue;
|
||||
|
||||
const GLFWvidmode mode = vidmodeFromCGDisplayMode(dm, link);
|
||||
|
||||
for (j = 0; j < *count; j++)
|
||||
{
|
||||
if (_glfwCompareVideoModes(result + j, &mode) == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
// Skip duplicate modes
|
||||
if (i < *count)
|
||||
continue;
|
||||
|
||||
(*count)++;
|
||||
result[*count - 1] = mode;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
|
||||
{
|
||||
uint32_t i, size = CGDisplayGammaTableCapacity(monitor->ns.displayID);
|
||||
CGGammaValue* values = calloc(size * 3, sizeof(CGGammaValue));
|
||||
|
||||
CGGetDisplayTransferByTable(monitor->ns.displayID,
|
||||
size,
|
||||
values,
|
||||
values + size,
|
||||
values + size * 2,
|
||||
&size);
|
||||
|
||||
_glfwAllocGammaArrays(ramp, size);
|
||||
|
||||
for (i = 0; i < size; i++)
|
||||
{
|
||||
ramp->red[i] = (unsigned short) (values[i] * 65535);
|
||||
ramp->green[i] = (unsigned short) (values[i + size] * 65535);
|
||||
ramp->blue[i] = (unsigned short) (values[i + size * 2] * 65535);
|
||||
}
|
||||
|
||||
free(values);
|
||||
}
|
||||
|
||||
void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp)
|
||||
{
|
||||
int i;
|
||||
CGGammaValue* values = calloc(ramp->size * 3, sizeof(CGGammaValue));
|
||||
|
||||
for (i = 0; i < ramp->size; i++)
|
||||
{
|
||||
values[i] = ramp->red[i] / 65535.f;
|
||||
values[i + ramp->size] = ramp->green[i] / 65535.f;
|
||||
values[i + ramp->size * 2] = ramp->blue[i] / 65535.f;
|
||||
}
|
||||
|
||||
CGSetDisplayTransferByTable(monitor->ns.displayID,
|
||||
ramp->size,
|
||||
values,
|
||||
values + ramp->size,
|
||||
values + ramp->size * 2);
|
||||
|
||||
free(values);
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW native API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
GLFWAPI CGDirectDisplayID glfwGetCocoaMonitor(GLFWmonitor* handle)
|
||||
{
|
||||
_GLFWmonitor* monitor = (_GLFWmonitor*) handle;
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(kCGNullDirectDisplay);
|
||||
return monitor->ns.displayID;
|
||||
}
|
||||
|
||||
176
glfw/cocoa_platform.h
vendored
Normal file
176
glfw/cocoa_platform.h
vendored
Normal file
@@ -0,0 +1,176 @@
|
||||
//========================================================================
|
||||
// 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 <stdint.h>
|
||||
#include <dlfcn.h>
|
||||
|
||||
#include <Carbon/Carbon.h>
|
||||
#if defined(__OBJC__)
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#else
|
||||
typedef void* id;
|
||||
#endif
|
||||
|
||||
typedef VkFlags VkMacOSSurfaceCreateFlagsMVK;
|
||||
typedef int (* GLFWcocoatextinputfilterfun)(int,int,int);
|
||||
typedef int (* GLFWapplicationshouldhandlereopenfun)(int);
|
||||
typedef int (* GLFWcocoatogglefullscreenfun)(GLFWwindow*);
|
||||
|
||||
typedef struct VkMacOSSurfaceCreateInfoMVK
|
||||
{
|
||||
VkStructureType sType;
|
||||
const void* pNext;
|
||||
VkMacOSSurfaceCreateFlagsMVK flags;
|
||||
const void* pView;
|
||||
} VkMacOSSurfaceCreateInfoMVK;
|
||||
|
||||
typedef VkResult (APIENTRY *PFN_vkCreateMacOSSurfaceMVK)(VkInstance,const VkMacOSSurfaceCreateInfoMVK*,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
|
||||
#define _GLFW_PLATFORM_MONITOR_STATE _GLFWmonitorNS ns
|
||||
#define _GLFW_PLATFORM_CURSOR_STATE _GLFWcursorNS ns
|
||||
|
||||
// HIToolbox.framework pointer typedefs
|
||||
#define kTISPropertyUnicodeKeyLayoutData _glfw.ns.tis.kPropertyUnicodeKeyLayoutData
|
||||
typedef TISInputSourceRef (*PFN_TISCopyCurrentKeyboardLayoutInputSource)(void);
|
||||
#define TISCopyCurrentKeyboardLayoutInputSource _glfw.ns.tis.CopyCurrentKeyboardLayoutInputSource
|
||||
typedef void* (*PFN_TISGetInputSourceProperty)(TISInputSourceRef,CFStringRef);
|
||||
#define TISGetInputSourceProperty _glfw.ns.tis.GetInputSourceProperty
|
||||
typedef UInt8 (*PFN_LMGetKbdType)(void);
|
||||
#define LMGetKbdType _glfw.ns.tis.GetKbdType
|
||||
|
||||
|
||||
// Cocoa-specific per-window data
|
||||
//
|
||||
typedef struct _GLFWwindowNS
|
||||
{
|
||||
id object;
|
||||
id delegate;
|
||||
id view;
|
||||
id layer;
|
||||
|
||||
GLFWbool maximized;
|
||||
|
||||
// Cached window properties to filter out duplicate events
|
||||
int width, height;
|
||||
int fbWidth, fbHeight;
|
||||
float xscale, yscale;
|
||||
|
||||
// The total sum of the distances the cursor has been warped
|
||||
// since the last cursor motion event was processed
|
||||
// This is kept to counteract Cocoa doing the same internally
|
||||
double cursorWarpDeltaX, cursorWarpDeltaY;
|
||||
|
||||
// The text input filter callback
|
||||
GLFWcocoatextinputfilterfun textInputFilterCallback;
|
||||
// The toggle fullscreen intercept callback
|
||||
GLFWcocoatogglefullscreenfun toggleFullscreenCallback;
|
||||
// Dead key state
|
||||
UInt32 deadKeyState;
|
||||
} _GLFWwindowNS;
|
||||
|
||||
// Cocoa-specific global data
|
||||
//
|
||||
typedef struct _GLFWlibraryNS
|
||||
{
|
||||
CGEventSourceRef eventSource;
|
||||
id delegate;
|
||||
id autoreleasePool;
|
||||
GLFWbool cursorHidden;
|
||||
TISInputSourceRef inputSource;
|
||||
IOHIDManagerRef hidManager;
|
||||
id unicodeData;
|
||||
id listener;
|
||||
|
||||
char keyName[64];
|
||||
char text[256];
|
||||
short int keycodes[256];
|
||||
short int scancodes[GLFW_KEY_LAST + 1];
|
||||
char* clipboardString;
|
||||
CGPoint cascadePoint;
|
||||
// Where to place the cursor when re-enabled
|
||||
double restoreCursorPosX, restoreCursorPosY;
|
||||
// The window whose disabled cursor mode is active
|
||||
_GLFWwindow* disabledCursorWindow;
|
||||
|
||||
struct {
|
||||
CFBundleRef bundle;
|
||||
PFN_TISCopyCurrentKeyboardLayoutInputSource CopyCurrentKeyboardLayoutInputSource;
|
||||
PFN_TISGetInputSourceProperty GetInputSourceProperty;
|
||||
PFN_LMGetKbdType GetKbdType;
|
||||
CFStringRef kPropertyUnicodeKeyLayoutData;
|
||||
} tis;
|
||||
|
||||
} _GLFWlibraryNS;
|
||||
|
||||
// Cocoa-specific per-monitor data
|
||||
//
|
||||
typedef struct _GLFWmonitorNS
|
||||
{
|
||||
CGDirectDisplayID displayID;
|
||||
CGDisplayModeRef previousMode;
|
||||
uint32_t unitNumber;
|
||||
id screen;
|
||||
|
||||
} _GLFWmonitorNS;
|
||||
|
||||
// Cocoa-specific per-cursor data
|
||||
//
|
||||
typedef struct _GLFWcursorNS
|
||||
{
|
||||
id object;
|
||||
|
||||
} _GLFWcursorNS;
|
||||
|
||||
// Cocoa-specific global timer data
|
||||
//
|
||||
typedef struct _GLFWtimerNS
|
||||
{
|
||||
uint64_t frequency;
|
||||
|
||||
} _GLFWtimerNS;
|
||||
|
||||
|
||||
void _glfwInitTimerNS(void);
|
||||
|
||||
void _glfwPollMonitorsNS(void);
|
||||
void _glfwSetVideoModeNS(_GLFWmonitor* monitor, const GLFWvidmode* desired);
|
||||
void _glfwRestoreVideoModeNS(_GLFWmonitor* monitor);
|
||||
60
glfw/cocoa_time.c
vendored
Normal file
60
glfw/cocoa_time.c
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
//========================================================================
|
||||
// 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;
|
||||
}
|
||||
|
||||
2251
glfw/cocoa_window.m
Normal file
2251
glfw/cocoa_window.m
Normal file
File diff suppressed because it is too large
Load Diff
758
glfw/context.c
vendored
Normal file
758
glfw/context.c
vendored
Normal file
@@ -0,0 +1,758 @@
|
||||
//========================================================================
|
||||
// GLFW 3.3 - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||
// Copyright (c) 2006-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 <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW internal API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Checks whether the desired context attributes are valid
|
||||
//
|
||||
// This function checks things like whether the specified client API version
|
||||
// exists and whether all relevant options have supported and non-conflicting
|
||||
// values
|
||||
//
|
||||
GLFWbool _glfwIsValidContextConfig(const _GLFWctxconfig* ctxconfig)
|
||||
{
|
||||
if (ctxconfig->share)
|
||||
{
|
||||
if (ctxconfig->client == GLFW_NO_API ||
|
||||
ctxconfig->share->context.client == GLFW_NO_API)
|
||||
{
|
||||
_glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (ctxconfig->source != GLFW_NATIVE_CONTEXT_API &&
|
||||
ctxconfig->source != GLFW_EGL_CONTEXT_API &&
|
||||
ctxconfig->source != GLFW_OSMESA_CONTEXT_API)
|
||||
{
|
||||
_glfwInputError(GLFW_INVALID_ENUM,
|
||||
"Invalid context creation API 0x%08X",
|
||||
ctxconfig->source);
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
if (ctxconfig->client != GLFW_NO_API &&
|
||||
ctxconfig->client != GLFW_OPENGL_API &&
|
||||
ctxconfig->client != GLFW_OPENGL_ES_API)
|
||||
{
|
||||
_glfwInputError(GLFW_INVALID_ENUM,
|
||||
"Invalid client API 0x%08X",
|
||||
ctxconfig->client);
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
if (ctxconfig->client == GLFW_OPENGL_API)
|
||||
{
|
||||
if ((ctxconfig->major < 1 || ctxconfig->minor < 0) ||
|
||||
(ctxconfig->major == 1 && ctxconfig->minor > 5) ||
|
||||
(ctxconfig->major == 2 && ctxconfig->minor > 1) ||
|
||||
(ctxconfig->major == 3 && ctxconfig->minor > 3))
|
||||
{
|
||||
// OpenGL 1.0 is the smallest valid version
|
||||
// OpenGL 1.x series ended with version 1.5
|
||||
// OpenGL 2.x series ended with version 2.1
|
||||
// OpenGL 3.x series ended with version 3.3
|
||||
// For now, let everything else through
|
||||
|
||||
_glfwInputError(GLFW_INVALID_VALUE,
|
||||
"Invalid OpenGL version %i.%i",
|
||||
ctxconfig->major, ctxconfig->minor);
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
if (ctxconfig->profile)
|
||||
{
|
||||
if (ctxconfig->profile != GLFW_OPENGL_CORE_PROFILE &&
|
||||
ctxconfig->profile != GLFW_OPENGL_COMPAT_PROFILE)
|
||||
{
|
||||
_glfwInputError(GLFW_INVALID_ENUM,
|
||||
"Invalid OpenGL profile 0x%08X",
|
||||
ctxconfig->profile);
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
if (ctxconfig->major <= 2 ||
|
||||
(ctxconfig->major == 3 && ctxconfig->minor < 2))
|
||||
{
|
||||
// Desktop OpenGL context profiles are only defined for version 3.2
|
||||
// and above
|
||||
|
||||
_glfwInputError(GLFW_INVALID_VALUE,
|
||||
"Context profiles are only defined for OpenGL version 3.2 and above");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (ctxconfig->forward && ctxconfig->major <= 2)
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
else if (ctxconfig->client == GLFW_OPENGL_ES_API)
|
||||
{
|
||||
if (ctxconfig->major < 1 || ctxconfig->minor < 0 ||
|
||||
(ctxconfig->major == 1 && ctxconfig->minor > 1) ||
|
||||
(ctxconfig->major == 2 && ctxconfig->minor > 0))
|
||||
{
|
||||
// OpenGL ES 1.0 is the smallest valid version
|
||||
// OpenGL ES 1.x series ended with version 1.1
|
||||
// OpenGL ES 2.x series ended with version 2.0
|
||||
// For now, let everything else through
|
||||
|
||||
_glfwInputError(GLFW_INVALID_VALUE,
|
||||
"Invalid OpenGL ES version %i.%i",
|
||||
ctxconfig->major, ctxconfig->minor);
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (ctxconfig->robustness)
|
||||
{
|
||||
if (ctxconfig->robustness != GLFW_NO_RESET_NOTIFICATION &&
|
||||
ctxconfig->robustness != GLFW_LOSE_CONTEXT_ON_RESET)
|
||||
{
|
||||
_glfwInputError(GLFW_INVALID_ENUM,
|
||||
"Invalid context robustness mode 0x%08X",
|
||||
ctxconfig->robustness);
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (ctxconfig->release)
|
||||
{
|
||||
if (ctxconfig->release != GLFW_RELEASE_BEHAVIOR_NONE &&
|
||||
ctxconfig->release != GLFW_RELEASE_BEHAVIOR_FLUSH)
|
||||
{
|
||||
_glfwInputError(GLFW_INVALID_ENUM,
|
||||
"Invalid context release behavior 0x%08X",
|
||||
ctxconfig->release);
|
||||
return GLFW_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;
|
||||
}
|
||||
|
||||
// Retrieves the attributes of the current context
|
||||
//
|
||||
GLFWbool _glfwRefreshContextAttribs(_GLFWwindow* window,
|
||||
const _GLFWctxconfig* ctxconfig)
|
||||
{
|
||||
int i;
|
||||
_GLFWwindow* previous;
|
||||
const char* version;
|
||||
const char* prefixes[] =
|
||||
{
|
||||
"OpenGL ES-CM ",
|
||||
"OpenGL ES-CL ",
|
||||
"OpenGL ES ",
|
||||
NULL
|
||||
};
|
||||
|
||||
window->context.source = ctxconfig->source;
|
||||
window->context.client = GLFW_OPENGL_API;
|
||||
|
||||
previous = _glfwPlatformGetTls(&_glfw.contextSlot);;
|
||||
glfwMakeContextCurrent((GLFWwindow*) window);
|
||||
|
||||
window->context.GetIntegerv = (PFNGLGETINTEGERVPROC)
|
||||
window->context.getProcAddress("glGetIntegerv");
|
||||
window->context.GetString = (PFNGLGETSTRINGPROC)
|
||||
window->context.getProcAddress("glGetString");
|
||||
if (!window->context.GetIntegerv || !window->context.GetString)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR, "Entry point retrieval is broken");
|
||||
glfwMakeContextCurrent((GLFWwindow*) previous);
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
version = (const char*) window->context.GetString(GL_VERSION);
|
||||
if (!version)
|
||||
{
|
||||
if (ctxconfig->client == GLFW_OPENGL_API)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"OpenGL version string retrieval is broken");
|
||||
}
|
||||
else
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"OpenGL ES version string retrieval is broken");
|
||||
}
|
||||
|
||||
glfwMakeContextCurrent((GLFWwindow*) previous);
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
for (i = 0; prefixes[i]; i++)
|
||||
{
|
||||
const size_t length = strlen(prefixes[i]);
|
||||
|
||||
if (strncmp(version, prefixes[i], length) == 0)
|
||||
{
|
||||
version += length;
|
||||
window->context.client = GLFW_OPENGL_ES_API;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!sscanf(version, "%d.%d.%d",
|
||||
&window->context.major,
|
||||
&window->context.minor,
|
||||
&window->context.revision))
|
||||
{
|
||||
if (window->context.client == GLFW_OPENGL_API)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"No version found in OpenGL version string");
|
||||
}
|
||||
else
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"No version found in OpenGL ES version string");
|
||||
}
|
||||
|
||||
glfwMakeContextCurrent((GLFWwindow*) previous);
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
if (window->context.major < ctxconfig->major ||
|
||||
(window->context.major == ctxconfig->major &&
|
||||
window->context.minor < ctxconfig->minor))
|
||||
{
|
||||
// The desired OpenGL version is greater than the actual version
|
||||
// This only happens if the machine lacks {GLX|WGL}_ARB_create_context
|
||||
// /and/ the user has requested an OpenGL version greater than 1.0
|
||||
|
||||
// For API consistency, we emulate the behavior of the
|
||||
// {GLX|WGL}_ARB_create_context extension and fail here
|
||||
|
||||
if (window->context.client == GLFW_OPENGL_API)
|
||||
{
|
||||
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
|
||||
"Requested OpenGL version %i.%i, got version %i.%i",
|
||||
ctxconfig->major, ctxconfig->minor,
|
||||
window->context.major, window->context.minor);
|
||||
}
|
||||
else
|
||||
{
|
||||
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
|
||||
"Requested OpenGL ES version %i.%i, got version %i.%i",
|
||||
ctxconfig->major, ctxconfig->minor,
|
||||
window->context.major, window->context.minor);
|
||||
}
|
||||
|
||||
glfwMakeContextCurrent((GLFWwindow*) previous);
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
if (window->context.major >= 3)
|
||||
{
|
||||
// OpenGL 3.0+ uses a different function for extension string retrieval
|
||||
// We cache it here instead of in glfwExtensionSupported mostly to alert
|
||||
// users as early as possible that their build may be broken
|
||||
|
||||
window->context.GetStringi = (PFNGLGETSTRINGIPROC)
|
||||
window->context.getProcAddress("glGetStringi");
|
||||
if (!window->context.GetStringi)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Entry point retrieval is broken");
|
||||
glfwMakeContextCurrent((GLFWwindow*) previous);
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (window->context.client == GLFW_OPENGL_API)
|
||||
{
|
||||
// Read back context flags (OpenGL 3.0 and above)
|
||||
if (window->context.major >= 3)
|
||||
{
|
||||
GLint flags;
|
||||
window->context.GetIntegerv(GL_CONTEXT_FLAGS, &flags);
|
||||
|
||||
if (flags & GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT)
|
||||
window->context.forward = GLFW_TRUE;
|
||||
|
||||
if (flags & GL_CONTEXT_FLAG_DEBUG_BIT)
|
||||
window->context.debug = GLFW_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;
|
||||
}
|
||||
|
||||
if (flags & GL_CONTEXT_FLAG_NO_ERROR_BIT_KHR)
|
||||
window->context.noerror = GLFW_TRUE;
|
||||
}
|
||||
|
||||
// Read back OpenGL context profile (OpenGL 3.2 and above)
|
||||
if (window->context.major >= 4 ||
|
||||
(window->context.major == 3 && window->context.minor >= 2))
|
||||
{
|
||||
GLint mask;
|
||||
window->context.GetIntegerv(GL_CONTEXT_PROFILE_MASK, &mask);
|
||||
|
||||
if (mask & GL_CONTEXT_COMPATIBILITY_PROFILE_BIT)
|
||||
window->context.profile = GLFW_OPENGL_COMPAT_PROFILE;
|
||||
else if (mask & GL_CONTEXT_CORE_PROFILE_BIT)
|
||||
window->context.profile = GLFW_OPENGL_CORE_PROFILE;
|
||||
else if (glfwExtensionSupported("GL_ARB_compatibility"))
|
||||
{
|
||||
// HACK: This is a workaround for the compatibility profile bit
|
||||
// not being set in the context flags if an OpenGL 3.2+
|
||||
// context was created without having requested a specific
|
||||
// version
|
||||
window->context.profile = GLFW_OPENGL_COMPAT_PROFILE;
|
||||
}
|
||||
}
|
||||
|
||||
// Read back robustness strategy
|
||||
if (glfwExtensionSupported("GL_ARB_robustness"))
|
||||
{
|
||||
// NOTE: We avoid using the context flags for detection, as they are
|
||||
// only present from 3.0 while the extension applies from 1.1
|
||||
|
||||
GLint strategy;
|
||||
window->context.GetIntegerv(GL_RESET_NOTIFICATION_STRATEGY_ARB,
|
||||
&strategy);
|
||||
|
||||
if (strategy == GL_LOSE_CONTEXT_ON_RESET_ARB)
|
||||
window->context.robustness = GLFW_LOSE_CONTEXT_ON_RESET;
|
||||
else if (strategy == GL_NO_RESET_NOTIFICATION_ARB)
|
||||
window->context.robustness = GLFW_NO_RESET_NOTIFICATION;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Read back robustness strategy
|
||||
if (glfwExtensionSupported("GL_EXT_robustness"))
|
||||
{
|
||||
// NOTE: The values of these constants match those of the OpenGL ARB
|
||||
// one, so we can reuse them here
|
||||
|
||||
GLint strategy;
|
||||
window->context.GetIntegerv(GL_RESET_NOTIFICATION_STRATEGY_ARB,
|
||||
&strategy);
|
||||
|
||||
if (strategy == GL_LOSE_CONTEXT_ON_RESET_ARB)
|
||||
window->context.robustness = GLFW_LOSE_CONTEXT_ON_RESET;
|
||||
else if (strategy == GL_NO_RESET_NOTIFICATION_ARB)
|
||||
window->context.robustness = GLFW_NO_RESET_NOTIFICATION;
|
||||
}
|
||||
}
|
||||
|
||||
if (glfwExtensionSupported("GL_KHR_context_flush_control"))
|
||||
{
|
||||
GLint behavior;
|
||||
window->context.GetIntegerv(GL_CONTEXT_RELEASE_BEHAVIOR, &behavior);
|
||||
|
||||
if (behavior == GL_NONE)
|
||||
window->context.release = GLFW_RELEASE_BEHAVIOR_NONE;
|
||||
else if (behavior == GL_CONTEXT_RELEASE_BEHAVIOR_FLUSH)
|
||||
window->context.release = GLFW_RELEASE_BEHAVIOR_FLUSH;
|
||||
}
|
||||
|
||||
// Clearing the front buffer to black to avoid garbage pixels left over from
|
||||
// previous uses of our bit of VRAM
|
||||
{
|
||||
PFNGLCLEARPROC glClear = (PFNGLCLEARPROC)
|
||||
window->context.getProcAddress("glClear");
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
window->context.swapBuffers(window);
|
||||
}
|
||||
|
||||
glfwMakeContextCurrent((GLFWwindow*) previous);
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
// Searches an extension string for the specified extension
|
||||
//
|
||||
GLFWbool _glfwStringInExtensionString(const char* string, const char* extensions)
|
||||
{
|
||||
const char* start = extensions;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
const char* where;
|
||||
const char* terminator;
|
||||
|
||||
where = strstr(start, string);
|
||||
if (!where)
|
||||
return GLFW_FALSE;
|
||||
|
||||
terminator = where + strlen(string);
|
||||
if (where == start || *(where - 1) == ' ')
|
||||
{
|
||||
if (*terminator == ' ' || *terminator == '\0')
|
||||
break;
|
||||
}
|
||||
|
||||
start = terminator;
|
||||
}
|
||||
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW public API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
GLFWAPI void glfwMakeContextCurrent(GLFWwindow* handle)
|
||||
{
|
||||
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||
_GLFWwindow* previous = _glfwPlatformGetTls(&_glfw.contextSlot);
|
||||
|
||||
_GLFW_REQUIRE_INIT();
|
||||
|
||||
if (window && window->context.client == GLFW_NO_API)
|
||||
{
|
||||
_glfwInputError(GLFW_NO_WINDOW_CONTEXT,
|
||||
"Cannot make current with a window that has no OpenGL or OpenGL ES context");
|
||||
return;
|
||||
}
|
||||
|
||||
if (previous)
|
||||
{
|
||||
if (!window || window->context.source != previous->context.source)
|
||||
previous->context.makeCurrent(NULL);
|
||||
}
|
||||
|
||||
if (window)
|
||||
window->context.makeCurrent(window);
|
||||
}
|
||||
|
||||
GLFWAPI GLFWwindow* glfwGetCurrentContext(void)
|
||||
{
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||
return _glfwPlatformGetTls(&_glfw.contextSlot);
|
||||
}
|
||||
|
||||
GLFWAPI void glfwSwapBuffers(GLFWwindow* handle)
|
||||
{
|
||||
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||
assert(window != NULL);
|
||||
|
||||
_GLFW_REQUIRE_INIT();
|
||||
|
||||
if (window->context.client == GLFW_NO_API)
|
||||
{
|
||||
_glfwInputError(GLFW_NO_WINDOW_CONTEXT,
|
||||
"Cannot swap buffers of a window that has no OpenGL or OpenGL ES context");
|
||||
return;
|
||||
}
|
||||
|
||||
window->context.swapBuffers(window);
|
||||
}
|
||||
|
||||
GLFWAPI void glfwSwapInterval(int interval)
|
||||
{
|
||||
_GLFWwindow* window;
|
||||
|
||||
_GLFW_REQUIRE_INIT();
|
||||
|
||||
window = _glfwPlatformGetTls(&_glfw.contextSlot);
|
||||
if (!window)
|
||||
{
|
||||
_glfwInputError(GLFW_NO_CURRENT_CONTEXT,
|
||||
"Cannot set swap interval without a current OpenGL or OpenGL ES context");
|
||||
return;
|
||||
}
|
||||
|
||||
window->context.swapInterval(interval);
|
||||
}
|
||||
|
||||
GLFWAPI int glfwExtensionSupported(const char* extension)
|
||||
{
|
||||
_GLFWwindow* window;
|
||||
assert(extension != NULL);
|
||||
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(GLFW_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;
|
||||
}
|
||||
|
||||
if (*extension == '\0')
|
||||
{
|
||||
_glfwInputError(GLFW_INVALID_VALUE, "Extension name cannot be an empty string");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
if (window->context.major >= 3)
|
||||
{
|
||||
int i;
|
||||
GLint count;
|
||||
|
||||
// Check if extension is in the modern OpenGL extensions string list
|
||||
|
||||
window->context.GetIntegerv(GL_NUM_EXTENSIONS, &count);
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
const char* en = (const char*)
|
||||
window->context.GetStringi(GL_EXTENSIONS, i);
|
||||
if (!en)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Extension string retrieval is broken");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
if (strcmp(en, extension) == 0)
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Check if extension is in the old style OpenGL extensions string
|
||||
|
||||
const char* extensions = (const char*)
|
||||
window->context.GetString(GL_EXTENSIONS);
|
||||
if (!extensions)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Extension string retrieval is broken");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
if (_glfwStringInExtensionString(extension, extensions))
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
// Check if extension is in the platform-specific string
|
||||
return window->context.extensionSupported(extension);
|
||||
}
|
||||
|
||||
GLFWAPI GLFWglproc glfwGetProcAddress(const char* procname)
|
||||
{
|
||||
_GLFWwindow* window;
|
||||
assert(procname != NULL);
|
||||
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||
|
||||
window = _glfwPlatformGetTls(&_glfw.contextSlot);
|
||||
if (!window)
|
||||
{
|
||||
_glfwInputError(GLFW_NO_CURRENT_CONTEXT,
|
||||
"Cannot query entry point without a current OpenGL or OpenGL ES context");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return window->context.getProcAddress(procname);
|
||||
}
|
||||
|
||||
295
glfw/dbus_glfw.c
vendored
Normal file
295
glfw/dbus_glfw.c
vendored
Normal file
@@ -0,0 +1,295 @@
|
||||
//========================================================================
|
||||
// GLFW 3.3 XKB - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2018 Kovid Goyal <kovid@kovidgoyal.net>
|
||||
//
|
||||
// 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 "dbus_glfw.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
static inline void
|
||||
report_error(DBusError *err, const char *fmt, ...) {
|
||||
static char buf[1024];
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
int n = vsnprintf(buf, sizeof(buf), fmt, args);
|
||||
va_end(args);
|
||||
snprintf(buf + n, sizeof(buf), ". DBUS error: %s", err->message);
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR, "%s", buf);
|
||||
dbus_error_free(err);
|
||||
}
|
||||
|
||||
static _GLFWDBUSData *dbus_data = NULL;
|
||||
|
||||
GLFWbool
|
||||
glfw_dbus_init(_GLFWDBUSData *dbus, EventLoopData *eld) {
|
||||
dbus->eld = eld;
|
||||
dbus_data = dbus;
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
on_dbus_watch_ready(int fd, int events, void *data) {
|
||||
DBusWatch *watch = (DBusWatch*)data;
|
||||
unsigned int flags = 0;
|
||||
if (events & POLLERR) flags |= DBUS_WATCH_ERROR;
|
||||
if (events & POLLHUP) flags |= DBUS_WATCH_HANGUP;
|
||||
if (events & POLLIN) flags |= DBUS_WATCH_READABLE;
|
||||
if (events & POLLOUT) flags |= DBUS_WATCH_WRITABLE;
|
||||
dbus_watch_handle(watch, flags);
|
||||
}
|
||||
|
||||
static inline int
|
||||
events_for_watch(DBusWatch *watch) {
|
||||
int events = 0;
|
||||
unsigned int flags = dbus_watch_get_flags(watch);
|
||||
if (flags & DBUS_WATCH_READABLE) events |= POLLIN;
|
||||
if (flags & DBUS_WATCH_WRITABLE) events |= POLLOUT;
|
||||
return events;
|
||||
}
|
||||
|
||||
static dbus_bool_t
|
||||
add_dbus_watch(DBusWatch *watch, void *data) {
|
||||
id_type watch_id = addWatch(dbus_data->eld, data, dbus_watch_get_unix_fd(watch), events_for_watch(watch), dbus_watch_get_enabled(watch), on_dbus_watch_ready, watch);
|
||||
if (!watch_id) return FALSE;
|
||||
id_type *idp = malloc(sizeof(id_type));
|
||||
if (!idp) return FALSE;
|
||||
*idp = watch_id;
|
||||
dbus_watch_set_data(watch, idp, free);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
remove_dbus_watch(DBusWatch *watch, void *data) {
|
||||
id_type *idp = dbus_watch_get_data(watch);
|
||||
if (idp) removeWatch(dbus_data->eld, *idp);
|
||||
}
|
||||
|
||||
static void
|
||||
toggle_dbus_watch(DBusWatch *watch, void *data) {
|
||||
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) {
|
||||
if (data) {
|
||||
DBusTimeout *t = (DBusTimeout*)data;
|
||||
dbus_timeout_handle(t);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
if (interval < 0) return FALSE;
|
||||
id_type timer_id = addTimer(dbus_data->eld, data, interval, enabled, on_dbus_timer_ready, timeout);
|
||||
if (!timer_id) return FALSE;
|
||||
id_type *idp = malloc(sizeof(id_type));
|
||||
if (!idp) {
|
||||
removeTimer(dbus_data->eld, timer_id);
|
||||
return FALSE;
|
||||
}
|
||||
*idp = timer_id;
|
||||
dbus_timeout_set_data(timeout, idp, free);
|
||||
return TRUE;
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
remove_dbus_timeout(DBusTimeout *timeout, void *data) {
|
||||
id_type *idp = dbus_timeout_get_data(timeout);
|
||||
if (idp) removeTimer(dbus_data->eld, *idp);
|
||||
}
|
||||
|
||||
static void
|
||||
toggle_dbus_timeout(DBusTimeout *timeout, void *data) {
|
||||
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) {
|
||||
DBusError err;
|
||||
dbus_error_init(&err);
|
||||
DBusConnection *ans = dbus_connection_open_private(path, &err);
|
||||
if (!ans) {
|
||||
report_error(&err, err_msg);
|
||||
return NULL;
|
||||
}
|
||||
dbus_connection_set_exit_on_disconnect(ans, FALSE);
|
||||
dbus_error_free(&err);
|
||||
if (register_on_bus) {
|
||||
if (!dbus_bus_register(ans, &err)) {
|
||||
report_error(&err, err_msg);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
if (!dbus_connection_set_watch_functions(ans, 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", path);
|
||||
dbus_connection_close(ans);
|
||||
dbus_connection_unref(ans);
|
||||
return NULL;
|
||||
}
|
||||
if (!dbus_connection_set_timeout_functions(ans, 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", path);
|
||||
dbus_connection_close(ans);
|
||||
dbus_connection_unref(ans);
|
||||
return NULL;
|
||||
}
|
||||
return ans;
|
||||
}
|
||||
|
||||
void
|
||||
glfw_dbus_dispatch(DBusConnection *conn) {
|
||||
while(dbus_connection_dispatch(conn) == DBUS_DISPATCH_DATA_REMAINS);
|
||||
}
|
||||
|
||||
void
|
||||
glfw_dbus_terminate(_GLFWDBUSData *dbus) {
|
||||
if (dbus_data) {
|
||||
dbus_data->eld = NULL;
|
||||
dbus_data = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
glfw_dbus_close_connection(DBusConnection *conn) {
|
||||
dbus_connection_close(conn);
|
||||
dbus_connection_unref(conn);
|
||||
}
|
||||
|
||||
GLFWbool
|
||||
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;
|
||||
va_end(ap);
|
||||
if (!ret) report_error(&err, failmsg);
|
||||
return ret;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
dbus_pending_callback callback;
|
||||
void *user_data;
|
||||
} MethodResponse;
|
||||
|
||||
static const char*
|
||||
format_message_error(DBusError *err) {
|
||||
static char buf[1024];
|
||||
snprintf(buf, sizeof(buf), "[%s] %s", err->name ? err->name : "", err->message);
|
||||
return buf;
|
||||
}
|
||||
|
||||
static void
|
||||
method_reply_received(DBusPendingCall *pending, void *user_data) {
|
||||
MethodResponse *res = (MethodResponse*)user_data;
|
||||
DBusMessage *msg = dbus_pending_call_steal_reply(pending);
|
||||
if (msg) {
|
||||
DBusError err;
|
||||
dbus_error_init(&err);
|
||||
if (dbus_set_error_from_message(&err, msg)) res->callback(NULL, format_message_error(&err), res->user_data);
|
||||
else res->callback(msg, NULL, res->user_data);
|
||||
dbus_message_unref(msg);
|
||||
}
|
||||
}
|
||||
|
||||
static GLFWbool
|
||||
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;
|
||||
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;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR, "Failed to call DBUS method: %s on node: %s and interface: %s could not add arguments", method, node, interface);
|
||||
}
|
||||
dbus_message_unref(msg);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
GLFWbool
|
||||
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;
|
||||
va_list ap;
|
||||
va_start(ap, user_data);
|
||||
retval = call_method(conn, node, path, interface, method, timeout, callback, user_data, ap);
|
||||
va_end(ap);
|
||||
return retval;
|
||||
}
|
||||
|
||||
GLFWbool
|
||||
glfw_dbus_call_method_no_reply(DBusConnection *conn, const char *node, const char *path, const char *interface, const char *method, ...) {
|
||||
GLFWbool retval;
|
||||
va_list ap;
|
||||
va_start(ap, method);
|
||||
retval = call_method(conn, node, path, interface, method, DBUS_TIMEOUT_USE_DEFAULT, NULL, NULL, ap);
|
||||
va_end(ap);
|
||||
return retval;
|
||||
}
|
||||
|
||||
int
|
||||
glfw_dbus_match_signal(DBusMessage *msg, const char *interface, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, interface);
|
||||
int ans = -1, num = -1;
|
||||
while(1) {
|
||||
num++;
|
||||
const char *name = va_arg(ap, const char*);
|
||||
if (!name) break;
|
||||
if (dbus_message_is_signal(msg, interface, name)) { ans = num; break; }
|
||||
}
|
||||
va_end(ap);
|
||||
return ans;
|
||||
}
|
||||
50
glfw/dbus_glfw.h
vendored
Normal file
50
glfw/dbus_glfw.h
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
//========================================================================
|
||||
// GLFW 3.3 XKB - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2018 Kovid Goyal <kovid@kovidgoyal.net>
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
//========================================================================
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <dbus/dbus.h>
|
||||
#include "backend_utils.h"
|
||||
|
||||
typedef void(*dbus_pending_callback)(DBusMessage *msg, const char* err, void* data);
|
||||
|
||||
typedef struct {
|
||||
EventLoopData* eld;
|
||||
} _GLFWDBUSData;
|
||||
|
||||
|
||||
GLFWbool 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);
|
||||
void glfw_dbus_close_connection(DBusConnection *conn);
|
||||
GLFWbool
|
||||
glfw_dbus_call_method_no_reply(DBusConnection *conn, const char *node, const char *path, const char *interface, const char *method, ...);
|
||||
GLFWbool
|
||||
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, ...);
|
||||
int glfw_dbus_match_signal(DBusMessage *msg, const char *interface, ...);
|
||||
786
glfw/egl_context.c
vendored
Normal file
786
glfw/egl_context.c
vendored
Normal file
@@ -0,0 +1,786 @@
|
||||
//========================================================================
|
||||
// GLFW 3.3 EGL - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||
// Copyright (c) 2006-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 <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
|
||||
// Return a description of the specified EGL error
|
||||
//
|
||||
static const char* getEGLErrorString(EGLint error)
|
||||
{
|
||||
switch (error)
|
||||
{
|
||||
case EGL_SUCCESS:
|
||||
return "Success";
|
||||
case EGL_NOT_INITIALIZED:
|
||||
return "EGL is not or could not be initialized";
|
||||
case EGL_BAD_ACCESS:
|
||||
return "EGL cannot access a requested resource";
|
||||
case EGL_BAD_ALLOC:
|
||||
return "EGL failed to allocate resources for the requested operation";
|
||||
case EGL_BAD_ATTRIBUTE:
|
||||
return "An unrecognized attribute or attribute value was passed in the attribute list";
|
||||
case EGL_BAD_CONTEXT:
|
||||
return "An EGLContext argument does not name a valid EGL rendering context";
|
||||
case EGL_BAD_CONFIG:
|
||||
return "An EGLConfig argument does not name a valid EGL frame buffer configuration";
|
||||
case EGL_BAD_CURRENT_SURFACE:
|
||||
return "The current surface of the calling thread is a window, pixel buffer or pixmap that is no longer valid";
|
||||
case EGL_BAD_DISPLAY:
|
||||
return "An EGLDisplay argument does not name a valid EGL display connection";
|
||||
case EGL_BAD_SURFACE:
|
||||
return "An EGLSurface argument does not name a valid surface configured for GL rendering";
|
||||
case EGL_BAD_MATCH:
|
||||
return "Arguments are inconsistent";
|
||||
case EGL_BAD_PARAMETER:
|
||||
return "One or more argument values are invalid";
|
||||
case EGL_BAD_NATIVE_PIXMAP:
|
||||
return "A NativePixmapType argument does not refer to a valid native pixmap";
|
||||
case EGL_BAD_NATIVE_WINDOW:
|
||||
return "A NativeWindowType argument does not refer to a valid native window";
|
||||
case EGL_CONTEXT_LOST:
|
||||
return "The application must destroy all contexts and reinitialise";
|
||||
default:
|
||||
return "ERROR: UNKNOWN EGL ERROR";
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the specified attribute of the specified EGLConfig
|
||||
//
|
||||
static int getEGLConfigAttrib(EGLConfig config, int attrib)
|
||||
{
|
||||
int value;
|
||||
eglGetConfigAttrib(_glfw.egl.display, config, attrib, &value);
|
||||
return value;
|
||||
}
|
||||
|
||||
// Return the EGLConfig most closely matching the specified hints
|
||||
//
|
||||
static GLFWbool chooseEGLConfig(const _GLFWctxconfig* ctxconfig,
|
||||
const _GLFWfbconfig* desired,
|
||||
EGLConfig* result)
|
||||
{
|
||||
EGLConfig* nativeConfigs;
|
||||
_GLFWfbconfig* usableConfigs;
|
||||
const _GLFWfbconfig* closest;
|
||||
int i, nativeCount, usableCount;
|
||||
|
||||
eglGetConfigs(_glfw.egl.display, NULL, 0, &nativeCount);
|
||||
if (!nativeCount)
|
||||
{
|
||||
_glfwInputError(GLFW_API_UNAVAILABLE, "EGL: No EGLConfigs returned");
|
||||
return GLFW_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)
|
||||
{
|
||||
u->transparent = _glfwIsVisualTransparentX11(vis[0].visual);
|
||||
XFree(vis);
|
||||
}
|
||||
}
|
||||
#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++;
|
||||
}
|
||||
|
||||
closest = _glfwChooseFBConfig(desired, usableConfigs, usableCount);
|
||||
if (closest)
|
||||
*result = (EGLConfig) closest->handle;
|
||||
|
||||
free(nativeConfigs);
|
||||
free(usableConfigs);
|
||||
|
||||
return closest != NULL;
|
||||
}
|
||||
|
||||
static void makeContextCurrentEGL(_GLFWwindow* window)
|
||||
{
|
||||
if (window)
|
||||
{
|
||||
if (!eglMakeCurrent(_glfw.egl.display,
|
||||
window->context.egl.surface,
|
||||
window->context.egl.surface,
|
||||
window->context.egl.handle))
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"EGL: Failed to make context current: %s",
|
||||
getEGLErrorString(eglGetError()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!eglMakeCurrent(_glfw.egl.display,
|
||||
EGL_NO_SURFACE,
|
||||
EGL_NO_SURFACE,
|
||||
EGL_NO_CONTEXT))
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"EGL: Failed to clear current context: %s",
|
||||
getEGLErrorString(eglGetError()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
_glfwPlatformSetTls(&_glfw.contextSlot, window);
|
||||
}
|
||||
|
||||
static void swapBuffersEGL(_GLFWwindow* window)
|
||||
{
|
||||
if (window != _glfwPlatformGetTls(&_glfw.contextSlot))
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"EGL: The context must be current on the calling thread when swapping buffers");
|
||||
return;
|
||||
}
|
||||
|
||||
eglSwapBuffers(_glfw.egl.display, window->context.egl.surface);
|
||||
}
|
||||
|
||||
static void swapIntervalEGL(int interval)
|
||||
{
|
||||
eglSwapInterval(_glfw.egl.display, interval);
|
||||
}
|
||||
|
||||
static int extensionSupportedEGL(const char* extension)
|
||||
{
|
||||
const char* extensions = eglQueryString(_glfw.egl.display, EGL_EXTENSIONS);
|
||||
if (extensions)
|
||||
{
|
||||
if (_glfwStringInExtensionString(extension, extensions))
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
static GLFWglproc getProcAddressEGL(const char* procname)
|
||||
{
|
||||
_GLFWwindow* window = _glfwPlatformGetTls(&_glfw.contextSlot);
|
||||
|
||||
if (window->context.egl.client)
|
||||
{
|
||||
GLFWglproc proc = (GLFWglproc) _glfw_dlsym(window->context.egl.client,
|
||||
procname);
|
||||
if (proc)
|
||||
return proc;
|
||||
}
|
||||
|
||||
return eglGetProcAddress(procname);
|
||||
}
|
||||
|
||||
static void destroyContextEGL(_GLFWwindow* window)
|
||||
{
|
||||
#if defined(_GLFW_X11)
|
||||
// NOTE: Do not unload libGL.so.1 while the X11 display is still open,
|
||||
// as it will make XCloseDisplay segfault
|
||||
if (window->context.client != GLFW_OPENGL_API)
|
||||
#endif // _GLFW_X11
|
||||
{
|
||||
if (window->context.egl.client)
|
||||
{
|
||||
_glfw_dlclose(window->context.egl.client);
|
||||
window->context.egl.client = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (window->context.egl.surface)
|
||||
{
|
||||
eglDestroySurface(_glfw.egl.display, window->context.egl.surface);
|
||||
window->context.egl.surface = EGL_NO_SURFACE;
|
||||
}
|
||||
|
||||
if (window->context.egl.handle)
|
||||
{
|
||||
eglDestroyContext(_glfw.egl.display, window->context.egl.handle);
|
||||
window->context.egl.handle = EGL_NO_CONTEXT;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW internal API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Initialize EGL
|
||||
//
|
||||
GLFWbool _glfwInitEGL(void)
|
||||
{
|
||||
int i;
|
||||
const char* sonames[] =
|
||||
{
|
||||
#if defined(_GLFW_EGL_LIBRARY)
|
||||
_GLFW_EGL_LIBRARY,
|
||||
#elif defined(_GLFW_WIN32)
|
||||
"libEGL.dll",
|
||||
"EGL.dll",
|
||||
#elif defined(_GLFW_COCOA)
|
||||
"libEGL.dylib",
|
||||
#elif defined(__CYGWIN__)
|
||||
"libEGL-1.so",
|
||||
#else
|
||||
"libEGL.so.1",
|
||||
#endif
|
||||
NULL
|
||||
};
|
||||
|
||||
if (_glfw.egl.handle)
|
||||
return GLFW_TRUE;
|
||||
|
||||
for (i = 0; sonames[i]; i++)
|
||||
{
|
||||
_glfw.egl.handle = _glfw_dlopen(sonames[i]);
|
||||
if (_glfw.egl.handle)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!_glfw.egl.handle)
|
||||
{
|
||||
_glfwInputError(GLFW_API_UNAVAILABLE, "EGL: Library not found");
|
||||
return GLFW_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");
|
||||
|
||||
if (!_glfw.egl.GetConfigAttrib ||
|
||||
!_glfw.egl.GetConfigs ||
|
||||
!_glfw.egl.GetDisplay ||
|
||||
!_glfw.egl.GetError ||
|
||||
!_glfw.egl.Initialize ||
|
||||
!_glfw.egl.Terminate ||
|
||||
!_glfw.egl.BindAPI ||
|
||||
!_glfw.egl.CreateContext ||
|
||||
!_glfw.egl.DestroySurface ||
|
||||
!_glfw.egl.DestroyContext ||
|
||||
!_glfw.egl.CreateWindowSurface ||
|
||||
!_glfw.egl.MakeCurrent ||
|
||||
!_glfw.egl.SwapBuffers ||
|
||||
!_glfw.egl.SwapInterval ||
|
||||
!_glfw.egl.QueryString ||
|
||||
!_glfw.egl.GetProcAddress)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"EGL: Failed to load required entry points");
|
||||
|
||||
_glfwTerminateEGL();
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
_glfw.egl.display = eglGetDisplay(_GLFW_EGL_NATIVE_DISPLAY);
|
||||
if (_glfw.egl.display == EGL_NO_DISPLAY)
|
||||
{
|
||||
_glfwInputError(GLFW_API_UNAVAILABLE,
|
||||
"EGL: Failed to get EGL display: %s",
|
||||
getEGLErrorString(eglGetError()));
|
||||
|
||||
_glfwTerminateEGL();
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
if (!eglInitialize(_glfw.egl.display, &_glfw.egl.major, &_glfw.egl.minor))
|
||||
{
|
||||
_glfwInputError(GLFW_API_UNAVAILABLE,
|
||||
"EGL: Failed to initialize EGL: %s",
|
||||
getEGLErrorString(eglGetError()));
|
||||
|
||||
_glfwTerminateEGL();
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
_glfw.egl.KHR_create_context =
|
||||
extensionSupportedEGL("EGL_KHR_create_context");
|
||||
_glfw.egl.KHR_create_context_no_error =
|
||||
extensionSupportedEGL("EGL_KHR_create_context_no_error");
|
||||
_glfw.egl.KHR_gl_colorspace =
|
||||
extensionSupportedEGL("EGL_KHR_gl_colorspace");
|
||||
_glfw.egl.KHR_get_all_proc_addresses =
|
||||
extensionSupportedEGL("EGL_KHR_get_all_proc_addresses");
|
||||
_glfw.egl.KHR_context_flush_control =
|
||||
extensionSupportedEGL("EGL_KHR_context_flush_control");
|
||||
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
// Terminate EGL
|
||||
//
|
||||
void _glfwTerminateEGL(void)
|
||||
{
|
||||
if (_glfw.egl.display)
|
||||
{
|
||||
eglTerminate(_glfw.egl.display);
|
||||
_glfw.egl.display = EGL_NO_DISPLAY;
|
||||
}
|
||||
|
||||
if (_glfw.egl.handle)
|
||||
{
|
||||
_glfw_dlclose(_glfw.egl.handle);
|
||||
_glfw.egl.handle = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#define setAttrib(a, v) \
|
||||
{ \
|
||||
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,
|
||||
const _GLFWctxconfig* ctxconfig,
|
||||
const _GLFWfbconfig* fbconfig)
|
||||
{
|
||||
EGLint attribs[40];
|
||||
EGLConfig config;
|
||||
EGLContext share = NULL;
|
||||
int index = 0;
|
||||
|
||||
if (!_glfw.egl.display)
|
||||
{
|
||||
_glfwInputError(GLFW_API_UNAVAILABLE, "EGL: API not available");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
if (ctxconfig->share)
|
||||
share = ctxconfig->share->context.egl.handle;
|
||||
|
||||
if (!chooseEGLConfig(ctxconfig, fbconfig, &config))
|
||||
{
|
||||
_glfwInputError(GLFW_FORMAT_UNAVAILABLE,
|
||||
"EGL: Failed to find a suitable EGLConfig");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
if (ctxconfig->client == GLFW_OPENGL_ES_API)
|
||||
{
|
||||
if (!eglBindAPI(EGL_OPENGL_ES_API))
|
||||
{
|
||||
_glfwInputError(GLFW_API_UNAVAILABLE,
|
||||
"EGL: Failed to bind OpenGL ES: %s",
|
||||
getEGLErrorString(eglGetError()));
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!eglBindAPI(EGL_OPENGL_API))
|
||||
{
|
||||
_glfwInputError(GLFW_API_UNAVAILABLE,
|
||||
"EGL: Failed to bind OpenGL: %s",
|
||||
getEGLErrorString(eglGetError()));
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (_glfw.egl.KHR_create_context)
|
||||
{
|
||||
int mask = 0, flags = 0;
|
||||
|
||||
if (ctxconfig->client == GLFW_OPENGL_API)
|
||||
{
|
||||
if (ctxconfig->forward)
|
||||
flags |= EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR;
|
||||
|
||||
if (ctxconfig->profile == GLFW_OPENGL_CORE_PROFILE)
|
||||
mask |= EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR;
|
||||
else if (ctxconfig->profile == GLFW_OPENGL_COMPAT_PROFILE)
|
||||
mask |= EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR;
|
||||
}
|
||||
|
||||
if (ctxconfig->debug)
|
||||
flags |= EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR;
|
||||
|
||||
if (ctxconfig->robustness)
|
||||
{
|
||||
if (ctxconfig->robustness == GLFW_NO_RESET_NOTIFICATION)
|
||||
{
|
||||
setAttrib(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR,
|
||||
EGL_NO_RESET_NOTIFICATION_KHR);
|
||||
}
|
||||
else if (ctxconfig->robustness == GLFW_LOSE_CONTEXT_ON_RESET)
|
||||
{
|
||||
setAttrib(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR,
|
||||
EGL_LOSE_CONTEXT_ON_RESET_KHR);
|
||||
}
|
||||
|
||||
flags |= EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR;
|
||||
}
|
||||
|
||||
if (ctxconfig->noerror)
|
||||
{
|
||||
if (_glfw.egl.KHR_create_context_no_error)
|
||||
setAttrib(EGL_CONTEXT_OPENGL_NO_ERROR_KHR, GLFW_TRUE);
|
||||
}
|
||||
|
||||
if (ctxconfig->major != 1 || ctxconfig->minor != 0)
|
||||
{
|
||||
setAttrib(EGL_CONTEXT_MAJOR_VERSION_KHR, ctxconfig->major);
|
||||
setAttrib(EGL_CONTEXT_MINOR_VERSION_KHR, ctxconfig->minor);
|
||||
}
|
||||
|
||||
if (mask)
|
||||
setAttrib(EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR, mask);
|
||||
|
||||
if (flags)
|
||||
setAttrib(EGL_CONTEXT_FLAGS_KHR, flags);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ctxconfig->client == GLFW_OPENGL_ES_API)
|
||||
setAttrib(EGL_CONTEXT_CLIENT_VERSION, ctxconfig->major);
|
||||
}
|
||||
|
||||
if (_glfw.egl.KHR_context_flush_control)
|
||||
{
|
||||
if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_NONE)
|
||||
{
|
||||
setAttrib(EGL_CONTEXT_RELEASE_BEHAVIOR_KHR,
|
||||
EGL_CONTEXT_RELEASE_BEHAVIOR_NONE_KHR);
|
||||
}
|
||||
else if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_FLUSH)
|
||||
{
|
||||
setAttrib(EGL_CONTEXT_RELEASE_BEHAVIOR_KHR,
|
||||
EGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_KHR);
|
||||
}
|
||||
}
|
||||
|
||||
setAttrib(EGL_NONE, EGL_NONE);
|
||||
|
||||
window->context.egl.handle = eglCreateContext(_glfw.egl.display,
|
||||
config, share, attribs);
|
||||
|
||||
if (window->context.egl.handle == EGL_NO_CONTEXT)
|
||||
{
|
||||
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
|
||||
"EGL: Failed to create context: %s",
|
||||
getEGLErrorString(eglGetError()));
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
// Set up attributes for surface creation
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
window->context.egl.config = config;
|
||||
|
||||
// Load the appropriate client library
|
||||
if (!_glfw.egl.KHR_get_all_proc_addresses)
|
||||
{
|
||||
int i;
|
||||
const char** sonames;
|
||||
const char* es1sonames[] =
|
||||
{
|
||||
#if defined(_GLFW_GLESV1_LIBRARY)
|
||||
_GLFW_GLESV1_LIBRARY,
|
||||
#elif defined(_GLFW_WIN32)
|
||||
"GLESv1_CM.dll",
|
||||
"libGLES_CM.dll",
|
||||
#elif defined(_GLFW_COCOA)
|
||||
"libGLESv1_CM.dylib",
|
||||
#else
|
||||
"libGLESv1_CM.so.1",
|
||||
"libGLES_CM.so.1",
|
||||
#endif
|
||||
NULL
|
||||
};
|
||||
const char* es2sonames[] =
|
||||
{
|
||||
#if defined(_GLFW_GLESV2_LIBRARY)
|
||||
_GLFW_GLESV2_LIBRARY,
|
||||
#elif defined(_GLFW_WIN32)
|
||||
"GLESv2.dll",
|
||||
"libGLESv2.dll",
|
||||
#elif defined(_GLFW_COCOA)
|
||||
"libGLESv2.dylib",
|
||||
#elif defined(__CYGWIN__)
|
||||
"libGLESv2-2.so",
|
||||
#else
|
||||
"libGLESv2.so.2",
|
||||
#endif
|
||||
NULL
|
||||
};
|
||||
const char* glsonames[] =
|
||||
{
|
||||
#if defined(_GLFW_OPENGL_LIBRARY)
|
||||
_GLFW_OPENGL_LIBRARY,
|
||||
#elif defined(_GLFW_WIN32)
|
||||
#elif defined(_GLFW_COCOA)
|
||||
#else
|
||||
"libGL.so.1",
|
||||
#endif
|
||||
NULL
|
||||
};
|
||||
|
||||
if (ctxconfig->client == GLFW_OPENGL_ES_API)
|
||||
{
|
||||
if (ctxconfig->major == 1)
|
||||
sonames = es1sonames;
|
||||
else
|
||||
sonames = es2sonames;
|
||||
}
|
||||
else
|
||||
sonames = glsonames;
|
||||
|
||||
for (i = 0; sonames[i]; i++)
|
||||
{
|
||||
// HACK: Match presence of lib prefix to increase chance of finding
|
||||
// a matching pair in the jungle that is Win32 EGL/GLES
|
||||
if (_glfw.egl.prefix != (strncmp(sonames[i], "lib", 3) == 0))
|
||||
continue;
|
||||
|
||||
window->context.egl.client = _glfw_dlopen(sonames[i]);
|
||||
if (window->context.egl.client)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!window->context.egl.client)
|
||||
{
|
||||
_glfwInputError(GLFW_API_UNAVAILABLE,
|
||||
"EGL: Failed to load client library");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
window->context.makeCurrent = makeContextCurrentEGL;
|
||||
window->context.swapBuffers = swapBuffersEGL;
|
||||
window->context.swapInterval = swapIntervalEGL;
|
||||
window->context.extensionSupported = extensionSupportedEGL;
|
||||
window->context.getProcAddress = getProcAddressEGL;
|
||||
window->context.destroy = destroyContextEGL;
|
||||
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
#undef setAttrib
|
||||
|
||||
// Returns the Visual and depth of the chosen EGLConfig
|
||||
//
|
||||
#if defined(_GLFW_X11)
|
||||
GLFWbool _glfwChooseVisualEGL(const _GLFWwndconfig* wndconfig,
|
||||
const _GLFWctxconfig* ctxconfig,
|
||||
const _GLFWfbconfig* fbconfig,
|
||||
Visual** visual, int* depth)
|
||||
{
|
||||
XVisualInfo* result;
|
||||
XVisualInfo desired;
|
||||
EGLConfig native;
|
||||
EGLint visualID = 0, count = 0;
|
||||
const long vimask = VisualScreenMask | VisualIDMask;
|
||||
|
||||
if (!chooseEGLConfig(ctxconfig, fbconfig, &native))
|
||||
{
|
||||
_glfwInputError(GLFW_FORMAT_UNAVAILABLE,
|
||||
"EGL: Failed to find a suitable EGLConfig");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
eglGetConfigAttrib(_glfw.egl.display, native,
|
||||
EGL_NATIVE_VISUAL_ID, &visualID);
|
||||
|
||||
desired.screen = _glfw.x11.screen;
|
||||
desired.visualid = visualID;
|
||||
|
||||
result = XGetVisualInfo(_glfw.x11.display, vimask, &desired, &count);
|
||||
if (!result)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"EGL: Failed to retrieve Visual for EGLConfig");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
*visual = result->visual;
|
||||
*depth = result->depth;
|
||||
|
||||
XFree(result);
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
#endif // _GLFW_X11
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW native API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
GLFWAPI EGLDisplay glfwGetEGLDisplay(void)
|
||||
{
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(EGL_NO_DISPLAY);
|
||||
return _glfw.egl.display;
|
||||
}
|
||||
|
||||
GLFWAPI EGLContext glfwGetEGLContext(GLFWwindow* handle)
|
||||
{
|
||||
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(EGL_NO_CONTEXT);
|
||||
|
||||
if (window->context.client == GLFW_NO_API)
|
||||
{
|
||||
_glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
|
||||
return EGL_NO_CONTEXT;
|
||||
}
|
||||
|
||||
return window->context.egl.handle;
|
||||
}
|
||||
|
||||
GLFWAPI EGLSurface glfwGetEGLSurface(GLFWwindow* handle)
|
||||
{
|
||||
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(EGL_NO_SURFACE);
|
||||
|
||||
if (window->context.client == GLFW_NO_API)
|
||||
{
|
||||
_glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
|
||||
return EGL_NO_SURFACE;
|
||||
}
|
||||
|
||||
return window->context.egl.surface;
|
||||
}
|
||||
|
||||
214
glfw/egl_context.h
vendored
Normal file
214
glfw/egl_context.h
vendored
Normal file
@@ -0,0 +1,214 @@
|
||||
//========================================================================
|
||||
// GLFW 3.3 EGL - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||
// Copyright (c) 2006-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.
|
||||
//
|
||||
//========================================================================
|
||||
|
||||
#if defined(_GLFW_USE_EGLPLATFORM_H)
|
||||
#include <EGL/eglplatform.h>
|
||||
#elif 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"
|
||||
#endif
|
||||
|
||||
#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_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_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_OPENGL_ES_BIT 0x0001
|
||||
#define EGL_OPENGL_ES2_BIT 0x0004
|
||||
#define EGL_OPENGL_BIT 0x0008
|
||||
#define EGL_ALPHA_SIZE 0x3021
|
||||
#define EGL_BLUE_SIZE 0x3022
|
||||
#define EGL_GREEN_SIZE 0x3023
|
||||
#define EGL_RED_SIZE 0x3024
|
||||
#define EGL_DEPTH_SIZE 0x3025
|
||||
#define EGL_STENCIL_SIZE 0x3026
|
||||
#define EGL_SAMPLES 0x3031
|
||||
#define EGL_OPENGL_ES_API 0x30a0
|
||||
#define EGL_OPENGL_API 0x30a2
|
||||
#define EGL_NONE 0x3038
|
||||
#define EGL_EXTENSIONS 0x3055
|
||||
#define EGL_CONTEXT_CLIENT_VERSION 0x3098
|
||||
#define EGL_NATIVE_VISUAL_ID 0x302e
|
||||
#define EGL_NO_SURFACE ((EGLSurface) 0)
|
||||
#define EGL_NO_DISPLAY ((EGLDisplay) 0)
|
||||
#define EGL_NO_CONTEXT ((EGLContext) 0)
|
||||
#define EGL_DEFAULT_DISPLAY ((EGLNativeDisplayType) 0)
|
||||
|
||||
#define EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR 0x00000002
|
||||
#define EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR 0x00000001
|
||||
#define EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR 0x00000002
|
||||
#define EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR 0x00000001
|
||||
#define EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR 0x31bd
|
||||
#define EGL_NO_RESET_NOTIFICATION_KHR 0x31be
|
||||
#define EGL_LOSE_CONTEXT_ON_RESET_KHR 0x31bf
|
||||
#define EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR 0x00000004
|
||||
#define EGL_CONTEXT_MAJOR_VERSION_KHR 0x3098
|
||||
#define EGL_CONTEXT_MINOR_VERSION_KHR 0x30fb
|
||||
#define EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR 0x30fd
|
||||
#define EGL_CONTEXT_FLAGS_KHR 0x30fc
|
||||
#define EGL_CONTEXT_OPENGL_NO_ERROR_KHR 0x31b3
|
||||
#define EGL_GL_COLORSPACE_KHR 0x309d
|
||||
#define EGL_GL_COLORSPACE_SRGB_KHR 0x3089
|
||||
#define EGL_CONTEXT_RELEASE_BEHAVIOR_KHR 0x2097
|
||||
#define EGL_CONTEXT_RELEASE_BEHAVIOR_NONE_KHR 0
|
||||
#define EGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_KHR 0x2098
|
||||
|
||||
typedef int EGLint;
|
||||
typedef unsigned int EGLBoolean;
|
||||
typedef unsigned int EGLenum;
|
||||
typedef void* EGLConfig;
|
||||
typedef void* EGLContext;
|
||||
typedef void* EGLDisplay;
|
||||
typedef void* EGLSurface;
|
||||
|
||||
// EGL function pointer typedefs
|
||||
typedef EGLBoolean (EGLAPIENTRY * PFN_eglGetConfigAttrib)(EGLDisplay,EGLConfig,EGLint,EGLint*);
|
||||
typedef EGLBoolean (EGLAPIENTRY * PFN_eglGetConfigs)(EGLDisplay,EGLConfig*,EGLint,EGLint*);
|
||||
typedef EGLDisplay (EGLAPIENTRY * PFN_eglGetDisplay)(EGLNativeDisplayType);
|
||||
typedef EGLint (EGLAPIENTRY * PFN_eglGetError)(void);
|
||||
typedef EGLBoolean (EGLAPIENTRY * PFN_eglInitialize)(EGLDisplay,EGLint*,EGLint*);
|
||||
typedef EGLBoolean (EGLAPIENTRY * PFN_eglTerminate)(EGLDisplay);
|
||||
typedef EGLBoolean (EGLAPIENTRY * PFN_eglBindAPI)(EGLenum);
|
||||
typedef EGLContext (EGLAPIENTRY * PFN_eglCreateContext)(EGLDisplay,EGLConfig,EGLContext,const EGLint*);
|
||||
typedef EGLBoolean (EGLAPIENTRY * PFN_eglDestroySurface)(EGLDisplay,EGLSurface);
|
||||
typedef EGLBoolean (EGLAPIENTRY * PFN_eglDestroyContext)(EGLDisplay,EGLContext);
|
||||
typedef EGLSurface (EGLAPIENTRY * PFN_eglCreateWindowSurface)(EGLDisplay,EGLConfig,EGLNativeWindowType,const EGLint*);
|
||||
typedef EGLBoolean (EGLAPIENTRY * PFN_eglMakeCurrent)(EGLDisplay,EGLSurface,EGLSurface,EGLContext);
|
||||
typedef EGLBoolean (EGLAPIENTRY * PFN_eglSwapBuffers)(EGLDisplay,EGLSurface);
|
||||
typedef EGLBoolean (EGLAPIENTRY * PFN_eglSwapInterval)(EGLDisplay,EGLint);
|
||||
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 eglGetDisplay _glfw.egl.GetDisplay
|
||||
#define eglGetError _glfw.egl.GetError
|
||||
#define eglInitialize _glfw.egl.Initialize
|
||||
#define eglTerminate _glfw.egl.Terminate
|
||||
#define eglBindAPI _glfw.egl.BindAPI
|
||||
#define eglCreateContext _glfw.egl.CreateContext
|
||||
#define eglDestroySurface _glfw.egl.DestroySurface
|
||||
#define eglDestroyContext _glfw.egl.DestroyContext
|
||||
#define eglCreateWindowSurface _glfw.egl.CreateWindowSurface
|
||||
#define eglMakeCurrent _glfw.egl.MakeCurrent
|
||||
#define eglSwapBuffers _glfw.egl.SwapBuffers
|
||||
#define eglSwapInterval _glfw.egl.SwapInterval
|
||||
#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
|
||||
|
||||
|
||||
// EGL-specific per-context data
|
||||
//
|
||||
typedef struct _GLFWcontextEGL
|
||||
{
|
||||
EGLConfig config;
|
||||
EGLContext handle;
|
||||
EGLSurface surface;
|
||||
|
||||
void* client;
|
||||
|
||||
} _GLFWcontextEGL;
|
||||
|
||||
// EGL-specific global data
|
||||
//
|
||||
typedef struct _GLFWlibraryEGL
|
||||
{
|
||||
EGLDisplay display;
|
||||
EGLint major, minor;
|
||||
GLFWbool 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;
|
||||
|
||||
void* handle;
|
||||
|
||||
PFN_eglGetConfigAttrib GetConfigAttrib;
|
||||
PFN_eglGetConfigs GetConfigs;
|
||||
PFN_eglGetDisplay GetDisplay;
|
||||
PFN_eglGetError GetError;
|
||||
PFN_eglInitialize Initialize;
|
||||
PFN_eglTerminate Terminate;
|
||||
PFN_eglBindAPI BindAPI;
|
||||
PFN_eglCreateContext CreateContext;
|
||||
PFN_eglDestroySurface DestroySurface;
|
||||
PFN_eglDestroyContext DestroyContext;
|
||||
PFN_eglCreateWindowSurface CreateWindowSurface;
|
||||
PFN_eglMakeCurrent MakeCurrent;
|
||||
PFN_eglSwapBuffers SwapBuffers;
|
||||
PFN_eglSwapInterval SwapInterval;
|
||||
PFN_eglQueryString QueryString;
|
||||
PFN_eglGetProcAddress GetProcAddress;
|
||||
|
||||
} _GLFWlibraryEGL;
|
||||
|
||||
|
||||
GLFWbool _glfwInitEGL(void);
|
||||
void _glfwTerminateEGL(void);
|
||||
GLFWbool _glfwCreateContextEGL(_GLFWwindow* window,
|
||||
const _GLFWctxconfig* ctxconfig,
|
||||
const _GLFWfbconfig* fbconfig);
|
||||
#if defined(_GLFW_X11)
|
||||
GLFWbool _glfwChooseVisualEGL(const _GLFWwndconfig* wndconfig,
|
||||
const _GLFWctxconfig* ctxconfig,
|
||||
const _GLFWfbconfig* fbconfig,
|
||||
Visual** visual, int* depth);
|
||||
#endif /*_GLFW_X11*/
|
||||
277
glfw/glfw.py
Executable file
277
glfw/glfw.py
Executable file
@@ -0,0 +1,277 @@
|
||||
#!/usr/bin/env python
|
||||
# vim:fileencoding=utf-8
|
||||
# License: GPL v3 Copyright: 2017, Kovid Goyal <kovid at kovidgoyal.net>
|
||||
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
|
||||
_plat = sys.platform.lower()
|
||||
is_macos = 'darwin' in _plat
|
||||
is_freebsd = 'freebsd' in _plat
|
||||
is_netbsd = 'netbsd' in _plat
|
||||
is_dragonflybsd = 'dragonfly' in _plat
|
||||
is_bsd = is_freebsd or is_netbsd or is_dragonflybsd
|
||||
base = os.path.dirname(os.path.abspath(__file__))
|
||||
|
||||
|
||||
def wayland_protocol_file_name(base, ext='c'):
|
||||
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'):
|
||||
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.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')))
|
||||
module_sources = list(sinfo[module]['sources'])
|
||||
if module in ('x11', 'wayland'):
|
||||
remove = 'linux_joystick.c' if is_bsd else 'null_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'):
|
||||
at_least_version('xkbcommon', 0, 5)
|
||||
|
||||
if module == 'x11':
|
||||
for dep in 'x11 xrandr xinerama xcursor xkbcommon xkbcommon-x11 x11-xcb dbus-1'.split():
|
||||
ans.cflags.extend(pkg_config(dep, '--cflags-only-I'))
|
||||
ans.ldpaths.extend(pkg_config(dep, '--libs'))
|
||||
|
||||
elif module == 'cocoa':
|
||||
for f in 'Cocoa IOKit CoreFoundation CoreVideo'.split():
|
||||
ans.ldpaths.extend(('-framework', f))
|
||||
|
||||
elif module == 'wayland':
|
||||
at_least_version('wayland-protocols', *sinfo['wayland_protocols'])
|
||||
ans.wayland_packagedir = os.path.abspath(pkg_config('wayland-protocols', '--variable=pkgdatadir')[0])
|
||||
ans.wayland_scanner = os.path.abspath(pkg_config('wayland-scanner', '--variable=wayland_scanner')[0])
|
||||
scanner_version = tuple(map(int, pkg_config('wayland-scanner', '--modversion')[0].strip().split('.')))
|
||||
ans.wayland_scanner_code = 'private-code' if scanner_version >= (1, 14, 91) else 'code'
|
||||
ans.wayland_protocols = tuple(sinfo[module]['protocols'])
|
||||
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():
|
||||
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
|
||||
#include <unistd.h>
|
||||
#include <sys/syscall.h>
|
||||
int main(void) {
|
||||
return syscall(__NR_memfd_create, "test", 0);
|
||||
}''')
|
||||
if has_memfd_create:
|
||||
ans.cppflags.append('-DHAS_MEMFD_CREATE')
|
||||
|
||||
return ans
|
||||
|
||||
|
||||
def build_wayland_protocols(env, run_tool, emphasis, newer, dest_dir):
|
||||
for protocol in env.wayland_protocols:
|
||||
src = os.path.join(env.wayland_packagedir, protocol)
|
||||
if not os.path.exists(src):
|
||||
raise SystemExit('The wayland-protocols package on your system is missing the {} protocol definition file'.format(protocol))
|
||||
for ext in 'hc':
|
||||
dest = wayland_protocol_file_name(src, ext)
|
||||
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
|
||||
|
||||
|
||||
class Arg:
|
||||
|
||||
def __init__(self, decl):
|
||||
self.type, self.name = decl.rsplit(' ', 1)
|
||||
self.type = self.type.strip()
|
||||
self.name = self.name.strip()
|
||||
while self.name.startswith('*'):
|
||||
self.name = self.name[1:]
|
||||
self.type = self.type + '*'
|
||||
|
||||
def __repr__(self):
|
||||
return 'Arg({}, {})'.format(self.type, self.name)
|
||||
|
||||
|
||||
class Function:
|
||||
|
||||
def __init__(self, declaration, check_fail=True):
|
||||
self.check_fail = check_fail
|
||||
m = re.match(
|
||||
r'(.+?)\s+(glfw[A-Z][a-zA-Z0-9]+)[(](.+)[)]$', declaration
|
||||
)
|
||||
if m is None:
|
||||
raise SystemExit('Failed to parse ' + repr(declaration))
|
||||
self.restype = m.group(1).strip()
|
||||
self.name = m.group(2)
|
||||
args = m.group(3).strip().split(',')
|
||||
args = [x.strip() for x in args]
|
||||
self.args = []
|
||||
for a in args:
|
||||
if a == 'void':
|
||||
continue
|
||||
self.args.append(Arg(a))
|
||||
|
||||
def declaration(self):
|
||||
return 'typedef {restype} (*{name}_func)({args});\n{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):
|
||||
ans = '*(void **) (&{name}_impl) = dlsym(handle, "{name}");'.format(
|
||||
name=self.name
|
||||
)
|
||||
if self.check_fail:
|
||||
ans += '\n if ({name}_impl == NULL) fail("Failed to load glfw function {name} with error: %s", dlerror());'.format(
|
||||
name=self.name
|
||||
)
|
||||
return ans
|
||||
|
||||
|
||||
def generate_wrappers(glfw_header):
|
||||
src = open(glfw_header).read()
|
||||
functions = []
|
||||
first = None
|
||||
for m in re.finditer(r'^GLFWAPI\s+(.+[)]);\s*$', src, flags=re.MULTILINE):
|
||||
if first is None:
|
||||
first = m.start()
|
||||
decl = m.group(1)
|
||||
if 'VkInstance' in decl:
|
||||
continue
|
||||
functions.append(Function(decl))
|
||||
for line in '''\
|
||||
void* glfwGetCocoaWindow(GLFWwindow* window)
|
||||
void* glfwGetNSGLContext(GLFWwindow *window)
|
||||
uint32_t glfwGetCocoaMonitor(GLFWmonitor* monitor)
|
||||
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)
|
||||
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)
|
||||
void glfwRequestWaylandFrameEvent(GLFWwindow *handle, unsigned long long id, GLFWwaylandframecallbackfunc callback)
|
||||
'''.splitlines():
|
||||
if line:
|
||||
functions.append(Function(line.strip(), check_fail=False))
|
||||
|
||||
declarations = [f.declaration() for f in functions]
|
||||
p = src.find(' * GLFW API tokens')
|
||||
p = src.find('*/', p)
|
||||
preamble = src[p + 2:first]
|
||||
header = '''\
|
||||
#pragma once
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
{}
|
||||
|
||||
typedef int (* GLFWcocoatextinputfilterfun)(int,int,unsigned int);
|
||||
typedef int (* GLFWapplicationshouldhandlereopenfun)(int);
|
||||
typedef int (* GLFWcocoatogglefullscreenfun)(GLFWwindow*);
|
||||
typedef void (*GLFWwaylandframecallbackfunc)(unsigned long long id);
|
||||
{}
|
||||
|
||||
const char* load_glfw(const char* path);
|
||||
'''.format(preamble, '\n\n'.join(declarations))
|
||||
with open('../kitty/glfw-wrapper.h', 'w') as f:
|
||||
f.write(header)
|
||||
|
||||
code = '''
|
||||
#include "data-types.h"
|
||||
#include "glfw-wrapper.h"
|
||||
#include <dlfcn.h>
|
||||
|
||||
static void* handle = NULL;
|
||||
|
||||
#define fail(msg, ...) { snprintf(buf, sizeof(buf), msg, __VA_ARGS__); return buf; }
|
||||
|
||||
const char*
|
||||
load_glfw(const char* path) {
|
||||
static char buf[2048];
|
||||
handle = dlopen(path, RTLD_LAZY);
|
||||
if (handle == NULL) fail("Failed to dlopen %s with error: %s", path, dlerror());
|
||||
dlerror();
|
||||
|
||||
LOAD
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
unload_glfw() {
|
||||
if (handle) { dlclose(handle); handle = NULL; }
|
||||
}
|
||||
'''.replace('LOAD', '\n\n '.join(f.load() for f in functions))
|
||||
with open('../kitty/glfw-wrapper.c', 'w') as f:
|
||||
f.write(code)
|
||||
|
||||
|
||||
def main():
|
||||
os.chdir(os.path.dirname(os.path.abspath(__file__)))
|
||||
generate_wrappers('glfw3.h')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
5480
glfw/glfw3.h
vendored
Normal file
5480
glfw/glfw3.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
698
glfw/glx_context.c
vendored
Normal file
698
glfw/glx_context.c
vendored
Normal file
@@ -0,0 +1,698 @@
|
||||
//========================================================================
|
||||
// GLFW 3.3 GLX - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||
// Copyright (c) 2006-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 <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
#ifndef GLXBadProfileARB
|
||||
#define GLXBadProfileARB 13
|
||||
#endif
|
||||
|
||||
|
||||
// Returns the specified attribute of the specified GLXFBConfig
|
||||
//
|
||||
static int getGLXFBConfigAttrib(GLXFBConfig fbconfig, int attrib)
|
||||
{
|
||||
int value;
|
||||
glXGetFBConfigAttrib(_glfw.x11.display, fbconfig, attrib, &value);
|
||||
return value;
|
||||
}
|
||||
|
||||
// Return the GLXFBConfig most closely matching the specified hints
|
||||
//
|
||||
static GLFWbool chooseGLXFBConfig(const _GLFWfbconfig* desired,
|
||||
GLXFBConfig* result)
|
||||
{
|
||||
GLXFBConfig* nativeConfigs;
|
||||
_GLFWfbconfig* usableConfigs;
|
||||
const _GLFWfbconfig* closest;
|
||||
int i, nativeCount, usableCount;
|
||||
const char* vendor;
|
||||
GLFWbool trustWindowBit = GLFW_TRUE;
|
||||
|
||||
// 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);
|
||||
if (!nativeConfigs || !nativeCount)
|
||||
{
|
||||
_glfwInputError(GLFW_API_UNAVAILABLE, "GLX: No GLXFBConfigs returned");
|
||||
return GLFW_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)
|
||||
{
|
||||
XVisualInfo* vi = glXGetVisualFromFBConfig(_glfw.x11.display, n);
|
||||
if (vi)
|
||||
{
|
||||
u->transparent = _glfwIsVisualTransparentX11(vi->visual);
|
||||
XFree(vi);
|
||||
}
|
||||
}
|
||||
|
||||
u->redBits = getGLXFBConfigAttrib(n, GLX_RED_SIZE);
|
||||
u->greenBits = getGLXFBConfigAttrib(n, GLX_GREEN_SIZE);
|
||||
u->blueBits = getGLXFBConfigAttrib(n, GLX_BLUE_SIZE);
|
||||
|
||||
u->alphaBits = getGLXFBConfigAttrib(n, GLX_ALPHA_SIZE);
|
||||
u->depthBits = getGLXFBConfigAttrib(n, GLX_DEPTH_SIZE);
|
||||
u->stencilBits = getGLXFBConfigAttrib(n, GLX_STENCIL_SIZE);
|
||||
|
||||
u->accumRedBits = getGLXFBConfigAttrib(n, GLX_ACCUM_RED_SIZE);
|
||||
u->accumGreenBits = getGLXFBConfigAttrib(n, GLX_ACCUM_GREEN_SIZE);
|
||||
u->accumBlueBits = getGLXFBConfigAttrib(n, GLX_ACCUM_BLUE_SIZE);
|
||||
u->accumAlphaBits = getGLXFBConfigAttrib(n, GLX_ACCUM_ALPHA_SIZE);
|
||||
|
||||
u->auxBuffers = getGLXFBConfigAttrib(n, GLX_AUX_BUFFERS);
|
||||
|
||||
if (getGLXFBConfigAttrib(n, GLX_STEREO))
|
||||
u->stereo = 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;
|
||||
|
||||
XFree(nativeConfigs);
|
||||
free(usableConfigs);
|
||||
|
||||
return closest != NULL;
|
||||
}
|
||||
|
||||
// Create the OpenGL context using legacy API
|
||||
//
|
||||
static GLXContext createLegacyContextGLX(_GLFWwindow* window,
|
||||
GLXFBConfig fbconfig,
|
||||
GLXContext share)
|
||||
{
|
||||
return glXCreateNewContext(_glfw.x11.display,
|
||||
fbconfig,
|
||||
GLX_RGBA_TYPE,
|
||||
share,
|
||||
True);
|
||||
}
|
||||
|
||||
static void makeContextCurrentGLX(_GLFWwindow* window)
|
||||
{
|
||||
if (window)
|
||||
{
|
||||
if (!glXMakeCurrent(_glfw.x11.display,
|
||||
window->context.glx.window,
|
||||
window->context.glx.handle))
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"GLX: Failed to make context current");
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!glXMakeCurrent(_glfw.x11.display, None, NULL))
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"GLX: Failed to clear current context");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
_glfwPlatformSetTls(&_glfw.contextSlot, window);
|
||||
}
|
||||
|
||||
static void swapBuffersGLX(_GLFWwindow* window)
|
||||
{
|
||||
glXSwapBuffers(_glfw.x11.display, window->context.glx.window);
|
||||
}
|
||||
|
||||
static void swapIntervalGLX(int interval)
|
||||
{
|
||||
_GLFWwindow* window = _glfwPlatformGetTls(&_glfw.contextSlot);
|
||||
|
||||
if (_glfw.glx.EXT_swap_control)
|
||||
{
|
||||
_glfw.glx.SwapIntervalEXT(_glfw.x11.display,
|
||||
window->context.glx.window,
|
||||
interval);
|
||||
}
|
||||
else if (_glfw.glx.MESA_swap_control)
|
||||
_glfw.glx.SwapIntervalMESA(interval);
|
||||
else if (_glfw.glx.SGI_swap_control)
|
||||
{
|
||||
if (interval > 0)
|
||||
_glfw.glx.SwapIntervalSGI(interval);
|
||||
}
|
||||
}
|
||||
|
||||
static int extensionSupportedGLX(const char* extension)
|
||||
{
|
||||
const char* extensions =
|
||||
glXQueryExtensionsString(_glfw.x11.display, _glfw.x11.screen);
|
||||
if (extensions)
|
||||
{
|
||||
if (_glfwStringInExtensionString(extension, extensions))
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
static GLFWglproc getProcAddressGLX(const char* procname)
|
||||
{
|
||||
if (_glfw.glx.GetProcAddress)
|
||||
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);
|
||||
}
|
||||
|
||||
// Destroy the OpenGL context
|
||||
//
|
||||
static void destroyContextGLX(_GLFWwindow* window)
|
||||
{
|
||||
if (window->context.glx.window)
|
||||
{
|
||||
glXDestroyWindow(_glfw.x11.display, window->context.glx.window);
|
||||
window->context.glx.window = None;
|
||||
}
|
||||
|
||||
if (window->context.glx.handle)
|
||||
{
|
||||
glXDestroyContext(_glfw.x11.display, window->context.glx.handle);
|
||||
window->context.glx.handle = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW internal API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Initialize GLX
|
||||
//
|
||||
GLFWbool _glfwInitGLX(void)
|
||||
{
|
||||
int i;
|
||||
const char* sonames[] =
|
||||
{
|
||||
#if defined(_GLFW_GLX_LIBRARY)
|
||||
_GLFW_GLX_LIBRARY,
|
||||
#elif defined(__CYGWIN__)
|
||||
"libGL-1.so",
|
||||
#else
|
||||
"libGL.so.1",
|
||||
"libGL.so",
|
||||
#endif
|
||||
NULL
|
||||
};
|
||||
|
||||
if (_glfw.glx.handle)
|
||||
return GLFW_TRUE;
|
||||
|
||||
for (i = 0; sonames[i]; i++)
|
||||
{
|
||||
_glfw.glx.handle = _glfw_dlopen(sonames[i]);
|
||||
if (_glfw.glx.handle)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!_glfw.glx.handle)
|
||||
{
|
||||
_glfwInputError(GLFW_API_UNAVAILABLE, "GLX: Failed to load GLX");
|
||||
return GLFW_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");
|
||||
|
||||
if (!_glfw.glx.GetFBConfigs ||
|
||||
!_glfw.glx.GetFBConfigAttrib ||
|
||||
!_glfw.glx.GetClientString ||
|
||||
!_glfw.glx.QueryExtension ||
|
||||
!_glfw.glx.QueryVersion ||
|
||||
!_glfw.glx.DestroyContext ||
|
||||
!_glfw.glx.MakeCurrent ||
|
||||
!_glfw.glx.SwapBuffers ||
|
||||
!_glfw.glx.QueryExtensionsString ||
|
||||
!_glfw.glx.CreateNewContext ||
|
||||
!_glfw.glx.CreateWindow ||
|
||||
!_glfw.glx.DestroyWindow ||
|
||||
!_glfw.glx.GetProcAddress ||
|
||||
!_glfw.glx.GetProcAddressARB ||
|
||||
!_glfw.glx.GetVisualFromFBConfig)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"GLX: Failed to load required entry points");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
if (!glXQueryExtension(_glfw.x11.display,
|
||||
&_glfw.glx.errorBase,
|
||||
&_glfw.glx.eventBase))
|
||||
{
|
||||
_glfwInputError(GLFW_API_UNAVAILABLE, "GLX: GLX extension not found");
|
||||
return GLFW_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;
|
||||
}
|
||||
|
||||
if (_glfw.glx.major == 1 && _glfw.glx.minor < 3)
|
||||
{
|
||||
_glfwInputError(GLFW_API_UNAVAILABLE,
|
||||
"GLX: GLX version 1.3 is required");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
if (extensionSupportedGLX("GLX_EXT_swap_control"))
|
||||
{
|
||||
_glfw.glx.SwapIntervalEXT = (PFNGLXSWAPINTERVALEXTPROC)
|
||||
getProcAddressGLX("glXSwapIntervalEXT");
|
||||
|
||||
if (_glfw.glx.SwapIntervalEXT)
|
||||
_glfw.glx.EXT_swap_control = GLFW_TRUE;
|
||||
}
|
||||
|
||||
if (extensionSupportedGLX("GLX_SGI_swap_control"))
|
||||
{
|
||||
_glfw.glx.SwapIntervalSGI = (PFNGLXSWAPINTERVALSGIPROC)
|
||||
getProcAddressGLX("glXSwapIntervalSGI");
|
||||
|
||||
if (_glfw.glx.SwapIntervalSGI)
|
||||
_glfw.glx.SGI_swap_control = GLFW_TRUE;
|
||||
}
|
||||
|
||||
if (extensionSupportedGLX("GLX_MESA_swap_control"))
|
||||
{
|
||||
_glfw.glx.SwapIntervalMESA = (PFNGLXSWAPINTERVALMESAPROC)
|
||||
getProcAddressGLX("glXSwapIntervalMESA");
|
||||
|
||||
if (_glfw.glx.SwapIntervalMESA)
|
||||
_glfw.glx.MESA_swap_control = GLFW_TRUE;
|
||||
}
|
||||
|
||||
if (extensionSupportedGLX("GLX_ARB_multisample"))
|
||||
_glfw.glx.ARB_multisample = GLFW_TRUE;
|
||||
|
||||
if (extensionSupportedGLX("GLX_ARB_framebuffer_sRGB"))
|
||||
_glfw.glx.ARB_framebuffer_sRGB = GLFW_TRUE;
|
||||
|
||||
if (extensionSupportedGLX("GLX_EXT_framebuffer_sRGB"))
|
||||
_glfw.glx.EXT_framebuffer_sRGB = GLFW_TRUE;
|
||||
|
||||
if (extensionSupportedGLX("GLX_ARB_create_context"))
|
||||
{
|
||||
_glfw.glx.CreateContextAttribsARB = (PFNGLXCREATECONTEXTATTRIBSARBPROC)
|
||||
getProcAddressGLX("glXCreateContextAttribsARB");
|
||||
|
||||
if (_glfw.glx.CreateContextAttribsARB)
|
||||
_glfw.glx.ARB_create_context = GLFW_TRUE;
|
||||
}
|
||||
|
||||
if (extensionSupportedGLX("GLX_ARB_create_context_robustness"))
|
||||
_glfw.glx.ARB_create_context_robustness = GLFW_TRUE;
|
||||
|
||||
if (extensionSupportedGLX("GLX_ARB_create_context_profile"))
|
||||
_glfw.glx.ARB_create_context_profile = GLFW_TRUE;
|
||||
|
||||
if (extensionSupportedGLX("GLX_EXT_create_context_es2_profile"))
|
||||
_glfw.glx.EXT_create_context_es2_profile = GLFW_TRUE;
|
||||
|
||||
if (extensionSupportedGLX("GLX_ARB_create_context_no_error"))
|
||||
_glfw.glx.ARB_create_context_no_error = GLFW_TRUE;
|
||||
|
||||
if (extensionSupportedGLX("GLX_ARB_context_flush_control"))
|
||||
_glfw.glx.ARB_context_flush_control = GLFW_TRUE;
|
||||
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
// Terminate GLX
|
||||
//
|
||||
void _glfwTerminateGLX(void)
|
||||
{
|
||||
// NOTE: This function must not call any X11 functions, as it is called
|
||||
// after XCloseDisplay (see _glfwPlatformTerminate for details)
|
||||
|
||||
if (_glfw.glx.handle)
|
||||
{
|
||||
_glfw_dlclose(_glfw.glx.handle);
|
||||
_glfw.glx.handle = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#define setAttrib(a, v) \
|
||||
{ \
|
||||
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,
|
||||
const _GLFWctxconfig* ctxconfig,
|
||||
const _GLFWfbconfig* fbconfig)
|
||||
{
|
||||
int attribs[40];
|
||||
GLXFBConfig native = NULL;
|
||||
GLXContext share = NULL;
|
||||
|
||||
if (ctxconfig->share)
|
||||
share = ctxconfig->share->context.glx.handle;
|
||||
|
||||
if (!chooseGLXFBConfig(fbconfig, &native))
|
||||
{
|
||||
_glfwInputError(GLFW_FORMAT_UNAVAILABLE,
|
||||
"GLX: Failed to find a suitable GLXFBConfig");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
if (ctxconfig->client == GLFW_OPENGL_ES_API)
|
||||
{
|
||||
if (!_glfw.glx.ARB_create_context ||
|
||||
!_glfw.glx.ARB_create_context_profile ||
|
||||
!_glfw.glx.EXT_create_context_es2_profile)
|
||||
{
|
||||
_glfwInputError(GLFW_API_UNAVAILABLE,
|
||||
"GLX: OpenGL ES requested but GLX_EXT_create_context_es2_profile is unavailable");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (ctxconfig->forward)
|
||||
{
|
||||
if (!_glfw.glx.ARB_create_context)
|
||||
{
|
||||
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
|
||||
"GLX: Forward compatibility requested but GLX_ARB_create_context_profile is unavailable");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (ctxconfig->profile)
|
||||
{
|
||||
if (!_glfw.glx.ARB_create_context ||
|
||||
!_glfw.glx.ARB_create_context_profile)
|
||||
{
|
||||
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
|
||||
"GLX: An OpenGL profile requested but GLX_ARB_create_context_profile is unavailable");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
_glfwGrabErrorHandlerX11();
|
||||
|
||||
if (_glfw.glx.ARB_create_context)
|
||||
{
|
||||
int index = 0, mask = 0, flags = 0;
|
||||
|
||||
if (ctxconfig->client == GLFW_OPENGL_API)
|
||||
{
|
||||
if (ctxconfig->forward)
|
||||
flags |= GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;
|
||||
|
||||
if (ctxconfig->profile == GLFW_OPENGL_CORE_PROFILE)
|
||||
mask |= GLX_CONTEXT_CORE_PROFILE_BIT_ARB;
|
||||
else if (ctxconfig->profile == GLFW_OPENGL_COMPAT_PROFILE)
|
||||
mask |= GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB;
|
||||
}
|
||||
else
|
||||
mask |= GLX_CONTEXT_ES2_PROFILE_BIT_EXT;
|
||||
|
||||
if (ctxconfig->debug)
|
||||
flags |= GLX_CONTEXT_DEBUG_BIT_ARB;
|
||||
|
||||
if (ctxconfig->robustness)
|
||||
{
|
||||
if (_glfw.glx.ARB_create_context_robustness)
|
||||
{
|
||||
if (ctxconfig->robustness == GLFW_NO_RESET_NOTIFICATION)
|
||||
{
|
||||
setAttrib(GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB,
|
||||
GLX_NO_RESET_NOTIFICATION_ARB);
|
||||
}
|
||||
else if (ctxconfig->robustness == GLFW_LOSE_CONTEXT_ON_RESET)
|
||||
{
|
||||
setAttrib(GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB,
|
||||
GLX_LOSE_CONTEXT_ON_RESET_ARB);
|
||||
}
|
||||
|
||||
flags |= GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB;
|
||||
}
|
||||
}
|
||||
|
||||
if (ctxconfig->release)
|
||||
{
|
||||
if (_glfw.glx.ARB_context_flush_control)
|
||||
{
|
||||
if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_NONE)
|
||||
{
|
||||
setAttrib(GLX_CONTEXT_RELEASE_BEHAVIOR_ARB,
|
||||
GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB);
|
||||
}
|
||||
else if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_FLUSH)
|
||||
{
|
||||
setAttrib(GLX_CONTEXT_RELEASE_BEHAVIOR_ARB,
|
||||
GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ctxconfig->noerror)
|
||||
{
|
||||
if (_glfw.glx.ARB_create_context_no_error)
|
||||
setAttrib(GLX_CONTEXT_OPENGL_NO_ERROR_ARB, GLFW_TRUE);
|
||||
}
|
||||
|
||||
// NOTE: Only request an explicitly versioned context when necessary, as
|
||||
// explicitly requesting version 1.0 does not always return the
|
||||
// highest version supported by the driver
|
||||
if (ctxconfig->major != 1 || ctxconfig->minor != 0)
|
||||
{
|
||||
setAttrib(GLX_CONTEXT_MAJOR_VERSION_ARB, ctxconfig->major);
|
||||
setAttrib(GLX_CONTEXT_MINOR_VERSION_ARB, ctxconfig->minor);
|
||||
}
|
||||
|
||||
if (mask)
|
||||
setAttrib(GLX_CONTEXT_PROFILE_MASK_ARB, mask);
|
||||
|
||||
if (flags)
|
||||
setAttrib(GLX_CONTEXT_FLAGS_ARB, flags);
|
||||
|
||||
setAttrib(None, None);
|
||||
|
||||
window->context.glx.handle =
|
||||
_glfw.glx.CreateContextAttribsARB(_glfw.x11.display,
|
||||
native,
|
||||
share,
|
||||
True,
|
||||
attribs);
|
||||
|
||||
// HACK: This is a fallback for broken versions of the Mesa
|
||||
// implementation of GLX_ARB_create_context_profile that fail
|
||||
// default 1.0 context creation with a GLXBadProfileARB error in
|
||||
// violation of the extension spec
|
||||
if (!window->context.glx.handle)
|
||||
{
|
||||
if (_glfw.x11.errorCode == _glfw.glx.errorBase + GLXBadProfileARB &&
|
||||
ctxconfig->client == GLFW_OPENGL_API &&
|
||||
ctxconfig->profile == GLFW_OPENGL_ANY_PROFILE &&
|
||||
ctxconfig->forward == GLFW_FALSE)
|
||||
{
|
||||
window->context.glx.handle =
|
||||
createLegacyContextGLX(window, native, share);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
window->context.glx.handle =
|
||||
createLegacyContextGLX(window, native, share);
|
||||
}
|
||||
|
||||
_glfwReleaseErrorHandlerX11();
|
||||
|
||||
if (!window->context.glx.handle)
|
||||
{
|
||||
_glfwInputErrorX11(GLFW_VERSION_UNAVAILABLE, "GLX: Failed to create context");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
window->context.glx.window =
|
||||
glXCreateWindow(_glfw.x11.display, native, window->x11.handle, NULL);
|
||||
if (!window->context.glx.window)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR, "GLX: Failed to create window");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
window->context.makeCurrent = makeContextCurrentGLX;
|
||||
window->context.swapBuffers = swapBuffersGLX;
|
||||
window->context.swapInterval = swapIntervalGLX;
|
||||
window->context.extensionSupported = extensionSupportedGLX;
|
||||
window->context.getProcAddress = getProcAddressGLX;
|
||||
window->context.destroy = destroyContextGLX;
|
||||
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
#undef setAttrib
|
||||
|
||||
// Returns the Visual and depth of the chosen GLXFBConfig
|
||||
//
|
||||
GLFWbool _glfwChooseVisualGLX(const _GLFWwndconfig* wndconfig,
|
||||
const _GLFWctxconfig* ctxconfig,
|
||||
const _GLFWfbconfig* fbconfig,
|
||||
Visual** visual, int* depth)
|
||||
{
|
||||
GLXFBConfig native;
|
||||
XVisualInfo* result;
|
||||
|
||||
if (!chooseGLXFBConfig(fbconfig, &native))
|
||||
{
|
||||
_glfwInputError(GLFW_FORMAT_UNAVAILABLE,
|
||||
"GLX: Failed to find a suitable GLXFBConfig");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
result = glXGetVisualFromFBConfig(_glfw.x11.display, native);
|
||||
if (!result)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"GLX: Failed to retrieve Visual for GLXFBConfig");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
*visual = result->visual;
|
||||
*depth = result->depth;
|
||||
|
||||
XFree(result);
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW native API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
GLFWAPI GLXContext glfwGetGLXContext(GLFWwindow* handle)
|
||||
{
|
||||
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||
|
||||
if (window->context.client == GLFW_NO_API)
|
||||
{
|
||||
_glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return window->context.glx.handle;
|
||||
}
|
||||
|
||||
GLFWAPI GLXWindow glfwGetGLXWindow(GLFWwindow* handle)
|
||||
{
|
||||
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(None);
|
||||
|
||||
if (window->context.client == GLFW_NO_API)
|
||||
{
|
||||
_glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
|
||||
return None;
|
||||
}
|
||||
|
||||
return window->context.glx.window;
|
||||
}
|
||||
|
||||
181
glfw/glx_context.h
vendored
Normal file
181
glfw/glx_context.h
vendored
Normal file
@@ -0,0 +1,181 @@
|
||||
//========================================================================
|
||||
// GLFW 3.3 GLX - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||
// Copyright (c) 2006-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.
|
||||
//
|
||||
//========================================================================
|
||||
|
||||
#define GLX_VENDOR 1
|
||||
#define GLX_RGBA_BIT 0x00000001
|
||||
#define GLX_WINDOW_BIT 0x00000001
|
||||
#define GLX_DRAWABLE_TYPE 0x8010
|
||||
#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_RED_SIZE 8
|
||||
#define GLX_GREEN_SIZE 9
|
||||
#define GLX_BLUE_SIZE 10
|
||||
#define GLX_ALPHA_SIZE 11
|
||||
#define GLX_DEPTH_SIZE 12
|
||||
#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_ALPHA_SIZE 17
|
||||
#define GLX_SAMPLES 0x186a1
|
||||
#define GLX_VISUAL_ID 0x800b
|
||||
|
||||
#define GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20b2
|
||||
#define GLX_CONTEXT_DEBUG_BIT_ARB 0x00000001
|
||||
#define GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002
|
||||
#define GLX_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001
|
||||
#define GLX_CONTEXT_PROFILE_MASK_ARB 0x9126
|
||||
#define GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x00000002
|
||||
#define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091
|
||||
#define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092
|
||||
#define GLX_CONTEXT_FLAGS_ARB 0x2094
|
||||
#define GLX_CONTEXT_ES2_PROFILE_BIT_EXT 0x00000004
|
||||
#define GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB 0x00000004
|
||||
#define GLX_LOSE_CONTEXT_ON_RESET_ARB 0x8252
|
||||
#define GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB 0x8256
|
||||
#define GLX_NO_RESET_NOTIFICATION_ARB 0x8261
|
||||
#define GLX_CONTEXT_RELEASE_BEHAVIOR_ARB 0x2097
|
||||
#define GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB 0
|
||||
#define GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB 0x2098
|
||||
#define GLX_CONTEXT_OPENGL_NO_ERROR_ARB 0x31b3
|
||||
|
||||
typedef XID GLXWindow;
|
||||
typedef XID GLXDrawable;
|
||||
typedef struct __GLXFBConfig* GLXFBConfig;
|
||||
typedef struct __GLXcontext* GLXContext;
|
||||
typedef void (*__GLXextproc)(void);
|
||||
|
||||
typedef int (*PFNGLXGETFBCONFIGATTRIBPROC)(Display*,GLXFBConfig,int,int*);
|
||||
typedef const char* (*PFNGLXGETCLIENTSTRINGPROC)(Display*,int);
|
||||
typedef Bool (*PFNGLXQUERYEXTENSIONPROC)(Display*,int*,int*);
|
||||
typedef Bool (*PFNGLXQUERYVERSIONPROC)(Display*,int*,int*);
|
||||
typedef void (*PFNGLXDESTROYCONTEXTPROC)(Display*,GLXContext);
|
||||
typedef Bool (*PFNGLXMAKECURRENTPROC)(Display*,GLXDrawable,GLXContext);
|
||||
typedef void (*PFNGLXSWAPBUFFERSPROC)(Display*,GLXDrawable);
|
||||
typedef const char* (*PFNGLXQUERYEXTENSIONSSTRINGPROC)(Display*,int);
|
||||
typedef GLXFBConfig* (*PFNGLXGETFBCONFIGSPROC)(Display*,int,int*);
|
||||
typedef GLXContext (*PFNGLXCREATENEWCONTEXTPROC)(Display*,GLXFBConfig,int,GLXContext,Bool);
|
||||
typedef __GLXextproc (* PFNGLXGETPROCADDRESSPROC)(const GLubyte *procName);
|
||||
typedef void (*PFNGLXSWAPINTERVALEXTPROC)(Display*,GLXDrawable,int);
|
||||
typedef XVisualInfo* (*PFNGLXGETVISUALFROMFBCONFIGPROC)(Display*,GLXFBConfig);
|
||||
typedef GLXWindow (*PFNGLXCREATEWINDOWPROC)(Display*,GLXFBConfig,Window,const int*);
|
||||
typedef void (*PFNGLXDESTROYWINDOWPROC)(Display*,GLXWindow);
|
||||
|
||||
typedef int (*PFNGLXSWAPINTERVALMESAPROC)(int);
|
||||
typedef int (*PFNGLXSWAPINTERVALSGIPROC)(int);
|
||||
typedef GLXContext (*PFNGLXCREATECONTEXTATTRIBSARBPROC)(Display*,GLXFBConfig,GLXContext,Bool,const int*);
|
||||
|
||||
// libGL.so function pointer typedefs
|
||||
#define glXGetFBConfigs _glfw.glx.GetFBConfigs
|
||||
#define glXGetFBConfigAttrib _glfw.glx.GetFBConfigAttrib
|
||||
#define glXGetClientString _glfw.glx.GetClientString
|
||||
#define glXQueryExtension _glfw.glx.QueryExtension
|
||||
#define glXQueryVersion _glfw.glx.QueryVersion
|
||||
#define glXDestroyContext _glfw.glx.DestroyContext
|
||||
#define glXMakeCurrent _glfw.glx.MakeCurrent
|
||||
#define glXSwapBuffers _glfw.glx.SwapBuffers
|
||||
#define glXQueryExtensionsString _glfw.glx.QueryExtensionsString
|
||||
#define glXCreateNewContext _glfw.glx.CreateNewContext
|
||||
#define glXGetVisualFromFBConfig _glfw.glx.GetVisualFromFBConfig
|
||||
#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
|
||||
|
||||
|
||||
// GLX-specific per-context data
|
||||
//
|
||||
typedef struct _GLFWcontextGLX
|
||||
{
|
||||
GLXContext handle;
|
||||
GLXWindow window;
|
||||
|
||||
} _GLFWcontextGLX;
|
||||
|
||||
// GLX-specific global data
|
||||
//
|
||||
typedef struct _GLFWlibraryGLX
|
||||
{
|
||||
int major, minor;
|
||||
int eventBase;
|
||||
int errorBase;
|
||||
|
||||
// dlopen handle for libGL.so.1
|
||||
void* handle;
|
||||
|
||||
// GLX 1.3 functions
|
||||
PFNGLXGETFBCONFIGSPROC GetFBConfigs;
|
||||
PFNGLXGETFBCONFIGATTRIBPROC GetFBConfigAttrib;
|
||||
PFNGLXGETCLIENTSTRINGPROC GetClientString;
|
||||
PFNGLXQUERYEXTENSIONPROC QueryExtension;
|
||||
PFNGLXQUERYVERSIONPROC QueryVersion;
|
||||
PFNGLXDESTROYCONTEXTPROC DestroyContext;
|
||||
PFNGLXMAKECURRENTPROC MakeCurrent;
|
||||
PFNGLXSWAPBUFFERSPROC SwapBuffers;
|
||||
PFNGLXQUERYEXTENSIONSSTRINGPROC QueryExtensionsString;
|
||||
PFNGLXCREATENEWCONTEXTPROC CreateNewContext;
|
||||
PFNGLXGETVISUALFROMFBCONFIGPROC GetVisualFromFBConfig;
|
||||
PFNGLXCREATEWINDOWPROC CreateWindow;
|
||||
PFNGLXDESTROYWINDOWPROC DestroyWindow;
|
||||
|
||||
// GLX 1.4 and extension functions
|
||||
PFNGLXGETPROCADDRESSPROC GetProcAddress;
|
||||
PFNGLXGETPROCADDRESSPROC GetProcAddressARB;
|
||||
PFNGLXSWAPINTERVALSGIPROC SwapIntervalSGI;
|
||||
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;
|
||||
|
||||
} _GLFWlibraryGLX;
|
||||
|
||||
GLFWbool _glfwInitGLX(void);
|
||||
void _glfwTerminateGLX(void);
|
||||
GLFWbool _glfwCreateContextGLX(_GLFWwindow* window,
|
||||
const _GLFWctxconfig* ctxconfig,
|
||||
const _GLFWfbconfig* fbconfig);
|
||||
void _glfwDestroyContextGLX(_GLFWwindow* window);
|
||||
GLFWbool _glfwChooseVisualGLX(const _GLFWwndconfig* wndconfig,
|
||||
const _GLFWctxconfig* ctxconfig,
|
||||
const _GLFWfbconfig* fbconfig,
|
||||
Visual** visual, int* depth);
|
||||
|
||||
426
glfw/ibus_glfw.c
vendored
Normal file
426
glfw/ibus_glfw.c
vendored
Normal file
@@ -0,0 +1,426 @@
|
||||
//========================================================================
|
||||
// GLFW 3.3 XKB - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2018 Kovid Goyal <kovid@kovidgoyal.net>
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would
|
||||
// be appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such, and must not
|
||||
// be misrepresented as being the original software.
|
||||
//
|
||||
// 3. This notice may not be removed or altered from any source
|
||||
// distribution.
|
||||
//
|
||||
//========================================================================
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "internal.h"
|
||||
#include "ibus_glfw.h"
|
||||
|
||||
#define debug(...) if (_glfw.hints.init.debugKeyboard) printf(__VA_ARGS__);
|
||||
static const char IBUS_SERVICE[] = "org.freedesktop.IBus";
|
||||
static const char IBUS_PATH[] = "/org/freedesktop/IBus";
|
||||
static const char IBUS_INTERFACE[] = "org.freedesktop.IBus";
|
||||
static const char IBUS_INPUT_INTERFACE[] = "org.freedesktop.IBus.InputContext";
|
||||
enum Capabilities {
|
||||
IBUS_CAP_PREEDIT_TEXT = 1 << 0,
|
||||
IBUS_CAP_AUXILIARY_TEXT = 1 << 1,
|
||||
IBUS_CAP_LOOKUP_TABLE = 1 << 2,
|
||||
IBUS_CAP_FOCUS = 1 << 3,
|
||||
IBUS_CAP_PROPERTY = 1 << 4,
|
||||
IBUS_CAP_SURROUNDING_TEXT = 1 << 5
|
||||
};
|
||||
|
||||
|
||||
static inline GLFWbool
|
||||
test_env_var(const char *name, const char *val) {
|
||||
const char *q = getenv(name);
|
||||
return (q && strcmp(q, val) == 0) ? GLFW_TRUE : GLFW_FALSE;
|
||||
}
|
||||
|
||||
static inline GLFWbool
|
||||
MIN(size_t a, size_t b) {
|
||||
return a < b ? a : b;
|
||||
}
|
||||
|
||||
static const char*
|
||||
get_ibus_text_from_message(DBusMessage *msg) {
|
||||
/* The message structure is (from dbus-monitor)
|
||||
variant struct {
|
||||
string "IBusText"
|
||||
array [
|
||||
]
|
||||
string "ash "
|
||||
variant struct {
|
||||
string "IBusAttrList"
|
||||
array [
|
||||
]
|
||||
array [
|
||||
]
|
||||
}
|
||||
}
|
||||
*/
|
||||
const char *text = NULL;
|
||||
const char *struct_id = NULL;
|
||||
DBusMessageIter iter, sub1, sub2;
|
||||
dbus_message_iter_init(msg, &iter);
|
||||
|
||||
if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) return NULL;
|
||||
|
||||
dbus_message_iter_recurse(&iter, &sub1);
|
||||
|
||||
if (dbus_message_iter_get_arg_type(&sub1) != DBUS_TYPE_STRUCT) return NULL;
|
||||
|
||||
dbus_message_iter_recurse(&sub1, &sub2);
|
||||
|
||||
if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_STRING) return NULL;
|
||||
|
||||
dbus_message_iter_get_basic(&sub2, &struct_id);
|
||||
if (!struct_id || strncmp(struct_id, "IBusText", sizeof("IBusText")) != 0) return NULL;
|
||||
|
||||
dbus_message_iter_next(&sub2);
|
||||
dbus_message_iter_next(&sub2);
|
||||
|
||||
if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_STRING) return NULL;
|
||||
|
||||
dbus_message_iter_get_basic(&sub2, &text);
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
static inline void
|
||||
send_text(const char *text, int state) {
|
||||
_GLFWwindow *w = _glfwFocusedWindow();
|
||||
if (w && w->callbacks.keyboard) {
|
||||
w->callbacks.keyboard((GLFWwindow*) w, GLFW_KEY_UNKNOWN, 0, GLFW_PRESS, 0, text, state);
|
||||
}
|
||||
}
|
||||
|
||||
// Connection handling {{{
|
||||
|
||||
static DBusHandlerResult
|
||||
message_handler(DBusConnection *conn, 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;
|
||||
(void)ibus;
|
||||
const char *text;
|
||||
switch(glfw_dbus_match_signal(msg, IBUS_INPUT_INTERFACE, "CommitText", "UpdatePreeditText", "HidePreeditText", "ShowPreeditText", NULL)) {
|
||||
case 0:
|
||||
text = get_ibus_text_from_message(msg);
|
||||
debug("IBUS: CommitText: '%s'\n", text ? text : "(nil)");
|
||||
send_text(text, 2);
|
||||
break;
|
||||
case 1:
|
||||
text = get_ibus_text_from_message(msg);
|
||||
send_text(text, 1);
|
||||
debug("IBUS: UpdatePreeditText: '%s'\n", text ? text : "(nil)");
|
||||
break;
|
||||
case 2:
|
||||
debug("IBUS: HidePreeditText\n");
|
||||
break;
|
||||
case 3:
|
||||
debug("IBUS: ShowPreeditText\n");
|
||||
break;
|
||||
}
|
||||
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
|
||||
}
|
||||
|
||||
static inline const char*
|
||||
get_ibus_address_file_name(void) {
|
||||
const char *addr;
|
||||
static char ans[PATH_MAX];
|
||||
addr = getenv("IBUS_ADDRESS");
|
||||
int offset = 0;
|
||||
if (addr && addr[0]) {
|
||||
memcpy(ans, addr, MIN(strlen(addr), sizeof(ans)));
|
||||
return ans;
|
||||
}
|
||||
|
||||
const char *de = getenv("DISPLAY");
|
||||
if (!de || !de[0]) de = ":0.0";
|
||||
char *display = _glfw_strdup(de);
|
||||
const char *host = display;
|
||||
char *disp_num = strrchr(display, ':');
|
||||
char *screen_num = strrchr(display, '.');
|
||||
|
||||
if (!disp_num) {
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR, "Could not get IBUS address file name as DISPLAY env var has no colon");
|
||||
free(display);
|
||||
return NULL;
|
||||
}
|
||||
*disp_num = 0;
|
||||
disp_num++;
|
||||
if (screen_num) *screen_num = 0;
|
||||
if (!*host) host = "unix";
|
||||
|
||||
memset(ans, 0, sizeof(ans));
|
||||
const char *conf_env = getenv("XDG_CONFIG_HOME");
|
||||
if (conf_env && conf_env[0]) {
|
||||
offset = snprintf(ans, sizeof(ans), "%s", conf_env);
|
||||
} else {
|
||||
conf_env = getenv("HOME");
|
||||
if (!conf_env || !conf_env[0]) {
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR, "Could not get IBUS address file name as no HOME env var is set");
|
||||
free(display);
|
||||
return NULL;
|
||||
}
|
||||
offset = snprintf(ans, sizeof(ans), "%s/.config", conf_env);
|
||||
}
|
||||
char *key = dbus_get_local_machine_id();
|
||||
snprintf(ans + offset, sizeof(ans) - offset, "/ibus/bus/%s-%s-%s", key, host, disp_num);
|
||||
dbus_free(key);
|
||||
free(display);
|
||||
return ans;
|
||||
}
|
||||
|
||||
|
||||
static inline GLFWbool
|
||||
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;
|
||||
}
|
||||
int stat_result = fstat(fileno(addr_file), &s);
|
||||
GLFWbool found = GLFW_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;
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR, "Could not find IBUS_ADDRESS in %s", ibus->address_file_name);
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
input_context_created(DBusMessage *msg, const char* errmsg, void *data) {
|
||||
if (errmsg) {
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR, "IBUS: Failed to create input context with error: %s", errmsg);
|
||||
return;
|
||||
}
|
||||
const char *path = NULL;
|
||||
if (!glfw_dbus_get_args(msg, "Failed to get IBUS context path from reply", DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID)) return;
|
||||
_GLFWIBUSData *ibus = (_GLFWIBUSData*)data;
|
||||
free((void*)ibus->input_ctx_path);
|
||||
ibus->input_ctx_path = _glfw_strdup(path);
|
||||
if (!ibus->input_ctx_path) return;
|
||||
dbus_bus_add_match(ibus->conn, "type='signal',interface='org.freedesktop.IBus.InputContext'", NULL);
|
||||
DBusObjectPathVTable ibus_vtable = {.message_function = message_handler};
|
||||
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);
|
||||
glfw_ibus_set_cursor_geometry(ibus, 0, 0, 0, 0);
|
||||
debug("Connected to IBUS daemon for IME input management\n");
|
||||
}
|
||||
|
||||
GLFWbool
|
||||
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;
|
||||
free((void*)ibus->address_file_name);
|
||||
ibus->address_file_name = _glfw_strdup(address_file_name);
|
||||
if (!read_ibus_address(ibus)) return GLFW_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;
|
||||
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 GLFW_TRUE;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
glfw_connect_to_ibus(_GLFWIBUSData *ibus) {
|
||||
if (ibus->inited) return;
|
||||
if (!test_env_var("GLFW_IM_MODULE", "ibus")) return;
|
||||
ibus->inited = GLFW_TRUE;
|
||||
setup_connection(ibus);
|
||||
}
|
||||
|
||||
void
|
||||
glfw_ibus_terminate(_GLFWIBUSData *ibus) {
|
||||
if (ibus->conn) {
|
||||
glfw_dbus_close_connection(ibus->conn);
|
||||
ibus->conn = NULL;
|
||||
}
|
||||
#define F(x) if (ibus->x) { free((void*)ibus->x); ibus->x = NULL; }
|
||||
F(input_ctx_path);
|
||||
F(address);
|
||||
F(address_file_name);
|
||||
#undef F
|
||||
|
||||
ibus->ok = GLFW_FALSE;
|
||||
}
|
||||
|
||||
static GLFWbool
|
||||
check_connection(_GLFWIBUSData *ibus) {
|
||||
if (!ibus->inited) return GLFW_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;
|
||||
setup_connection(ibus);
|
||||
}
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
glfw_ibus_dispatch(_GLFWIBUSData *ibus) {
|
||||
if (ibus->conn) glfw_dbus_dispatch(ibus->conn);
|
||||
}
|
||||
// }}}
|
||||
|
||||
static void
|
||||
simple_message(_GLFWIBUSData *ibus, const char *method) {
|
||||
if (check_connection(ibus)) {
|
||||
glfw_dbus_call_method_no_reply(ibus->conn, IBUS_SERVICE, ibus->input_ctx_path, IBUS_INPUT_INTERFACE, method, DBUS_TYPE_INVALID);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
glfw_ibus_set_focused(_GLFWIBUSData *ibus, GLFWbool focused) {
|
||||
simple_message(ibus, focused ? "FocusIn" : "FocusOut");
|
||||
}
|
||||
|
||||
void
|
||||
glfw_ibus_set_cursor_geometry(_GLFWIBUSData *ibus, int x, int y, int w, int h) {
|
||||
if (check_connection(ibus)) {
|
||||
glfw_dbus_call_method_no_reply(ibus->conn, IBUS_SERVICE, ibus->input_ctx_path, IBUS_INPUT_INTERFACE, "SetCursorLocation",
|
||||
DBUS_TYPE_INT32, &x, DBUS_TYPE_INT32, &y, DBUS_TYPE_INT32, &w, DBUS_TYPE_INT32, &h, DBUS_TYPE_INVALID);
|
||||
}
|
||||
}
|
||||
|
||||
typedef enum
|
||||
{
|
||||
IBUS_SHIFT_MASK = 1 << 0,
|
||||
IBUS_LOCK_MASK = 1 << 1,
|
||||
IBUS_CONTROL_MASK = 1 << 2,
|
||||
IBUS_MOD1_MASK = 1 << 3,
|
||||
IBUS_MOD2_MASK = 1 << 4,
|
||||
IBUS_MOD3_MASK = 1 << 5,
|
||||
IBUS_MOD4_MASK = 1 << 6,
|
||||
IBUS_MOD5_MASK = 1 << 7,
|
||||
IBUS_BUTTON1_MASK = 1 << 8,
|
||||
IBUS_BUTTON2_MASK = 1 << 9,
|
||||
IBUS_BUTTON3_MASK = 1 << 10,
|
||||
IBUS_BUTTON4_MASK = 1 << 11,
|
||||
IBUS_BUTTON5_MASK = 1 << 12,
|
||||
|
||||
/* The next few modifiers are used by XKB, so we skip to the end.
|
||||
* Bits 15 - 23 are currently unused. Bit 29 is used internally.
|
||||
*/
|
||||
|
||||
/* ibus mask */
|
||||
IBUS_HANDLED_MASK = 1 << 24,
|
||||
IBUS_FORWARD_MASK = 1 << 25,
|
||||
IBUS_IGNORED_MASK = IBUS_FORWARD_MASK,
|
||||
|
||||
IBUS_SUPER_MASK = 1 << 26,
|
||||
IBUS_HYPER_MASK = 1 << 27,
|
||||
IBUS_META_MASK = 1 << 28,
|
||||
|
||||
IBUS_RELEASE_MASK = 1 << 30,
|
||||
|
||||
IBUS_MODIFIER_MASK = 0x5f001fff
|
||||
} IBusModifierType;
|
||||
|
||||
|
||||
static inline uint32_t
|
||||
ibus_key_state(unsigned int glfw_modifiers, int action) {
|
||||
uint32_t ans = action == GLFW_RELEASE ? IBUS_RELEASE_MASK : 0;
|
||||
#define M(g, i) if(glfw_modifiers & GLFW_MOD_##g) ans |= i
|
||||
M(SHIFT, IBUS_SHIFT_MASK);
|
||||
M(CAPS_LOCK, IBUS_LOCK_MASK);
|
||||
M(CONTROL, IBUS_CONTROL_MASK);
|
||||
M(ALT, IBUS_MOD1_MASK);
|
||||
M(NUM_LOCK, IBUS_MOD2_MASK);
|
||||
M(SUPER, IBUS_MOD4_MASK);
|
||||
#undef M
|
||||
return ans;
|
||||
}
|
||||
|
||||
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;
|
||||
if (errmsg) {
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR, "IBUS: Failed to process key with error: %s", errmsg);
|
||||
failed = GLFW_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);
|
||||
}
|
||||
glfw_xkb_key_from_ime(ev, handled ? GLFW_TRUE : GLFW_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);
|
||||
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,
|
||||
&state, DBUS_TYPE_INVALID)) {
|
||||
free(ev);
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
55
glfw/ibus_glfw.h
vendored
Normal file
55
glfw/ibus_glfw.h
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
//========================================================================
|
||||
// GLFW 3.3 XKB - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2018 Kovid Goyal <kovid@kovidgoyal.net>
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
//========================================================================
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "dbus_glfw.h"
|
||||
#include <xkbcommon/xkbcommon.h>
|
||||
|
||||
typedef struct {
|
||||
GLFWbool 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;
|
||||
GLFWid window_id;
|
||||
int glfw_keycode;
|
||||
char text[64];
|
||||
} KeyEvent;
|
||||
|
||||
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_dispatch(_GLFWIBUSData *ibus);
|
||||
GLFWbool ibus_process_key(const KeyEvent *ev_, _GLFWIBUSData *ibus);
|
||||
void glfw_ibus_set_cursor_geometry(_GLFWIBUSData *ibus, int x, int y, int w, int h);
|
||||
322
glfw/init.c
vendored
Normal file
322
glfw/init.c
vendored
Normal file
@@ -0,0 +1,322 @@
|
||||
//========================================================================
|
||||
// GLFW 3.3 - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||
// Copyright (c) 2006-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 "mappings.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <assert.h>
|
||||
|
||||
|
||||
// The global variables below comprise all mutable global data in GLFW
|
||||
//
|
||||
// Any other global variable is a bug
|
||||
|
||||
// Global state shared between compilation units of GLFW
|
||||
//
|
||||
_GLFWlibrary _glfw = { GLFW_FALSE };
|
||||
|
||||
// These are outside of _glfw so they can be used before initialization and
|
||||
// after termination
|
||||
//
|
||||
static _GLFWerror _glfwMainThreadError;
|
||||
static GLFWerrorfun _glfwErrorCallback;
|
||||
static _GLFWinitconfig _glfwInitHints =
|
||||
{
|
||||
GLFW_TRUE, // hat buttons
|
||||
GLFW_FALSE, // debug keyboard
|
||||
GLFW_TRUE, // enable joystick
|
||||
{
|
||||
GLFW_TRUE, // macOS menu bar
|
||||
GLFW_TRUE // macOS bundle chdir
|
||||
}
|
||||
};
|
||||
|
||||
// Terminate the library
|
||||
//
|
||||
static void terminate(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
memset(&_glfw.callbacks, 0, sizeof(_glfw.callbacks));
|
||||
|
||||
while (_glfw.windowListHead)
|
||||
glfwDestroyWindow((GLFWwindow*) _glfw.windowListHead);
|
||||
|
||||
while (_glfw.cursorListHead)
|
||||
glfwDestroyCursor((GLFWcursor*) _glfw.cursorListHead);
|
||||
|
||||
for (i = 0; i < _glfw.monitorCount; i++)
|
||||
{
|
||||
_GLFWmonitor* monitor = _glfw.monitors[i];
|
||||
if (monitor->originalRamp.size)
|
||||
_glfwPlatformSetGammaRamp(monitor, &monitor->originalRamp);
|
||||
_glfwFreeMonitor(monitor);
|
||||
}
|
||||
|
||||
free(_glfw.monitors);
|
||||
_glfw.monitors = NULL;
|
||||
_glfw.monitorCount = 0;
|
||||
|
||||
free(_glfw.mappings);
|
||||
_glfw.mappings = NULL;
|
||||
_glfw.mappingCount = 0;
|
||||
|
||||
_glfwTerminateVulkan();
|
||||
_glfwPlatformTerminate();
|
||||
|
||||
_glfw.initialized = GLFW_FALSE;
|
||||
|
||||
while (_glfw.errorListHead)
|
||||
{
|
||||
_GLFWerror* error = _glfw.errorListHead;
|
||||
_glfw.errorListHead = error->next;
|
||||
free(error);
|
||||
}
|
||||
|
||||
_glfwPlatformDestroyTls(&_glfw.contextSlot);
|
||||
_glfwPlatformDestroyTls(&_glfw.errorSlot);
|
||||
_glfwPlatformDestroyMutex(&_glfw.errorLock);
|
||||
|
||||
memset(&_glfw, 0, sizeof(_glfw));
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW internal API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
char* _glfw_strdup(const char* source)
|
||||
{
|
||||
const size_t length = strlen(source);
|
||||
char* result = malloc(length + 1);
|
||||
memcpy(result, source, length);
|
||||
result[length] = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW event API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Notifies shared code of an error
|
||||
//
|
||||
void _glfwInputError(int code, const char* format, ...)
|
||||
{
|
||||
_GLFWerror* error;
|
||||
char description[_GLFW_MESSAGE_SIZE];
|
||||
|
||||
if (format)
|
||||
{
|
||||
va_list vl;
|
||||
|
||||
va_start(vl, format);
|
||||
vsnprintf(description, sizeof(description), format, vl);
|
||||
va_end(vl);
|
||||
|
||||
description[sizeof(description) - 1] = '\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
if (code == GLFW_NOT_INITIALIZED)
|
||||
strcpy(description, "The GLFW library is not initialized");
|
||||
else if (code == GLFW_NO_CURRENT_CONTEXT)
|
||||
strcpy(description, "There is no current context");
|
||||
else if (code == GLFW_INVALID_ENUM)
|
||||
strcpy(description, "Invalid argument for enum parameter");
|
||||
else if (code == GLFW_INVALID_VALUE)
|
||||
strcpy(description, "Invalid value for parameter");
|
||||
else if (code == GLFW_OUT_OF_MEMORY)
|
||||
strcpy(description, "Out of memory");
|
||||
else if (code == GLFW_API_UNAVAILABLE)
|
||||
strcpy(description, "The requested API is unavailable");
|
||||
else if (code == GLFW_VERSION_UNAVAILABLE)
|
||||
strcpy(description, "The requested API version is unavailable");
|
||||
else if (code == GLFW_PLATFORM_ERROR)
|
||||
strcpy(description, "A platform-specific error occurred");
|
||||
else if (code == GLFW_FORMAT_UNAVAILABLE)
|
||||
strcpy(description, "The requested format is unavailable");
|
||||
else if (code == GLFW_NO_WINDOW_CONTEXT)
|
||||
strcpy(description, "The specified window has no context");
|
||||
else
|
||||
strcpy(description, "ERROR: UNKNOWN GLFW ERROR");
|
||||
}
|
||||
|
||||
if (_glfw.initialized)
|
||||
{
|
||||
error = _glfwPlatformGetTls(&_glfw.errorSlot);
|
||||
if (!error)
|
||||
{
|
||||
error = calloc(1, sizeof(_GLFWerror));
|
||||
_glfwPlatformSetTls(&_glfw.errorSlot, error);
|
||||
_glfwPlatformLockMutex(&_glfw.errorLock);
|
||||
error->next = _glfw.errorListHead;
|
||||
_glfw.errorListHead = error;
|
||||
_glfwPlatformUnlockMutex(&_glfw.errorLock);
|
||||
}
|
||||
}
|
||||
else
|
||||
error = &_glfwMainThreadError;
|
||||
|
||||
error->code = code;
|
||||
strcpy(error->description, description);
|
||||
|
||||
if (_glfwErrorCallback)
|
||||
_glfwErrorCallback(code, description);
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW public API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
GLFWAPI int glfwInit(void)
|
||||
{
|
||||
if (_glfw.initialized)
|
||||
return GLFW_TRUE;
|
||||
|
||||
memset(&_glfw, 0, sizeof(_glfw));
|
||||
_glfw.hints.init = _glfwInitHints;
|
||||
|
||||
if (!_glfwPlatformInit())
|
||||
{
|
||||
terminate();
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
if (!_glfwPlatformCreateMutex(&_glfw.errorLock) ||
|
||||
!_glfwPlatformCreateTls(&_glfw.errorSlot) ||
|
||||
!_glfwPlatformCreateTls(&_glfw.contextSlot))
|
||||
{
|
||||
terminate();
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
_glfwPlatformSetTls(&_glfw.errorSlot, &_glfwMainThreadError);
|
||||
|
||||
_glfw.initialized = GLFW_TRUE;
|
||||
_glfw.timer.offset = _glfwPlatformGetTimerValue();
|
||||
|
||||
glfwDefaultWindowHints();
|
||||
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; _glfwDefaultMappings[i]; i++)
|
||||
{
|
||||
if (!glfwUpdateGamepadMappings(_glfwDefaultMappings[i]))
|
||||
{
|
||||
terminate();
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
GLFWAPI void glfwTerminate(void)
|
||||
{
|
||||
if (!_glfw.initialized)
|
||||
return;
|
||||
|
||||
terminate();
|
||||
}
|
||||
|
||||
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_DEBUG_KEYBOARD:
|
||||
_glfwInitHints.debugKeyboard = value;
|
||||
return;
|
||||
case GLFW_COCOA_CHDIR_RESOURCES:
|
||||
_glfwInitHints.ns.chdir = value;
|
||||
return;
|
||||
case GLFW_COCOA_MENUBAR:
|
||||
_glfwInitHints.ns.menubar = value;
|
||||
return;
|
||||
}
|
||||
|
||||
_glfwInputError(GLFW_INVALID_ENUM,
|
||||
"Invalid init hint 0x%08X", hint);
|
||||
}
|
||||
|
||||
GLFWAPI void glfwGetVersion(int* major, int* minor, int* rev)
|
||||
{
|
||||
if (major != NULL)
|
||||
*major = GLFW_VERSION_MAJOR;
|
||||
if (minor != NULL)
|
||||
*minor = GLFW_VERSION_MINOR;
|
||||
if (rev != NULL)
|
||||
*rev = GLFW_VERSION_REVISION;
|
||||
}
|
||||
|
||||
GLFWAPI const char* glfwGetVersionString(void)
|
||||
{
|
||||
return _glfwPlatformGetVersionString();
|
||||
}
|
||||
|
||||
GLFWAPI int glfwGetError(const char** description)
|
||||
{
|
||||
_GLFWerror* error;
|
||||
int code = GLFW_NO_ERROR;
|
||||
|
||||
if (description)
|
||||
*description = NULL;
|
||||
|
||||
if (_glfw.initialized)
|
||||
error = _glfwPlatformGetTls(&_glfw.errorSlot);
|
||||
else
|
||||
error = &_glfwMainThreadError;
|
||||
|
||||
if (error)
|
||||
{
|
||||
code = error->code;
|
||||
error->code = GLFW_NO_ERROR;
|
||||
if (description && code)
|
||||
*description = error->description;
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
GLFWAPI GLFWerrorfun glfwSetErrorCallback(GLFWerrorfun cbfun)
|
||||
{
|
||||
_GLFW_SWAP_POINTERS(_glfwErrorCallback, cbfun);
|
||||
return cbfun;
|
||||
}
|
||||
1425
glfw/input.c
vendored
Normal file
1425
glfw/input.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
783
glfw/internal.h
vendored
Normal file
783
glfw/internal.h
vendored
Normal file
@@ -0,0 +1,783 @@
|
||||
//========================================================================
|
||||
// GLFW 3.3 - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||
// Copyright (c) 2006-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.
|
||||
//
|
||||
//========================================================================
|
||||
|
||||
#pragma once
|
||||
|
||||
#if defined(_GLFW_USE_CONFIG_H)
|
||||
#include "glfw_config.h"
|
||||
#endif
|
||||
|
||||
#define arraysz(x) (sizeof(x)/sizeof(x[0]))
|
||||
|
||||
#if defined(GLFW_INCLUDE_GLCOREARB) || \
|
||||
defined(GLFW_INCLUDE_ES1) || \
|
||||
defined(GLFW_INCLUDE_ES2) || \
|
||||
defined(GLFW_INCLUDE_ES3) || \
|
||||
defined(GLFW_INCLUDE_ES31) || \
|
||||
defined(GLFW_INCLUDE_ES32) || \
|
||||
defined(GLFW_INCLUDE_NONE) || \
|
||||
defined(GLFW_INCLUDE_GLEXT) || \
|
||||
defined(GLFW_INCLUDE_GLU) || \
|
||||
defined(GLFW_INCLUDE_VULKAN) || \
|
||||
defined(GLFW_DLL)
|
||||
#error "You must not define any header option macros when compiling GLFW"
|
||||
#endif
|
||||
|
||||
#define GLFW_INCLUDE_NONE
|
||||
#include "glfw3.h"
|
||||
|
||||
#define _GLFW_INSERT_FIRST 0
|
||||
#define _GLFW_INSERT_LAST 1
|
||||
|
||||
#define _GLFW_POLL_PRESENCE 0
|
||||
#define _GLFW_POLL_AXES 1
|
||||
#define _GLFW_POLL_BUTTONS 2
|
||||
#define _GLFW_POLL_ALL (_GLFW_POLL_AXES | _GLFW_POLL_BUTTONS)
|
||||
|
||||
#define _GLFW_MESSAGE_SIZE 1024
|
||||
|
||||
typedef int GLFWbool;
|
||||
typedef unsigned long long GLFWid;
|
||||
|
||||
typedef struct _GLFWerror _GLFWerror;
|
||||
typedef struct _GLFWinitconfig _GLFWinitconfig;
|
||||
typedef struct _GLFWwndconfig _GLFWwndconfig;
|
||||
typedef struct _GLFWctxconfig _GLFWctxconfig;
|
||||
typedef struct _GLFWfbconfig _GLFWfbconfig;
|
||||
typedef struct _GLFWcontext _GLFWcontext;
|
||||
typedef struct _GLFWwindow _GLFWwindow;
|
||||
typedef struct _GLFWlibrary _GLFWlibrary;
|
||||
typedef struct _GLFWmonitor _GLFWmonitor;
|
||||
typedef struct _GLFWcursor _GLFWcursor;
|
||||
typedef struct _GLFWmapelement _GLFWmapelement;
|
||||
typedef struct _GLFWmapping _GLFWmapping;
|
||||
typedef struct _GLFWjoystick _GLFWjoystick;
|
||||
typedef struct _GLFWtls _GLFWtls;
|
||||
typedef struct _GLFWmutex _GLFWmutex;
|
||||
|
||||
typedef void (* _GLFWmakecontextcurrentfun)(_GLFWwindow*);
|
||||
typedef void (* _GLFWswapbuffersfun)(_GLFWwindow*);
|
||||
typedef void (* _GLFWswapintervalfun)(int);
|
||||
typedef int (* _GLFWextensionsupportedfun)(const char*);
|
||||
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_UNSIGNED_BYTE 0x1401
|
||||
#define GL_EXTENSIONS 0x1f03
|
||||
#define GL_NUM_EXTENSIONS 0x821d
|
||||
#define GL_CONTEXT_FLAGS 0x821e
|
||||
#define GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT 0x00000001
|
||||
#define GL_CONTEXT_FLAG_DEBUG_BIT 0x00000002
|
||||
#define GL_CONTEXT_PROFILE_MASK 0x9126
|
||||
#define GL_CONTEXT_COMPATIBILITY_PROFILE_BIT 0x00000002
|
||||
#define GL_CONTEXT_CORE_PROFILE_BIT 0x00000001
|
||||
#define GL_RESET_NOTIFICATION_STRATEGY_ARB 0x8256
|
||||
#define GL_LOSE_CONTEXT_ON_RESET_ARB 0x8252
|
||||
#define GL_NO_RESET_NOTIFICATION_ARB 0x8261
|
||||
#define GL_CONTEXT_RELEASE_BEHAVIOR 0x82fb
|
||||
#define GL_CONTEXT_RELEASE_BEHAVIOR_FLUSH 0x82fc
|
||||
#define GL_CONTEXT_FLAG_NO_ERROR_BIT_KHR 0x00000008
|
||||
|
||||
typedef int GLint;
|
||||
typedef unsigned int GLuint;
|
||||
typedef unsigned int GLenum;
|
||||
typedef unsigned int GLbitfield;
|
||||
typedef unsigned char GLubyte;
|
||||
|
||||
typedef void (APIENTRY * PFNGLCLEARPROC)(GLbitfield);
|
||||
typedef const GLubyte* (APIENTRY * PFNGLGETSTRINGPROC)(GLenum);
|
||||
typedef void (APIENTRY * PFNGLGETINTEGERVPROC)(GLenum,GLint*);
|
||||
typedef const GLubyte* (APIENTRY * PFNGLGETSTRINGIPROC)(GLenum,GLuint);
|
||||
|
||||
#define VK_NULL_HANDLE 0
|
||||
|
||||
typedef void* VkInstance;
|
||||
typedef void* VkPhysicalDevice;
|
||||
typedef uint64_t VkSurfaceKHR;
|
||||
typedef uint32_t VkFlags;
|
||||
typedef uint32_t VkBool32;
|
||||
|
||||
typedef enum VkStructureType
|
||||
{
|
||||
VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR = 1000004000,
|
||||
VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR = 1000005000,
|
||||
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_MAX_ENUM = 0x7FFFFFFF
|
||||
} VkStructureType;
|
||||
|
||||
typedef enum VkResult
|
||||
{
|
||||
VK_SUCCESS = 0,
|
||||
VK_NOT_READY = 1,
|
||||
VK_TIMEOUT = 2,
|
||||
VK_EVENT_SET = 3,
|
||||
VK_EVENT_RESET = 4,
|
||||
VK_INCOMPLETE = 5,
|
||||
VK_ERROR_OUT_OF_HOST_MEMORY = -1,
|
||||
VK_ERROR_OUT_OF_DEVICE_MEMORY = -2,
|
||||
VK_ERROR_INITIALIZATION_FAILED = -3,
|
||||
VK_ERROR_DEVICE_LOST = -4,
|
||||
VK_ERROR_MEMORY_MAP_FAILED = -5,
|
||||
VK_ERROR_LAYER_NOT_PRESENT = -6,
|
||||
VK_ERROR_EXTENSION_NOT_PRESENT = -7,
|
||||
VK_ERROR_FEATURE_NOT_PRESENT = -8,
|
||||
VK_ERROR_INCOMPATIBLE_DRIVER = -9,
|
||||
VK_ERROR_TOO_MANY_OBJECTS = -10,
|
||||
VK_ERROR_FORMAT_NOT_SUPPORTED = -11,
|
||||
VK_ERROR_SURFACE_LOST_KHR = -1000000000,
|
||||
VK_SUBOPTIMAL_KHR = 1000001003,
|
||||
VK_ERROR_OUT_OF_DATE_KHR = -1000001004,
|
||||
VK_ERROR_INCOMPATIBLE_DISPLAY_KHR = -1000003001,
|
||||
VK_ERROR_NATIVE_WINDOW_IN_USE_KHR = -1000000001,
|
||||
VK_ERROR_VALIDATION_FAILED_EXT = -1000011001,
|
||||
VK_RESULT_MAX_ENUM = 0x7FFFFFFF
|
||||
} VkResult;
|
||||
|
||||
typedef struct VkAllocationCallbacks VkAllocationCallbacks;
|
||||
|
||||
typedef struct VkExtensionProperties
|
||||
{
|
||||
char extensionName[256];
|
||||
uint32_t specVersion;
|
||||
} VkExtensionProperties;
|
||||
|
||||
typedef void (APIENTRY * PFN_vkVoidFunction)(void);
|
||||
|
||||
#if defined(_GLFW_VULKAN_STATIC)
|
||||
PFN_vkVoidFunction vkGetInstanceProcAddr(VkInstance,const char*);
|
||||
VkResult vkEnumerateInstanceExtensionProperties(const char*,uint32_t*,VkExtensionProperties*);
|
||||
#else
|
||||
typedef PFN_vkVoidFunction (APIENTRY * PFN_vkGetInstanceProcAddr)(VkInstance,const char*);
|
||||
typedef VkResult (APIENTRY * PFN_vkEnumerateInstanceExtensionProperties)(const char*,uint32_t*,VkExtensionProperties*);
|
||||
#define vkEnumerateInstanceExtensionProperties _glfw.vk.EnumerateInstanceExtensionProperties
|
||||
#define vkGetInstanceProcAddr _glfw.vk.GetInstanceProcAddr
|
||||
#endif
|
||||
|
||||
#if defined(_GLFW_COCOA)
|
||||
#include "cocoa_platform.h"
|
||||
#elif defined(_GLFW_WIN32)
|
||||
#include "win32_platform.h"
|
||||
#elif defined(_GLFW_X11)
|
||||
#include "x11_platform.h"
|
||||
#elif defined(_GLFW_WAYLAND)
|
||||
#include "wl_platform.h"
|
||||
#elif defined(_GLFW_OSMESA)
|
||||
#include "null_platform.h"
|
||||
#else
|
||||
#error "No supported window creation API selected"
|
||||
#endif
|
||||
|
||||
// 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)
|
||||
#define _GLFW_VERSION_NUMBER _GLFW_MAKE_VERSION(GLFW_VERSION_MAJOR, \
|
||||
GLFW_VERSION_MINOR, \
|
||||
GLFW_VERSION_REVISION)
|
||||
|
||||
// Checks for whether the library has been initialized
|
||||
#define _GLFW_REQUIRE_INIT() \
|
||||
if (!_glfw.initialized) \
|
||||
{ \
|
||||
_glfwInputError(GLFW_NOT_INITIALIZED, NULL); \
|
||||
return; \
|
||||
}
|
||||
#define _GLFW_REQUIRE_INIT_OR_RETURN(x) \
|
||||
if (!_glfw.initialized) \
|
||||
{ \
|
||||
_glfwInputError(GLFW_NOT_INITIALIZED, NULL); \
|
||||
return x; \
|
||||
}
|
||||
|
||||
// Swaps the provided pointers
|
||||
#define _GLFW_SWAP_POINTERS(x, y) \
|
||||
{ \
|
||||
void* t; \
|
||||
t = x; \
|
||||
x = y; \
|
||||
y = t; \
|
||||
}
|
||||
|
||||
// Per-thread error structure
|
||||
//
|
||||
struct _GLFWerror
|
||||
{
|
||||
_GLFWerror* next;
|
||||
int code;
|
||||
char description[_GLFW_MESSAGE_SIZE];
|
||||
};
|
||||
|
||||
// Initialization configuration
|
||||
//
|
||||
// Parameters relating to the initialization of the library
|
||||
//
|
||||
struct _GLFWinitconfig
|
||||
{
|
||||
GLFWbool hatButtons;
|
||||
GLFWbool debugKeyboard;
|
||||
GLFWbool enableJoysticks;
|
||||
struct {
|
||||
GLFWbool menubar;
|
||||
GLFWbool chdir;
|
||||
} ns;
|
||||
};
|
||||
|
||||
// Window configuration
|
||||
//
|
||||
// Parameters relating to the creation of the window but not directly related
|
||||
// to the framebuffer. This is used to pass window creation parameters from
|
||||
// shared code to the platform API.
|
||||
//
|
||||
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;
|
||||
struct {
|
||||
GLFWbool retina;
|
||||
char frameName[256];
|
||||
} ns;
|
||||
struct {
|
||||
char className[256];
|
||||
char instanceName[256];
|
||||
} x11;
|
||||
struct {
|
||||
char appId[256];
|
||||
} wl;
|
||||
};
|
||||
|
||||
// Context configuration
|
||||
//
|
||||
// Parameters relating to the creation of the context but not directly related
|
||||
// to the framebuffer. This is used to pass context creation parameters from
|
||||
// shared code to the platform API.
|
||||
//
|
||||
struct _GLFWctxconfig
|
||||
{
|
||||
int client;
|
||||
int source;
|
||||
int major;
|
||||
int minor;
|
||||
GLFWbool forward;
|
||||
GLFWbool debug;
|
||||
GLFWbool noerror;
|
||||
int profile;
|
||||
int robustness;
|
||||
int release;
|
||||
_GLFWwindow* share;
|
||||
struct {
|
||||
GLFWbool offline;
|
||||
} nsgl;
|
||||
};
|
||||
|
||||
// Framebuffer configuration
|
||||
//
|
||||
// This describes buffers and their sizes. It also contains
|
||||
// a platform-specific ID used to map back to the backend API object.
|
||||
//
|
||||
// It is used to pass framebuffer parameters from shared code to the platform
|
||||
// API and also to enumerate and select available framebuffer configs.
|
||||
//
|
||||
struct _GLFWfbconfig
|
||||
{
|
||||
int redBits;
|
||||
int greenBits;
|
||||
int blueBits;
|
||||
int alphaBits;
|
||||
int depthBits;
|
||||
int stencilBits;
|
||||
int accumRedBits;
|
||||
int accumGreenBits;
|
||||
int accumBlueBits;
|
||||
int accumAlphaBits;
|
||||
int auxBuffers;
|
||||
GLFWbool stereo;
|
||||
int samples;
|
||||
GLFWbool sRGB;
|
||||
GLFWbool doublebuffer;
|
||||
GLFWbool transparent;
|
||||
uintptr_t handle;
|
||||
};
|
||||
|
||||
// Context structure
|
||||
//
|
||||
struct _GLFWcontext
|
||||
{
|
||||
int client;
|
||||
int source;
|
||||
int major, minor, revision;
|
||||
GLFWbool forward, debug, noerror;
|
||||
int profile;
|
||||
int robustness;
|
||||
int release;
|
||||
|
||||
PFNGLGETSTRINGIPROC GetStringi;
|
||||
PFNGLGETINTEGERVPROC GetIntegerv;
|
||||
PFNGLGETSTRINGPROC GetString;
|
||||
|
||||
_GLFWmakecontextcurrentfun makeCurrent;
|
||||
_GLFWswapbuffersfun swapBuffers;
|
||||
_GLFWswapintervalfun swapInterval;
|
||||
_GLFWextensionsupportedfun extensionSupported;
|
||||
_GLFWgetprocaddressfun getProcAddress;
|
||||
_GLFWdestroycontextfun destroy;
|
||||
|
||||
// This is defined in the context API's context.h
|
||||
_GLFW_PLATFORM_CONTEXT_STATE;
|
||||
// This is defined in egl_context.h
|
||||
_GLFW_EGL_CONTEXT_STATE;
|
||||
// This is defined in osmesa_context.h
|
||||
_GLFW_OSMESA_CONTEXT_STATE;
|
||||
};
|
||||
|
||||
// Window and context structure
|
||||
//
|
||||
struct _GLFWwindow
|
||||
{
|
||||
struct _GLFWwindow* next;
|
||||
|
||||
// Window settings and state
|
||||
GLFWbool resizable;
|
||||
GLFWbool decorated;
|
||||
GLFWbool autoIconify;
|
||||
GLFWbool floating;
|
||||
GLFWbool focusOnShow;
|
||||
GLFWbool shouldClose;
|
||||
void* userPointer;
|
||||
GLFWid id;
|
||||
GLFWvidmode videoMode;
|
||||
_GLFWmonitor* monitor;
|
||||
_GLFWcursor* cursor;
|
||||
|
||||
int minwidth, minheight;
|
||||
int maxwidth, maxheight;
|
||||
int numer, denom;
|
||||
|
||||
GLFWbool stickyKeys;
|
||||
GLFWbool stickyMouseButtons;
|
||||
GLFWbool 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;
|
||||
|
||||
_GLFWcontext context;
|
||||
|
||||
struct {
|
||||
GLFWwindowposfun pos;
|
||||
GLFWwindowsizefun size;
|
||||
GLFWwindowclosefun close;
|
||||
GLFWwindowrefreshfun refresh;
|
||||
GLFWwindowfocusfun focus;
|
||||
GLFWwindowiconifyfun iconify;
|
||||
GLFWwindowmaximizefun maximize;
|
||||
GLFWframebuffersizefun fbsize;
|
||||
GLFWwindowcontentscalefun scale;
|
||||
GLFWmousebuttonfun mouseButton;
|
||||
GLFWcursorposfun cursorPos;
|
||||
GLFWcursorenterfun cursorEnter;
|
||||
GLFWscrollfun scroll;
|
||||
GLFWkeyboardfun keyboard;
|
||||
GLFWdropfun drop;
|
||||
} callbacks;
|
||||
|
||||
// This is defined in the window API's platform.h
|
||||
_GLFW_PLATFORM_WINDOW_STATE;
|
||||
};
|
||||
|
||||
// Monitor structure
|
||||
//
|
||||
struct _GLFWmonitor
|
||||
{
|
||||
char* name;
|
||||
void* userPointer;
|
||||
|
||||
// Physical dimensions in millimeters.
|
||||
int widthMM, heightMM;
|
||||
|
||||
// The window whose video mode is current on this monitor
|
||||
_GLFWwindow* window;
|
||||
|
||||
GLFWvidmode* modes;
|
||||
int modeCount;
|
||||
GLFWvidmode currentMode;
|
||||
|
||||
GLFWgammaramp originalRamp;
|
||||
GLFWgammaramp currentRamp;
|
||||
|
||||
// This is defined in the window API's platform.h
|
||||
_GLFW_PLATFORM_MONITOR_STATE;
|
||||
};
|
||||
|
||||
// Cursor structure
|
||||
//
|
||||
struct _GLFWcursor
|
||||
{
|
||||
_GLFWcursor* next;
|
||||
|
||||
// This is defined in the window API's platform.h
|
||||
_GLFW_PLATFORM_CURSOR_STATE;
|
||||
};
|
||||
|
||||
// Gamepad mapping element structure
|
||||
//
|
||||
struct _GLFWmapelement
|
||||
{
|
||||
uint8_t type;
|
||||
uint8_t index;
|
||||
int8_t axisScale;
|
||||
int8_t axisOffset;
|
||||
};
|
||||
|
||||
// Gamepad mapping structure
|
||||
//
|
||||
struct _GLFWmapping
|
||||
{
|
||||
char name[128];
|
||||
char guid[33];
|
||||
_GLFWmapelement buttons[15];
|
||||
_GLFWmapelement axes[6];
|
||||
};
|
||||
|
||||
// Joystick structure
|
||||
//
|
||||
struct _GLFWjoystick
|
||||
{
|
||||
GLFWbool present;
|
||||
float* axes;
|
||||
int axisCount;
|
||||
unsigned char* buttons;
|
||||
int buttonCount;
|
||||
unsigned char* hats;
|
||||
int hatCount;
|
||||
char* name;
|
||||
void* userPointer;
|
||||
char guid[33];
|
||||
_GLFWmapping* mapping;
|
||||
|
||||
// This is defined in the joystick API's joystick.h
|
||||
_GLFW_PLATFORM_JOYSTICK_STATE;
|
||||
};
|
||||
|
||||
// Thread local storage structure
|
||||
//
|
||||
struct _GLFWtls
|
||||
{
|
||||
// This is defined in the platform's thread.h
|
||||
_GLFW_PLATFORM_TLS_STATE;
|
||||
};
|
||||
|
||||
// Mutex structure
|
||||
//
|
||||
struct _GLFWmutex
|
||||
{
|
||||
// This is defined in the platform's thread.h
|
||||
_GLFW_PLATFORM_MUTEX_STATE;
|
||||
};
|
||||
|
||||
// Library global data
|
||||
//
|
||||
struct _GLFWlibrary
|
||||
{
|
||||
GLFWbool initialized;
|
||||
|
||||
struct {
|
||||
_GLFWinitconfig init;
|
||||
_GLFWfbconfig framebuffer;
|
||||
_GLFWwndconfig window;
|
||||
_GLFWctxconfig context;
|
||||
int refreshRate;
|
||||
} hints;
|
||||
|
||||
_GLFWerror* errorListHead;
|
||||
_GLFWcursor* cursorListHead;
|
||||
_GLFWwindow* windowListHead;
|
||||
GLFWid focusedWindowId;
|
||||
|
||||
_GLFWmonitor** monitors;
|
||||
int monitorCount;
|
||||
|
||||
_GLFWjoystick joysticks[GLFW_JOYSTICK_LAST + 1];
|
||||
_GLFWmapping* mappings;
|
||||
int mappingCount;
|
||||
|
||||
_GLFWtls errorSlot;
|
||||
_GLFWtls contextSlot;
|
||||
_GLFWmutex errorLock;
|
||||
|
||||
struct {
|
||||
uint64_t offset;
|
||||
// This is defined in the platform's time.h
|
||||
_GLFW_PLATFORM_LIBRARY_TIMER_STATE;
|
||||
} timer;
|
||||
|
||||
struct {
|
||||
GLFWbool available;
|
||||
void* handle;
|
||||
char* extensions[2];
|
||||
#if !defined(_GLFW_VULKAN_STATIC)
|
||||
PFN_vkEnumerateInstanceExtensionProperties EnumerateInstanceExtensionProperties;
|
||||
PFN_vkGetInstanceProcAddr GetInstanceProcAddr;
|
||||
#endif
|
||||
GLFWbool KHR_surface;
|
||||
#if defined(_GLFW_WIN32)
|
||||
GLFWbool KHR_win32_surface;
|
||||
#elif defined(_GLFW_COCOA)
|
||||
GLFWbool MVK_macos_surface;
|
||||
#elif defined(_GLFW_X11)
|
||||
GLFWbool KHR_xlib_surface;
|
||||
GLFWbool KHR_xcb_surface;
|
||||
#elif defined(_GLFW_WAYLAND)
|
||||
GLFWbool KHR_wayland_surface;
|
||||
#endif
|
||||
} vk;
|
||||
|
||||
struct {
|
||||
GLFWmonitorfun monitor;
|
||||
GLFWjoystickfun joystick;
|
||||
} 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;
|
||||
// This is defined in the platform's joystick.h
|
||||
_GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE;
|
||||
// This is defined in egl_context.h
|
||||
_GLFW_EGL_LIBRARY_CONTEXT_STATE;
|
||||
// This is defined in osmesa_context.h
|
||||
_GLFW_OSMESA_LIBRARY_CONTEXT_STATE;
|
||||
};
|
||||
|
||||
// Global state shared between compilation units of GLFW
|
||||
//
|
||||
extern _GLFWlibrary _glfw;
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW platform API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int _glfwPlatformInit(void);
|
||||
void _glfwPlatformTerminate(void);
|
||||
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);
|
||||
int _glfwPlatformCreateCursor(_GLFWcursor* cursor,
|
||||
const GLFWimage* image, int xhot, int yhot, int count);
|
||||
int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape);
|
||||
void _glfwPlatformDestroyCursor(_GLFWcursor* cursor);
|
||||
void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor);
|
||||
|
||||
const char* _glfwPlatformGetScancodeName(int scancode);
|
||||
int _glfwPlatformGetKeyScancode(int key);
|
||||
|
||||
void _glfwPlatformFreeMonitor(_GLFWmonitor* monitor);
|
||||
void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos);
|
||||
void _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor,
|
||||
float* xscale, float* yscale);
|
||||
GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count);
|
||||
void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode);
|
||||
void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp);
|
||||
void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp);
|
||||
|
||||
void _glfwPlatformSetClipboardString(const char* string);
|
||||
const char* _glfwPlatformGetClipboardString(void);
|
||||
#if defined(_GLFW_X11) || defined(_GLFW_WAYLAND)
|
||||
void _glfwPlatformSetPrimarySelectionString(const char* string);
|
||||
const char* _glfwPlatformGetPrimarySelectionString(void);
|
||||
#endif
|
||||
|
||||
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,
|
||||
const _GLFWfbconfig* fbconfig);
|
||||
void _glfwPlatformDestroyWindow(_GLFWwindow* window);
|
||||
void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title);
|
||||
void _glfwPlatformSetWindowIcon(_GLFWwindow* window,
|
||||
int count, const GLFWimage* images);
|
||||
void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos);
|
||||
void _glfwPlatformSetWindowPos(_GLFWwindow* window, int xpos, int ypos);
|
||||
void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height);
|
||||
void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height);
|
||||
void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window,
|
||||
int minwidth, int minheight,
|
||||
int maxwidth, int maxheight);
|
||||
void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window, int numer, int denom);
|
||||
void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* height);
|
||||
void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window,
|
||||
int* left, int* top,
|
||||
int* right, int* bottom);
|
||||
void _glfwPlatformGetWindowContentScale(_GLFWwindow* window,
|
||||
float* xscale, float* yscale);
|
||||
double _glfwPlatformGetDoubleClickInterval(_GLFWwindow* window);
|
||||
void _glfwPlatformIconifyWindow(_GLFWwindow* window);
|
||||
void _glfwPlatformRestoreWindow(_GLFWwindow* window);
|
||||
void _glfwPlatformMaximizeWindow(_GLFWwindow* window);
|
||||
void _glfwPlatformShowWindow(_GLFWwindow* window);
|
||||
void _glfwPlatformHideWindow(_GLFWwindow* window);
|
||||
void _glfwPlatformRequestWindowAttention(_GLFWwindow* window);
|
||||
int _glfwPlatformWindowBell(_GLFWwindow* window);
|
||||
void _glfwPlatformFocusWindow(_GLFWwindow* window);
|
||||
void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, _GLFWmonitor* monitor,
|
||||
int xpos, int ypos, int width, int height,
|
||||
int refreshRate);
|
||||
int _glfwPlatformWindowFocused(_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 _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 _glfwPlatformPostEmptyEvent(void);
|
||||
|
||||
void _glfwPlatformGetRequiredInstanceExtensions(char** extensions);
|
||||
int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance,
|
||||
VkPhysicalDevice device,
|
||||
uint32_t queuefamily);
|
||||
VkResult _glfwPlatformCreateWindowSurface(VkInstance instance,
|
||||
_GLFWwindow* window,
|
||||
const VkAllocationCallbacks* allocator,
|
||||
VkSurfaceKHR* surface);
|
||||
|
||||
GLFWbool _glfwPlatformCreateTls(_GLFWtls* tls);
|
||||
void _glfwPlatformDestroyTls(_GLFWtls* tls);
|
||||
void* _glfwPlatformGetTls(_GLFWtls* tls);
|
||||
void _glfwPlatformSetTls(_GLFWtls* tls, void* value);
|
||||
|
||||
GLFWbool _glfwPlatformCreateMutex(_GLFWmutex* mutex);
|
||||
void _glfwPlatformDestroyMutex(_GLFWmutex* mutex);
|
||||
void _glfwPlatformLockMutex(_GLFWmutex* mutex);
|
||||
void _glfwPlatformUnlockMutex(_GLFWmutex* mutex);
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW event API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void _glfwInputWindowFocus(_GLFWwindow* window, GLFWbool focused);
|
||||
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 _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 _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 _glfwInputJoystick(_GLFWjoystick* js, int event);
|
||||
void _glfwInputJoystickAxis(_GLFWjoystick* js, int axis, float value);
|
||||
void _glfwInputJoystickButton(_GLFWjoystick* js, int button, char value);
|
||||
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__)
|
||||
void _glfwInputError(int code, const char* format, ...)
|
||||
__attribute__((format(printf, 2, 3)));
|
||||
#else
|
||||
void _glfwInputError(int code, const char* format, ...);
|
||||
#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,
|
||||
const _GLFWctxconfig* ctxconfig);
|
||||
GLFWbool _glfwIsValidContextConfig(const _GLFWctxconfig* ctxconfig);
|
||||
|
||||
const GLFWvidmode* _glfwChooseVideoMode(_GLFWmonitor* monitor,
|
||||
const GLFWvidmode* desired);
|
||||
int _glfwCompareVideoModes(const GLFWvidmode* first, const GLFWvidmode* second);
|
||||
_GLFWmonitor* _glfwAllocMonitor(const char* name, int widthMM, int heightMM);
|
||||
void _glfwFreeMonitor(_GLFWmonitor* monitor);
|
||||
void _glfwAllocGammaArrays(GLFWgammaramp* ramp, unsigned int size);
|
||||
void _glfwFreeGammaArrays(GLFWgammaramp* ramp);
|
||||
void _glfwSplitBPP(int bpp, int* red, int* green, int* blue);
|
||||
|
||||
_GLFWjoystick* _glfwAllocJoystick(const char* name,
|
||||
const char* guid,
|
||||
int axisCount,
|
||||
int buttonCount,
|
||||
int hatCount);
|
||||
void _glfwFreeJoystick(_GLFWjoystick* js);
|
||||
const char* _glfwGetKeyName(int key);
|
||||
|
||||
GLFWbool _glfwInitVulkan(int mode);
|
||||
void _glfwTerminateVulkan(void);
|
||||
const char* _glfwGetVulkanResultString(VkResult result);
|
||||
_GLFWwindow* _glfwFocusedWindow();
|
||||
_GLFWwindow* _glfwWindowForId(GLFWid id);
|
||||
|
||||
char* _glfw_strdup(const char* source);
|
||||
433
glfw/linux_joystick.c
vendored
Normal file
433
glfw/linux_joystick.c
vendored
Normal file
@@ -0,0 +1,433 @@
|
||||
//========================================================================
|
||||
// GLFW 3.3 Linux - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||
// Copyright (c) 2006-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 <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/inotify.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <dirent.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifndef SYN_DROPPED // < v2.6.39 kernel headers
|
||||
// Workaround for CentOS-6, which is supported till 2020-11-30, but still on v2.6.32
|
||||
#define SYN_DROPPED 3
|
||||
#endif
|
||||
|
||||
// Apply an EV_KEY event to the specified joystick
|
||||
//
|
||||
static void handleKeyEvent(_GLFWjoystick* js, int code, int value)
|
||||
{
|
||||
_glfwInputJoystickButton(js,
|
||||
js->linjs.keyMap[code - BTN_MISC],
|
||||
value ? GLFW_PRESS : GLFW_RELEASE);
|
||||
}
|
||||
|
||||
// Apply an EV_ABS event to the specified joystick
|
||||
//
|
||||
static void handleAbsEvent(_GLFWjoystick* js, int code, int value)
|
||||
{
|
||||
const int index = js->linjs.absMap[code];
|
||||
|
||||
if (code >= ABS_HAT0X && code <= ABS_HAT3Y)
|
||||
{
|
||||
static const char stateMap[3][3] =
|
||||
{
|
||||
{ GLFW_HAT_CENTERED, GLFW_HAT_UP, GLFW_HAT_DOWN },
|
||||
{ GLFW_HAT_LEFT, GLFW_HAT_LEFT_UP, GLFW_HAT_LEFT_DOWN },
|
||||
{ GLFW_HAT_RIGHT, GLFW_HAT_RIGHT_UP, GLFW_HAT_RIGHT_DOWN },
|
||||
};
|
||||
|
||||
const int hat = (code - ABS_HAT0X) / 2;
|
||||
const int axis = (code - ABS_HAT0X) % 2;
|
||||
int* state = js->linjs.hats[hat];
|
||||
|
||||
// NOTE: Looking at several input drivers, it seems all hat events use
|
||||
// -1 for left / up, 0 for centered and 1 for right / down
|
||||
if (value == 0)
|
||||
state[axis] = 0;
|
||||
else if (value < 0)
|
||||
state[axis] = 1;
|
||||
else if (value > 0)
|
||||
state[axis] = 2;
|
||||
|
||||
_glfwInputJoystickHat(js, index, stateMap[state[0]][state[1]]);
|
||||
}
|
||||
else
|
||||
{
|
||||
const struct input_absinfo* info = &js->linjs.absInfo[code];
|
||||
float normalized = value;
|
||||
|
||||
const int range = info->maximum - info->minimum;
|
||||
if (range)
|
||||
{
|
||||
// Normalize to 0.0 -> 1.0
|
||||
normalized = (normalized - info->minimum) / range;
|
||||
// Normalize to -1.0 -> 1.0
|
||||
normalized = normalized * 2.0f - 1.0f;
|
||||
}
|
||||
|
||||
_glfwInputJoystickAxis(js, index, normalized);
|
||||
}
|
||||
}
|
||||
|
||||
// Poll state of absolute axes
|
||||
//
|
||||
static void pollAbsState(_GLFWjoystick* js)
|
||||
{
|
||||
int code;
|
||||
|
||||
for (code = 0; code < ABS_CNT; code++)
|
||||
{
|
||||
if (js->linjs.absMap[code] < 0)
|
||||
continue;
|
||||
|
||||
struct input_absinfo* info = &js->linjs.absInfo[code];
|
||||
|
||||
if (ioctl(js->linjs.fd, EVIOCGABS(code), info) < 0)
|
||||
continue;
|
||||
|
||||
handleAbsEvent(js, code, info->value);
|
||||
}
|
||||
}
|
||||
|
||||
#define isBitSet(bit, arr) (arr[(bit) / 8] & (1 << ((bit) % 8)))
|
||||
|
||||
// Attempt to open the specified joystick device
|
||||
//
|
||||
static GLFWbool 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++)
|
||||
{
|
||||
if (!_glfw.joysticks[jid].present)
|
||||
continue;
|
||||
if (strcmp(_glfw.joysticks[jid].linjs.path, path) == 0)
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
linjs.fd = open(path, O_RDONLY | O_NONBLOCK);
|
||||
if (linjs.fd == -1)
|
||||
return GLFW_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)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Linux: Failed to query input device: %s",
|
||||
strerror(errno));
|
||||
close(linjs.fd);
|
||||
return GLFW_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;
|
||||
}
|
||||
|
||||
if (ioctl(linjs.fd, EVIOCGNAME(sizeof(name)), name) < 0)
|
||||
strncpy(name, "Unknown", sizeof(name));
|
||||
|
||||
// Generate a joystick GUID that matches the SDL 2.0.5+ one
|
||||
if (id.vendor && id.product && id.version)
|
||||
{
|
||||
sprintf(guid, "%02x%02x0000%02x%02x0000%02x%02x0000%02x%02x0000",
|
||||
id.bustype & 0xff, id.bustype >> 8,
|
||||
id.vendor & 0xff, id.vendor >> 8,
|
||||
id.product & 0xff, id.product >> 8,
|
||||
id.version & 0xff, id.version >> 8);
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(guid, "%02x%02x0000%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x00",
|
||||
id.bustype & 0xff, id.bustype >> 8,
|
||||
name[0], name[1], name[2], name[3],
|
||||
name[4], name[5], name[6], name[7],
|
||||
name[8], name[9], name[10]);
|
||||
}
|
||||
|
||||
for (code = BTN_MISC; code < KEY_CNT; code++)
|
||||
{
|
||||
if (!isBitSet(code, keyBits))
|
||||
continue;
|
||||
|
||||
linjs.keyMap[code - BTN_MISC] = buttonCount;
|
||||
buttonCount++;
|
||||
}
|
||||
|
||||
for (code = 0; code < ABS_CNT; code++)
|
||||
{
|
||||
linjs.absMap[code] = -1;
|
||||
if (!isBitSet(code, absBits))
|
||||
continue;
|
||||
|
||||
if (code >= ABS_HAT0X && code <= ABS_HAT3Y)
|
||||
{
|
||||
linjs.absMap[code] = hatCount;
|
||||
hatCount++;
|
||||
// Skip the Y axis
|
||||
code++;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ioctl(linjs.fd, EVIOCGABS(code), &linjs.absInfo[code]) < 0)
|
||||
continue;
|
||||
|
||||
linjs.absMap[code] = axisCount;
|
||||
axisCount++;
|
||||
}
|
||||
}
|
||||
|
||||
js = _glfwAllocJoystick(name, guid, axisCount, buttonCount, hatCount);
|
||||
if (!js)
|
||||
{
|
||||
close(linjs.fd);
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
strncpy(linjs.path, path, sizeof(linjs.path) - 1);
|
||||
memcpy(&js->linjs, &linjs, sizeof(linjs));
|
||||
|
||||
pollAbsState(js);
|
||||
|
||||
_glfwInputJoystick(js, GLFW_CONNECTED);
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
#undef isBitSet
|
||||
|
||||
// Frees all resources associated with the specified joystick
|
||||
//
|
||||
static void closeJoystick(_GLFWjoystick* js)
|
||||
{
|
||||
close(js->linjs.fd);
|
||||
_glfwFreeJoystick(js);
|
||||
_glfwInputJoystick(js, GLFW_DISCONNECTED);
|
||||
}
|
||||
|
||||
// Lexically compare joysticks by name; used by qsort
|
||||
//
|
||||
static int compareJoysticks(const void* fp, const void* sp)
|
||||
{
|
||||
const _GLFWjoystick* fj = fp;
|
||||
const _GLFWjoystick* sj = sp;
|
||||
return strcmp(fj->linjs.path, sj->linjs.path);
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW internal API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Initialize joystick interface
|
||||
//
|
||||
GLFWbool _glfwInitJoysticksLinux(void)
|
||||
{
|
||||
DIR* dir;
|
||||
int count = 0;
|
||||
const char* dirname = "/dev/input";
|
||||
|
||||
_glfw.linjs.inotify = inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
|
||||
if (_glfw.linjs.inotify > 0)
|
||||
{
|
||||
// HACK: Register for IN_ATTRIB to get notified when udev is done
|
||||
// This works well in practice but the true way is libudev
|
||||
|
||||
_glfw.linjs.watch = inotify_add_watch(_glfw.linjs.inotify,
|
||||
dirname,
|
||||
IN_CREATE | IN_ATTRIB | IN_DELETE);
|
||||
}
|
||||
|
||||
// Continue without device connection notifications if inotify fails
|
||||
|
||||
if (regcomp(&_glfw.linjs.regex, "^event[0-9]\\+$", 0) != 0)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR, "Linux: Failed to compile regex");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
dir = opendir(dirname);
|
||||
if (dir)
|
||||
{
|
||||
struct dirent* entry;
|
||||
|
||||
while ((entry = readdir(dir)))
|
||||
{
|
||||
regmatch_t match;
|
||||
|
||||
if (regexec(&_glfw.linjs.regex, entry->d_name, 1, &match, 0) != 0)
|
||||
continue;
|
||||
|
||||
char path[PATH_MAX];
|
||||
|
||||
snprintf(path, sizeof(path), "%s/%s", dirname, entry->d_name);
|
||||
|
||||
if (openJoystickDevice(path))
|
||||
count++;
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
}
|
||||
|
||||
// Continue with no joysticks if enumeration fails
|
||||
|
||||
qsort(_glfw.joysticks, count, sizeof(_GLFWjoystick), compareJoysticks);
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
// Close all opened joystick handles
|
||||
//
|
||||
void _glfwTerminateJoysticksLinux(void)
|
||||
{
|
||||
int jid;
|
||||
|
||||
for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++)
|
||||
{
|
||||
_GLFWjoystick* js = _glfw.joysticks + jid;
|
||||
if (js->present)
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
// Read all queued events (non-blocking)
|
||||
for (;;)
|
||||
{
|
||||
struct input_event e;
|
||||
|
||||
errno = 0;
|
||||
if (read(js->linjs.fd, &e, sizeof(e)) < 0)
|
||||
{
|
||||
// Reset the joystick slot if the device was disconnected
|
||||
if (errno == ENODEV)
|
||||
closeJoystick(js);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (e.type == EV_SYN)
|
||||
{
|
||||
if (e.code == SYN_DROPPED)
|
||||
_glfw.linjs.dropped = GLFW_TRUE;
|
||||
else if (e.code == SYN_REPORT)
|
||||
{
|
||||
_glfw.linjs.dropped = GLFW_FALSE;
|
||||
pollAbsState(js);
|
||||
}
|
||||
}
|
||||
|
||||
if (_glfw.linjs.dropped)
|
||||
continue;
|
||||
|
||||
if (e.type == EV_KEY)
|
||||
handleKeyEvent(js, e.code, e.value);
|
||||
else if (e.type == EV_ABS)
|
||||
handleAbsEvent(js, e.code, e.value);
|
||||
}
|
||||
|
||||
return js->present;
|
||||
}
|
||||
|
||||
void _glfwPlatformUpdateGamepadGUID(char* guid)
|
||||
{
|
||||
}
|
||||
62
glfw/linux_joystick.h
vendored
Normal file
62
glfw/linux_joystick.h
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
//========================================================================
|
||||
// GLFW 3.3 Linux - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2014 Jonas Ådahl <jadahl@gmail.com>
|
||||
//
|
||||
// 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 <linux/input.h>
|
||||
#include <linux/limits.h>
|
||||
#include <regex.h>
|
||||
|
||||
#define _GLFW_PLATFORM_JOYSTICK_STATE _GLFWjoystickLinux linjs
|
||||
#define _GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE _GLFWlibraryLinux linjs
|
||||
|
||||
#define _GLFW_PLATFORM_MAPPING_NAME "Linux"
|
||||
|
||||
// Linux-specific joystick data
|
||||
//
|
||||
typedef struct _GLFWjoystickLinux
|
||||
{
|
||||
int fd;
|
||||
char path[PATH_MAX];
|
||||
int keyMap[KEY_CNT - BTN_MISC];
|
||||
int absMap[ABS_CNT];
|
||||
struct input_absinfo absInfo[ABS_CNT];
|
||||
int hats[4][2];
|
||||
} _GLFWjoystickLinux;
|
||||
|
||||
// Linux-specific joystick API data
|
||||
//
|
||||
typedef struct _GLFWlibraryLinux
|
||||
{
|
||||
int inotify;
|
||||
int watch;
|
||||
regex_t regex;
|
||||
GLFWbool dropped;
|
||||
} _GLFWlibraryLinux;
|
||||
|
||||
|
||||
GLFWbool _glfwInitJoysticksLinux(void);
|
||||
void _glfwTerminateJoysticksLinux(void);
|
||||
void _glfwDetectJoystickConnectionLinux(void);
|
||||
|
||||
478
glfw/mappings.h
vendored
Normal file
478
glfw/mappings.h
vendored
Normal file
@@ -0,0 +1,478 @@
|
||||
//========================================================================
|
||||
// GLFW 3.3 - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2006-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.
|
||||
//
|
||||
//========================================================================
|
||||
// As mappings.h.in, this file is used by CMake to produce the mappings.h
|
||||
// header file. If you are adding a GLFW specific gamepad mapping, this is
|
||||
// where to put it.
|
||||
//========================================================================
|
||||
// As mappings.h, this provides all pre-defined gamepad mappings, including
|
||||
// all available in SDL_GameControllerDB. Do not edit this file. Any gamepad
|
||||
// mappings not specific to GLFW should be submitted to SDL_GameControllerDB.
|
||||
// This file can be re-generated from mappings.h.in and the upstream
|
||||
// gamecontrollerdb.txt with the GenerateMappings.cmake script.
|
||||
//========================================================================
|
||||
|
||||
// All gamepad mappings not labeled GLFW are copied from the
|
||||
// SDL_GameControllerDB project under the following license:
|
||||
//
|
||||
// Simple DirectMedia Layer
|
||||
// Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.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.
|
||||
|
||||
const char* _glfwDefaultMappings[] =
|
||||
{
|
||||
"03000000fa2d00000100000000000000,3DRUDDER,leftx:a0,lefty:a1,rightx:a5,righty:a2,platform:Windows,",
|
||||
"03000000022000000090000000000000,8Bitdo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,",
|
||||
"03000000203800000900000000000000,8Bitdo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,",
|
||||
"03000000102800000900000000000000,8Bitdo SFC30 GamePad,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows,",
|
||||
"03000000a00500003232000000000000,8Bitdo Zero GamePad,a:b0,b:b1,back:b10,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Windows,",
|
||||
"030000008f0e00001200000000000000,Acme,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Windows,",
|
||||
"03000000341a00003608000000000000,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
|
||||
"03000000c01100001352000000000000,Battalife Joystick,a:b6,b:b7,back:b2,leftshoulder:b0,leftx:a0,lefty:a1,rightshoulder:b1,start:b3,x:b4,y:b5,platform:Windows,",
|
||||
"030000006b1400000055000000000000,bigben ps3padstreetnew,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,",
|
||||
"0300000066f700000500000000000000,BrutalLegendTest,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b3,platform:Windows,",
|
||||
"03000000d81d00000b00000000000000,BUFFALO BSGP1601 Series ,a:b5,b:b3,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b9,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b13,x:b4,y:b2,platform:Windows,",
|
||||
"03000000e82000006058000000000000,Cideko AK08b,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,",
|
||||
"030000005e0400008e02000000000000,Controller (XBOX 360 For Windows),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
|
||||
"03000000260900008888000000000000,Cyber Gadget GameCube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:a4,rightx:a2,righty:a3~,start:b7,x:b2,y:b3,platform:Windows,",
|
||||
"03000000a306000022f6000000000000,Cyborg V.3 Rumble Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:-a3,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Windows,",
|
||||
"03000000791d00000103000000000000,Dual Box WII,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,",
|
||||
"030000004f04000023b3000000000000,Dual Trigger 3-in-1,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
|
||||
"03000000341a00000108000000000000,EXEQ RF USB Gamepad 8206,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,",
|
||||
"030000000d0f00008500000000000000,Fighting Commander 2016 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
|
||||
"030000000d0f00008400000000000000,Fighting Commander 5,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
|
||||
"030000000d0f00008800000000000000,Fighting Stick mini 4,a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b8,x:b0,y:b3,platform:Windows,",
|
||||
"030000000d0f00008700000000000000,Fighting Stick mini 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,",
|
||||
"030000000d0f00002700000000000000,FIGHTING STICK V3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,",
|
||||
"78696e70757403000000000000000000,Fightstick TES,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,start:b7,x:b2,y:b3,platform:Windows,",
|
||||
"03000000790000000600000000000000,G-Shark GS-GP702,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b3,y:b0,platform:Windows,",
|
||||
"03000000260900002625000000000000,Gamecube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,lefttrigger:a4,leftx:a0,lefty:a1,righttrigger:a5,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Windows,",
|
||||
"030000008f0e00000d31000000000000,GAMEPAD 3 TURBO,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
|
||||
"03000000280400000140000000000000,GamePad Pro USB,a:b1,b:b2,back:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,",
|
||||
"03000000ffff00000000000000000000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,",
|
||||
"03000000451300000010000000000000,Generic USB Joystick,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,",
|
||||
"03000000341a00000302000000000000,Hama Scorpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
|
||||
"030000000d0f00004900000000000000,Hatsune Miku Sho Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
|
||||
"03000000d81400000862000000000000,HitBox Edition Cthulhu+,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b5,lefttrigger:b4,rightshoulder:b7,righttrigger:b6,start:b9,x:b0,y:b3,platform:Windows,",
|
||||
"030000000d0f00005f00000000000000,Hori Fighting Commander 4 (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
|
||||
"030000000d0f00005e00000000000000,Hori Fighting Commander 4 (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
|
||||
"030000000d0f00004000000000000000,Hori Fighting Stick Mini 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b5,lefttrigger:b4,rightshoulder:b7,righttrigger:b6,start:b9,x:b0,y:b3,platform:Windows,",
|
||||
"030000000d0f00006e00000000000000,HORIPAD 4 (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
|
||||
"030000000d0f00006600000000000000,HORIPAD 4 (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
|
||||
"030000000d0f0000ee00000000000000,HORIPAD mini4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
|
||||
"030000000d0f00004d00000000000000,HORIPAD3 A,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
|
||||
"03000000250900000017000000000000,HRAP2 on PS/SS/N64 Joypad to USB BOX,a:b2,b:b1,back:b9,leftshoulder:b5,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b6,start:b8,x:b3,y:b0,platform:Windows,",
|
||||
"030000008f0e00001330000000000000,HuiJia SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b9,x:b3,y:b0,platform:Windows,",
|
||||
"03000000d81d00000f00000000000000,iBUFFALO BSGP1204 Series,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,",
|
||||
"03000000d81d00001000000000000000,iBUFFALO BSGP1204P Series,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,",
|
||||
"03000000830500006020000000000000,iBuffalo SNES Controller,a:b1,b:b0,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b2,platform:Windows,",
|
||||
"03000000b50700001403000000000000,IMPACT BLACK,a:b2,b:b3,back:b8,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Windows,",
|
||||
"030000006f0e00002401000000000000,INJUSTICE FightStick for PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,",
|
||||
"03000000491900000204000000000000,Ipega PG-9023,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,",
|
||||
"030000006d04000011c2000000000000,Logitech Cordless Wingman,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b5,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b2,righttrigger:b7,rightx:a3,righty:a4,x:b4,platform:Windows,",
|
||||
"030000006d04000016c2000000000000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
|
||||
"030000006d04000018c2000000000000,Logitech F510 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
|
||||
"030000006d04000019c2000000000000,Logitech F710 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
|
||||
"03000000380700005032000000000000,Mad Catz FightPad PRO (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
|
||||
"03000000380700005082000000000000,Mad Catz FightPad PRO (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
|
||||
"03000000380700008433000000000000,Mad Catz FightStick TE S+ PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,",
|
||||
"03000000380700008483000000000000,Mad Catz FightStick TE S+ PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b6,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
|
||||
"03000000380700008134000000000000,Mad Catz FightStick TE2+ PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b7,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b4,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
|
||||
"03000000380700008184000000000000,Mad Catz FightStick TE2+ PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b5,leftstick:b10,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
|
||||
"03000000380700008034000000000000,Mad Catz TE2 PS3 Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
|
||||
"03000000380700008084000000000000,Mad Catz TE2 PS4 Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
|
||||
"03000000380700008532000000000000,Madcatz Arcade Fightstick TE S PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
|
||||
"03000000380700003888000000000000,Madcatz Arcade Fightstick TE S+ PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
|
||||
"03000000380700001888000000000000,MadCatz SFIV FightStick PS3,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b5,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b4,righttrigger:b6,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,",
|
||||
"03000000380700008081000000000000,MADCATZ SFV Arcade FightStick Alpha PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
|
||||
"030000008305000031b0000000000000,MaxfireBlaze3,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,",
|
||||
"03000000250900000128000000000000,Mayflash Arcade Stick,a:b1,b:b2,back:b8,leftshoulder:b0,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b3,righttrigger:b7,start:b9,x:b5,y:b6,platform:Windows,",
|
||||
"03000000790000004418000000000000,Mayflash GameCube Controller,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Windows,",
|
||||
"03000000790000004318000000000000,Mayflash GameCube Controller Adapter,a:b1,b:b2,back:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b0,leftshoulder:b4,leftstick:b0,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b0,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Windows,",
|
||||
"030000008f0e00001030000000000000,Mayflash USB Adapter for original Sega Saturn controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b5,rightshoulder:b2,righttrigger:b7,start:b9,x:b3,y:b4,platform:Windows,",
|
||||
"0300000025090000e803000000000000,Mayflash Wii Classic Controller,a:b1,b:b0,back:b8,dpdown:b13,dpleft:b12,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Windows,",
|
||||
"03000000790000000018000000000000,Mayflash WiiU Pro Game Controller Adapter (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
|
||||
"030000001008000001e5000000000000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b6,start:b9,x:b3,y:b0,platform:Windows,",
|
||||
"03000000bd12000015d0000000000000,Nintendo Retrolink USB Super SNES Classic Controller,a:b2,b:b1,back:b8,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Windows,",
|
||||
"030000007e0500000920000000000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,",
|
||||
"030000004b120000014d000000000000,NYKO AIRFLO,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:a3,leftstick:a0,lefttrigger:b6,leftx:h0.6,lefty:h0.12,rightshoulder:b5,rightstick:a2,righttrigger:b7,rightx:h0.9,righty:h0.4,start:b9,x:b2,y:b3,platform:Windows,",
|
||||
"03000000362800000100000000000000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:b13,rightx:a3,righty:a4,x:b1,y:b2,platform:Windows,",
|
||||
"03000000120c0000f60e000000000000,P4 Wired Gamepad,a:b1,b:b2,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b5,lefttrigger:b7,rightshoulder:b4,righttrigger:b6,start:b9,x:b0,y:b3,platform:Windows,",
|
||||
"030000008f0e00000300000000000000,Piranha xtreme,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows,",
|
||||
"03000000d62000006dca000000000000,PowerA Pro Ex,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
|
||||
"030000008f0e00007530000000000000,PS (R) Gamepad,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b1,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
|
||||
"03000000e30500009605000000000000,PS to USB convert cable,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows,",
|
||||
"03000000100800000100000000000000,PS1 USB,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows,",
|
||||
"03000000100800000300000000000000,PS2 USB,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a4,righty:a2,start:b9,x:b3,y:b0,platform:Windows,",
|
||||
"03000000888800000803000000000000,PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.8,dpleft:h0.4,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b9,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b0,y:b3,platform:Windows,",
|
||||
"030000004c0500006802000000000000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Windows,",
|
||||
"03000000250900000500000000000000,PS3 DualShock,a:b2,b:b1,back:b9,dpdown:h0.8,dpleft:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b0,y:b3,platform:Windows,",
|
||||
"03000000100000008200000000000000,PS360+ v1.66,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:h0.4,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,",
|
||||
"030000004c050000a00b000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
|
||||
"030000004c050000c405000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
|
||||
"030000004c050000cc09000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
|
||||
"03000000300f00000011000000000000,QanBa Arcade JoyStick 1008,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b10,x:b0,y:b3,platform:Windows,",
|
||||
"03000000300f00001611000000000000,QanBa Arcade JoyStick 4018,a:b1,b:b2,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b8,x:b0,y:b3,platform:Windows,",
|
||||
"03000000222c00000020000000000000,QANBA DRONE ARCADE JOYSTICK,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,rightshoulder:b5,righttrigger:a4,start:b9,x:b0,y:b3,platform:Windows,",
|
||||
"03000000300f00001210000000000000,QanBa Joystick Plus,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b2,y:b3,platform:Windows,",
|
||||
"03000000341a00000104000000000000,QanBa Joystick Q4RAF,a:b5,b:b6,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b0,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b3,righttrigger:b7,start:b9,x:b1,y:b2,platform:Windows,",
|
||||
"03000000222c00000223000000000000,Qanba Obsidian Arcade Joystick PS3 Mode,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
|
||||
"03000000222c00000023000000000000,Qanba Obsidian Arcade Joystick PS4 Mode,a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
|
||||
"03000000321500000003000000000000,Razer Hydra,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
|
||||
"030000000d0f00001100000000000000,REAL ARCADE PRO.3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,",
|
||||
"030000000d0f00008b00000000000000,Real Arcade Pro.4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
|
||||
"030000000d0f00008a00000000000000,Real Arcade Pro.4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
|
||||
"030000000d0f00006b00000000000000,Real Arcade Pro.4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
|
||||
"030000000d0f00006a00000000000000,Real Arcade Pro.4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
|
||||
"030000000d0f00007000000000000000,REAL ARCADE PRO.4 VLX,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,",
|
||||
"030000000d0f00002200000000000000,REAL ARCADE Pro.V3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
|
||||
"030000000d0f00005c00000000000000,Real Arcade Pro.V4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
|
||||
"030000000d0f00005b00000000000000,Real Arcade Pro.V4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
|
||||
"03000000790000001100000000000000,Retrolink SNES Controller,a:b2,b:b1,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Windows,",
|
||||
"0300000000f000000300000000000000,RetroUSB.com RetroPad,a:b1,b:b5,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Windows,",
|
||||
"0300000000f00000f100000000000000,RetroUSB.com Super RetroPort,a:b1,b:b5,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Windows,",
|
||||
"030000006b140000010d000000000000,Revolution Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
|
||||
"030000006f0e00001e01000000000000,Rock Candy Gamepad for PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
|
||||
"030000004f04000003d0000000000000,run'n'drive,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b7,leftshoulder:a3,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:a4,rightstick:b11,righttrigger:b5,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
|
||||
"03000000a30600001af5000000000000,Saitek Cyborg,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows,",
|
||||
"03000000a306000023f6000000000000,Saitek Cyborg V.1 Game pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Windows,",
|
||||
"03000000300f00001201000000000000,Saitek Dual Analog Pad,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Windows,",
|
||||
"03000000a30600000cff000000000000,Saitek P2500 Force Rumble Pad,a:b2,b:b3,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,x:b0,y:b1,platform:Windows,",
|
||||
"03000000a30600000c04000000000000,Saitek P2900,a:b1,b:b2,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b3,platform:Windows,",
|
||||
"03000000300f00001001000000000000,Saitek P480 Rumble Pad,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Windows,",
|
||||
"03000000a30600000b04000000000000,Saitek P990,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b3,platform:Windows,",
|
||||
"03000000a30600000b04000000010000,Saitek P990 Dual Analog Pad,a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b8,x:b0,y:b3,platform:Windows,",
|
||||
"03000000300f00001101000000000000,saitek rumble pad,a:b2,b:b3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Windows,",
|
||||
"0300000000050000289b000000000000,Saturn_Adapter_2.0,a:b1,b:b2,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b0,y:b3,platform:Windows,",
|
||||
"030000009b2800000500000000000000,Saturn_Adapter_2.0,a:b1,b:b2,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b0,y:b3,platform:Windows,",
|
||||
"03000000341a00000208000000000000,SL-6555-SBK,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:-a4,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a4,rightx:a3,righty:a2,start:b7,x:b2,y:b3,platform:Windows,",
|
||||
"030000008f0e00000800000000000000,SpeedLink Strike FX Wireless,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,",
|
||||
"03000000ff1100003133000000000000,SVEN X-PAD,a:b2,b:b3,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a4,start:b5,x:b0,y:b1,platform:Windows,",
|
||||
"03000000fa1900000706000000000000,Team 5,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,",
|
||||
"03000000b50700001203000000000000,Techmobility X6-38V,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Windows,",
|
||||
"030000004f04000015b3000000000000,Thrustmaster Dual Analog 2,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Windows,",
|
||||
"030000004f04000000b3000000000000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b11,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b1,y:b3,platform:Windows,",
|
||||
"030000004f04000004b3000000000000,Thrustmaster Firestorm Dual Power 3,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Windows,",
|
||||
"03000000666600000488000000000000,TigerGame PS/PS2 Game Controller Adapter,a:b2,b:b1,back:b9,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows,",
|
||||
"03000000d90400000200000000000000,TwinShock PS2,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows,",
|
||||
"03000000380700006652000000000000,UnKnown,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows,",
|
||||
"03000000632500002305000000000000,USB Vibration Joystick (BM),a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,",
|
||||
"03000000790000001b18000000000000,Venom Arcade Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,",
|
||||
"03000000450c00002043000000000000,XEOX Gamepad SL-6556-BK,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,",
|
||||
"03000000172700004431000000000000,XiaoMi Game Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b20,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a7,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows,",
|
||||
"03000000786901006e70000000000000,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
|
||||
"03000000203800000900000000010000,8Bitdo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,",
|
||||
"03000000022000000090000001000000,8Bitdo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,",
|
||||
"03000000102800000900000000000000,8Bitdo SFC30 GamePad Joystick,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X,",
|
||||
"03000000a00500003232000008010000,8Bitdo Zero GamePad,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Mac OS X,",
|
||||
"030000008305000031b0000000000000,Cideko AK08b,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,",
|
||||
"03000000260900008888000088020000,Cyber Gadget GameCube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:a5,rightx:a2,righty:a3~,start:b7,x:b2,y:b3,platform:Mac OS X,",
|
||||
"03000000a306000022f6000001030000,Cyborg V.3 Rumble Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:-a3,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Mac OS X,",
|
||||
"03000000790000000600000000000000,G-Shark GP-702,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b3,y:b0,platform:Mac OS X,",
|
||||
"03000000ad1b000001f9000000000000,Gamestop BB-070 X360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,",
|
||||
"0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X,",
|
||||
"030000000d0f00005f00000000010000,Hori Fighting Commander 4 (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,",
|
||||
"030000000d0f00005e00000000010000,Hori Fighting Commander 4 (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,",
|
||||
"030000000d0f00005f00000000000000,HORI Fighting Commander 4 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,",
|
||||
"030000000d0f00005e00000000000000,HORI Fighting Commander 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,",
|
||||
"030000000d0f00004d00000000000000,HORI Gem Pad 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,",
|
||||
"030000000d0f00006e00000000010000,HORIPAD 4 (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,",
|
||||
"030000000d0f00006600000000010000,HORIPAD 4 (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,",
|
||||
"030000000d0f00006600000000000000,HORIPAD FPS PLUS 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,",
|
||||
"030000008f0e00001330000011010000,HuiJia SNES Controller,a:b4,b:b2,back:b16,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,leftshoulder:b12,rightshoulder:b14,start:b18,x:b6,y:b0,platform:Mac OS X,",
|
||||
"03000000830500006020000000010000,iBuffalo SNES Controller,a:b1,b:b0,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b2,platform:Mac OS X,",
|
||||
"03000000830500006020000000000000,iBuffalo USB 2-axis 8-button Gamepad,a:b1,b:b0,back:b6,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b3,y:b2,platform:Mac OS X,",
|
||||
"030000006d04000016c2000000020000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,",
|
||||
"030000006d04000016c2000000030000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,",
|
||||
"030000006d04000016c2000014040000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,",
|
||||
"030000006d04000016c2000000000000,Logitech F310 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,",
|
||||
"030000006d04000018c2000000000000,Logitech F510 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,",
|
||||
"030000006d0400001fc2000000000000,Logitech F710 Gamepad (XInput),a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,",
|
||||
"030000006d04000019c2000000000000,Logitech Wireless Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,",
|
||||
"03000000380700005032000000010000,Mad Catz FightPad PRO (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,",
|
||||
"03000000380700005082000000010000,Mad Catz FightPad PRO (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,",
|
||||
"03000000790000004418000000010000,Mayflash GameCube Controller,a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Mac OS X,",
|
||||
"0300000025090000e803000000000000,Mayflash Wii Classic Controller,a:b1,b:b0,back:b8,dpdown:b13,dpleft:b12,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Mac OS X,",
|
||||
"03000000790000000018000000000000,Mayflash WiiU Pro Game Controller Adapter (DInput),a:b4,b:b8,back:b32,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b16,leftstick:b40,lefttrigger:b24,leftx:a0,lefty:a4,rightshoulder:b20,rightstick:b44,righttrigger:b28,rightx:a8,righty:a12,start:b36,x:b0,y:b12,platform:Mac OS X,",
|
||||
"03000000d8140000cecf000000000000,MC Cthulhu,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X,",
|
||||
"030000001008000001e5000006010000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b6,start:b9,x:b3,y:b0,platform:Mac OS X,",
|
||||
"030000007e0500000920000000000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X,",
|
||||
"030000008f0e00000300000000000000,Piranha xtreme,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Mac OS X,",
|
||||
"030000004c0500006802000000010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Mac OS X,",
|
||||
"030000004c0500006802000000000000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Mac OS X,",
|
||||
"030000004c050000a00b000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,",
|
||||
"030000004c050000cc09000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,",
|
||||
"030000004c050000c405000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,",
|
||||
"030000004c050000c405000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,",
|
||||
"030000008916000000fd000000000000,Razer Onza TE,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,",
|
||||
"03000000321500000010000000010000,Razer RAIJU,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,",
|
||||
"0300000032150000030a000000000000,Razer Wildcat,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,",
|
||||
"03000000790000001100000000000000,Retrolink Classic Controller,a:b2,b:b1,back:b8,leftshoulder:b4,leftx:a3,lefty:a4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Mac OS X,",
|
||||
"03000000790000001100000006010000,Retrolink SNES Controller,a:b2,b:b1,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Mac OS X,",
|
||||
"030000006b140000010d000000010000,Revolution Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,",
|
||||
"03000000811700007e05000000000000,Sega Saturn,a:b2,b:b4,dpdown:b16,dpleft:b15,dpright:b14,dpup:b17,leftshoulder:b8,lefttrigger:a5,leftx:a0,lefty:a2,rightshoulder:b9,righttrigger:a4,start:b13,x:b0,y:b6,platform:Mac OS X,",
|
||||
"03000000b40400000a01000000000000,Sega Saturn USB Gamepad,a:b0,b:b1,back:b5,guide:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b8,x:b3,y:b4,platform:Mac OS X,",
|
||||
"030000003512000021ab000000000000,SFC30 Joystick,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X,",
|
||||
"030000004c050000cc09000000000000,Sony DualShock 4 V2,a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,",
|
||||
"030000004c050000a00b000000000000,Sony DualShock 4 Wireless Adaptor,a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,",
|
||||
"030000005e0400008e02000001000000,Steam Virtual GamePad,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,",
|
||||
"03000000110100002014000000000000,SteelSeries Nimbus,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b12,x:b2,y:b3,platform:Mac OS X,",
|
||||
"03000000110100002014000001000000,SteelSeries Nimbus,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,x:b2,y:b3,platform:Mac OS X,",
|
||||
"03000000381000002014000001000000,SteelSeries Nimbus,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,x:b2,y:b3,platform:Mac OS X,",
|
||||
"03000000110100001714000000000000,SteelSeries Stratus XL,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,start:b12,x:b2,y:b3,platform:Mac OS X,",
|
||||
"03000000110100001714000020010000,SteelSeries Stratus XL,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,start:b12,x:b2,y:b3,platform:Mac OS X,",
|
||||
"030000004f04000015b3000000000000,Thrustmaster Dual Analog 3.2,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Mac OS X,",
|
||||
"030000004f04000000b3000000000000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b11,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b1,y:b3,platform:Mac OS X,",
|
||||
"03000000bd12000015d0000000010000,Tomee SNES USB Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Mac OS X,",
|
||||
"03000000bd12000015d0000000000000,Tomee SNES USB Controller,a:b2,b:b1,back:b8,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Mac OS X,",
|
||||
"03000000100800000100000000000000,Twin USB Joystick,a:b4,b:b2,back:b16,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b12,leftstick:b20,lefttrigger:b8,leftx:a0,lefty:a2,rightshoulder:b14,rightstick:b22,righttrigger:b10,rightx:a6,righty:a4,start:b18,x:b6,y:b0,platform:Mac OS X,",
|
||||
"050000005769696d6f74652028303000,Wii Remote,a:b4,b:b5,back:b7,dpdown:b3,dpleft:b0,dpright:b1,dpup:b2,guide:b8,leftshoulder:b11,lefttrigger:b12,leftx:a0,lefty:a1,start:b6,x:b10,y:b9,platform:Mac OS X,",
|
||||
"050000005769696d6f74652028313800,Wii U Pro Controller,a:b16,b:b15,back:b7,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b8,leftshoulder:b19,leftstick:b23,lefttrigger:b21,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b24,righttrigger:b22,rightx:a2,righty:a3,start:b6,x:b18,y:b17,platform:Mac OS X,",
|
||||
"030000005e0400008e02000000000000,X360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,",
|
||||
"03000000c6240000045d000000000000,Xbox 360 Wired Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,",
|
||||
"030000005e040000e302000000000000,Xbox One Wired Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,",
|
||||
"030000005e040000d102000000000000,Xbox One Wired Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,",
|
||||
"030000005e040000dd02000000000000,Xbox One Wired Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,",
|
||||
"030000005e040000e002000000000000,Xbox Wireless Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Mac OS X,",
|
||||
"030000005e040000fd02000003090000,Xbox Wireless Controller,a:b0,b:b1,back:b16,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,",
|
||||
"030000005e040000ea02000000000000,Xbox Wireless Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,",
|
||||
"030000005e040000e002000003090000,Xbox Wireless Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Mac OS X,",
|
||||
"03000000172700004431000029010000,XiaoMi Game Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a6,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Mac OS X,",
|
||||
"03000000120c0000100e000000010000,ZEROPLUS P4 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,",
|
||||
"05000000203800000900000000010000,8Bitdo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,",
|
||||
"03000000022000000090000011010000,8Bitdo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,",
|
||||
"05000000c82d00002038000000010000,8Bitdo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,",
|
||||
"03000000c82d00000190000011010000,8Bitdo NES30 Pro 8Bitdo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,",
|
||||
"05000000c82d00003028000000010000,8Bitdo SFC30 GamePad,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux,",
|
||||
"05000000102800000900000000010000,8Bitdo SFC30 GamePad,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux,",
|
||||
"05000000a00500003232000008010000,8Bitdo Zero GamePad,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Linux,",
|
||||
"05000000a00500003232000001000000,8Bitdo Zero GamePad,a:b0,b:b1,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Linux,",
|
||||
"030000006f0e00003901000020060000,Afterglow Wired Controller for Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
|
||||
"03000000100000008200000011010000,Akishop Customs PS360+ v1.66,a:b1,b:b2,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,",
|
||||
"05000000050b00000045000031000000,ASUS Gamepad,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b10,x:b2,y:b3,platform:Linux,",
|
||||
"03000000666600006706000000010000,boom PSX to PC Converter,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a2,righty:a3,start:b11,x:b3,y:b0,platform:Linux,",
|
||||
"03000000e82000006058000001010000,Cideko AK08b,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,",
|
||||
"03000000260900008888000000010000,Cyber Gadget GameCube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:a5,rightx:a2,righty:a3~,start:b7,x:b2,y:b3,platform:Linux,",
|
||||
"03000000a306000022f6000011010000,Cyborg V.3 Rumble Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:-a3,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Linux,",
|
||||
"03000000b40400000a01000000010000,CYPRESS USB Gamepad,a:b0,b:b1,back:b5,guide:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b8,x:b3,y:b4,platform:Linux,",
|
||||
"03000000790000000600000010010000,DragonRise Inc. Generic USB Joystick,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b3,y:b0,platform:Linux,",
|
||||
"030000006f0e00003001000001010000,EA Sports PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
|
||||
"03000000341a000005f7000010010000,GameCube {HuiJia USB box},a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Linux,",
|
||||
"0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,",
|
||||
"030000006f0e00000104000000010000,Gamestop Logic3 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
|
||||
"030000006f0e00001304000000010000,Generic X-Box pad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:a0,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:a3,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
|
||||
"030000006f0e00001f01000000010000,Generic X-Box pad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
|
||||
"03000000f0250000c183000010010000,Goodbetterbest Ltd USB Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
|
||||
"03000000280400000140000000010000,Gravis GamePad Pro USB ,a:b1,b:b2,back:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,",
|
||||
"030000008f0e00000610000000010000,GreenAsia Electronics 4Axes 12Keys GamePad ,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a3,righty:a2,start:b11,x:b3,y:b0,platform:Linux,",
|
||||
"030000008f0e00001200000010010000,GreenAsia Inc. USB Joystick,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Linux,",
|
||||
"030000008f0e00000300000010010000,GreenAsia Inc. USB Joystick,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux,",
|
||||
"0500000047532067616d657061640000,GS gamepad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,",
|
||||
"06000000adde0000efbe000002010000,Hidromancer Game Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
|
||||
"03000000d81400000862000011010000,HitBox (PS3/PC) Analog Mode,a:b1,b:b2,back:b8,guide:b9,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b12,x:b0,y:b3,platform:Linux,",
|
||||
"03000000c9110000f055000011010000,HJC Game GAMEPAD,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,",
|
||||
"030000000d0f00000d00000000010000,hori,a:b0,b:b6,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b3,leftx:b4,lefty:b5,rightshoulder:b7,start:b9,x:b1,y:b2,platform:Linux,",
|
||||
"030000000d0f00001000000011010000,HORI CO. LTD. FIGHTING STICK 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,",
|
||||
"030000000d0f00006a00000011010000,HORI CO. LTD. Real Arcade Pro.4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
|
||||
"030000000d0f00006b00000011010000,HORI CO. LTD. Real Arcade Pro.4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
|
||||
"030000000d0f00002200000011010000,HORI CO. LTD. REAL ARCADE Pro.V3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,",
|
||||
"030000000d0f00005f00000011010000,Hori Fighting Commander 4 (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
|
||||
"030000000d0f00005e00000011010000,Hori Fighting Commander 4 (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
|
||||
"03000000ad1b000001f5000033050000,Hori Pad EX Turbo 2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
|
||||
"030000000d0f00006e00000011010000,HORIPAD 4 (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
|
||||
"030000000d0f00006600000011010000,HORIPAD 4 (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
|
||||
"030000000d0f00006700000001010000,HORIPAD ONE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
|
||||
"030000008f0e00001330000010010000,HuiJia SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b9,x:b3,y:b0,platform:Linux,",
|
||||
"03000000830500006020000010010000,iBuffalo SNES Controller,a:b1,b:b0,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b2,platform:Linux,",
|
||||
"050000006964726f69643a636f6e0000,idroid:con,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
|
||||
"03000000b50700001503000010010000,impact,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Linux,",
|
||||
"03000000fd0500000030000000010000,InterAct GoPad I-73000 (Fighting Game Layout),a:b3,b:b4,back:b6,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,start:b7,x:b0,y:b1,platform:Linux,",
|
||||
"030000006e0500000320000010010000,JC-U3613M - DirectInput Mode,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b0,y:b1,platform:Linux,",
|
||||
"03000000300f00001001000010010000,Jess Tech Dual Analog Rumble Pad,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Linux,",
|
||||
"03000000ba2200002010000001010000,Jess Technology USB Game Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux,",
|
||||
"030000006f0e00000103000000020000,Logic3 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
|
||||
"030000006d04000019c2000010010000,Logitech Cordless RumblePad 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
|
||||
"030000006d04000016c2000011010000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
|
||||
"030000006d04000016c2000010010000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
|
||||
"030000006d0400001dc2000014400000,Logitech F310 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
|
||||
"030000006d0400001ec2000020200000,Logitech F510 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
|
||||
"030000006d04000019c2000011010000,Logitech F710 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
|
||||
"030000006d0400001fc2000005030000,Logitech F710 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
|
||||
"030000006d04000015c2000010010000,Logitech Logitech Extreme 3D,a:b0,b:b4,back:b6,guide:b8,leftshoulder:b9,leftstick:h0.8,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:h0.2,start:b7,x:b2,y:b5,platform:Linux,",
|
||||
"030000006d04000018c2000010010000,Logitech RumblePad 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
|
||||
"030000006d04000011c2000010010000,Logitech WingMan Cordless RumblePad,a:b0,b:b1,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b6,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b10,rightx:a3,righty:a4,start:b8,x:b3,y:b4,platform:Linux,",
|
||||
"05000000380700006652000025010000,Mad Catz C.T.R.L.R ,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
|
||||
"03000000380700005032000011010000,Mad Catz FightPad PRO (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
|
||||
"03000000380700005082000011010000,Mad Catz FightPad PRO (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
|
||||
"03000000ad1b00002ef0000090040000,Mad Catz Fightpad SFxT,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,start:b7,x:b2,y:b3,platform:Linux,",
|
||||
"03000000380700008034000011010000,Mad Catz fightstick (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
|
||||
"03000000380700008084000011010000,Mad Catz fightstick (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
|
||||
"03000000380700008433000011010000,Mad Catz FightStick TE S+ PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
|
||||
"03000000380700008483000011010000,Mad Catz FightStick TE S+ PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
|
||||
"03000000380700001647000010040000,Mad Catz Wired Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
|
||||
"03000000380700003847000090040000,Mad Catz Wired Xbox 360 Controller (SFIV),a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,",
|
||||
"03000000ad1b000016f0000090040000,Mad Catz Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
|
||||
"03000000380700001888000010010000,MadCatz PC USB Wired Stick 8818,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
|
||||
"03000000380700003888000010010000,MadCatz PC USB Wired Stick 8838,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:a0,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
|
||||
"03000000790000004418000010010000,Mayflash GameCube Controller,a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Linux,",
|
||||
"03000000780000000600000010010000,Microntek USB Joystick,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux,",
|
||||
"030000005e0400008e02000004010000,Microsoft X-Box 360 pad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
|
||||
"030000005e0400008e02000062230000,Microsoft X-Box 360 pad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
|
||||
"030000005e040000d102000001010000,Microsoft X-Box One pad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
|
||||
"030000005e040000d102000003020000,Microsoft X-Box One pad v2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
|
||||
"030000005e0400008502000000010000,Microsoft X-Box pad (Japan),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,platform:Linux,",
|
||||
"030000005e0400008902000021010000,Microsoft X-Box pad v2 (US),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,platform:Linux,",
|
||||
"05000000d6200000ad0d000001000000,Moga Pro,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Linux,",
|
||||
"030000001008000001e5000010010000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b6,start:b9,x:b3,y:b0,platform:Linux,",
|
||||
"050000007e0500000920000001000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,",
|
||||
"050000007e0500003003000001000000,Nintendo Wii Remote Pro Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Linux,",
|
||||
"05000000010000000100000003000000,Nintendo Wiimote,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,",
|
||||
"030000000d0500000308000010010000,Nostromo n45 Dual Analog Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b12,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b10,x:b2,y:b3,platform:Linux,",
|
||||
"03000000550900001072000011010000,NVIDIA Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b13,leftshoulder:b4,leftstick:b8,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux,",
|
||||
"03000000451300000830000010010000,NYKO CORE,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
|
||||
"030000005e0400000202000000010000,Old Xbox pad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,platform:Linux,",
|
||||
"05000000362800000100000002010000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2,platform:Linux,",
|
||||
"05000000362800000100000003010000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2,platform:Linux,",
|
||||
"03000000ff1100003133000010010000,PC Game Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,",
|
||||
"030000006f0e00006401000001010000,PDP Battlefield One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
|
||||
"03000000ff1100004133000010010000,PS2 Controller,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux,",
|
||||
"030000004c0500006802000010010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux,",
|
||||
"050000004c0500006802000000810000,PS3 Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,",
|
||||
"03000000341a00003608000011010000,PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
|
||||
"030000004c0500006802000011810000,PS3 Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,",
|
||||
"050000004c0500006802000000010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:a12,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:a13,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux,",
|
||||
"030000004c0500006802000010810000,PS3 Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,",
|
||||
"030000004c0500006802000011010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux,",
|
||||
"060000004c0500006802000000010000,PS3 Controller (Bluetooth),a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux,",
|
||||
"05000000504c415953544154494f4e00,PS3 Controller (Bluetooth),a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux,",
|
||||
"050000004c050000c405000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
|
||||
"030000004c050000a00b000011010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
|
||||
"050000004c050000cc09000000810000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,",
|
||||
"050000004c050000c405000000810000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,",
|
||||
"030000004c050000c405000011810000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,",
|
||||
"050000004c050000cc09000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
|
||||
"030000004c050000cc09000011010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
|
||||
"030000004c050000a00b000011810000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,",
|
||||
"030000004c050000cc09000011810000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,",
|
||||
"030000004c050000c405000011010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
|
||||
"03000000300f00001211000011010000,QanBa Arcade JoyStick,a:b2,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b5,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b6,start:b9,x:b1,y:b3,platform:Linux,",
|
||||
"030000009b2800000300000001010000,raphnet.net 4nes4snes v1.5,a:b0,b:b4,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Linux,",
|
||||
"030000008916000001fd000024010000,Razer Onza Classic Edition,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
|
||||
"030000008916000000fd000024010000,Razer Onza Tournament,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
|
||||
"03000000321500000010000011010000,Razer RAIJU,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
|
||||
"03000000c6240000045d000025010000,Razer Sabertooth,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
|
||||
"03000000321500000009000011010000,Razer Serval,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux,",
|
||||
"050000003215000000090000163a0000,Razer Serval,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux,",
|
||||
"0300000032150000030a000001010000,Razer Wildcat,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
|
||||
"03000000790000001100000010010000,Retrolink SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Linux,",
|
||||
"0300000000f000000300000000010000,RetroUSB.com RetroPad,a:b1,b:b5,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Linux,",
|
||||
"0300000000f00000f100000000010000,RetroUSB.com Super RetroPort,a:b1,b:b5,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Linux,",
|
||||
"030000006b140000010d000011010000,Revolution Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
|
||||
"030000006f0e00001e01000011010000,Rock Candy Gamepad for PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
|
||||
"030000006f0e00004601000001010000,Rock Candy Wired Controller for Xbox One,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
|
||||
"03000000a306000023f6000011010000,Saitek Cyborg V.1 Game Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Linux,",
|
||||
"03000000a30600000cff000010010000,Saitek P2500 Force Rumble Pad,a:b2,b:b3,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,x:b0,y:b1,platform:Linux,",
|
||||
"03000000a30600000c04000011010000,Saitek P2900 Wireless Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b12,x:b0,y:b3,platform:Linux,",
|
||||
"03000000a30600000901000000010000,Saitek P880,a:b2,b:b3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,x:b0,y:b1,platform:Linux,",
|
||||
"03000000a30600000b04000000010000,Saitek P990 Dual Analog Pad,a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b8,x:b0,y:b3,platform:Linux,",
|
||||
"03000000a306000018f5000010010000,Saitek PLC Saitek P3200 Rumble Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Linux,",
|
||||
"03000000c01600008704000011010000,Serial/Keyboard/Mouse/Joystick,a:b12,b:b10,back:b4,dpdown:b2,dpleft:b3,dpright:b1,dpup:b0,leftshoulder:b9,leftstick:b14,lefttrigger:b6,leftx:a1,lefty:a0,rightshoulder:b8,rightstick:b15,righttrigger:b7,rightx:a2,righty:a3,start:b5,x:b13,y:b11,platform:Linux,",
|
||||
"03000000f025000021c1000010010000,ShanWan Gioteck PS3 Wired Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,",
|
||||
"03000000250900000500000000010000,Sony PS2 pad with SmartJoy adapter,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Linux,",
|
||||
"030000005e0400008e02000073050000,Speedlink TORID Wireless Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
|
||||
"030000005e0400008e02000020200000,SpeedLink XEOX Pro Analog Gamepad pad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
|
||||
"03000000de2800000211000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,",
|
||||
"05000000de2800000511000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,",
|
||||
"03000000de2800000112000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,",
|
||||
"05000000de2800000212000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,",
|
||||
"03000000de280000fc11000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
|
||||
"03000000de2800004211000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,",
|
||||
"03000000de280000ff11000001000000,Steam Virtual Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
|
||||
"03000000666600000488000000010000,Super Joy Box 5 Pro,a:b2,b:b1,back:b9,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Linux,",
|
||||
"030000004f04000020b3000010010000,Thrustmaster 2 in 1 DT,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Linux,",
|
||||
"030000004f04000015b3000010010000,Thrustmaster Dual Analog 4,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Linux,",
|
||||
"030000004f04000023b3000000010000,Thrustmaster Dual Trigger 3-in-1,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
|
||||
"030000004f04000000b3000010010000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b11,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b1,y:b3,platform:Linux,",
|
||||
"030000004f04000008d0000000010000,Thrustmaster Run N Drive Wireless,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
|
||||
"030000004f04000009d0000000010000,Thrustmaster Run N Drive Wireless PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
|
||||
"03000000bd12000015d0000010010000,Tomee SNES USB Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Linux,",
|
||||
"03000000d814000007cd000011010000,Toodles 2008 Chimp PC/PS3,a:b0,b:b1,back:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b3,y:b2,platform:Linux,",
|
||||
"03000000100800000100000010010000,Twin USB PS2 Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux,",
|
||||
"03000000100800000300000010010000,USB Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux,",
|
||||
"03000000790000001100000000010000,USB Gamepad1,a:b2,b:b1,back:b8,dpdown:a0,dpleft:a1,dpright:a2,dpup:a4,start:b9,platform:Linux,",
|
||||
"05000000ac0500003232000001000000,VR-BOX,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Linux,",
|
||||
"030000005e0400008e02000014010000,X360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
|
||||
"030000005e0400008e02000010010000,X360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
|
||||
"030000005e0400001907000000010000,X360 Wireless Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
|
||||
"030000005e0400009102000007010000,X360 Wireless Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
|
||||
"030000005e040000a102000007010000,X360 Wireless Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
|
||||
"030000005e040000a102000000010000,X360 Wireless Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
|
||||
"0000000058626f782033363020576900,Xbox 360 Wireless Controller,a:b0,b:b1,back:b14,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,guide:b7,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Linux,",
|
||||
"0000000058626f782047616d65706100,Xbox Gamepad (userspace driver),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux,",
|
||||
"050000005e040000e002000003090000,Xbox One Wireless Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
|
||||
"050000005e040000fd02000003090000,Xbox One Wireless Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
|
||||
"03000000450c00002043000010010000,XEOX Gamepad SL-6556-BK,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,",
|
||||
"05000000172700004431000029010000,XiaoMi Game Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b20,leftshoulder:b6,leftstick:b13,lefttrigger:a7,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a6,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Linux,",
|
||||
"03000000c0160000e105000001010000,Xin-Mo Xin-Mo Dual Arcade,a:b4,b:b3,back:b6,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b9,leftshoulder:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b1,y:b0,platform:Linux,",
|
||||
"03000000120c0000100e000011010000,ZEROPLUS P4 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
|
||||
"64633436313965656664373634323364,Microsoft X-Box 360 pad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,x:b2,y:b3,platform:Android,",
|
||||
"61363931656135336130663561616264,NVIDIA Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,",
|
||||
"4e564944494120436f72706f72617469,NVIDIA Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,",
|
||||
"37336435666338653565313731303834,NVIDIA Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,",
|
||||
"35643031303033326130316330353564,PS4 Controller,a:b1,b:b17,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b3,leftstick:b4,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:+a4,rightx:a2,righty:a5,start:b16,x:b0,y:b2,platform:Android,",
|
||||
"05000000de2800000511000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Android,",
|
||||
"5477696e20555342204a6f7973746963,Twin USB Joystick,a:b22,b:b21,back:b28,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b26,leftstick:b30,lefttrigger:b24,leftx:a0,lefty:a1,rightshoulder:b27,rightstick:b31,righttrigger:b25,rightx:a3,righty:a2,start:b29,x:b23,y:b20,platform:Android,",
|
||||
"34356136633366613530316338376136,Xbox Wireless Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b3,leftstick:b15,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b16,righttrigger:a5,rightx:a3,righty:a4,x:b17,y:b2,platform:Android,",
|
||||
"4d466947616d65706164010000000000,MFi Extended Gamepad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:iOS,",
|
||||
"4d466947616d65706164020000000000,MFi Gamepad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,rightshoulder:b5,start:b6,x:b2,y:b3,platform:iOS,",
|
||||
"05000000de2800000511000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:iOS,",
|
||||
|
||||
"78696e70757401000000000000000000,XInput Gamepad (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,",
|
||||
"78696e70757402000000000000000000,XInput Wheel (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,",
|
||||
"78696e70757403000000000000000000,XInput Arcade Stick (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,",
|
||||
"78696e70757404000000000000000000,XInput Flight Stick (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,",
|
||||
"78696e70757405000000000000000000,XInput Dance Pad (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,",
|
||||
"78696e70757406000000000000000000,XInput Guitar (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,",
|
||||
"78696e70757408000000000000000000,XInput Drum Kit (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,",
|
||||
NULL
|
||||
};
|
||||
|
||||
54
glfw/memfd.h
vendored
Normal file
54
glfw/memfd.h
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Kovid Goyal <kovid at kovidgoyal.net>
|
||||
*
|
||||
* Distributed under terms of the GPL3 license.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef HAS_MEMFD_CREATE
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/syscall.h>
|
||||
static inline int memfd_create(const char *name, unsigned int flags) {
|
||||
return syscall(__NR_memfd_create, name, flags);
|
||||
}
|
||||
|
||||
#ifndef F_LINUX_SPECIFIC_BASE
|
||||
#define F_LINUX_SPECIFIC_BASE 1024
|
||||
#endif
|
||||
|
||||
#ifndef F_ADD_SEALS
|
||||
#define F_ADD_SEALS (F_LINUX_SPECIFIC_BASE + 9)
|
||||
#define F_GET_SEALS (F_LINUX_SPECIFIC_BASE + 10)
|
||||
|
||||
#define F_SEAL_SEAL 0x0001 /* prevent further seals from being set */
|
||||
#define F_SEAL_SHRINK 0x0002 /* prevent file from shrinking */
|
||||
#define F_SEAL_GROW 0x0004 /* prevent file from growing */
|
||||
#define F_SEAL_WRITE 0x0008 /* prevent writes */
|
||||
#endif
|
||||
|
||||
#ifndef MFD_CLOEXEC
|
||||
#define MFD_CLOEXEC 0x0001U
|
||||
#define MFD_ALLOW_SEALING 0x0002U
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
static inline int
|
||||
createTmpfileCloexec(char* tmpname)
|
||||
{
|
||||
int fd;
|
||||
|
||||
fd = mkostemp(tmpname, O_CLOEXEC);
|
||||
if (fd >= 0)
|
||||
unlink(tmpname);
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
#endif
|
||||
508
glfw/monitor.c
vendored
Normal file
508
glfw/monitor.c
vendored
Normal file
@@ -0,0 +1,508 @@
|
||||
//========================================================================
|
||||
// GLFW 3.3 - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||
// Copyright (c) 2006-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 <assert.h>
|
||||
#include <math.h>
|
||||
#include <float.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
|
||||
|
||||
// Lexically compare video modes, used by qsort
|
||||
//
|
||||
static int compareVideoModes(const void* fp, const void* sp)
|
||||
{
|
||||
const GLFWvidmode* fm = fp;
|
||||
const GLFWvidmode* sm = sp;
|
||||
const int fbpp = fm->redBits + fm->greenBits + fm->blueBits;
|
||||
const int sbpp = sm->redBits + sm->greenBits + sm->blueBits;
|
||||
const int farea = fm->width * fm->height;
|
||||
const int sarea = sm->width * sm->height;
|
||||
|
||||
// First sort on color bits per pixel
|
||||
if (fbpp != sbpp)
|
||||
return fbpp - sbpp;
|
||||
|
||||
// Then sort on screen area
|
||||
if (farea != sarea)
|
||||
return farea - sarea;
|
||||
|
||||
// Lastly sort on refresh rate
|
||||
return fm->refreshRate - sm->refreshRate;
|
||||
}
|
||||
|
||||
// Retrieves the available modes for the specified monitor
|
||||
//
|
||||
static GLFWbool refreshVideoModes(_GLFWmonitor* monitor)
|
||||
{
|
||||
int modeCount;
|
||||
GLFWvidmode* modes;
|
||||
|
||||
if (monitor->modes)
|
||||
return GLFW_TRUE;
|
||||
|
||||
modes = _glfwPlatformGetVideoModes(monitor, &modeCount);
|
||||
if (!modes)
|
||||
return GLFW_FALSE;
|
||||
|
||||
qsort(modes, modeCount, sizeof(GLFWvidmode), compareVideoModes);
|
||||
|
||||
free(monitor->modes);
|
||||
monitor->modes = modes;
|
||||
monitor->modeCount = modeCount;
|
||||
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW event API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Notifies shared code of a monitor connection or disconnection
|
||||
//
|
||||
void _glfwInputMonitor(_GLFWmonitor* monitor, int action, int placement)
|
||||
{
|
||||
if (action == GLFW_CONNECTED)
|
||||
{
|
||||
_glfw.monitorCount++;
|
||||
_glfw.monitors =
|
||||
realloc(_glfw.monitors, sizeof(_GLFWmonitor*) * _glfw.monitorCount);
|
||||
|
||||
if (placement == _GLFW_INSERT_FIRST)
|
||||
{
|
||||
memmove(_glfw.monitors + 1,
|
||||
_glfw.monitors,
|
||||
(_glfw.monitorCount - 1) * sizeof(_GLFWmonitor*));
|
||||
_glfw.monitors[0] = monitor;
|
||||
}
|
||||
else
|
||||
_glfw.monitors[_glfw.monitorCount - 1] = monitor;
|
||||
}
|
||||
else if (action == GLFW_DISCONNECTED)
|
||||
{
|
||||
int i;
|
||||
_GLFWwindow* window;
|
||||
|
||||
for (window = _glfw.windowListHead; window; window = window->next)
|
||||
{
|
||||
if (window->monitor == monitor)
|
||||
{
|
||||
int width, height, xoff, yoff;
|
||||
_glfwPlatformGetWindowSize(window, &width, &height);
|
||||
_glfwPlatformSetWindowMonitor(window, NULL, 0, 0, width, height, 0);
|
||||
_glfwPlatformGetWindowFrameSize(window, &xoff, &yoff, NULL, NULL);
|
||||
_glfwPlatformSetWindowPos(window, xoff, yoff);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < _glfw.monitorCount; i++)
|
||||
{
|
||||
if (_glfw.monitors[i] == monitor)
|
||||
{
|
||||
_glfw.monitorCount--;
|
||||
memmove(_glfw.monitors + i,
|
||||
_glfw.monitors + i + 1,
|
||||
(_glfw.monitorCount - i) * sizeof(_GLFWmonitor*));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_glfw.callbacks.monitor)
|
||||
_glfw.callbacks.monitor((GLFWmonitor*) monitor, action);
|
||||
|
||||
if (action == GLFW_DISCONNECTED)
|
||||
_glfwFreeMonitor(monitor);
|
||||
}
|
||||
|
||||
// Notifies shared code that a full screen window has acquired or released
|
||||
// a monitor
|
||||
//
|
||||
void _glfwInputMonitorWindow(_GLFWmonitor* monitor, _GLFWwindow* window)
|
||||
{
|
||||
monitor->window = window;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW internal API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Allocates and returns a monitor object with the specified name and dimensions
|
||||
//
|
||||
_GLFWmonitor* _glfwAllocMonitor(const char* name, int widthMM, int heightMM)
|
||||
{
|
||||
_GLFWmonitor* monitor = calloc(1, sizeof(_GLFWmonitor));
|
||||
monitor->widthMM = widthMM;
|
||||
monitor->heightMM = heightMM;
|
||||
|
||||
if (name)
|
||||
monitor->name = _glfw_strdup(name);
|
||||
|
||||
return monitor;
|
||||
}
|
||||
|
||||
// Frees a monitor object and any data associated with it
|
||||
//
|
||||
void _glfwFreeMonitor(_GLFWmonitor* monitor)
|
||||
{
|
||||
if (monitor == NULL)
|
||||
return;
|
||||
|
||||
_glfwPlatformFreeMonitor(monitor);
|
||||
|
||||
_glfwFreeGammaArrays(&monitor->originalRamp);
|
||||
_glfwFreeGammaArrays(&monitor->currentRamp);
|
||||
|
||||
free(monitor->modes);
|
||||
free(monitor->name);
|
||||
free(monitor);
|
||||
}
|
||||
|
||||
// Allocates red, green and blue value arrays of the specified size
|
||||
//
|
||||
void _glfwAllocGammaArrays(GLFWgammaramp* ramp, unsigned int size)
|
||||
{
|
||||
ramp->red = calloc(size, sizeof(unsigned short));
|
||||
ramp->green = calloc(size, sizeof(unsigned short));
|
||||
ramp->blue = calloc(size, sizeof(unsigned short));
|
||||
ramp->size = size;
|
||||
}
|
||||
|
||||
// Frees the red, green and blue value arrays and clears the struct
|
||||
//
|
||||
void _glfwFreeGammaArrays(GLFWgammaramp* ramp)
|
||||
{
|
||||
free(ramp->red);
|
||||
free(ramp->green);
|
||||
free(ramp->blue);
|
||||
|
||||
memset(ramp, 0, sizeof(GLFWgammaramp));
|
||||
}
|
||||
|
||||
// Chooses the video mode most closely matching the desired one
|
||||
//
|
||||
const GLFWvidmode* _glfwChooseVideoMode(_GLFWmonitor* monitor,
|
||||
const GLFWvidmode* desired)
|
||||
{
|
||||
int i;
|
||||
unsigned int sizeDiff, leastSizeDiff = UINT_MAX;
|
||||
unsigned int rateDiff, leastRateDiff = UINT_MAX;
|
||||
unsigned int colorDiff, leastColorDiff = UINT_MAX;
|
||||
const GLFWvidmode* current;
|
||||
const GLFWvidmode* closest = NULL;
|
||||
|
||||
if (!refreshVideoModes(monitor))
|
||||
return NULL;
|
||||
|
||||
for (i = 0; i < monitor->modeCount; i++)
|
||||
{
|
||||
current = monitor->modes + i;
|
||||
|
||||
colorDiff = 0;
|
||||
|
||||
if (desired->redBits != GLFW_DONT_CARE)
|
||||
colorDiff += abs(current->redBits - desired->redBits);
|
||||
if (desired->greenBits != GLFW_DONT_CARE)
|
||||
colorDiff += abs(current->greenBits - desired->greenBits);
|
||||
if (desired->blueBits != GLFW_DONT_CARE)
|
||||
colorDiff += abs(current->blueBits - desired->blueBits);
|
||||
|
||||
sizeDiff = abs((current->width - desired->width) *
|
||||
(current->width - desired->width) +
|
||||
(current->height - desired->height) *
|
||||
(current->height - desired->height));
|
||||
|
||||
if (desired->refreshRate != GLFW_DONT_CARE)
|
||||
rateDiff = abs(current->refreshRate - desired->refreshRate);
|
||||
else
|
||||
rateDiff = UINT_MAX - current->refreshRate;
|
||||
|
||||
if ((colorDiff < leastColorDiff) ||
|
||||
(colorDiff == leastColorDiff && sizeDiff < leastSizeDiff) ||
|
||||
(colorDiff == leastColorDiff && sizeDiff == leastSizeDiff && rateDiff < leastRateDiff))
|
||||
{
|
||||
closest = current;
|
||||
leastSizeDiff = sizeDiff;
|
||||
leastRateDiff = rateDiff;
|
||||
leastColorDiff = colorDiff;
|
||||
}
|
||||
}
|
||||
|
||||
return closest;
|
||||
}
|
||||
|
||||
// Performs lexical comparison between two @ref GLFWvidmode structures
|
||||
//
|
||||
int _glfwCompareVideoModes(const GLFWvidmode* fm, const GLFWvidmode* sm)
|
||||
{
|
||||
return compareVideoModes(fm, sm);
|
||||
}
|
||||
|
||||
// Splits a color depth into red, green and blue bit depths
|
||||
//
|
||||
void _glfwSplitBPP(int bpp, int* red, int* green, int* blue)
|
||||
{
|
||||
int delta;
|
||||
|
||||
// We assume that by 32 the user really meant 24
|
||||
if (bpp == 32)
|
||||
bpp = 24;
|
||||
|
||||
// Convert "bits per pixel" to red, green & blue sizes
|
||||
|
||||
*red = *green = *blue = bpp / 3;
|
||||
delta = bpp - (*red * 3);
|
||||
if (delta >= 1)
|
||||
*green = *green + 1;
|
||||
|
||||
if (delta == 2)
|
||||
*red = *red + 1;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW public API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
GLFWAPI GLFWmonitor** glfwGetMonitors(int* count)
|
||||
{
|
||||
assert(count != NULL);
|
||||
|
||||
*count = 0;
|
||||
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||
|
||||
*count = _glfw.monitorCount;
|
||||
return (GLFWmonitor**) _glfw.monitors;
|
||||
}
|
||||
|
||||
GLFWAPI GLFWmonitor* glfwGetPrimaryMonitor(void)
|
||||
{
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||
|
||||
if (!_glfw.monitorCount)
|
||||
return NULL;
|
||||
|
||||
return (GLFWmonitor*) _glfw.monitors[0];
|
||||
}
|
||||
|
||||
GLFWAPI void glfwGetMonitorPos(GLFWmonitor* handle, int* xpos, int* ypos)
|
||||
{
|
||||
_GLFWmonitor* monitor = (_GLFWmonitor*) handle;
|
||||
assert(monitor != NULL);
|
||||
|
||||
if (xpos)
|
||||
*xpos = 0;
|
||||
if (ypos)
|
||||
*ypos = 0;
|
||||
|
||||
_GLFW_REQUIRE_INIT();
|
||||
|
||||
_glfwPlatformGetMonitorPos(monitor, xpos, ypos);
|
||||
}
|
||||
|
||||
GLFWAPI void glfwGetMonitorPhysicalSize(GLFWmonitor* handle, int* widthMM, int* heightMM)
|
||||
{
|
||||
_GLFWmonitor* monitor = (_GLFWmonitor*) handle;
|
||||
assert(monitor != NULL);
|
||||
|
||||
if (widthMM)
|
||||
*widthMM = 0;
|
||||
if (heightMM)
|
||||
*heightMM = 0;
|
||||
|
||||
_GLFW_REQUIRE_INIT();
|
||||
|
||||
if (widthMM)
|
||||
*widthMM = monitor->widthMM;
|
||||
if (heightMM)
|
||||
*heightMM = monitor->heightMM;
|
||||
}
|
||||
|
||||
GLFWAPI void glfwGetMonitorContentScale(GLFWmonitor* handle,
|
||||
float* xscale, float* yscale)
|
||||
{
|
||||
_GLFWmonitor* monitor = (_GLFWmonitor*) handle;
|
||||
assert(monitor != NULL);
|
||||
|
||||
if (xscale)
|
||||
*xscale = 0.f;
|
||||
if (yscale)
|
||||
*yscale = 0.f;
|
||||
|
||||
_GLFW_REQUIRE_INIT();
|
||||
_glfwPlatformGetMonitorContentScale(monitor, xscale, yscale);
|
||||
}
|
||||
|
||||
GLFWAPI const char* glfwGetMonitorName(GLFWmonitor* handle)
|
||||
{
|
||||
_GLFWmonitor* monitor = (_GLFWmonitor*) handle;
|
||||
assert(monitor != NULL);
|
||||
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||
return monitor->name;
|
||||
}
|
||||
|
||||
GLFWAPI void glfwSetMonitorUserPointer(GLFWmonitor* handle, void* pointer)
|
||||
{
|
||||
_GLFWmonitor* monitor = (_GLFWmonitor*) handle;
|
||||
assert(monitor != NULL);
|
||||
|
||||
_GLFW_REQUIRE_INIT();
|
||||
monitor->userPointer = pointer;
|
||||
}
|
||||
|
||||
GLFWAPI void* glfwGetMonitorUserPointer(GLFWmonitor* handle)
|
||||
{
|
||||
_GLFWmonitor* monitor = (_GLFWmonitor*) handle;
|
||||
assert(monitor != NULL);
|
||||
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||
return monitor->userPointer;
|
||||
}
|
||||
|
||||
GLFWAPI GLFWmonitorfun glfwSetMonitorCallback(GLFWmonitorfun cbfun)
|
||||
{
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||
_GLFW_SWAP_POINTERS(_glfw.callbacks.monitor, cbfun);
|
||||
return cbfun;
|
||||
}
|
||||
|
||||
GLFWAPI const GLFWvidmode* glfwGetVideoModes(GLFWmonitor* handle, int* count)
|
||||
{
|
||||
_GLFWmonitor* monitor = (_GLFWmonitor*) handle;
|
||||
assert(monitor != NULL);
|
||||
assert(count != NULL);
|
||||
|
||||
*count = 0;
|
||||
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||
|
||||
if (!refreshVideoModes(monitor))
|
||||
return NULL;
|
||||
|
||||
*count = monitor->modeCount;
|
||||
return monitor->modes;
|
||||
}
|
||||
|
||||
GLFWAPI const GLFWvidmode* glfwGetVideoMode(GLFWmonitor* handle)
|
||||
{
|
||||
_GLFWmonitor* monitor = (_GLFWmonitor*) handle;
|
||||
assert(monitor != NULL);
|
||||
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||
|
||||
_glfwPlatformGetVideoMode(monitor, &monitor->currentMode);
|
||||
return &monitor->currentMode;
|
||||
}
|
||||
|
||||
GLFWAPI void glfwSetGamma(GLFWmonitor* handle, float gamma)
|
||||
{
|
||||
int i;
|
||||
unsigned short values[256];
|
||||
GLFWgammaramp ramp;
|
||||
assert(handle != NULL);
|
||||
assert(gamma == gamma);
|
||||
assert(gamma >= 0.f);
|
||||
assert(gamma <= FLT_MAX);
|
||||
|
||||
_GLFW_REQUIRE_INIT();
|
||||
|
||||
if (gamma != gamma || gamma <= 0.f || gamma > FLT_MAX)
|
||||
{
|
||||
_glfwInputError(GLFW_INVALID_VALUE, "Invalid gamma value %f", gamma);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < 256; i++)
|
||||
{
|
||||
float value;
|
||||
|
||||
// Calculate intensity
|
||||
value = i / 255.f;
|
||||
// Apply gamma curve
|
||||
value = powf(value, 1.f / gamma) * 65535.f + 0.5f;
|
||||
|
||||
// Clamp to value range
|
||||
if (value > 65535.f)
|
||||
value = 65535.f;
|
||||
|
||||
values[i] = (unsigned short) value;
|
||||
}
|
||||
|
||||
ramp.red = values;
|
||||
ramp.green = values;
|
||||
ramp.blue = values;
|
||||
ramp.size = 256;
|
||||
|
||||
glfwSetGammaRamp(handle, &ramp);
|
||||
}
|
||||
|
||||
GLFWAPI const GLFWgammaramp* glfwGetGammaRamp(GLFWmonitor* handle)
|
||||
{
|
||||
_GLFWmonitor* monitor = (_GLFWmonitor*) handle;
|
||||
assert(monitor != NULL);
|
||||
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||
|
||||
_glfwFreeGammaArrays(&monitor->currentRamp);
|
||||
_glfwPlatformGetGammaRamp(monitor, &monitor->currentRamp);
|
||||
|
||||
return &monitor->currentRamp;
|
||||
}
|
||||
|
||||
GLFWAPI void glfwSetGammaRamp(GLFWmonitor* handle, const GLFWgammaramp* ramp)
|
||||
{
|
||||
_GLFWmonitor* monitor = (_GLFWmonitor*) handle;
|
||||
assert(monitor != NULL);
|
||||
assert(ramp != NULL);
|
||||
assert(ramp->size > 0);
|
||||
assert(ramp->red != NULL);
|
||||
assert(ramp->green != NULL);
|
||||
assert(ramp->blue != NULL);
|
||||
|
||||
if (ramp->size <= 0)
|
||||
{
|
||||
_glfwInputError(GLFW_INVALID_VALUE,
|
||||
"Invalid gamma ramp size %i",
|
||||
ramp->size);
|
||||
return;
|
||||
}
|
||||
|
||||
_GLFW_REQUIRE_INIT();
|
||||
|
||||
if (!monitor->originalRamp.size)
|
||||
_glfwPlatformGetGammaRamp(monitor, &monitor->originalRamp);
|
||||
|
||||
_glfwPlatformSetGammaRamp(monitor, ramp);
|
||||
}
|
||||
|
||||
56
glfw/nsgl_context.h
vendored
Normal file
56
glfw/nsgl_context.h
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
//========================================================================
|
||||
// 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.
|
||||
//
|
||||
//========================================================================
|
||||
|
||||
#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;
|
||||
|
||||
} _GLFWcontextNSGL;
|
||||
|
||||
// NSGL-specific global data
|
||||
//
|
||||
typedef struct _GLFWlibraryNSGL
|
||||
{
|
||||
// dlopen handle for OpenGL.framework (for glfwGetProcAddress)
|
||||
CFBundleRef framework;
|
||||
|
||||
} _GLFWlibraryNSGL;
|
||||
|
||||
|
||||
GLFWbool _glfwInitNSGL(void);
|
||||
void _glfwTerminateNSGL(void);
|
||||
GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window,
|
||||
const _GLFWctxconfig* ctxconfig,
|
||||
const _GLFWfbconfig* fbconfig);
|
||||
void _glfwDestroyContextNSGL(_GLFWwindow* window);
|
||||
|
||||
339
glfw/nsgl_context.m
Normal file
339
glfw/nsgl_context.m
Normal file
@@ -0,0 +1,339 @@
|
||||
//========================================================================
|
||||
// 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"
|
||||
|
||||
|
||||
#if (MAC_OS_X_VERSION_MAX_ALLOWED < 101400)
|
||||
#define NSOpenGLContextParameterSwapInterval NSOpenGLCPSwapInterval
|
||||
#define NSOpenGLContextParameterSurfaceOpacity NSOpenGLCPSurfaceOpacity
|
||||
#endif
|
||||
|
||||
static void makeContextCurrentNSGL(_GLFWwindow* window)
|
||||
{
|
||||
if (window)
|
||||
[window->context.nsgl.object makeCurrentContext];
|
||||
else
|
||||
[NSOpenGLContext clearCurrentContext];
|
||||
|
||||
_glfwPlatformSetTls(&_glfw.contextSlot, window);
|
||||
}
|
||||
|
||||
static void swapBuffersNSGL(_GLFWwindow* window)
|
||||
{
|
||||
// ARP appears to be unnecessary, but this is future-proof
|
||||
[window->context.nsgl.object flushBuffer];
|
||||
}
|
||||
|
||||
static void swapIntervalNSGL(int interval)
|
||||
{
|
||||
_GLFWwindow* window = _glfwPlatformGetTls(&_glfw.contextSlot);
|
||||
|
||||
GLint sync = interval;
|
||||
[window->context.nsgl.object setValues:&sync
|
||||
forParameter:NSOpenGLContextParameterSwapInterval];
|
||||
}
|
||||
|
||||
static int extensionSupportedNSGL(const char* extension)
|
||||
{
|
||||
// There are no NSGL extensions
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
static GLFWglproc getProcAddressNSGL(const char* procname)
|
||||
{
|
||||
CFStringRef symbolName = CFStringCreateWithCString(kCFAllocatorDefault,
|
||||
procname,
|
||||
kCFStringEncodingASCII);
|
||||
|
||||
GLFWglproc symbol = CFBundleGetFunctionPointerForName(_glfw.nsgl.framework,
|
||||
symbolName);
|
||||
|
||||
CFRelease(symbolName);
|
||||
|
||||
return symbol;
|
||||
}
|
||||
|
||||
// Destroy the OpenGL context
|
||||
//
|
||||
static void destroyContextNSGL(_GLFWwindow* window)
|
||||
{
|
||||
[window->context.nsgl.pixelFormat release];
|
||||
window->context.nsgl.pixelFormat = nil;
|
||||
|
||||
[window->context.nsgl.object release];
|
||||
window->context.nsgl.object = nil;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW internal API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Initialize OpenGL support
|
||||
//
|
||||
GLFWbool _glfwInitNSGL(void)
|
||||
{
|
||||
if (_glfw.nsgl.framework)
|
||||
return GLFW_TRUE;
|
||||
|
||||
_glfw.nsgl.framework =
|
||||
CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengl"));
|
||||
if (_glfw.nsgl.framework == NULL)
|
||||
{
|
||||
_glfwInputError(GLFW_API_UNAVAILABLE,
|
||||
"NSGL: Failed to locate OpenGL framework");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
// Terminate OpenGL support
|
||||
//
|
||||
void _glfwTerminateNSGL(void)
|
||||
{
|
||||
}
|
||||
|
||||
// Create the OpenGL context
|
||||
//
|
||||
GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window,
|
||||
const _GLFWctxconfig* ctxconfig,
|
||||
const _GLFWfbconfig* fbconfig)
|
||||
{
|
||||
if (ctxconfig->client == GLFW_OPENGL_ES_API)
|
||||
{
|
||||
_glfwInputError(GLFW_API_UNAVAILABLE,
|
||||
"NSGL: OpenGL ES is not available on macOS");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
if (ctxconfig->major > 2)
|
||||
{
|
||||
if (ctxconfig->major == 3 && ctxconfig->minor < 2)
|
||||
{
|
||||
_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;
|
||||
}
|
||||
}
|
||||
|
||||
// Context robustness modes (GL_KHR_robustness) are not yet supported by
|
||||
// macOS but are not a hard constraint, so ignore and continue
|
||||
|
||||
// Context release behaviors (GL_KHR_context_flush_control) are not yet
|
||||
// supported by macOS but are not a hard constraint, so ignore and continue
|
||||
|
||||
// Debug contexts (GL_KHR_debug) are not yet supported by macOS but are not
|
||||
// a hard constraint, so ignore and continue
|
||||
|
||||
// No-error contexts (GL_KHR_no_error) are not yet supported by macOS but
|
||||
// are not a hard constraint, so ignore and continue
|
||||
|
||||
#define addAttrib(a) \
|
||||
{ \
|
||||
assert((size_t) index < sizeof(attribs) / sizeof(attribs[0])); \
|
||||
attribs[index++] = a; \
|
||||
}
|
||||
#define setAttrib(a, v) { addAttrib(a); addAttrib(v); }
|
||||
|
||||
NSOpenGLPixelFormatAttribute attribs[40];
|
||||
int index = 0;
|
||||
|
||||
addAttrib(NSOpenGLPFAAccelerated);
|
||||
addAttrib(NSOpenGLPFAClosestPolicy);
|
||||
|
||||
if (ctxconfig->nsgl.offline)
|
||||
{
|
||||
addAttrib(NSOpenGLPFAAllowOfflineRenderers);
|
||||
// NOTE: This replaces the NSSupportsAutomaticGraphicsSwitching key in
|
||||
// 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
|
||||
if (ctxconfig->major >= 4)
|
||||
{
|
||||
setAttrib(NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion4_1Core);
|
||||
}
|
||||
else
|
||||
#endif /*MAC_OS_X_VERSION_MAX_ALLOWED*/
|
||||
if (ctxconfig->major >= 3)
|
||||
{
|
||||
setAttrib(NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core);
|
||||
}
|
||||
|
||||
if (ctxconfig->major <= 2)
|
||||
{
|
||||
if (fbconfig->auxBuffers != GLFW_DONT_CARE)
|
||||
setAttrib(NSOpenGLPFAAuxBuffers, fbconfig->auxBuffers);
|
||||
|
||||
if (fbconfig->accumRedBits != GLFW_DONT_CARE &&
|
||||
fbconfig->accumGreenBits != GLFW_DONT_CARE &&
|
||||
fbconfig->accumBlueBits != GLFW_DONT_CARE &&
|
||||
fbconfig->accumAlphaBits != GLFW_DONT_CARE)
|
||||
{
|
||||
const int accumBits = fbconfig->accumRedBits +
|
||||
fbconfig->accumGreenBits +
|
||||
fbconfig->accumBlueBits +
|
||||
fbconfig->accumAlphaBits;
|
||||
|
||||
setAttrib(NSOpenGLPFAAccumSize, accumBits);
|
||||
}
|
||||
}
|
||||
|
||||
if (fbconfig->redBits != GLFW_DONT_CARE &&
|
||||
fbconfig->greenBits != GLFW_DONT_CARE &&
|
||||
fbconfig->blueBits != GLFW_DONT_CARE)
|
||||
{
|
||||
int colorBits = fbconfig->redBits +
|
||||
fbconfig->greenBits +
|
||||
fbconfig->blueBits;
|
||||
|
||||
// macOS needs non-zero color size, so set reasonable values
|
||||
if (colorBits == 0)
|
||||
colorBits = 24;
|
||||
else if (colorBits < 15)
|
||||
colorBits = 15;
|
||||
|
||||
setAttrib(NSOpenGLPFAColorSize, colorBits);
|
||||
}
|
||||
|
||||
if (fbconfig->alphaBits != GLFW_DONT_CARE)
|
||||
setAttrib(NSOpenGLPFAAlphaSize, fbconfig->alphaBits);
|
||||
|
||||
if (fbconfig->depthBits != GLFW_DONT_CARE)
|
||||
setAttrib(NSOpenGLPFADepthSize, fbconfig->depthBits);
|
||||
|
||||
if (fbconfig->stencilBits != GLFW_DONT_CARE)
|
||||
setAttrib(NSOpenGLPFAStencilSize, fbconfig->stencilBits);
|
||||
|
||||
if (fbconfig->stereo)
|
||||
{
|
||||
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 101200
|
||||
_glfwInputError(GLFW_FORMAT_UNAVAILABLE,
|
||||
"NSGL: Stereo rendering is deprecated");
|
||||
return GLFW_FALSE;
|
||||
#else
|
||||
addAttrib(NSOpenGLPFAStereo);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (fbconfig->doublebuffer)
|
||||
addAttrib(NSOpenGLPFADoubleBuffer);
|
||||
|
||||
if (fbconfig->samples != GLFW_DONT_CARE)
|
||||
{
|
||||
if (fbconfig->samples == 0)
|
||||
{
|
||||
setAttrib(NSOpenGLPFASampleBuffers, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
setAttrib(NSOpenGLPFASampleBuffers, 1);
|
||||
setAttrib(NSOpenGLPFASamples, fbconfig->samples);
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: All NSOpenGLPixelFormats on the relevant cards support sRGB
|
||||
// framebuffer, so there's no need (and no way) to request it
|
||||
|
||||
addAttrib(0);
|
||||
|
||||
#undef addAttrib
|
||||
#undef setAttrib
|
||||
|
||||
window->context.nsgl.pixelFormat =
|
||||
[[NSOpenGLPixelFormat alloc] initWithAttributes:attribs];
|
||||
if (window->context.nsgl.pixelFormat == nil)
|
||||
{
|
||||
_glfwInputError(GLFW_FORMAT_UNAVAILABLE,
|
||||
"NSGL: Failed to find a suitable pixel format");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
NSOpenGLContext* share = NULL;
|
||||
|
||||
if (ctxconfig->share)
|
||||
share = ctxconfig->share->context.nsgl.object;
|
||||
|
||||
window->context.nsgl.object =
|
||||
[[NSOpenGLContext alloc] initWithFormat:window->context.nsgl.pixelFormat
|
||||
shareContext:share];
|
||||
if (window->context.nsgl.object == nil)
|
||||
{
|
||||
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
|
||||
"NSGL: Failed to create OpenGL context");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
if (fbconfig->transparent)
|
||||
{
|
||||
GLint opaque = 0;
|
||||
[window->context.nsgl.object setValues:&opaque forParameter:NSOpenGLContextParameterSurfaceOpacity];
|
||||
}
|
||||
|
||||
[window->context.nsgl.object setView:window->ns.view];
|
||||
|
||||
window->context.makeCurrent = makeContextCurrentNSGL;
|
||||
window->context.swapBuffers = swapBuffersNSGL;
|
||||
window->context.swapInterval = swapIntervalNSGL;
|
||||
window->context.extensionSupported = extensionSupportedNSGL;
|
||||
window->context.getProcAddress = getProcAddressNSGL;
|
||||
window->context.destroy = destroyContextNSGL;
|
||||
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW native API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
GLFWAPI id glfwGetNSGLContext(GLFWwindow* handle)
|
||||
{
|
||||
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(nil);
|
||||
|
||||
if (window->context.client == GLFW_NO_API)
|
||||
{
|
||||
_glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return window->context.nsgl.object;
|
||||
}
|
||||
50
glfw/null_init.c
vendored
Normal file
50
glfw/null_init.c
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
//========================================================================
|
||||
// GLFW 3.3 - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2016 Google Inc.
|
||||
// Copyright (c) 2006-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"
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW platform API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int _glfwPlatformInit(void)
|
||||
{
|
||||
_glfwInitTimerPOSIX();
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
void _glfwPlatformTerminate(void)
|
||||
{
|
||||
_glfwTerminateOSMesa();
|
||||
}
|
||||
|
||||
const char* _glfwPlatformGetVersionString(void)
|
||||
{
|
||||
return _GLFW_VERSION_NUMBER " null OSMesa";
|
||||
}
|
||||
|
||||
42
glfw/null_joystick.c
vendored
Normal file
42
glfw/null_joystick.c
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
//========================================================================
|
||||
// GLFW 3.3 - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2006-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"
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW platform API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int _glfwPlatformPollJoystick(_GLFWjoystick* js, int mode)
|
||||
{
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
void _glfwPlatformUpdateGamepadGUID(char* guid)
|
||||
{
|
||||
}
|
||||
|
||||
31
glfw/null_joystick.h
vendored
Normal file
31
glfw/null_joystick.h
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
//========================================================================
|
||||
// GLFW 3.3 - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2006-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.
|
||||
//
|
||||
//========================================================================
|
||||
|
||||
#define _GLFW_PLATFORM_JOYSTICK_STATE int nulljs
|
||||
#define _GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE int nulljs
|
||||
|
||||
#define _GLFW_PLATFORM_MAPPING_NAME ""
|
||||
|
||||
68
glfw/null_monitor.c
vendored
Normal file
68
glfw/null_monitor.c
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
//========================================================================
|
||||
// GLFW 3.3 - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2016 Google Inc.
|
||||
// Copyright (c) 2006-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"
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW platform API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void _glfwPlatformFreeMonitor(_GLFWmonitor* monitor)
|
||||
{
|
||||
}
|
||||
|
||||
void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos)
|
||||
{
|
||||
}
|
||||
|
||||
void _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor,
|
||||
float* xscale, float* yscale)
|
||||
{
|
||||
if (xscale)
|
||||
*xscale = 1.f;
|
||||
if (yscale)
|
||||
*yscale = 1.f;
|
||||
}
|
||||
|
||||
GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* found)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode)
|
||||
{
|
||||
}
|
||||
|
||||
void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
|
||||
{
|
||||
}
|
||||
|
||||
void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp)
|
||||
{
|
||||
}
|
||||
|
||||
62
glfw/null_platform.h
vendored
Normal file
62
glfw/null_platform.h
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
//========================================================================
|
||||
// GLFW 3.3 - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2016 Google Inc.
|
||||
// Copyright (c) 2006-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 <dlfcn.h>
|
||||
|
||||
#define _GLFW_PLATFORM_WINDOW_STATE _GLFWwindowNull null
|
||||
|
||||
#define _GLFW_PLATFORM_CONTEXT_STATE
|
||||
#define _GLFW_PLATFORM_MONITOR_STATE
|
||||
#define _GLFW_PLATFORM_CURSOR_STATE
|
||||
#define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE
|
||||
#define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE
|
||||
#define _GLFW_EGL_CONTEXT_STATE
|
||||
#define _GLFW_EGL_LIBRARY_CONTEXT_STATE
|
||||
|
||||
#include "osmesa_context.h"
|
||||
#include "posix_time.h"
|
||||
#include "posix_thread.h"
|
||||
#include "null_joystick.h"
|
||||
|
||||
#if defined(_GLFW_WIN32)
|
||||
#define _glfw_dlopen(name) LoadLibraryA(name)
|
||||
#define _glfw_dlclose(handle) FreeLibrary((HMODULE) handle)
|
||||
#define _glfw_dlsym(handle, name) GetProcAddress((HMODULE) handle, name)
|
||||
#else
|
||||
#define _glfw_dlopen(name) dlopen(name, RTLD_LAZY | RTLD_LOCAL)
|
||||
#define _glfw_dlclose(handle) dlclose(handle)
|
||||
#define _glfw_dlsym(handle, name) dlsym(handle, name)
|
||||
#endif
|
||||
|
||||
// Null-specific per-window data
|
||||
//
|
||||
typedef struct _GLFWwindowNull
|
||||
{
|
||||
int width;
|
||||
int height;
|
||||
} _GLFWwindowNull;
|
||||
|
||||
330
glfw/null_window.c
vendored
Normal file
330
glfw/null_window.c
vendored
Normal file
@@ -0,0 +1,330 @@
|
||||
//========================================================================
|
||||
// GLFW 3.3 - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2016 Google Inc.
|
||||
// Copyright (c) 2006-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"
|
||||
|
||||
|
||||
static int createNativeWindow(_GLFWwindow* window,
|
||||
const _GLFWwndconfig* wndconfig)
|
||||
{
|
||||
window->null.width = wndconfig->width;
|
||||
window->null.height = wndconfig->height;
|
||||
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW platform API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int _glfwPlatformCreateWindow(_GLFWwindow* window,
|
||||
const _GLFWwndconfig* wndconfig,
|
||||
const _GLFWctxconfig* ctxconfig,
|
||||
const _GLFWfbconfig* fbconfig)
|
||||
{
|
||||
if (!createNativeWindow(window, wndconfig))
|
||||
return GLFW_FALSE;
|
||||
|
||||
if (ctxconfig->client != GLFW_NO_API)
|
||||
{
|
||||
if (ctxconfig->source == GLFW_NATIVE_CONTEXT_API ||
|
||||
ctxconfig->source == GLFW_OSMESA_CONTEXT_API)
|
||||
{
|
||||
if (!_glfwInitOSMesa())
|
||||
return GLFW_FALSE;
|
||||
if (!_glfwCreateContextOSMesa(window, ctxconfig, fbconfig))
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
_glfwInputError(GLFW_API_UNAVAILABLE, "Null: EGL not available");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
void _glfwPlatformDestroyWindow(_GLFWwindow* window)
|
||||
{
|
||||
if (window->context.destroy)
|
||||
window->context.destroy(window);
|
||||
}
|
||||
|
||||
void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title)
|
||||
{
|
||||
}
|
||||
|
||||
void _glfwPlatformSetWindowIcon(_GLFWwindow* window, int count,
|
||||
const GLFWimage* images)
|
||||
{
|
||||
}
|
||||
|
||||
void _glfwPlatformSetWindowMonitor(_GLFWwindow* window,
|
||||
_GLFWmonitor* monitor,
|
||||
int xpos, int ypos,
|
||||
int width, int height,
|
||||
int refreshRate)
|
||||
{
|
||||
}
|
||||
|
||||
void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos)
|
||||
{
|
||||
}
|
||||
|
||||
void _glfwPlatformSetWindowPos(_GLFWwindow* window, int xpos, int ypos)
|
||||
{
|
||||
}
|
||||
|
||||
void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height)
|
||||
{
|
||||
if (width)
|
||||
*width = window->null.width;
|
||||
if (height)
|
||||
*height = window->null.height;
|
||||
}
|
||||
|
||||
void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height)
|
||||
{
|
||||
window->null.width = width;
|
||||
window->null.height = height;
|
||||
}
|
||||
|
||||
void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window,
|
||||
int minwidth, int minheight,
|
||||
int maxwidth, int maxheight)
|
||||
{
|
||||
}
|
||||
|
||||
void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window, int n, int d)
|
||||
{
|
||||
}
|
||||
|
||||
void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* height)
|
||||
{
|
||||
if (width)
|
||||
*width = window->null.width;
|
||||
if (height)
|
||||
*height = window->null.height;
|
||||
}
|
||||
|
||||
void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window,
|
||||
int* left, int* top,
|
||||
int* right, int* bottom)
|
||||
{
|
||||
}
|
||||
|
||||
void _glfwPlatformGetWindowContentScale(_GLFWwindow* window,
|
||||
float* xscale, float* yscale)
|
||||
{
|
||||
if (xscale)
|
||||
*xscale = 1.f;
|
||||
if (yscale)
|
||||
*yscale = 1.f;
|
||||
}
|
||||
|
||||
double _glfwPlatformGetDoubleClickInterval(_GLFWwindow* window)
|
||||
{
|
||||
return 0.5;
|
||||
}
|
||||
|
||||
void _glfwPlatformIconifyWindow(_GLFWwindow* window)
|
||||
{
|
||||
}
|
||||
|
||||
void _glfwPlatformRestoreWindow(_GLFWwindow* window)
|
||||
{
|
||||
}
|
||||
|
||||
void _glfwPlatformMaximizeWindow(_GLFWwindow* window)
|
||||
{
|
||||
}
|
||||
|
||||
int _glfwPlatformWindowMaximized(_GLFWwindow* window)
|
||||
{
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
int _glfwPlatformWindowHovered(_GLFWwindow* window)
|
||||
{
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
int _glfwPlatformFramebufferTransparent(_GLFWwindow* window)
|
||||
{
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
void _glfwPlatformSetWindowResizable(_GLFWwindow* window, GLFWbool enabled)
|
||||
{
|
||||
}
|
||||
|
||||
void _glfwPlatformSetWindowDecorated(_GLFWwindow* window, GLFWbool enabled)
|
||||
{
|
||||
}
|
||||
|
||||
void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled)
|
||||
{
|
||||
}
|
||||
|
||||
float _glfwPlatformGetWindowOpacity(_GLFWwindow* window)
|
||||
{
|
||||
return 1.f;
|
||||
}
|
||||
|
||||
void _glfwPlatformSetWindowOpacity(_GLFWwindow* window, float opacity)
|
||||
{
|
||||
}
|
||||
|
||||
void _glfwPlatformShowWindow(_GLFWwindow* window)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void _glfwPlatformRequestWindowAttention(_GLFWwindow* window)
|
||||
{
|
||||
}
|
||||
|
||||
int _glfwPlatformWindowBell(_GLFWwindow* window)
|
||||
{
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
void _glfwPlatformUnhideWindow(_GLFWwindow* window)
|
||||
{
|
||||
}
|
||||
|
||||
void _glfwPlatformHideWindow(_GLFWwindow* window)
|
||||
{
|
||||
}
|
||||
|
||||
void _glfwPlatformFocusWindow(_GLFWwindow* window)
|
||||
{
|
||||
}
|
||||
|
||||
int _glfwPlatformWindowFocused(_GLFWwindow* window)
|
||||
{
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
int _glfwPlatformWindowIconified(_GLFWwindow* window)
|
||||
{
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
int _glfwPlatformWindowVisible(_GLFWwindow* window)
|
||||
{
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
void _glfwPlatformPollEvents(void)
|
||||
{
|
||||
}
|
||||
|
||||
void _glfwPlatformWaitEvents(void)
|
||||
{
|
||||
}
|
||||
|
||||
void _glfwPlatformWaitEventsTimeout(double timeout)
|
||||
{
|
||||
}
|
||||
|
||||
void _glfwPlatformPostEmptyEvent(void)
|
||||
{
|
||||
}
|
||||
|
||||
void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos)
|
||||
{
|
||||
}
|
||||
|
||||
void _glfwPlatformSetCursorPos(_GLFWwindow* window, double x, double y)
|
||||
{
|
||||
}
|
||||
|
||||
void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode)
|
||||
{
|
||||
}
|
||||
|
||||
int _glfwPlatformCreateCursor(_GLFWcursor* cursor,
|
||||
const GLFWimage* image,
|
||||
int xhot, int yhot, int count)
|
||||
{
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape)
|
||||
{
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
void _glfwPlatformDestroyCursor(_GLFWcursor* cursor)
|
||||
{
|
||||
}
|
||||
|
||||
void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor)
|
||||
{
|
||||
}
|
||||
|
||||
void _glfwPlatformSetClipboardString(const char* string)
|
||||
{
|
||||
}
|
||||
|
||||
const char* _glfwPlatformGetClipboardString(void)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char* _glfwPlatformGetScancodeName(int scancode)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
int _glfwPlatformGetKeyScancode(int key)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
void _glfwPlatformGetRequiredInstanceExtensions(char** extensions)
|
||||
{
|
||||
}
|
||||
|
||||
int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance,
|
||||
VkPhysicalDevice device,
|
||||
uint32_t queuefamily)
|
||||
{
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
VkResult _glfwPlatformCreateWindowSurface(VkInstance instance,
|
||||
_GLFWwindow* window,
|
||||
const VkAllocationCallbacks* allocator,
|
||||
VkSurfaceKHR* surface)
|
||||
{
|
||||
// This seems like the most appropriate error to return here
|
||||
return VK_ERROR_INITIALIZATION_FAILED;
|
||||
}
|
||||
370
glfw/osmesa_context.c
vendored
Normal file
370
glfw/osmesa_context.c
vendored
Normal file
@@ -0,0 +1,370 @@
|
||||
//========================================================================
|
||||
// GLFW 3.3 OSMesa - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2016 Google Inc.
|
||||
// Copyright (c) 2006-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 <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
|
||||
static void makeContextCurrentOSMesa(_GLFWwindow* window)
|
||||
{
|
||||
if (window)
|
||||
{
|
||||
int width, height;
|
||||
_glfwPlatformGetFramebufferSize(window, &width, &height);
|
||||
|
||||
// Check to see if we need to allocate a new buffer
|
||||
if ((window->context.osmesa.buffer == NULL) ||
|
||||
(width != window->context.osmesa.width) ||
|
||||
(height != window->context.osmesa.height))
|
||||
{
|
||||
free(window->context.osmesa.buffer);
|
||||
|
||||
// Allocate the new buffer (width * height * 8-bit RGBA)
|
||||
window->context.osmesa.buffer = calloc(4, width * height);
|
||||
window->context.osmesa.width = width;
|
||||
window->context.osmesa.height = height;
|
||||
}
|
||||
|
||||
if (!OSMesaMakeCurrent(window->context.osmesa.handle,
|
||||
window->context.osmesa.buffer,
|
||||
GL_UNSIGNED_BYTE,
|
||||
width, height))
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"OSMesa: Failed to make context current");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
_glfwPlatformSetTls(&_glfw.contextSlot, window);
|
||||
}
|
||||
|
||||
static GLFWglproc getProcAddressOSMesa(const char* procname)
|
||||
{
|
||||
return (GLFWglproc) OSMesaGetProcAddress(procname);
|
||||
}
|
||||
|
||||
static void destroyContextOSMesa(_GLFWwindow* window)
|
||||
{
|
||||
if (window->context.osmesa.handle)
|
||||
{
|
||||
OSMesaDestroyContext(window->context.osmesa.handle);
|
||||
window->context.osmesa.handle = NULL;
|
||||
}
|
||||
|
||||
if (window->context.osmesa.buffer)
|
||||
{
|
||||
free(window->context.osmesa.buffer);
|
||||
window->context.osmesa.width = 0;
|
||||
window->context.osmesa.height = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void swapBuffersOSMesa(_GLFWwindow* window)
|
||||
{
|
||||
// No double buffering on OSMesa
|
||||
}
|
||||
|
||||
static void swapIntervalOSMesa(int interval)
|
||||
{
|
||||
// No swap interval on OSMesa
|
||||
}
|
||||
|
||||
static int extensionSupportedOSMesa(const char* extension)
|
||||
{
|
||||
// OSMesa does not have extensions
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW internal API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
GLFWbool _glfwInitOSMesa(void)
|
||||
{
|
||||
int i;
|
||||
const char* sonames[] =
|
||||
{
|
||||
#if defined(_GLFW_OSMESA_LIBRARY)
|
||||
_GLFW_OSMESA_LIBRARY,
|
||||
#elif defined(_WIN32)
|
||||
"libOSMesa.dll",
|
||||
"OSMesa.dll",
|
||||
#elif defined(__APPLE__)
|
||||
"libOSMesa.8.dylib",
|
||||
#elif defined(__CYGWIN__)
|
||||
"libOSMesa-8.so",
|
||||
#else
|
||||
"libOSMesa.so.8",
|
||||
"libOSMesa.so.6",
|
||||
#endif
|
||||
NULL
|
||||
};
|
||||
|
||||
if (_glfw.osmesa.handle)
|
||||
return GLFW_TRUE;
|
||||
|
||||
for (i = 0; sonames[i]; i++)
|
||||
{
|
||||
_glfw.osmesa.handle = _glfw_dlopen(sonames[i]);
|
||||
if (_glfw.osmesa.handle)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!_glfw.osmesa.handle)
|
||||
{
|
||||
_glfwInputError(GLFW_API_UNAVAILABLE, "OSMesa: Library not found");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
_glfw.osmesa.CreateContextExt = (PFN_OSMesaCreateContextExt)
|
||||
_glfw_dlsym(_glfw.osmesa.handle, "OSMesaCreateContextExt");
|
||||
_glfw.osmesa.CreateContextAttribs = (PFN_OSMesaCreateContextAttribs)
|
||||
_glfw_dlsym(_glfw.osmesa.handle, "OSMesaCreateContextAttribs");
|
||||
_glfw.osmesa.DestroyContext = (PFN_OSMesaDestroyContext)
|
||||
_glfw_dlsym(_glfw.osmesa.handle, "OSMesaDestroyContext");
|
||||
_glfw.osmesa.MakeCurrent = (PFN_OSMesaMakeCurrent)
|
||||
_glfw_dlsym(_glfw.osmesa.handle, "OSMesaMakeCurrent");
|
||||
_glfw.osmesa.GetColorBuffer = (PFN_OSMesaGetColorBuffer)
|
||||
_glfw_dlsym(_glfw.osmesa.handle, "OSMesaGetColorBuffer");
|
||||
_glfw.osmesa.GetDepthBuffer = (PFN_OSMesaGetDepthBuffer)
|
||||
_glfw_dlsym(_glfw.osmesa.handle, "OSMesaGetDepthBuffer");
|
||||
_glfw.osmesa.GetProcAddress = (PFN_OSMesaGetProcAddress)
|
||||
_glfw_dlsym(_glfw.osmesa.handle, "OSMesaGetProcAddress");
|
||||
|
||||
if (!_glfw.osmesa.CreateContextExt ||
|
||||
!_glfw.osmesa.DestroyContext ||
|
||||
!_glfw.osmesa.MakeCurrent ||
|
||||
!_glfw.osmesa.GetColorBuffer ||
|
||||
!_glfw.osmesa.GetDepthBuffer ||
|
||||
!_glfw.osmesa.GetProcAddress)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"OSMesa: Failed to load required entry points");
|
||||
|
||||
_glfwTerminateOSMesa();
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
void _glfwTerminateOSMesa(void)
|
||||
{
|
||||
if (_glfw.osmesa.handle)
|
||||
{
|
||||
_glfw_dlclose(_glfw.osmesa.handle);
|
||||
_glfw.osmesa.handle = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#define setAttrib(a, v) \
|
||||
{ \
|
||||
assert((size_t) (index + 1) < sizeof(attribs) / sizeof(attribs[0])); \
|
||||
attribs[index++] = a; \
|
||||
attribs[index++] = v; \
|
||||
}
|
||||
|
||||
GLFWbool _glfwCreateContextOSMesa(_GLFWwindow* window,
|
||||
const _GLFWctxconfig* ctxconfig,
|
||||
const _GLFWfbconfig* fbconfig)
|
||||
{
|
||||
OSMesaContext share = NULL;
|
||||
const int accumBits = fbconfig->accumRedBits +
|
||||
fbconfig->accumGreenBits +
|
||||
fbconfig->accumBlueBits +
|
||||
fbconfig->accumAlphaBits;
|
||||
|
||||
if (ctxconfig->client == GLFW_OPENGL_ES_API)
|
||||
{
|
||||
_glfwInputError(GLFW_API_UNAVAILABLE,
|
||||
"OSMesa: OpenGL ES is not available on OSMesa");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
if (ctxconfig->share)
|
||||
share = ctxconfig->share->context.osmesa.handle;
|
||||
|
||||
if (OSMesaCreateContextAttribs)
|
||||
{
|
||||
int index = 0, attribs[40];
|
||||
|
||||
setAttrib(OSMESA_FORMAT, OSMESA_RGBA);
|
||||
setAttrib(OSMESA_DEPTH_BITS, fbconfig->depthBits);
|
||||
setAttrib(OSMESA_STENCIL_BITS, fbconfig->stencilBits);
|
||||
setAttrib(OSMESA_ACCUM_BITS, accumBits);
|
||||
|
||||
if (ctxconfig->profile == GLFW_OPENGL_CORE_PROFILE)
|
||||
{
|
||||
setAttrib(OSMESA_PROFILE, OSMESA_CORE_PROFILE);
|
||||
}
|
||||
else if (ctxconfig->profile == GLFW_OPENGL_COMPAT_PROFILE)
|
||||
{
|
||||
setAttrib(OSMESA_PROFILE, OSMESA_COMPAT_PROFILE);
|
||||
}
|
||||
|
||||
if (ctxconfig->major != 1 || ctxconfig->minor != 0)
|
||||
{
|
||||
setAttrib(OSMESA_CONTEXT_MAJOR_VERSION, ctxconfig->major);
|
||||
setAttrib(OSMESA_CONTEXT_MINOR_VERSION, ctxconfig->minor);
|
||||
}
|
||||
|
||||
if (ctxconfig->forward)
|
||||
{
|
||||
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
|
||||
"OSMesa: Foward-compatible contexts not supported");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
setAttrib(0, 0);
|
||||
|
||||
window->context.osmesa.handle =
|
||||
OSMesaCreateContextAttribs(attribs, share);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ctxconfig->profile)
|
||||
{
|
||||
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
|
||||
"OSMesa: OpenGL profiles unavailable");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
window->context.osmesa.handle =
|
||||
OSMesaCreateContextExt(OSMESA_RGBA,
|
||||
fbconfig->depthBits,
|
||||
fbconfig->stencilBits,
|
||||
accumBits,
|
||||
share);
|
||||
}
|
||||
|
||||
if (window->context.osmesa.handle == NULL)
|
||||
{
|
||||
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
|
||||
"OSMesa: Failed to create context");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
window->context.makeCurrent = makeContextCurrentOSMesa;
|
||||
window->context.swapBuffers = swapBuffersOSMesa;
|
||||
window->context.swapInterval = swapIntervalOSMesa;
|
||||
window->context.extensionSupported = extensionSupportedOSMesa;
|
||||
window->context.getProcAddress = getProcAddressOSMesa;
|
||||
window->context.destroy = destroyContextOSMesa;
|
||||
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
#undef setAttrib
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW native API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
GLFWAPI int glfwGetOSMesaColorBuffer(GLFWwindow* handle, int* width,
|
||||
int* height, int* format, void** buffer)
|
||||
{
|
||||
void* mesaBuffer;
|
||||
GLint mesaWidth, mesaHeight, mesaFormat;
|
||||
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||
assert(window != NULL);
|
||||
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE);
|
||||
|
||||
if (!OSMesaGetColorBuffer(window->context.osmesa.handle,
|
||||
&mesaWidth, &mesaHeight,
|
||||
&mesaFormat, &mesaBuffer))
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"OSMesa: Failed to retrieve color buffer");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
if (width)
|
||||
*width = mesaWidth;
|
||||
if (height)
|
||||
*height = mesaHeight;
|
||||
if (format)
|
||||
*format = mesaFormat;
|
||||
if (buffer)
|
||||
*buffer = mesaBuffer;
|
||||
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
GLFWAPI int glfwGetOSMesaDepthBuffer(GLFWwindow* handle,
|
||||
int* width, int* height,
|
||||
int* bytesPerValue,
|
||||
void** buffer)
|
||||
{
|
||||
void* mesaBuffer;
|
||||
GLint mesaWidth, mesaHeight, mesaBytes;
|
||||
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||
assert(window != NULL);
|
||||
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE);
|
||||
|
||||
if (!OSMesaGetDepthBuffer(window->context.osmesa.handle,
|
||||
&mesaWidth, &mesaHeight,
|
||||
&mesaBytes, &mesaBuffer))
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"OSMesa: Failed to retrieve depth buffer");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
if (width)
|
||||
*width = mesaWidth;
|
||||
if (height)
|
||||
*height = mesaHeight;
|
||||
if (bytesPerValue)
|
||||
*bytesPerValue = mesaBytes;
|
||||
if (buffer)
|
||||
*buffer = mesaBuffer;
|
||||
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
GLFWAPI OSMesaContext glfwGetOSMesaContext(GLFWwindow* handle)
|
||||
{
|
||||
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||
|
||||
if (window->context.client == GLFW_NO_API)
|
||||
{
|
||||
_glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return window->context.osmesa.handle;
|
||||
}
|
||||
|
||||
94
glfw/osmesa_context.h
vendored
Normal file
94
glfw/osmesa_context.h
vendored
Normal file
@@ -0,0 +1,94 @@
|
||||
//========================================================================
|
||||
// GLFW 3.3 OSMesa - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2016 Google Inc.
|
||||
// Copyright (c) 2006-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.
|
||||
//
|
||||
//========================================================================
|
||||
|
||||
#define OSMESA_RGBA 0x1908
|
||||
#define OSMESA_FORMAT 0x22
|
||||
#define OSMESA_DEPTH_BITS 0x30
|
||||
#define OSMESA_STENCIL_BITS 0x31
|
||||
#define OSMESA_ACCUM_BITS 0x32
|
||||
#define OSMESA_PROFILE 0x33
|
||||
#define OSMESA_CORE_PROFILE 0x34
|
||||
#define OSMESA_COMPAT_PROFILE 0x35
|
||||
#define OSMESA_CONTEXT_MAJOR_VERSION 0x36
|
||||
#define OSMESA_CONTEXT_MINOR_VERSION 0x37
|
||||
|
||||
typedef void* OSMesaContext;
|
||||
typedef void (*OSMESAproc)(void);
|
||||
|
||||
typedef OSMesaContext (GLAPIENTRY * PFN_OSMesaCreateContextExt)(GLenum,GLint,GLint,GLint,OSMesaContext);
|
||||
typedef OSMesaContext (GLAPIENTRY * PFN_OSMesaCreateContextAttribs)(const int*,OSMesaContext);
|
||||
typedef void (GLAPIENTRY * PFN_OSMesaDestroyContext)(OSMesaContext);
|
||||
typedef int (GLAPIENTRY * PFN_OSMesaMakeCurrent)(OSMesaContext,void*,int,int,int);
|
||||
typedef int (GLAPIENTRY * PFN_OSMesaGetColorBuffer)(OSMesaContext,int*,int*,int*,void**);
|
||||
typedef int (GLAPIENTRY * PFN_OSMesaGetDepthBuffer)(OSMesaContext,int*,int*,int*,void**);
|
||||
typedef GLFWglproc (GLAPIENTRY * PFN_OSMesaGetProcAddress)(const char*);
|
||||
#define OSMesaCreateContextExt _glfw.osmesa.CreateContextExt
|
||||
#define OSMesaCreateContextAttribs _glfw.osmesa.CreateContextAttribs
|
||||
#define OSMesaDestroyContext _glfw.osmesa.DestroyContext
|
||||
#define OSMesaMakeCurrent _glfw.osmesa.MakeCurrent
|
||||
#define OSMesaGetColorBuffer _glfw.osmesa.GetColorBuffer
|
||||
#define OSMesaGetDepthBuffer _glfw.osmesa.GetDepthBuffer
|
||||
#define OSMesaGetProcAddress _glfw.osmesa.GetProcAddress
|
||||
|
||||
#define _GLFW_OSMESA_CONTEXT_STATE _GLFWcontextOSMesa osmesa
|
||||
#define _GLFW_OSMESA_LIBRARY_CONTEXT_STATE _GLFWlibraryOSMesa osmesa
|
||||
|
||||
|
||||
// OSMesa-specific per-context data
|
||||
//
|
||||
typedef struct _GLFWcontextOSMesa
|
||||
{
|
||||
OSMesaContext handle;
|
||||
int width;
|
||||
int height;
|
||||
void* buffer;
|
||||
|
||||
} _GLFWcontextOSMesa;
|
||||
|
||||
// OSMesa-specific global data
|
||||
//
|
||||
typedef struct _GLFWlibraryOSMesa
|
||||
{
|
||||
void* handle;
|
||||
|
||||
PFN_OSMesaCreateContextExt CreateContextExt;
|
||||
PFN_OSMesaCreateContextAttribs CreateContextAttribs;
|
||||
PFN_OSMesaDestroyContext DestroyContext;
|
||||
PFN_OSMesaMakeCurrent MakeCurrent;
|
||||
PFN_OSMesaGetColorBuffer GetColorBuffer;
|
||||
PFN_OSMesaGetDepthBuffer GetDepthBuffer;
|
||||
PFN_OSMesaGetProcAddress GetProcAddress;
|
||||
|
||||
} _GLFWlibraryOSMesa;
|
||||
|
||||
|
||||
GLFWbool _glfwInitOSMesa(void);
|
||||
void _glfwTerminateOSMesa(void);
|
||||
GLFWbool _glfwCreateContextOSMesa(_GLFWwindow* window,
|
||||
const _GLFWctxconfig* ctxconfig,
|
||||
const _GLFWfbconfig* fbconfig);
|
||||
|
||||
103
glfw/posix_thread.c
vendored
Normal file
103
glfw/posix_thread.c
vendored
Normal file
@@ -0,0 +1,103 @@
|
||||
//========================================================================
|
||||
// GLFW 3.3 POSIX - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||
// Copyright (c) 2006-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 <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW platform API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
GLFWbool _glfwPlatformCreateTls(_GLFWtls* tls)
|
||||
{
|
||||
assert(tls->posix.allocated == GLFW_FALSE);
|
||||
|
||||
if (pthread_key_create(&tls->posix.key, NULL) != 0)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"POSIX: Failed to create context TLS");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
tls->posix.allocated = GLFW_TRUE;
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
void _glfwPlatformDestroyTls(_GLFWtls* tls)
|
||||
{
|
||||
if (tls->posix.allocated)
|
||||
pthread_key_delete(tls->posix.key);
|
||||
memset(tls, 0, sizeof(_GLFWtls));
|
||||
}
|
||||
|
||||
void* _glfwPlatformGetTls(_GLFWtls* tls)
|
||||
{
|
||||
assert(tls->posix.allocated == GLFW_TRUE);
|
||||
return pthread_getspecific(tls->posix.key);
|
||||
}
|
||||
|
||||
void _glfwPlatformSetTls(_GLFWtls* tls, void* value)
|
||||
{
|
||||
assert(tls->posix.allocated == GLFW_TRUE);
|
||||
pthread_setspecific(tls->posix.key, value);
|
||||
}
|
||||
|
||||
GLFWbool _glfwPlatformCreateMutex(_GLFWmutex* mutex)
|
||||
{
|
||||
assert(mutex->posix.allocated == GLFW_FALSE);
|
||||
|
||||
if (pthread_mutex_init(&mutex->posix.handle, NULL) != 0)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR, "POSIX: Failed to create mutex");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
return mutex->posix.allocated = GLFW_TRUE;
|
||||
}
|
||||
|
||||
void _glfwPlatformDestroyMutex(_GLFWmutex* mutex)
|
||||
{
|
||||
if (mutex->posix.allocated)
|
||||
pthread_mutex_destroy(&mutex->posix.handle);
|
||||
memset(mutex, 0, sizeof(_GLFWmutex));
|
||||
}
|
||||
|
||||
void _glfwPlatformLockMutex(_GLFWmutex* mutex)
|
||||
{
|
||||
assert(mutex->posix.allocated == GLFW_TRUE);
|
||||
pthread_mutex_lock(&mutex->posix.handle);
|
||||
}
|
||||
|
||||
void _glfwPlatformUnlockMutex(_GLFWmutex* mutex)
|
||||
{
|
||||
assert(mutex->posix.allocated == GLFW_TRUE);
|
||||
pthread_mutex_unlock(&mutex->posix.handle);
|
||||
}
|
||||
|
||||
51
glfw/posix_thread.h
vendored
Normal file
51
glfw/posix_thread.h
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
//========================================================================
|
||||
// GLFW 3.3 POSIX - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||
// Copyright (c) 2006-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 <pthread.h>
|
||||
|
||||
#define _GLFW_PLATFORM_TLS_STATE _GLFWtlsPOSIX posix
|
||||
#define _GLFW_PLATFORM_MUTEX_STATE _GLFWmutexPOSIX posix
|
||||
|
||||
|
||||
// POSIX-specific thread local storage data
|
||||
//
|
||||
typedef struct _GLFWtlsPOSIX
|
||||
{
|
||||
GLFWbool allocated;
|
||||
pthread_key_t key;
|
||||
|
||||
} _GLFWtlsPOSIX;
|
||||
|
||||
// POSIX-specific mutex data
|
||||
//
|
||||
typedef struct _GLFWmutexPOSIX
|
||||
{
|
||||
GLFWbool allocated;
|
||||
pthread_mutex_t handle;
|
||||
|
||||
} _GLFWmutexPOSIX;
|
||||
|
||||
85
glfw/posix_time.c
vendored
Normal file
85
glfw/posix_time.c
vendored
Normal file
@@ -0,0 +1,85 @@
|
||||
//========================================================================
|
||||
// GLFW 3.3 POSIX - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||
// Copyright (c) 2006-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 <sys/time.h>
|
||||
#include <time.h>
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW internal API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Initialise timer
|
||||
//
|
||||
void _glfwInitTimerPOSIX(void)
|
||||
{
|
||||
#if defined(CLOCK_MONOTONIC)
|
||||
struct timespec ts;
|
||||
|
||||
if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0)
|
||||
{
|
||||
_glfw.timer.posix.monotonic = GLFW_TRUE;
|
||||
_glfw.timer.posix.frequency = 1000000000;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
_glfw.timer.posix.monotonic = GLFW_FALSE;
|
||||
_glfw.timer.posix.frequency = 1000000;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW platform API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
uint64_t _glfwPlatformGetTimerValue(void)
|
||||
{
|
||||
#if defined(CLOCK_MONOTONIC)
|
||||
if (_glfw.timer.posix.monotonic)
|
||||
{
|
||||
struct timespec ts;
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
return (uint64_t) ts.tv_sec * (uint64_t) 1000000000 + (uint64_t) ts.tv_nsec;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
return (uint64_t) tv.tv_sec * (uint64_t) 1000000 + (uint64_t) tv.tv_usec;
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t _glfwPlatformGetTimerFrequency(void)
|
||||
{
|
||||
return _glfw.timer.posix.frequency;
|
||||
}
|
||||
|
||||
44
glfw/posix_time.h
vendored
Normal file
44
glfw/posix_time.h
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
//========================================================================
|
||||
// GLFW 3.3 POSIX - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||
// Copyright (c) 2006-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.
|
||||
//
|
||||
//========================================================================
|
||||
|
||||
#define _GLFW_PLATFORM_LIBRARY_TIMER_STATE _GLFWtimerPOSIX posix
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
// POSIX-specific global timer data
|
||||
//
|
||||
typedef struct _GLFWtimerPOSIX
|
||||
{
|
||||
GLFWbool monotonic;
|
||||
uint64_t frequency;
|
||||
|
||||
} _GLFWtimerPOSIX;
|
||||
|
||||
|
||||
void _glfwInitTimerPOSIX(void);
|
||||
|
||||
150
glfw/source-info.json
Normal file
150
glfw/source-info.json
Normal file
@@ -0,0 +1,150 @@
|
||||
{
|
||||
"cocoa": {
|
||||
"headers": [
|
||||
"cocoa_platform.h",
|
||||
"cocoa_joystick.h",
|
||||
"posix_thread.h",
|
||||
"nsgl_context.h",
|
||||
"egl_context.h",
|
||||
"osmesa_context.h"
|
||||
],
|
||||
"sources": [
|
||||
"cocoa_init.m",
|
||||
"cocoa_joystick.m",
|
||||
"cocoa_monitor.m",
|
||||
"cocoa_window.m",
|
||||
"cocoa_time.c",
|
||||
"posix_thread.c",
|
||||
"nsgl_context.m",
|
||||
"egl_context.c",
|
||||
"osmesa_context.c"
|
||||
]
|
||||
},
|
||||
"common": {
|
||||
"headers": [
|
||||
"internal.h",
|
||||
"mappings.h"
|
||||
],
|
||||
"sources": [
|
||||
"context.c",
|
||||
"init.c",
|
||||
"input.c",
|
||||
"monitor.c",
|
||||
"vulkan.c",
|
||||
"window.c"
|
||||
]
|
||||
},
|
||||
"osmesa": {
|
||||
"headers": [
|
||||
"null_platform.h",
|
||||
"null_joystick.h",
|
||||
"posix_time.h",
|
||||
"posix_thread.h",
|
||||
"osmesa_context.h"
|
||||
],
|
||||
"sources": [
|
||||
"null_init.c",
|
||||
"null_monitor.c",
|
||||
"null_window.c",
|
||||
"null_joystick.c",
|
||||
"posix_time.c",
|
||||
"posix_thread.c",
|
||||
"osmesa_context.c"
|
||||
]
|
||||
},
|
||||
"wayland": {
|
||||
"headers": [
|
||||
"wl_platform.h",
|
||||
"posix_time.h",
|
||||
"posix_thread.h",
|
||||
"xkb_glfw.h",
|
||||
"dbus_glfw.h",
|
||||
"ibus_glfw.h",
|
||||
"backend_utils.h",
|
||||
"egl_context.h",
|
||||
"osmesa_context.h",
|
||||
"linux_joystick.h",
|
||||
"null_joystick.h"
|
||||
],
|
||||
"protocols": [
|
||||
"stable/xdg-shell/xdg-shell.xml",
|
||||
"stable/viewporter/viewporter.xml",
|
||||
"unstable/relative-pointer/relative-pointer-unstable-v1.xml",
|
||||
"unstable/pointer-constraints/pointer-constraints-unstable-v1.xml",
|
||||
"unstable/idle-inhibit/idle-inhibit-unstable-v1.xml",
|
||||
"unstable/xdg-decoration/xdg-decoration-unstable-v1.xml",
|
||||
"unstable/primary-selection/primary-selection-unstable-v1.xml"
|
||||
],
|
||||
"sources": [
|
||||
"wl_init.c",
|
||||
"wl_monitor.c",
|
||||
"wl_window.c",
|
||||
"posix_time.c",
|
||||
"posix_thread.c",
|
||||
"xkb_glfw.c",
|
||||
"dbus_glfw.c",
|
||||
"ibus_glfw.c",
|
||||
"egl_context.c",
|
||||
"osmesa_context.c",
|
||||
"backend_utils.c",
|
||||
"linux_joystick.c",
|
||||
"null_joystick.c"
|
||||
]
|
||||
},
|
||||
"wayland_protocols": [
|
||||
1,
|
||||
17
|
||||
],
|
||||
"win32": {
|
||||
"headers": [
|
||||
"win32_platform.h",
|
||||
"win32_joystick.h",
|
||||
"wgl_context.h",
|
||||
"egl_context.h",
|
||||
"osmesa_context.h"
|
||||
],
|
||||
"sources": [
|
||||
"win32_init.c",
|
||||
"win32_joystick.c",
|
||||
"win32_monitor.c",
|
||||
"win32_time.c",
|
||||
"win32_thread.c",
|
||||
"win32_window.c",
|
||||
"wgl_context.c",
|
||||
"egl_context.c",
|
||||
"osmesa_context.c"
|
||||
]
|
||||
},
|
||||
"x11": {
|
||||
"headers": [
|
||||
"x11_platform.h",
|
||||
"xkb_glfw.h",
|
||||
"dbus_glfw.h",
|
||||
"ibus_glfw.h",
|
||||
"backend_utils.h",
|
||||
"posix_time.h",
|
||||
"posix_thread.h",
|
||||
"glx_context.h",
|
||||
"egl_context.h",
|
||||
"osmesa_context.h",
|
||||
"linux_joystick.h",
|
||||
"null_joystick.h"
|
||||
],
|
||||
"sources": [
|
||||
"x11_init.c",
|
||||
"x11_monitor.c",
|
||||
"x11_window.c",
|
||||
"xkb_glfw.c",
|
||||
"dbus_glfw.c",
|
||||
"ibus_glfw.c",
|
||||
"posix_time.c",
|
||||
"posix_thread.c",
|
||||
"glx_context.c",
|
||||
"egl_context.c",
|
||||
"osmesa_context.c",
|
||||
"backend_utils.c",
|
||||
"linux_joystick.c",
|
||||
"null_joystick.c"
|
||||
]
|
||||
}
|
||||
}
|
||||
325
glfw/vulkan.c
vendored
Normal file
325
glfw/vulkan.c
vendored
Normal file
@@ -0,0 +1,325 @@
|
||||
//========================================================================
|
||||
// GLFW 3.3 - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||
// Copyright (c) 2006-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 <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define _GLFW_FIND_LOADER 1
|
||||
#define _GLFW_REQUIRE_LOADER 2
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW internal API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
GLFWbool _glfwInitVulkan(int mode)
|
||||
{
|
||||
VkResult err;
|
||||
VkExtensionProperties* ep;
|
||||
uint32_t i, count;
|
||||
|
||||
if (_glfw.vk.available)
|
||||
return GLFW_TRUE;
|
||||
|
||||
#if !defined(_GLFW_VULKAN_STATIC)
|
||||
#if defined(_GLFW_VULKAN_LIBRARY)
|
||||
_glfw.vk.handle = _glfw_dlopen(_GLFW_VULKAN_LIBRARY);
|
||||
#elif defined(_GLFW_WIN32)
|
||||
_glfw.vk.handle = _glfw_dlopen("vulkan-1.dll");
|
||||
#elif defined(_GLFW_COCOA)
|
||||
_glfw.vk.handle = _glfw_dlopen("libvulkan.1.dylib");
|
||||
#else
|
||||
_glfw.vk.handle = _glfw_dlopen("libvulkan.so.1");
|
||||
#endif
|
||||
if (!_glfw.vk.handle)
|
||||
{
|
||||
if (mode == _GLFW_REQUIRE_LOADER)
|
||||
_glfwInputError(GLFW_API_UNAVAILABLE, "Vulkan: Loader not found");
|
||||
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
_glfw.vk.GetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)
|
||||
_glfw_dlsym(_glfw.vk.handle, "vkGetInstanceProcAddr");
|
||||
if (!_glfw.vk.GetInstanceProcAddr)
|
||||
{
|
||||
_glfwInputError(GLFW_API_UNAVAILABLE,
|
||||
"Vulkan: Loader does not export vkGetInstanceProcAddr");
|
||||
|
||||
_glfwTerminateVulkan();
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
_glfw.vk.EnumerateInstanceExtensionProperties = (PFN_vkEnumerateInstanceExtensionProperties)
|
||||
vkGetInstanceProcAddr(NULL, "vkEnumerateInstanceExtensionProperties");
|
||||
if (!_glfw.vk.EnumerateInstanceExtensionProperties)
|
||||
{
|
||||
_glfwInputError(GLFW_API_UNAVAILABLE,
|
||||
"Vulkan: Failed to retrieve vkEnumerateInstanceExtensionProperties");
|
||||
|
||||
_glfwTerminateVulkan();
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
#endif // _GLFW_VULKAN_STATIC
|
||||
|
||||
err = vkEnumerateInstanceExtensionProperties(NULL, &count, NULL);
|
||||
if (err)
|
||||
{
|
||||
// NOTE: This happens on systems with a loader but without any Vulkan ICD
|
||||
if (mode == _GLFW_REQUIRE_LOADER)
|
||||
{
|
||||
_glfwInputError(GLFW_API_UNAVAILABLE,
|
||||
"Vulkan: Failed to query instance extension count: %s",
|
||||
_glfwGetVulkanResultString(err));
|
||||
}
|
||||
|
||||
_glfwTerminateVulkan();
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
ep = calloc(count, sizeof(VkExtensionProperties));
|
||||
|
||||
err = vkEnumerateInstanceExtensionProperties(NULL, &count, ep);
|
||||
if (err)
|
||||
{
|
||||
_glfwInputError(GLFW_API_UNAVAILABLE,
|
||||
"Vulkan: Failed to query instance extensions: %s",
|
||||
_glfwGetVulkanResultString(err));
|
||||
|
||||
free(ep);
|
||||
_glfwTerminateVulkan();
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
if (strcmp(ep[i].extensionName, "VK_KHR_surface") == 0)
|
||||
_glfw.vk.KHR_surface = GLFW_TRUE;
|
||||
#if defined(_GLFW_WIN32)
|
||||
else if (strcmp(ep[i].extensionName, "VK_KHR_win32_surface") == 0)
|
||||
_glfw.vk.KHR_win32_surface = GLFW_TRUE;
|
||||
#elif defined(_GLFW_COCOA)
|
||||
else if (strcmp(ep[i].extensionName, "VK_MVK_macos_surface") == 0)
|
||||
_glfw.vk.MVK_macos_surface = GLFW_TRUE;
|
||||
#elif defined(_GLFW_X11)
|
||||
else if (strcmp(ep[i].extensionName, "VK_KHR_xlib_surface") == 0)
|
||||
_glfw.vk.KHR_xlib_surface = GLFW_TRUE;
|
||||
else if (strcmp(ep[i].extensionName, "VK_KHR_xcb_surface") == 0)
|
||||
_glfw.vk.KHR_xcb_surface = GLFW_TRUE;
|
||||
#elif defined(_GLFW_WAYLAND)
|
||||
else if (strcmp(ep[i].extensionName, "VK_KHR_wayland_surface") == 0)
|
||||
_glfw.vk.KHR_wayland_surface = GLFW_TRUE;
|
||||
#endif
|
||||
}
|
||||
|
||||
free(ep);
|
||||
|
||||
_glfw.vk.available = GLFW_TRUE;
|
||||
|
||||
_glfwPlatformGetRequiredInstanceExtensions(_glfw.vk.extensions);
|
||||
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
void _glfwTerminateVulkan(void)
|
||||
{
|
||||
#if !defined(_GLFW_VULKAN_STATIC)
|
||||
if (_glfw.vk.handle)
|
||||
_glfw_dlclose(_glfw.vk.handle);
|
||||
#endif
|
||||
}
|
||||
|
||||
const char* _glfwGetVulkanResultString(VkResult result)
|
||||
{
|
||||
switch (result)
|
||||
{
|
||||
case VK_SUCCESS:
|
||||
return "Success";
|
||||
case VK_NOT_READY:
|
||||
return "A fence or query has not yet completed";
|
||||
case VK_TIMEOUT:
|
||||
return "A wait operation has not completed in the specified time";
|
||||
case VK_EVENT_SET:
|
||||
return "An event is signaled";
|
||||
case VK_EVENT_RESET:
|
||||
return "An event is unsignaled";
|
||||
case VK_INCOMPLETE:
|
||||
return "A return array was too small for the result";
|
||||
case VK_ERROR_OUT_OF_HOST_MEMORY:
|
||||
return "A host memory allocation has failed";
|
||||
case VK_ERROR_OUT_OF_DEVICE_MEMORY:
|
||||
return "A device memory allocation has failed";
|
||||
case VK_ERROR_INITIALIZATION_FAILED:
|
||||
return "Initialization of an object could not be completed for implementation-specific reasons";
|
||||
case VK_ERROR_DEVICE_LOST:
|
||||
return "The logical or physical device has been lost";
|
||||
case VK_ERROR_MEMORY_MAP_FAILED:
|
||||
return "Mapping of a memory object has failed";
|
||||
case VK_ERROR_LAYER_NOT_PRESENT:
|
||||
return "A requested layer is not present or could not be loaded";
|
||||
case VK_ERROR_EXTENSION_NOT_PRESENT:
|
||||
return "A requested extension is not supported";
|
||||
case VK_ERROR_FEATURE_NOT_PRESENT:
|
||||
return "A requested feature is not supported";
|
||||
case VK_ERROR_INCOMPATIBLE_DRIVER:
|
||||
return "The requested version of Vulkan is not supported by the driver or is otherwise incompatible";
|
||||
case VK_ERROR_TOO_MANY_OBJECTS:
|
||||
return "Too many objects of the type have already been created";
|
||||
case VK_ERROR_FORMAT_NOT_SUPPORTED:
|
||||
return "A requested format is not supported on this device";
|
||||
case VK_ERROR_SURFACE_LOST_KHR:
|
||||
return "A surface is no longer available";
|
||||
case VK_SUBOPTIMAL_KHR:
|
||||
return "A swapchain no longer matches the surface properties exactly, but can still be used";
|
||||
case VK_ERROR_OUT_OF_DATE_KHR:
|
||||
return "A surface has changed in such a way that it is no longer compatible with the swapchain";
|
||||
case VK_ERROR_INCOMPATIBLE_DISPLAY_KHR:
|
||||
return "The display used by a swapchain does not use the same presentable image layout";
|
||||
case VK_ERROR_NATIVE_WINDOW_IN_USE_KHR:
|
||||
return "The requested window is already connected to a VkSurfaceKHR, or to some other non-Vulkan API";
|
||||
case VK_ERROR_VALIDATION_FAILED_EXT:
|
||||
return "A validation layer found an error";
|
||||
default:
|
||||
return "ERROR: UNKNOWN VULKAN ERROR";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW public API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
GLFWAPI int glfwVulkanSupported(void)
|
||||
{
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE);
|
||||
return _glfwInitVulkan(_GLFW_FIND_LOADER);
|
||||
}
|
||||
|
||||
GLFWAPI const char** glfwGetRequiredInstanceExtensions(uint32_t* count)
|
||||
{
|
||||
assert(count != NULL);
|
||||
|
||||
*count = 0;
|
||||
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||
|
||||
if (!_glfwInitVulkan(_GLFW_REQUIRE_LOADER))
|
||||
return NULL;
|
||||
|
||||
if (!_glfw.vk.extensions[0])
|
||||
return NULL;
|
||||
|
||||
*count = 2;
|
||||
return (const char**) _glfw.vk.extensions;
|
||||
}
|
||||
|
||||
GLFWAPI GLFWvkproc glfwGetInstanceProcAddress(VkInstance instance,
|
||||
const char* procname)
|
||||
{
|
||||
GLFWvkproc proc;
|
||||
assert(procname != NULL);
|
||||
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||
|
||||
if (!_glfwInitVulkan(_GLFW_REQUIRE_LOADER))
|
||||
return NULL;
|
||||
|
||||
proc = (GLFWvkproc) vkGetInstanceProcAddr(instance, procname);
|
||||
#if defined(_GLFW_VULKAN_STATIC)
|
||||
if (!proc)
|
||||
{
|
||||
if (strcmp(procname, "vkGetInstanceProcAddr") == 0)
|
||||
return (GLFWvkproc) vkGetInstanceProcAddr;
|
||||
}
|
||||
#else
|
||||
if (!proc)
|
||||
proc = (GLFWvkproc) _glfw_dlsym(_glfw.vk.handle, procname);
|
||||
#endif
|
||||
|
||||
return proc;
|
||||
}
|
||||
|
||||
GLFWAPI int glfwGetPhysicalDevicePresentationSupport(VkInstance instance,
|
||||
VkPhysicalDevice device,
|
||||
uint32_t queuefamily)
|
||||
{
|
||||
assert(instance != VK_NULL_HANDLE);
|
||||
assert(device != VK_NULL_HANDLE);
|
||||
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE);
|
||||
|
||||
if (!_glfwInitVulkan(_GLFW_REQUIRE_LOADER))
|
||||
return GLFW_FALSE;
|
||||
|
||||
if (!_glfw.vk.extensions[0])
|
||||
{
|
||||
_glfwInputError(GLFW_API_UNAVAILABLE,
|
||||
"Vulkan: Window surface creation extensions not found");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
return _glfwPlatformGetPhysicalDevicePresentationSupport(instance,
|
||||
device,
|
||||
queuefamily);
|
||||
}
|
||||
|
||||
GLFWAPI VkResult glfwCreateWindowSurface(VkInstance instance,
|
||||
GLFWwindow* handle,
|
||||
const VkAllocationCallbacks* allocator,
|
||||
VkSurfaceKHR* surface)
|
||||
{
|
||||
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||
assert(instance != VK_NULL_HANDLE);
|
||||
assert(window != NULL);
|
||||
assert(surface != NULL);
|
||||
|
||||
*surface = VK_NULL_HANDLE;
|
||||
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(VK_ERROR_INITIALIZATION_FAILED);
|
||||
|
||||
if (!_glfwInitVulkan(_GLFW_REQUIRE_LOADER))
|
||||
return VK_ERROR_INITIALIZATION_FAILED;
|
||||
|
||||
if (!_glfw.vk.extensions[0])
|
||||
{
|
||||
_glfwInputError(GLFW_API_UNAVAILABLE,
|
||||
"Vulkan: Window surface creation extensions not found");
|
||||
return VK_ERROR_EXTENSION_NOT_PRESENT;
|
||||
}
|
||||
|
||||
if (window->context.client != GLFW_NO_API)
|
||||
{
|
||||
_glfwInputError(GLFW_INVALID_VALUE,
|
||||
"Vulkan: Window surface creation requires the window to have the client API set to GLFW_NO_API");
|
||||
return VK_ERROR_NATIVE_WINDOW_IN_USE_KHR;
|
||||
}
|
||||
|
||||
return _glfwPlatformCreateWindowSurface(instance, window, allocator, surface);
|
||||
}
|
||||
744
glfw/wgl_context.c
vendored
Normal file
744
glfw/wgl_context.c
vendored
Normal file
@@ -0,0 +1,744 @@
|
||||
//========================================================================
|
||||
// GLFW 3.3 WGL - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||
// Copyright (c) 2006-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 <stdlib.h>
|
||||
#include <malloc.h>
|
||||
#include <assert.h>
|
||||
|
||||
|
||||
// Returns the specified attribute of the specified pixel format
|
||||
//
|
||||
static int getPixelFormatAttrib(_GLFWwindow* window, int pixelFormat, int attrib)
|
||||
{
|
||||
int value = 0;
|
||||
|
||||
assert(_glfw.wgl.ARB_pixel_format);
|
||||
|
||||
if (!_glfw.wgl.GetPixelFormatAttribivARB(window->context.wgl.dc,
|
||||
pixelFormat,
|
||||
0, 1, &attrib, &value))
|
||||
{
|
||||
_glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
|
||||
"WGL: Failed to retrieve pixel format attribute");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
// Return a list of available and usable framebuffer configs
|
||||
//
|
||||
static int choosePixelFormat(_GLFWwindow* window,
|
||||
const _GLFWctxconfig* ctxconfig,
|
||||
const _GLFWfbconfig* fbconfig)
|
||||
{
|
||||
_GLFWfbconfig* usableConfigs;
|
||||
const _GLFWfbconfig* closest;
|
||||
int i, pixelFormat, nativeCount, usableCount;
|
||||
|
||||
if (_glfw.wgl.ARB_pixel_format)
|
||||
{
|
||||
nativeCount = getPixelFormatAttrib(window,
|
||||
1,
|
||||
WGL_NUMBER_PIXEL_FORMATS_ARB);
|
||||
}
|
||||
else
|
||||
{
|
||||
nativeCount = DescribePixelFormat(window->context.wgl.dc,
|
||||
1,
|
||||
sizeof(PIXELFORMATDESCRIPTOR),
|
||||
NULL);
|
||||
}
|
||||
|
||||
usableConfigs = calloc(nativeCount, sizeof(_GLFWfbconfig));
|
||||
usableCount = 0;
|
||||
|
||||
for (i = 0; i < nativeCount; i++)
|
||||
{
|
||||
const int n = i + 1;
|
||||
_GLFWfbconfig* u = usableConfigs + usableCount;
|
||||
|
||||
if (_glfw.wgl.ARB_pixel_format)
|
||||
{
|
||||
// Get pixel format attributes through "modern" extension
|
||||
|
||||
if (!getPixelFormatAttrib(window, n, WGL_SUPPORT_OPENGL_ARB) ||
|
||||
!getPixelFormatAttrib(window, n, WGL_DRAW_TO_WINDOW_ARB))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (getPixelFormatAttrib(window, n, WGL_PIXEL_TYPE_ARB) !=
|
||||
WGL_TYPE_RGBA_ARB)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (getPixelFormatAttrib(window, n, WGL_ACCELERATION_ARB) ==
|
||||
WGL_NO_ACCELERATION_ARB)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
u->redBits = getPixelFormatAttrib(window, n, WGL_RED_BITS_ARB);
|
||||
u->greenBits = getPixelFormatAttrib(window, n, WGL_GREEN_BITS_ARB);
|
||||
u->blueBits = getPixelFormatAttrib(window, n, WGL_BLUE_BITS_ARB);
|
||||
u->alphaBits = getPixelFormatAttrib(window, n, WGL_ALPHA_BITS_ARB);
|
||||
|
||||
u->depthBits = getPixelFormatAttrib(window, n, WGL_DEPTH_BITS_ARB);
|
||||
u->stencilBits = getPixelFormatAttrib(window, n, WGL_STENCIL_BITS_ARB);
|
||||
|
||||
u->accumRedBits = getPixelFormatAttrib(window, n, WGL_ACCUM_RED_BITS_ARB);
|
||||
u->accumGreenBits = getPixelFormatAttrib(window, n, WGL_ACCUM_GREEN_BITS_ARB);
|
||||
u->accumBlueBits = getPixelFormatAttrib(window, n, WGL_ACCUM_BLUE_BITS_ARB);
|
||||
u->accumAlphaBits = getPixelFormatAttrib(window, n, WGL_ACCUM_ALPHA_BITS_ARB);
|
||||
|
||||
u->auxBuffers = getPixelFormatAttrib(window, n, WGL_AUX_BUFFERS_ARB);
|
||||
|
||||
if (getPixelFormatAttrib(window, n, WGL_STEREO_ARB))
|
||||
u->stereo = GLFW_TRUE;
|
||||
if (getPixelFormatAttrib(window, n, WGL_DOUBLE_BUFFER_ARB))
|
||||
u->doublebuffer = GLFW_TRUE;
|
||||
|
||||
if (_glfw.wgl.ARB_multisample)
|
||||
u->samples = getPixelFormatAttrib(window, n, WGL_SAMPLES_ARB);
|
||||
|
||||
if (ctxconfig->client == GLFW_OPENGL_API)
|
||||
{
|
||||
if (_glfw.wgl.ARB_framebuffer_sRGB ||
|
||||
_glfw.wgl.EXT_framebuffer_sRGB)
|
||||
{
|
||||
if (getPixelFormatAttrib(window, n, WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB))
|
||||
u->sRGB = GLFW_TRUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_glfw.wgl.EXT_colorspace)
|
||||
{
|
||||
if (getPixelFormatAttrib(window, n, WGL_COLORSPACE_EXT) ==
|
||||
WGL_COLORSPACE_SRGB_EXT)
|
||||
{
|
||||
u->sRGB = GLFW_TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Get pixel format attributes through legacy PFDs
|
||||
|
||||
PIXELFORMATDESCRIPTOR pfd;
|
||||
|
||||
if (!DescribePixelFormat(window->context.wgl.dc,
|
||||
n,
|
||||
sizeof(PIXELFORMATDESCRIPTOR),
|
||||
&pfd))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!(pfd.dwFlags & PFD_DRAW_TO_WINDOW) ||
|
||||
!(pfd.dwFlags & PFD_SUPPORT_OPENGL))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!(pfd.dwFlags & PFD_GENERIC_ACCELERATED) &&
|
||||
(pfd.dwFlags & PFD_GENERIC_FORMAT))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pfd.iPixelType != PFD_TYPE_RGBA)
|
||||
continue;
|
||||
|
||||
u->redBits = pfd.cRedBits;
|
||||
u->greenBits = pfd.cGreenBits;
|
||||
u->blueBits = pfd.cBlueBits;
|
||||
u->alphaBits = pfd.cAlphaBits;
|
||||
|
||||
u->depthBits = pfd.cDepthBits;
|
||||
u->stencilBits = pfd.cStencilBits;
|
||||
|
||||
u->accumRedBits = pfd.cAccumRedBits;
|
||||
u->accumGreenBits = pfd.cAccumGreenBits;
|
||||
u->accumBlueBits = pfd.cAccumBlueBits;
|
||||
u->accumAlphaBits = pfd.cAccumAlphaBits;
|
||||
|
||||
u->auxBuffers = pfd.cAuxBuffers;
|
||||
|
||||
if (pfd.dwFlags & PFD_STEREO)
|
||||
u->stereo = GLFW_TRUE;
|
||||
if (pfd.dwFlags & PFD_DOUBLEBUFFER)
|
||||
u->doublebuffer = GLFW_TRUE;
|
||||
}
|
||||
|
||||
u->handle = n;
|
||||
usableCount++;
|
||||
}
|
||||
|
||||
if (!usableCount)
|
||||
{
|
||||
_glfwInputError(GLFW_API_UNAVAILABLE,
|
||||
"WGL: The driver does not appear to support OpenGL");
|
||||
|
||||
free(usableConfigs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
closest = _glfwChooseFBConfig(fbconfig, usableConfigs, usableCount);
|
||||
if (!closest)
|
||||
{
|
||||
_glfwInputError(GLFW_FORMAT_UNAVAILABLE,
|
||||
"WGL: Failed to find a suitable pixel format");
|
||||
|
||||
free(usableConfigs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
pixelFormat = (int) closest->handle;
|
||||
free(usableConfigs);
|
||||
|
||||
return pixelFormat;
|
||||
}
|
||||
|
||||
static void makeContextCurrentWGL(_GLFWwindow* window)
|
||||
{
|
||||
if (window)
|
||||
{
|
||||
if (wglMakeCurrent(window->context.wgl.dc, window->context.wgl.handle))
|
||||
_glfwPlatformSetTls(&_glfw.contextSlot, window);
|
||||
else
|
||||
{
|
||||
_glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
|
||||
"WGL: Failed to make context current");
|
||||
_glfwPlatformSetTls(&_glfw.contextSlot, NULL);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!wglMakeCurrent(NULL, NULL))
|
||||
{
|
||||
_glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
|
||||
"WGL: Failed to clear current context");
|
||||
}
|
||||
|
||||
_glfwPlatformSetTls(&_glfw.contextSlot, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void swapBuffersWGL(_GLFWwindow* window)
|
||||
{
|
||||
if (!window->monitor)
|
||||
{
|
||||
if (IsWindowsVistaOrGreater())
|
||||
{
|
||||
BOOL enabled;
|
||||
|
||||
// HACK: Use DwmFlush when desktop composition is enabled
|
||||
if (SUCCEEDED(DwmIsCompositionEnabled(&enabled)) && enabled)
|
||||
{
|
||||
int count = abs(window->context.wgl.interval);
|
||||
while (count--)
|
||||
DwmFlush();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SwapBuffers(window->context.wgl.dc);
|
||||
}
|
||||
|
||||
static void swapIntervalWGL(int interval)
|
||||
{
|
||||
_GLFWwindow* window = _glfwPlatformGetTls(&_glfw.contextSlot);
|
||||
|
||||
window->context.wgl.interval = interval;
|
||||
|
||||
if (!window->monitor)
|
||||
{
|
||||
if (IsWindowsVistaOrGreater())
|
||||
{
|
||||
BOOL enabled;
|
||||
|
||||
// HACK: Disable WGL swap interval when desktop composition is enabled to
|
||||
// avoid interfering with DWM vsync
|
||||
if (SUCCEEDED(DwmIsCompositionEnabled(&enabled)) && enabled)
|
||||
interval = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (_glfw.wgl.EXT_swap_control)
|
||||
_glfw.wgl.SwapIntervalEXT(interval);
|
||||
}
|
||||
|
||||
static int extensionSupportedWGL(const char* extension)
|
||||
{
|
||||
const char* extensions;
|
||||
|
||||
if (_glfw.wgl.GetExtensionsStringEXT)
|
||||
{
|
||||
extensions = _glfw.wgl.GetExtensionsStringEXT();
|
||||
if (extensions)
|
||||
{
|
||||
if (_glfwStringInExtensionString(extension, extensions))
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (_glfw.wgl.GetExtensionsStringARB)
|
||||
{
|
||||
extensions = _glfw.wgl.GetExtensionsStringARB(wglGetCurrentDC());
|
||||
if (extensions)
|
||||
{
|
||||
if (_glfwStringInExtensionString(extension, extensions))
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
static GLFWglproc getProcAddressWGL(const char* procname)
|
||||
{
|
||||
const GLFWglproc proc = (GLFWglproc) wglGetProcAddress(procname);
|
||||
if (proc)
|
||||
return proc;
|
||||
|
||||
return (GLFWglproc) GetProcAddress(_glfw.wgl.instance, procname);
|
||||
}
|
||||
|
||||
// Destroy the OpenGL context
|
||||
//
|
||||
static void destroyContextWGL(_GLFWwindow* window)
|
||||
{
|
||||
if (window->context.wgl.handle)
|
||||
{
|
||||
wglDeleteContext(window->context.wgl.handle);
|
||||
window->context.wgl.handle = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW internal API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Initialize WGL
|
||||
//
|
||||
GLFWbool _glfwInitWGL(void)
|
||||
{
|
||||
PIXELFORMATDESCRIPTOR pfd;
|
||||
HGLRC prc, rc;
|
||||
HDC pdc, dc;
|
||||
|
||||
if (_glfw.wgl.instance)
|
||||
return GLFW_TRUE;
|
||||
|
||||
_glfw.wgl.instance = LoadLibraryA("opengl32.dll");
|
||||
if (!_glfw.wgl.instance)
|
||||
{
|
||||
_glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
|
||||
"WGL: Failed to load opengl32.dll");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
_glfw.wgl.CreateContext = (PFN_wglCreateContext)
|
||||
GetProcAddress(_glfw.wgl.instance, "wglCreateContext");
|
||||
_glfw.wgl.DeleteContext = (PFN_wglDeleteContext)
|
||||
GetProcAddress(_glfw.wgl.instance, "wglDeleteContext");
|
||||
_glfw.wgl.GetProcAddress = (PFN_wglGetProcAddress)
|
||||
GetProcAddress(_glfw.wgl.instance, "wglGetProcAddress");
|
||||
_glfw.wgl.GetCurrentDC = (PFN_wglGetCurrentDC)
|
||||
GetProcAddress(_glfw.wgl.instance, "wglGetCurrentDC");
|
||||
_glfw.wgl.GetCurrentContext = (PFN_wglGetCurrentContext)
|
||||
GetProcAddress(_glfw.wgl.instance, "wglGetCurrentContext");
|
||||
_glfw.wgl.MakeCurrent = (PFN_wglMakeCurrent)
|
||||
GetProcAddress(_glfw.wgl.instance, "wglMakeCurrent");
|
||||
_glfw.wgl.ShareLists = (PFN_wglShareLists)
|
||||
GetProcAddress(_glfw.wgl.instance, "wglShareLists");
|
||||
|
||||
// NOTE: A dummy context has to be created for opengl32.dll to load the
|
||||
// OpenGL ICD, from which we can then query WGL extensions
|
||||
// NOTE: This code will accept the Microsoft GDI ICD; accelerated context
|
||||
// creation failure occurs during manual pixel format enumeration
|
||||
|
||||
dc = GetDC(_glfw.win32.helperWindowHandle);;
|
||||
|
||||
ZeroMemory(&pfd, sizeof(pfd));
|
||||
pfd.nSize = sizeof(pfd);
|
||||
pfd.nVersion = 1;
|
||||
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
|
||||
pfd.iPixelType = PFD_TYPE_RGBA;
|
||||
pfd.cColorBits = 24;
|
||||
|
||||
if (!SetPixelFormat(dc, ChoosePixelFormat(dc, &pfd), &pfd))
|
||||
{
|
||||
_glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
|
||||
"WGL: Failed to set pixel format for dummy context");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
rc = wglCreateContext(dc);
|
||||
if (!rc)
|
||||
{
|
||||
_glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
|
||||
"WGL: Failed to create dummy context");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
pdc = wglGetCurrentDC();
|
||||
prc = wglGetCurrentContext();
|
||||
|
||||
if (!wglMakeCurrent(dc, rc))
|
||||
{
|
||||
_glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
|
||||
"WGL: Failed to make dummy context current");
|
||||
wglMakeCurrent(pdc, prc);
|
||||
wglDeleteContext(rc);
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
// NOTE: Functions must be loaded first as they're needed to retrieve the
|
||||
// extension string that tells us whether the functions are supported
|
||||
_glfw.wgl.GetExtensionsStringEXT = (PFNWGLGETEXTENSIONSSTRINGEXTPROC)
|
||||
wglGetProcAddress("wglGetExtensionsStringEXT");
|
||||
_glfw.wgl.GetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC)
|
||||
wglGetProcAddress("wglGetExtensionsStringARB");
|
||||
_glfw.wgl.CreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC)
|
||||
wglGetProcAddress("wglCreateContextAttribsARB");
|
||||
_glfw.wgl.SwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)
|
||||
wglGetProcAddress("wglSwapIntervalEXT");
|
||||
_glfw.wgl.GetPixelFormatAttribivARB = (PFNWGLGETPIXELFORMATATTRIBIVARBPROC)
|
||||
wglGetProcAddress("wglGetPixelFormatAttribivARB");
|
||||
|
||||
// NOTE: WGL_ARB_extensions_string and WGL_EXT_extensions_string are not
|
||||
// checked below as we are already using them
|
||||
_glfw.wgl.ARB_multisample =
|
||||
extensionSupportedWGL("WGL_ARB_multisample");
|
||||
_glfw.wgl.ARB_framebuffer_sRGB =
|
||||
extensionSupportedWGL("WGL_ARB_framebuffer_sRGB");
|
||||
_glfw.wgl.EXT_framebuffer_sRGB =
|
||||
extensionSupportedWGL("WGL_EXT_framebuffer_sRGB");
|
||||
_glfw.wgl.ARB_create_context =
|
||||
extensionSupportedWGL("WGL_ARB_create_context");
|
||||
_glfw.wgl.ARB_create_context_profile =
|
||||
extensionSupportedWGL("WGL_ARB_create_context_profile");
|
||||
_glfw.wgl.EXT_create_context_es2_profile =
|
||||
extensionSupportedWGL("WGL_EXT_create_context_es2_profile");
|
||||
_glfw.wgl.ARB_create_context_robustness =
|
||||
extensionSupportedWGL("WGL_ARB_create_context_robustness");
|
||||
_glfw.wgl.ARB_create_context_no_error =
|
||||
extensionSupportedWGL("WGL_ARB_create_context_no_error");
|
||||
_glfw.wgl.EXT_swap_control =
|
||||
extensionSupportedWGL("WGL_EXT_swap_control");
|
||||
_glfw.wgl.EXT_colorspace =
|
||||
extensionSupportedWGL("WGL_EXT_colorspace");
|
||||
_glfw.wgl.ARB_pixel_format =
|
||||
extensionSupportedWGL("WGL_ARB_pixel_format");
|
||||
_glfw.wgl.ARB_context_flush_control =
|
||||
extensionSupportedWGL("WGL_ARB_context_flush_control");
|
||||
|
||||
wglMakeCurrent(pdc, prc);
|
||||
wglDeleteContext(rc);
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
// Terminate WGL
|
||||
//
|
||||
void _glfwTerminateWGL(void)
|
||||
{
|
||||
if (_glfw.wgl.instance)
|
||||
FreeLibrary(_glfw.wgl.instance);
|
||||
}
|
||||
|
||||
#define setAttrib(a, v) \
|
||||
{ \
|
||||
assert((size_t) (index + 1) < sizeof(attribs) / sizeof(attribs[0])); \
|
||||
attribs[index++] = a; \
|
||||
attribs[index++] = v; \
|
||||
}
|
||||
|
||||
// Create the OpenGL or OpenGL ES context
|
||||
//
|
||||
GLFWbool _glfwCreateContextWGL(_GLFWwindow* window,
|
||||
const _GLFWctxconfig* ctxconfig,
|
||||
const _GLFWfbconfig* fbconfig)
|
||||
{
|
||||
int attribs[40];
|
||||
int pixelFormat;
|
||||
PIXELFORMATDESCRIPTOR pfd;
|
||||
HGLRC share = NULL;
|
||||
|
||||
if (ctxconfig->share)
|
||||
share = ctxconfig->share->context.wgl.handle;
|
||||
|
||||
window->context.wgl.dc = GetDC(window->win32.handle);
|
||||
if (!window->context.wgl.dc)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"WGL: Failed to retrieve DC for window");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
pixelFormat = choosePixelFormat(window, ctxconfig, fbconfig);
|
||||
if (!pixelFormat)
|
||||
return GLFW_FALSE;
|
||||
|
||||
if (!DescribePixelFormat(window->context.wgl.dc,
|
||||
pixelFormat, sizeof(pfd), &pfd))
|
||||
{
|
||||
_glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
|
||||
"WGL: Failed to retrieve PFD for selected pixel format");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
if (!SetPixelFormat(window->context.wgl.dc, pixelFormat, &pfd))
|
||||
{
|
||||
_glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
|
||||
"WGL: Failed to set selected pixel format");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
if (ctxconfig->client == GLFW_OPENGL_API)
|
||||
{
|
||||
if (ctxconfig->forward)
|
||||
{
|
||||
if (!_glfw.wgl.ARB_create_context)
|
||||
{
|
||||
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
|
||||
"WGL: A forward compatible OpenGL context requested but WGL_ARB_create_context is unavailable");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (ctxconfig->profile)
|
||||
{
|
||||
if (!_glfw.wgl.ARB_create_context_profile)
|
||||
{
|
||||
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
|
||||
"WGL: OpenGL profile requested but WGL_ARB_create_context_profile is unavailable");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!_glfw.wgl.ARB_create_context ||
|
||||
!_glfw.wgl.ARB_create_context_profile ||
|
||||
!_glfw.wgl.EXT_create_context_es2_profile)
|
||||
{
|
||||
_glfwInputError(GLFW_API_UNAVAILABLE,
|
||||
"WGL: OpenGL ES requested but WGL_ARB_create_context_es2_profile is unavailable");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (_glfw.wgl.ARB_create_context)
|
||||
{
|
||||
int index = 0, mask = 0, flags = 0;
|
||||
|
||||
if (ctxconfig->client == GLFW_OPENGL_API)
|
||||
{
|
||||
if (ctxconfig->forward)
|
||||
flags |= WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;
|
||||
|
||||
if (ctxconfig->profile == GLFW_OPENGL_CORE_PROFILE)
|
||||
mask |= WGL_CONTEXT_CORE_PROFILE_BIT_ARB;
|
||||
else if (ctxconfig->profile == GLFW_OPENGL_COMPAT_PROFILE)
|
||||
mask |= WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB;
|
||||
}
|
||||
else
|
||||
mask |= WGL_CONTEXT_ES2_PROFILE_BIT_EXT;
|
||||
|
||||
if (ctxconfig->debug)
|
||||
flags |= WGL_CONTEXT_DEBUG_BIT_ARB;
|
||||
|
||||
if (ctxconfig->robustness)
|
||||
{
|
||||
if (_glfw.wgl.ARB_create_context_robustness)
|
||||
{
|
||||
if (ctxconfig->robustness == GLFW_NO_RESET_NOTIFICATION)
|
||||
{
|
||||
setAttrib(WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB,
|
||||
WGL_NO_RESET_NOTIFICATION_ARB);
|
||||
}
|
||||
else if (ctxconfig->robustness == GLFW_LOSE_CONTEXT_ON_RESET)
|
||||
{
|
||||
setAttrib(WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB,
|
||||
WGL_LOSE_CONTEXT_ON_RESET_ARB);
|
||||
}
|
||||
|
||||
flags |= WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB;
|
||||
}
|
||||
}
|
||||
|
||||
if (ctxconfig->release)
|
||||
{
|
||||
if (_glfw.wgl.ARB_context_flush_control)
|
||||
{
|
||||
if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_NONE)
|
||||
{
|
||||
setAttrib(WGL_CONTEXT_RELEASE_BEHAVIOR_ARB,
|
||||
WGL_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB);
|
||||
}
|
||||
else if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_FLUSH)
|
||||
{
|
||||
setAttrib(WGL_CONTEXT_RELEASE_BEHAVIOR_ARB,
|
||||
WGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ctxconfig->noerror)
|
||||
{
|
||||
if (_glfw.wgl.ARB_create_context_no_error)
|
||||
setAttrib(WGL_CONTEXT_OPENGL_NO_ERROR_ARB, GLFW_TRUE);
|
||||
}
|
||||
|
||||
// NOTE: Only request an explicitly versioned context when necessary, as
|
||||
// explicitly requesting version 1.0 does not always return the
|
||||
// highest version supported by the driver
|
||||
if (ctxconfig->major != 1 || ctxconfig->minor != 0)
|
||||
{
|
||||
setAttrib(WGL_CONTEXT_MAJOR_VERSION_ARB, ctxconfig->major);
|
||||
setAttrib(WGL_CONTEXT_MINOR_VERSION_ARB, ctxconfig->minor);
|
||||
}
|
||||
|
||||
if (flags)
|
||||
setAttrib(WGL_CONTEXT_FLAGS_ARB, flags);
|
||||
|
||||
if (mask)
|
||||
setAttrib(WGL_CONTEXT_PROFILE_MASK_ARB, mask);
|
||||
|
||||
setAttrib(0, 0);
|
||||
|
||||
window->context.wgl.handle =
|
||||
_glfw.wgl.CreateContextAttribsARB(window->context.wgl.dc,
|
||||
share, attribs);
|
||||
if (!window->context.wgl.handle)
|
||||
{
|
||||
const DWORD error = GetLastError();
|
||||
|
||||
if (error == (0xc0070000 | ERROR_INVALID_VERSION_ARB))
|
||||
{
|
||||
if (ctxconfig->client == GLFW_OPENGL_API)
|
||||
{
|
||||
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
|
||||
"WGL: Driver does not support OpenGL version %i.%i",
|
||||
ctxconfig->major,
|
||||
ctxconfig->minor);
|
||||
}
|
||||
else
|
||||
{
|
||||
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
|
||||
"WGL: Driver does not support OpenGL ES version %i.%i",
|
||||
ctxconfig->major,
|
||||
ctxconfig->minor);
|
||||
}
|
||||
}
|
||||
else if (error == (0xc0070000 | ERROR_INVALID_PROFILE_ARB))
|
||||
{
|
||||
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
|
||||
"WGL: Driver does not support the requested OpenGL profile");
|
||||
}
|
||||
else if (error == (0xc0070000 | ERROR_INCOMPATIBLE_DEVICE_CONTEXTS_ARB))
|
||||
{
|
||||
_glfwInputError(GLFW_INVALID_VALUE,
|
||||
"WGL: The share context is not compatible with the requested context");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ctxconfig->client == GLFW_OPENGL_API)
|
||||
{
|
||||
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
|
||||
"WGL: Failed to create OpenGL context");
|
||||
}
|
||||
else
|
||||
{
|
||||
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
|
||||
"WGL: Failed to create OpenGL ES context");
|
||||
}
|
||||
}
|
||||
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
window->context.wgl.handle = wglCreateContext(window->context.wgl.dc);
|
||||
if (!window->context.wgl.handle)
|
||||
{
|
||||
_glfwInputErrorWin32(GLFW_VERSION_UNAVAILABLE,
|
||||
"WGL: Failed to create OpenGL context");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
if (share)
|
||||
{
|
||||
if (!wglShareLists(share, window->context.wgl.handle))
|
||||
{
|
||||
_glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
|
||||
"WGL: Failed to enable sharing with specified OpenGL context");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
window->context.makeCurrent = makeContextCurrentWGL;
|
||||
window->context.swapBuffers = swapBuffersWGL;
|
||||
window->context.swapInterval = swapIntervalWGL;
|
||||
window->context.extensionSupported = extensionSupportedWGL;
|
||||
window->context.getProcAddress = getProcAddressWGL;
|
||||
window->context.destroy = destroyContextWGL;
|
||||
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
#undef setAttrib
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW native API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
GLFWAPI HGLRC glfwGetWGLContext(GLFWwindow* handle)
|
||||
{
|
||||
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||
|
||||
if (window->context.client == GLFW_NO_API)
|
||||
{
|
||||
_glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return window->context.wgl.handle;
|
||||
}
|
||||
|
||||
159
glfw/wgl_context.h
vendored
Normal file
159
glfw/wgl_context.h
vendored
Normal file
@@ -0,0 +1,159 @@
|
||||
//========================================================================
|
||||
// GLFW 3.3 WGL - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||
// Copyright (c) 2006-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.
|
||||
//
|
||||
//========================================================================
|
||||
|
||||
#define WGL_NUMBER_PIXEL_FORMATS_ARB 0x2000
|
||||
#define WGL_SUPPORT_OPENGL_ARB 0x2010
|
||||
#define WGL_DRAW_TO_WINDOW_ARB 0x2001
|
||||
#define WGL_PIXEL_TYPE_ARB 0x2013
|
||||
#define WGL_TYPE_RGBA_ARB 0x202b
|
||||
#define WGL_ACCELERATION_ARB 0x2003
|
||||
#define WGL_NO_ACCELERATION_ARB 0x2025
|
||||
#define WGL_RED_BITS_ARB 0x2015
|
||||
#define WGL_RED_SHIFT_ARB 0x2016
|
||||
#define WGL_GREEN_BITS_ARB 0x2017
|
||||
#define WGL_GREEN_SHIFT_ARB 0x2018
|
||||
#define WGL_BLUE_BITS_ARB 0x2019
|
||||
#define WGL_BLUE_SHIFT_ARB 0x201a
|
||||
#define WGL_ALPHA_BITS_ARB 0x201b
|
||||
#define WGL_ALPHA_SHIFT_ARB 0x201c
|
||||
#define WGL_ACCUM_BITS_ARB 0x201d
|
||||
#define WGL_ACCUM_RED_BITS_ARB 0x201e
|
||||
#define WGL_ACCUM_GREEN_BITS_ARB 0x201f
|
||||
#define WGL_ACCUM_BLUE_BITS_ARB 0x2020
|
||||
#define WGL_ACCUM_ALPHA_BITS_ARB 0x2021
|
||||
#define WGL_DEPTH_BITS_ARB 0x2022
|
||||
#define WGL_STENCIL_BITS_ARB 0x2023
|
||||
#define WGL_AUX_BUFFERS_ARB 0x2024
|
||||
#define WGL_STEREO_ARB 0x2012
|
||||
#define WGL_DOUBLE_BUFFER_ARB 0x2011
|
||||
#define WGL_SAMPLES_ARB 0x2042
|
||||
#define WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20a9
|
||||
#define WGL_CONTEXT_DEBUG_BIT_ARB 0x00000001
|
||||
#define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x00000002
|
||||
#define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126
|
||||
#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001
|
||||
#define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002
|
||||
#define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091
|
||||
#define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092
|
||||
#define WGL_CONTEXT_FLAGS_ARB 0x2094
|
||||
#define WGL_CONTEXT_ES2_PROFILE_BIT_EXT 0x00000004
|
||||
#define WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB 0x00000004
|
||||
#define WGL_LOSE_CONTEXT_ON_RESET_ARB 0x8252
|
||||
#define WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB 0x8256
|
||||
#define WGL_NO_RESET_NOTIFICATION_ARB 0x8261
|
||||
#define WGL_CONTEXT_RELEASE_BEHAVIOR_ARB 0x2097
|
||||
#define WGL_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB 0
|
||||
#define WGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB 0x2098
|
||||
#define WGL_CONTEXT_OPENGL_NO_ERROR_ARB 0x31b3
|
||||
#define WGL_COLORSPACE_EXT 0x309d
|
||||
#define WGL_COLORSPACE_SRGB_EXT 0x3089
|
||||
|
||||
#define ERROR_INVALID_VERSION_ARB 0x2095
|
||||
#define ERROR_INVALID_PROFILE_ARB 0x2096
|
||||
#define ERROR_INCOMPATIBLE_DEVICE_CONTEXTS_ARB 0x2054
|
||||
|
||||
typedef BOOL (WINAPI * PFNWGLSWAPINTERVALEXTPROC)(int);
|
||||
typedef BOOL (WINAPI * PFNWGLGETPIXELFORMATATTRIBIVARBPROC)(HDC,int,int,UINT,const int*,int*);
|
||||
typedef const char* (WINAPI * PFNWGLGETEXTENSIONSSTRINGEXTPROC)(void);
|
||||
typedef const char* (WINAPI * PFNWGLGETEXTENSIONSSTRINGARBPROC)(HDC);
|
||||
typedef HGLRC (WINAPI * PFNWGLCREATECONTEXTATTRIBSARBPROC)(HDC,HGLRC,const int*);
|
||||
|
||||
typedef HGLRC (WINAPI * PFN_wglCreateContext)(HDC);
|
||||
typedef BOOL (WINAPI * PFN_wglDeleteContext)(HGLRC);
|
||||
typedef PROC (WINAPI * PFN_wglGetProcAddress)(LPCSTR);
|
||||
typedef HDC (WINAPI * PFN_wglGetCurrentDC)(void);
|
||||
typedef HGLRC (WINAPI * PFN_wglGetCurrentContext)(void);
|
||||
typedef BOOL (WINAPI * PFN_wglMakeCurrent)(HDC,HGLRC);
|
||||
typedef BOOL (WINAPI * PFN_wglShareLists)(HGLRC,HGLRC);
|
||||
|
||||
// opengl32.dll function pointer typedefs
|
||||
#define wglCreateContext _glfw.wgl.CreateContext
|
||||
#define wglDeleteContext _glfw.wgl.DeleteContext
|
||||
#define wglGetProcAddress _glfw.wgl.GetProcAddress
|
||||
#define wglGetCurrentDC _glfw.wgl.GetCurrentDC
|
||||
#define wglGetCurrentContext _glfw.wgl.GetCurrentContext
|
||||
#define wglMakeCurrent _glfw.wgl.MakeCurrent
|
||||
#define wglShareLists _glfw.wgl.ShareLists
|
||||
|
||||
#define _GLFW_RECREATION_NOT_NEEDED 0
|
||||
#define _GLFW_RECREATION_REQUIRED 1
|
||||
#define _GLFW_RECREATION_IMPOSSIBLE 2
|
||||
|
||||
#define _GLFW_PLATFORM_CONTEXT_STATE _GLFWcontextWGL wgl
|
||||
#define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE _GLFWlibraryWGL wgl
|
||||
|
||||
|
||||
// WGL-specific per-context data
|
||||
//
|
||||
typedef struct _GLFWcontextWGL
|
||||
{
|
||||
HDC dc;
|
||||
HGLRC handle;
|
||||
int interval;
|
||||
|
||||
} _GLFWcontextWGL;
|
||||
|
||||
// WGL-specific global data
|
||||
//
|
||||
typedef struct _GLFWlibraryWGL
|
||||
{
|
||||
HINSTANCE instance;
|
||||
PFN_wglCreateContext CreateContext;
|
||||
PFN_wglDeleteContext DeleteContext;
|
||||
PFN_wglGetProcAddress GetProcAddress;
|
||||
PFN_wglGetCurrentDC GetCurrentDC;
|
||||
PFN_wglGetCurrentContext GetCurrentContext;
|
||||
PFN_wglMakeCurrent MakeCurrent;
|
||||
PFN_wglShareLists ShareLists;
|
||||
|
||||
PFNWGLSWAPINTERVALEXTPROC SwapIntervalEXT;
|
||||
PFNWGLGETPIXELFORMATATTRIBIVARBPROC GetPixelFormatAttribivARB;
|
||||
PFNWGLGETEXTENSIONSSTRINGEXTPROC GetExtensionsStringEXT;
|
||||
PFNWGLGETEXTENSIONSSTRINGARBPROC GetExtensionsStringARB;
|
||||
PFNWGLCREATECONTEXTATTRIBSARBPROC CreateContextAttribsARB;
|
||||
GLFWbool EXT_swap_control;
|
||||
GLFWbool EXT_colorspace;
|
||||
GLFWbool ARB_multisample;
|
||||
GLFWbool ARB_framebuffer_sRGB;
|
||||
GLFWbool EXT_framebuffer_sRGB;
|
||||
GLFWbool ARB_pixel_format;
|
||||
GLFWbool ARB_create_context;
|
||||
GLFWbool ARB_create_context_profile;
|
||||
GLFWbool EXT_create_context_es2_profile;
|
||||
GLFWbool ARB_create_context_robustness;
|
||||
GLFWbool ARB_create_context_no_error;
|
||||
GLFWbool ARB_context_flush_control;
|
||||
|
||||
} _GLFWlibraryWGL;
|
||||
|
||||
|
||||
GLFWbool _glfwInitWGL(void);
|
||||
void _glfwTerminateWGL(void);
|
||||
GLFWbool _glfwCreateContextWGL(_GLFWwindow* window,
|
||||
const _GLFWctxconfig* ctxconfig,
|
||||
const _GLFWfbconfig* fbconfig);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user