Compare commits
1930 commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b41882c169 | |||
| bcab43b181 | |||
| 08e215c9bf | |||
|
|
4152ac76d0 | ||
|
|
a5858018d8 | ||
|
|
8685fd7b0c | ||
|
|
1fa157cf6d | ||
|
|
e0c5710059 | ||
|
|
42f0a6005b | ||
|
|
ae9ca17b40 | ||
|
|
972f23efe8 | ||
|
|
4c60d9df70 | ||
|
|
b7dfb47566 | ||
|
|
3284dd729b | ||
|
|
803e81ac39 | ||
|
|
34c7cc7d38 | ||
|
|
c47ae950f4 | ||
|
|
3f169ee5de | ||
|
|
10754745a9 | ||
|
|
8271cfc97b | ||
|
|
c11cadd8d6 | ||
|
|
dc4b082ee8 | ||
|
|
edf7098345 | ||
|
|
7299a3b0d5 | ||
|
|
b06a4b5e13 | ||
|
|
3faddf40d0 | ||
|
|
a6e3a2478c | ||
|
|
ff0b706ea3 | ||
|
|
4f44df7b17 | ||
|
|
be03497b82 | ||
|
|
ff20cbf89c | ||
|
|
fe0a202137 | ||
|
|
75a815fbf2 | ||
|
|
3b7401b065 | ||
|
|
d4d17d5d52 | ||
|
|
52ece2b017 | ||
|
|
d98f7ffaf5 | ||
|
|
5f650f8ed9 | ||
|
|
9f98f7440b | ||
|
|
5cb1281035 | ||
|
|
743dffd638 | ||
|
|
5c370c3333 | ||
|
|
cf0d256c13 | ||
|
|
6ebafcf107 | ||
|
|
8ad96a95d6 | ||
|
|
f41e3c2203 | ||
|
|
f0a80ce5e0 | ||
|
|
2928d6af0a | ||
|
|
93aacfc0dc | ||
|
|
19c263e53c | ||
|
|
a032090098 | ||
|
|
0b55c55f4a | ||
|
|
85c2764f5e | ||
|
|
c2bed4103c | ||
|
|
82729db330 | ||
|
|
f12904e641 | ||
|
|
b90c61c04f | ||
|
|
e333a330c0 | ||
|
|
1c64ef06d9 | ||
|
|
6b2c08d3e8 | ||
|
|
db8509dfe2 | ||
|
|
d2b9957fab | ||
|
|
362ea7b0f3 | ||
|
|
f7114016c6 | ||
|
|
0002f148c9 | ||
|
|
ffec41c426 | ||
|
|
f624449c12 | ||
|
|
70cdd819e4 | ||
|
|
cc14dd1baf | ||
|
|
c71fbd854d | ||
|
|
0e9196867b | ||
|
|
1e06ab464f | ||
|
|
623185170b | ||
|
|
d0583e1761 | ||
|
|
5b2efe54b1 | ||
|
|
457617b5a3 | ||
|
|
c60b3cb2ed | ||
|
|
fbf67ef050 | ||
|
|
be893a81b4 | ||
|
|
5a80bc120a | ||
|
|
a248805132 | ||
|
|
8ab4d1dc06 | ||
|
|
ae82a55400 | ||
|
|
bc09504ea5 | ||
|
|
f4bc8c3a64 | ||
|
|
b88813c7ef | ||
|
|
b4ee4674f9 | ||
|
|
93dbf88426 | ||
|
|
0eb4755a3e | ||
|
|
723870337f | ||
|
|
51f8849e54 | ||
|
|
b9b1eda2ef | ||
|
|
13dab66b1d | ||
|
|
9f59ed7868 | ||
|
|
a20142bcce | ||
|
|
d91952c555 | ||
|
|
8b17a7404b | ||
|
|
9ea6d0e15f | ||
|
|
a1e62dcb12 | ||
|
|
7a566942d5 | ||
|
|
68456a5d9a | ||
|
|
184af52f24 | ||
|
|
1af260ecbe | ||
|
|
0de216e783 | ||
|
|
661314e134 | ||
|
|
17fc159ae2 | ||
|
|
6716b8a0e3 | ||
|
|
59f19e465b | ||
|
|
e6ca141364 | ||
|
|
48176160ab | ||
|
|
e5a2b9e5b0 | ||
|
|
e80f705d76 | ||
|
|
1bf410e1fc | ||
|
|
1c767de9da | ||
|
|
a8a8929bb4 | ||
|
|
eb0d3f9f01 | ||
|
|
81a029e504 | ||
|
|
380d14998e | ||
|
|
fd48d102e1 | ||
|
|
531fc43203 | ||
|
|
5b6c42ca70 | ||
|
|
857a78ce4e | ||
|
|
339661229d | ||
|
|
ff061d177e | ||
|
|
407a623801 | ||
|
|
171ad7d338 | ||
|
|
f16ebef003 | ||
|
|
6507445787 | ||
|
|
f68ac7ef75 | ||
|
|
60f1c61323 | ||
|
|
9f9dbb0dc5 | ||
|
|
cfbbfb591a | ||
|
|
63eb6b3bda | ||
|
|
8606bc255b | ||
|
|
562171ab66 | ||
|
|
9ce9ef2705 | ||
|
|
02ff413002 | ||
|
|
1bc857b12c | ||
|
|
cd7bdc7a43 | ||
|
|
e123fd3e66 | ||
|
|
30756d8718 | ||
|
|
9433060760 | ||
|
|
a0ec2e4daf | ||
|
|
d9d9d9358f | ||
|
|
95c8f8b299 | ||
|
|
beeca9dacb | ||
|
|
47f9035601 | ||
|
|
db6114c6c5 | ||
|
|
cbeb6984e7 | ||
|
|
4330b49a84 | ||
|
|
2ad7f6edd4 | ||
|
|
ec120d5732 | ||
|
|
fe6c213024 | ||
|
|
b8fc0def97 | ||
|
|
c92fb5e85f | ||
|
|
7d209b2941 | ||
|
|
e92b20292b | ||
|
|
22e53345ba | ||
|
|
116537b494 | ||
|
|
c8b5023bb0 | ||
|
|
bcb34275ea | ||
|
|
21325f9385 | ||
|
|
50454c6d17 | ||
|
|
c65c7614bc | ||
|
|
891e029ba3 | ||
|
|
b1d1c9843f | ||
|
|
2a2c2b0e28 | ||
|
|
64db62d7e2 | ||
|
|
82de66a030 | ||
|
|
22fc8136a2 | ||
|
|
e7985ca4c4 | ||
|
|
6c3ebed76e | ||
|
|
f9fb24577a | ||
|
|
55f40ecc95 | ||
|
|
441a8714c7 | ||
|
|
57e6a57e6b | ||
|
|
c44292c723 | ||
|
|
f0b6714539 | ||
|
|
8f547c6fa0 | ||
|
|
d6e2ae0247 | ||
|
|
eb0480ba0d | ||
|
|
0896775f1b | ||
|
|
c99eb23869 | ||
|
|
92a3b91999 | ||
|
|
36aa465a21 | ||
|
|
fec17e5e79 | ||
|
|
eff484b96c | ||
|
|
2e697ce2bf | ||
|
|
0b13d398fe | ||
|
|
ac9df44788 | ||
|
|
e0cf88809d | ||
|
|
e43f949f8a | ||
|
|
8d03fcc8d7 | ||
|
|
5e18111121 | ||
|
|
fbf421df88 | ||
|
|
8f8b31e7a6 | ||
|
|
81e7498ec2 | ||
|
|
fa41c8229d | ||
|
|
5b1b79c29c | ||
|
|
eb623bd91d | ||
|
|
3dcaadbdf5 | ||
|
|
a649dbe4c4 | ||
|
|
f767782e3f | ||
|
|
f54dd4da4a | ||
|
|
3aa4e02720 | ||
|
|
8368566044 | ||
|
|
918e2bb9be | ||
|
|
a383ca1866 | ||
|
|
f1652b2951 | ||
|
|
cbfbd9712a | ||
|
|
9817553c66 | ||
|
|
6fce2d7288 | ||
|
|
107275238c | ||
|
|
3b77c784e2 | ||
|
|
d46df728fd | ||
|
|
8eb3ecc755 | ||
|
|
97c8a2f1cf | ||
|
|
a492fa3866 | ||
|
|
e165f84184 | ||
|
|
686eda9d48 | ||
|
|
70c5fe5cd8 | ||
|
|
32978176b1 | ||
|
|
1761909bca | ||
|
|
7d8f57083e | ||
|
|
a3c8533d74 | ||
|
|
0b3b012817 | ||
|
|
583c4074a5 | ||
|
|
922e53c68c | ||
|
|
17bc3b83db | ||
|
|
fab3370254 | ||
|
|
ee67278038 | ||
|
|
b9bd9d147f | ||
|
|
ec4beb1b39 | ||
|
|
31d3181e1e | ||
|
|
9b93d621b1 | ||
|
|
bd7f9aad05 | ||
|
|
48a024e032 | ||
|
|
bd02178e96 | ||
|
|
214fdb099c | ||
|
|
d622c09d09 | ||
|
|
529559712b | ||
|
|
293d3e5de9 | ||
|
|
f8464866eb | ||
|
|
ea444c35bb | ||
|
|
6a055fc747 | ||
|
|
a8452705d6 | ||
|
|
e5d20b56bc | ||
|
|
5faa66d297 | ||
|
|
610c59dc34 | ||
|
|
e5f22c06b4 | ||
|
|
6d3b17ee83 | ||
|
|
42447a50d6 | ||
|
|
d7f26038ee | ||
|
|
33df518f97 | ||
|
|
9ea565054a | ||
|
|
1f1a39d46c | ||
|
|
14c49230cc | ||
|
|
2525052779 | ||
|
|
f7f357f15f | ||
|
|
abffe75088 | ||
|
|
60efbf3f63 | ||
|
|
712bcfbce5 | ||
|
|
c87a1a7629 | ||
|
|
7bd207377c | ||
|
|
b9bef69554 | ||
|
|
70f54a1e1b | ||
|
|
f6c5c659a7 | ||
|
|
c23a0c20a4 | ||
|
|
3bbbb5aaca | ||
|
|
315806f598 | ||
|
|
6175ecd4c4 | ||
|
|
f88deb928a | ||
|
|
18901b8e59 | ||
|
|
7098558420 | ||
|
|
59438908de | ||
|
|
cbfdbe9fa1 | ||
|
|
c94a981711 | ||
|
|
beb1b578e8 | ||
|
|
c5beecb2c3 | ||
|
|
6e09eb2e6c | ||
|
|
6b491e4d6b | ||
|
|
4036c37e55 | ||
|
|
7ccc57eb7c | ||
|
|
e4a8f2b14f | ||
|
|
6535ff07c9 | ||
|
|
05ccbb2f2d | ||
|
|
09e195d1f2 | ||
|
|
fd5e790d08 | ||
|
|
69db0bcae6 | ||
|
|
8dfdcfb353 | ||
|
|
5700736505 | ||
|
|
75f6435f70 | ||
|
|
5dd224805d | ||
|
|
2ca7ad7efc | ||
|
|
9aa313402b | ||
|
|
1ff801f5f3 | ||
|
|
3cf6dfd7e6 | ||
|
|
f58c80fd39 | ||
|
|
6712fb954f | ||
|
|
efe665b455 | ||
|
|
920353370b | ||
|
|
834f019bab | ||
|
|
a5b7c91329 | ||
|
|
916e5d1aea | ||
|
|
9584b2d40e | ||
|
|
532ca053d6 | ||
|
|
ca99e8228c | ||
|
|
8ca40479a7 | ||
|
|
c26e91f074 | ||
|
|
76ac655c9e | ||
|
|
f8d5aad1a1 | ||
|
|
b8bb5e9bde | ||
|
|
7797deb935 | ||
|
|
d3c9c54b79 | ||
|
|
cedadf4fdc | ||
|
|
222dbe99d0 | ||
|
|
ebe74be75a | ||
|
|
afeda6cee6 | ||
|
|
6a1daff5f3 | ||
|
|
016eb7a23d | ||
|
|
ec6756f961 | ||
|
|
9264436f35 | ||
|
|
d5c52ef58e | ||
|
|
52b3c8cbc6 | ||
|
|
279a07c2ce | ||
|
|
17ae3fb704 | ||
|
|
43ed0db3b3 | ||
|
|
38f912c401 | ||
|
|
9cd070fd31 | ||
|
|
d9657a95cb | ||
|
|
9b1891e476 | ||
|
|
93e5e92b0a | ||
|
|
3cf0280b11 | ||
|
|
2cadc8abab | ||
|
|
f82a8630d7 | ||
|
|
bb963fb002 | ||
|
|
f11cf6f1de | ||
|
|
574ee71d56 | ||
|
|
7e1e24fea6 | ||
|
|
68eecf61cd | ||
|
|
f9742ab501 | ||
|
|
e42185b83d | ||
|
|
a51918fd27 | ||
|
|
379ee99c68 | ||
|
|
4036e35e73 | ||
|
|
d21f2e5729 | ||
|
|
4e5a284bc4 | ||
|
|
210930bef9 | ||
|
|
40d8fa8491 | ||
|
|
1c1746de61 | ||
|
|
619e9d285b | ||
|
|
ec3b3403e7 | ||
|
|
703394affb | ||
|
|
fe6a855bbb | ||
|
|
475e87b351 | ||
|
|
3d7ea9c02f | ||
|
|
2b0fd417d3 | ||
|
|
56904edbd2 | ||
|
|
e584a8bade | ||
|
|
2ac9ded2ac | ||
|
|
abb2f7ee6f | ||
|
|
79a2781923 | ||
|
|
d66c9222b0 | ||
|
|
b5a2ef77b7 | ||
|
|
c5d45b7653 | ||
|
|
c249a9f4b8 | ||
|
|
00cce1c8ff | ||
|
|
6b8e3358d6 | ||
|
|
80b96a3166 | ||
|
|
f9d1da6667 | ||
|
|
7532115318 | ||
|
|
1c29d6b1ba | ||
|
|
d0503bea43 | ||
|
|
fbb31503f1 | ||
|
|
9f02dca8de | ||
|
|
6a8d306992 | ||
|
|
e4b40abce6 | ||
|
|
9495f989b4 | ||
|
|
2c9c4d0905 | ||
|
|
e15409bbeb | ||
|
|
312073ce79 | ||
|
|
edc311544a | ||
|
|
37fe7b2efd | ||
|
|
c2670e9ab9 | ||
|
|
95ee08b340 | ||
|
|
ff6d771be0 | ||
|
|
64e4e913e1 | ||
|
|
ad52ba9c13 | ||
|
|
526aa1d020 | ||
|
|
5f0575737f | ||
|
|
4695f85829 | ||
|
|
1796dbcdc3 | ||
|
|
e354066945 | ||
|
|
2b14f27ca8 | ||
|
|
68c23fbdaf | ||
|
|
484d87d469 | ||
|
|
cefa63c2af | ||
|
|
9d67511871 | ||
|
|
5265fa3be8 | ||
|
|
dfb4dcd55c | ||
|
|
9d02fe9c23 | ||
|
|
76edcfc66c | ||
|
|
11451d68b7 | ||
|
|
3534dbdb89 | ||
|
|
6e2fe103bc | ||
|
|
7910bc42af | ||
|
|
0770494ddf | ||
|
|
49c0c97c5a | ||
|
|
e948445f6e | ||
|
|
7a6177532b | ||
|
|
f0de61ca21 | ||
|
|
c02a6184d3 | ||
|
|
15b4b1dd91 | ||
|
|
a6b877fec2 | ||
|
|
d2d1613e4f | ||
|
|
c7e14ecd30 | ||
|
|
9321f52e07 | ||
|
|
b04e8e00b0 | ||
|
|
5b373ea9f5 | ||
|
|
d52639fdfa | ||
|
|
e616e595ae | ||
|
|
cb47eb1d11 | ||
|
|
9b006b2c85 | ||
|
|
b35f78431f | ||
|
|
b62ab4b578 | ||
|
|
43527d3634 | ||
|
|
55a93b8a52 | ||
|
|
64ee8f8a72 | ||
|
|
b77cbad502 | ||
|
|
308226a4fc | ||
|
|
ee2168c665 | ||
|
|
c330d4334f | ||
|
|
cadf922417 | ||
|
|
ac8edc6a80 | ||
|
|
b2ea6b010c | ||
|
|
0b1d690676 | ||
|
|
2931184921 | ||
|
|
0bd11d5eb9 | ||
|
|
06b37c3907 | ||
|
|
522edc8712 | ||
|
|
f56ec180d3 | ||
|
|
fd50e78bc9 | ||
|
|
061981201d | ||
|
|
3fc8cb828c | ||
|
|
1ca6058bda | ||
|
|
ca4b68e425 | ||
|
|
8e8bfbb0b1 | ||
|
|
c757fd375c | ||
|
|
46b71eda64 | ||
|
|
d82538c69f | ||
|
|
8e9add2afd | ||
|
|
5e6cec962c | ||
|
|
6ade4d58ca | ||
|
|
83a0a62004 | ||
|
|
ff50dc36e9 | ||
|
|
ce9787b3f4 | ||
|
|
9eb82774e5 | ||
|
|
a2f48ea418 | ||
|
|
309c3c7848 | ||
|
|
0907fdf49c | ||
|
|
431325ff0c | ||
|
|
40831a90a0 | ||
|
|
b186d3bf1b | ||
|
|
560c53d87d | ||
|
|
fd42e9d082 | ||
|
|
17d0d696be | ||
|
|
88e34d7dd2 | ||
|
|
05aa4e1c54 | ||
|
|
748d2f656e | ||
|
|
6ea4769b39 | ||
|
|
72cbb7906a | ||
|
|
b6f946991d | ||
|
|
b10b966000 | ||
|
|
da04afa44e | ||
|
|
34812c33db | ||
|
|
117e38db35 | ||
|
|
151b5f6978 | ||
|
|
aa5a239ac9 | ||
|
|
019589e23f | ||
|
|
057695bc3f | ||
|
|
892f642f58 | ||
|
|
d560c26419 | ||
|
|
02b0c563f3 | ||
|
|
4926332c37 | ||
|
|
46dab01bcc | ||
|
|
474cd004df | ||
|
|
a4200acfa6 | ||
|
|
59ff7b2f89 | ||
|
|
ba077d8ff0 | ||
|
|
39d62e1487 | ||
|
|
6607c6440d | ||
|
|
f3e13193a6 | ||
|
|
8164b90bc2 | ||
|
|
36c0477dd0 | ||
|
|
ab11af9664 | ||
|
|
e40873be51 | ||
|
|
60529e810d | ||
|
|
f324a3a564 | ||
|
|
ee5d05f0fc | ||
|
|
bbb83317c0 | ||
|
|
0d6d19b280 | ||
|
|
541ef60fd7 | ||
|
|
4b55ec6830 | ||
|
|
7fcaf332e8 | ||
|
|
6582f42db8 | ||
|
|
ed93643021 | ||
|
|
d599513d4a | ||
|
|
6a01c399a9 | ||
|
|
da31e82aab | ||
|
|
32f3233324 | ||
|
|
2b0926dcd4 | ||
|
|
b965fb2a40 | ||
|
|
82759d4095 | ||
|
|
0dc45b54f3 | ||
|
|
ba24547d3d | ||
|
|
5ba2d2217b | ||
|
|
5a20862126 | ||
|
|
c3747fab56 | ||
|
|
dc72259a54 | ||
|
|
02cda6bebf | ||
|
|
73f06434a4 | ||
|
|
17e77e0407 | ||
|
|
cfac27251a | ||
|
|
76d998743a | ||
|
|
b7ef892ecf | ||
|
|
f0b4164e2e | ||
|
|
3bcfa94ee4 | ||
|
|
c467bb2640 | ||
|
|
e0c96276df | ||
|
|
378438ffe7 | ||
|
|
13648d196a | ||
|
|
8c54c9b412 | ||
|
|
38c1e72c9d | ||
|
|
0959672591 | ||
|
|
4d82cc5957 | ||
|
|
43fb4753fc | ||
|
|
f854b5bffb | ||
|
|
eb25dfd399 | ||
|
|
b627885788 | ||
|
|
c30036bdac | ||
|
|
766acadcf1 | ||
|
|
ef479ff539 | ||
|
|
6f1d2e771d | ||
|
|
ae445606e2 | ||
|
|
4f3dd1ddb4 | ||
|
|
d8f615751a | ||
|
|
7ce451d20c | ||
|
|
5212099b9f | ||
|
|
8cce3b98ce | ||
|
|
683fc77f80 | ||
|
|
ec9a72d9fb | ||
|
|
31bd9ec417 | ||
|
|
29b103c376 | ||
|
|
70a7047ee1 | ||
|
|
26f293523a | ||
|
|
45f007d412 | ||
|
|
22c8bc9b9b | ||
|
|
26cbc67385 | ||
|
|
41dad38177 | ||
|
|
838439080a | ||
|
|
6a88f2e880 | ||
|
|
8832607574 | ||
|
|
8fc7b2c171 | ||
|
|
afd1e71761 | ||
|
|
4fc95d646d | ||
|
|
91f592a875 | ||
|
|
059ec60e9f | ||
|
|
5648077978 | ||
|
|
1cb8cd3930 | ||
|
|
7fd6998f7c | ||
|
|
5e96fac52f | ||
|
|
4a9c4dbc04 | ||
|
|
9e74d0aea7 | ||
|
|
559024c331 | ||
|
|
16c18dde24 | ||
|
|
adbf7c8663 | ||
|
|
797bfe905e | ||
|
|
38169c8fdd | ||
|
|
c7b9969129 | ||
|
|
231b800784 | ||
|
|
8a959b4342 | ||
|
|
46174f78b3 | ||
|
|
b8cff8a434 | ||
|
|
150d693fe7 | ||
|
|
ecc9e4d8cd | ||
|
|
1e3a06560f | ||
|
|
b619f39555 | ||
|
|
02bb350bb3 | ||
|
|
bce43f74eb | ||
|
|
56dd1124ab | ||
|
|
4e785d12a9 | ||
|
|
127aab8159 | ||
|
|
78e86d879f | ||
|
|
00423bb738 | ||
|
|
8a64168a43 | ||
|
|
641d85b14e | ||
|
|
5bb8adbc32 | ||
|
|
ea42041f93 | ||
|
|
05a1c0aa73 | ||
|
|
790e544689 | ||
|
|
a209f9911c | ||
|
|
4b2bfbd85f | ||
|
|
4e8657568c | ||
|
|
81bf4eccba | ||
|
|
378e130f14 | ||
|
|
d7cf95b515 | ||
|
|
0ed880f3f7 | ||
|
|
b329ea8e96 | ||
|
|
ced38b1b0f | ||
|
|
d9cf1cb78e | ||
|
|
0d45b277d6 | ||
|
|
e95ba5bf59 | ||
|
|
4e8875b5e9 | ||
|
|
fdf1612f0f | ||
|
|
42caff5587 | ||
|
|
50a242f16a | ||
|
|
1ac1ff457a | ||
|
|
9a20206945 | ||
|
|
10cec2b7e2 | ||
|
|
d0d728c6a6 | ||
|
|
3370a6a83d | ||
|
|
1d67987459 | ||
|
|
1a0ed00f74 | ||
|
|
21953ddf3d | ||
|
|
d890178610 | ||
|
|
bca96a5d3b | ||
|
|
dfe58c4809 | ||
|
|
e8731883a5 | ||
|
|
0840103ae0 | ||
|
|
251288ec59 | ||
|
|
3d4dc19412 | ||
|
|
78c9e2080c | ||
|
|
1cbb62ed6a | ||
|
|
7580a9aaaa | ||
|
|
edc473e8b0 | ||
|
|
aaedce596e | ||
|
|
60d769a899 | ||
|
|
beee22a95e | ||
|
|
aa6a78f0a4 | ||
|
|
2b6e2ceb2e | ||
|
|
449d5e1113 | ||
|
|
cb6589db98 | ||
|
|
584b844aaf | ||
|
|
69c3ab1a49 | ||
|
|
00da4450db | ||
|
|
afbd879685 | ||
|
|
6a1baa89b1 | ||
|
|
a4529beb7c | ||
|
|
d1c8dc5420 | ||
|
|
ec26b753a2 | ||
|
|
0c317f2508 | ||
|
|
3c6536d932 | ||
|
|
2859f1b795 | ||
|
|
2be309de1d | ||
|
|
6491bb4fb7 | ||
|
|
1b86d35f7e | ||
|
|
549f5e8dff | ||
|
|
0f1484c2f4 | ||
|
|
f6d8e86439 | ||
|
|
61826dc7ac | ||
|
|
855d103aef | ||
|
|
77068c781d | ||
|
|
bfe7e090bc | ||
|
|
824438949e | ||
|
|
f1f1161c17 | ||
|
|
e1e23eb9bd | ||
|
|
c14f792f8f | ||
|
|
310fc629b0 | ||
|
|
314a0ea441 | ||
|
|
9607e3b5a8 | ||
|
|
a907ecd4ff | ||
|
|
3e35797b18 | ||
|
|
23be1db1e3 | ||
|
|
f309d86003 | ||
|
|
38e13282cd | ||
|
|
84c5e74459 | ||
|
|
36a8b2226f | ||
|
|
43966cc787 | ||
|
|
f51be7f201 | ||
|
|
66a6ef3859 | ||
|
|
745a671ce6 | ||
|
|
abe29647ae | ||
|
|
c63d0003a1 | ||
|
|
5d4b4ecbfb | ||
|
|
211199e864 | ||
|
|
e1fff05d0d | ||
|
|
5c8d675eed | ||
|
|
fd0c1f2ab4 | ||
|
|
31cc7f3b87 | ||
|
|
ecc04e8ba7 | ||
|
|
c51c6e38ac | ||
|
|
55f2daa21e | ||
|
|
2d2a5bebff | ||
|
|
6ca7c14b58 | ||
|
|
fdbbad04bb | ||
|
|
873914a2a6 | ||
|
|
50758505d5 | ||
|
|
462729d865 | ||
|
|
bf1602d9f9 | ||
|
|
d4de69381e | ||
|
|
503fc458d8 | ||
|
|
a3d59b525b | ||
|
|
b7a91e02e9 | ||
|
|
58b6eceb6d | ||
|
|
91d8a629eb | ||
|
|
8b38353012 | ||
|
|
3b04131259 | ||
|
|
d84699d8e5 | ||
|
|
ae3cc48f22 | ||
|
|
4adf658907 | ||
|
|
260a13a12f | ||
|
|
088e8af955 | ||
|
|
49abc193f7 | ||
|
|
a05c797e4a | ||
|
|
b46dc9ee0c | ||
|
|
75c0675e14 | ||
|
|
49d73d1893 | ||
|
|
409b56f6a3 | ||
|
|
148718b3bc | ||
|
|
5349667992 | ||
|
|
c4a4c34156 | ||
|
|
d4fbedcd35 | ||
|
|
5bfe6dc703 | ||
|
|
8453fbf4eb | ||
|
|
e15014e031 | ||
|
|
bc764f7065 | ||
|
|
06fcdbd9c7 | ||
|
|
01971cb6c7 | ||
|
|
d0f58baf29 | ||
|
|
8bfff87833 | ||
|
|
6821723b44 | ||
|
|
e589adb00d | ||
|
|
523eed048e | ||
|
|
e6bb809663 | ||
|
|
b5433bb753 | ||
|
|
bcb96c5532 | ||
|
|
f22b5971d1 | ||
|
|
87653077f8 | ||
|
|
a21882be33 | ||
|
|
37be9a8959 | ||
|
|
f5af40afce | ||
|
|
6375e471f3 | ||
|
|
c6497a7193 | ||
|
|
9517d0eaa4 | ||
|
|
78e9eddfb6 | ||
|
|
2f34ef141b | ||
|
|
8f948827a6 | ||
|
|
9856563f89 | ||
|
|
bb958a9e13 | ||
|
|
c75f85098c | ||
|
|
4a30e2acd9 | ||
|
|
ceec1943ff | ||
|
|
83c453cb82 | ||
|
|
54369adffa | ||
|
|
d23ed852fc | ||
|
|
a16d0c76a6 | ||
|
|
6a5f4f5954 | ||
|
|
b99c193e46 | ||
|
|
9b51d73a1e | ||
|
|
3c9447ca53 | ||
|
|
90c8609cbb | ||
|
|
b246f33ab1 | ||
|
|
e9c5594186 | ||
|
|
e827b75e22 | ||
|
|
9adacef70b | ||
|
|
f464dfbefa | ||
|
|
8c37d2ce25 | ||
|
|
ee8978b961 | ||
|
|
ab900d8752 | ||
|
|
0fea173fc8 | ||
|
|
a01d20cfe8 | ||
|
|
e4b6fedfb9 | ||
|
|
1fc7e80bdb | ||
|
|
b850b35778 | ||
|
|
2796ec1cf2 | ||
|
|
3d6476c902 | ||
|
|
9a67e0421b | ||
|
|
3bbdf9dc5a | ||
|
|
1f337a7a5e | ||
|
|
452a158107 | ||
|
|
f4f090e4b2 | ||
|
|
5a348fb7df | ||
|
|
aea8132001 | ||
|
|
cf7e3aa448 | ||
|
|
c7c8ca475b | ||
|
|
24e5f9974d | ||
|
|
dd33128c2f | ||
|
|
8b1d5560cf | ||
|
|
2388874738 | ||
|
|
4be32dbff4 | ||
|
|
8ebff1948f | ||
|
|
a301d54df8 | ||
|
|
ff2f85641a | ||
|
|
b49d0ca20e | ||
|
|
86b5e3bfbc | ||
|
|
54ccf9c6b3 | ||
|
|
e999ad664d | ||
|
|
9fb6b5d96b | ||
|
|
0fb63c68e9 | ||
|
|
83a4c61048 | ||
|
|
bef1321f00 | ||
|
|
0ece4af36a | ||
|
|
aba2cfe7a8 | ||
|
|
d4e8a44087 | ||
|
|
1905c41c65 | ||
|
|
bd5703d5c6 | ||
|
|
d037c54260 | ||
|
|
c3894d9288 | ||
|
|
3db3baa19e | ||
|
|
57d20a1bf6 | ||
|
|
472b52bc06 | ||
|
|
79b9edb85b | ||
|
|
f08167c877 | ||
|
|
ad85406220 | ||
|
|
d14f81e6ac | ||
|
|
826061d166 | ||
|
|
748419faa5 | ||
|
|
412c7dc7f7 | ||
|
|
8329de1ab5 | ||
|
|
144885d89f | ||
|
|
f7526d6be0 | ||
|
|
6910ca76bd | ||
|
|
6bdb1f413e | ||
|
|
81468253ea | ||
|
|
231e01e39b | ||
|
|
c6f713fefe | ||
|
|
91967f8ec0 | ||
|
|
0a47575c7f | ||
|
|
8801770981 | ||
|
|
66b99bd277 | ||
|
|
2794f485cb | ||
|
|
0ac3bef724 | ||
|
|
456c820d52 | ||
|
|
c35c2fea40 | ||
|
|
d6fbd89336 | ||
|
|
fb7548cb41 | ||
|
|
423b69f5d3 | ||
|
|
abdfc5ea40 | ||
|
|
59c886d855 | ||
|
|
d7a87ce6e2 | ||
|
|
d9f7448d82 | ||
|
|
b5c0d0b8aa | ||
|
|
b1d0a727cc | ||
|
|
ef2c73af80 | ||
|
|
16c62a6dbb | ||
|
|
2d1c6f88d2 | ||
|
|
82b8549542 | ||
|
|
69c2b2926e | ||
|
|
4078e1d17c | ||
|
|
af2fdb5d58 | ||
|
|
9190443d95 | ||
|
|
9bf1b49144 | ||
|
|
5cc6cb4945 | ||
|
|
9b327ddfd1 | ||
|
|
24915a3a9b | ||
|
|
90d0b8ecae | ||
|
|
ddb9f8394d | ||
|
|
a62ccb169a | ||
|
|
be6ee6e55f | ||
|
|
c2805aad92 | ||
|
|
4c4c9bb324 | ||
|
|
292a7456af | ||
|
|
2347050285 | ||
|
|
a58ab20e8b | ||
|
|
cc0792c1dc | ||
|
|
28c9122adb | ||
|
|
55076edaac | ||
|
|
81cd526f92 | ||
|
|
bd4733a0ff | ||
|
|
4f161da3d6 | ||
|
|
185c96849e | ||
|
|
b90910c0dc | ||
|
|
eb3b38d40b | ||
|
|
d9c8a37811 | ||
|
|
158c0f2911 | ||
|
|
44cb8f769e | ||
|
|
705b97c4ac | ||
|
|
c19f383685 | ||
|
|
bb5cd5b2dd | ||
|
|
bb9aa79b21 | ||
|
|
dfa4836216 | ||
|
|
18377d221d | ||
|
|
2aa21625bd | ||
|
|
2946009006 | ||
|
|
b0cc49218d | ||
|
|
a5c9b3e490 | ||
|
|
dfb841c303 | ||
|
|
5ceb0ec15d | ||
|
|
f707d86912 | ||
|
|
75f2cb5f65 | ||
|
|
a51e639d81 | ||
|
|
59b2340680 | ||
|
|
da3583fd5e | ||
|
|
04124988e8 | ||
|
|
390a357859 | ||
|
|
9a87498bb1 | ||
|
|
f58bb72d3a | ||
|
|
60cd5b7a48 | ||
|
|
25cf06f6cf | ||
|
|
e44aae0c20 | ||
|
|
fcb6f936ea | ||
|
|
9958d29764 | ||
|
|
239cdd67fd | ||
|
|
f01e3043b8 | ||
|
|
04c98abd1f | ||
|
|
53bfb92d65 | ||
|
|
2b3cac018e | ||
|
|
f909b0f114 | ||
|
|
fa1e343b04 | ||
|
|
22b12e3013 | ||
|
|
7a971735af | ||
|
|
6abb5b0c7e | ||
|
|
0dfcba9825 | ||
|
|
e5df8cdc62 | ||
|
|
f8bbe5124c | ||
|
|
948277895e | ||
|
|
708a7c24ef | ||
|
|
1ce614dfc0 | ||
|
|
930eeac900 | ||
|
|
ec93f8a1cd | ||
|
|
997fefbc11 | ||
|
|
c7eb141098 | ||
|
|
1f50cdfa8b | ||
|
|
1c530cbc66 | ||
|
|
9cd5b25745 | ||
|
|
78ff20ddf0 | ||
|
|
2626f89ea6 | ||
|
|
adbae0f74d | ||
|
|
46ac115bd1 | ||
|
|
3465efcdc1 | ||
|
|
cdf5736f1a | ||
|
|
2d6ca96e07 | ||
|
|
d9cad5e1b6 | ||
|
|
0c736217a7 | ||
|
|
77ecf09506 | ||
|
|
f1ac1847ff | ||
|
|
ce821294e2 | ||
|
|
6f174a9e08 | ||
|
|
5b3e489108 | ||
|
|
2670b8f772 | ||
|
|
858c0e26d1 | ||
|
|
b5ef049ea1 | ||
|
|
615e0dae46 | ||
|
|
ce4766772d | ||
|
|
8d6618104e | ||
|
|
50e1bec85f | ||
|
|
b8a204c21d | ||
|
|
2ee5118d7a | ||
|
|
5d005f11fa | ||
|
|
54c89104de | ||
|
|
b2ad21a65c | ||
|
|
72cb5d24b6 | ||
|
|
9868b18378 | ||
|
|
208f4c48db | ||
|
|
4506871310 | ||
|
|
6483f4ec22 | ||
|
|
ae1fe860ff | ||
|
|
49974d5e34 | ||
|
|
94bc132084 | ||
|
|
e9c3fcbb64 | ||
|
|
40147d3a3f | ||
|
|
23ecce0e7a | ||
|
|
465e3d979d | ||
|
|
b10a43dabc | ||
|
|
5bd7ff884d | ||
|
|
2118440488 | ||
|
|
c505eb55ff | ||
|
|
f5c5cfa960 | ||
|
|
0302bfdc22 | ||
|
|
4f868a1f3c | ||
|
|
94c55fe909 | ||
|
|
742bce016c | ||
|
|
4cf62c114e | ||
|
|
41f5f67f6c | ||
|
|
02d7badd15 | ||
|
|
0e80ecc534 | ||
|
|
be6268a7ec | ||
|
|
a9549dbca0 | ||
|
|
b06fbdb743 | ||
|
|
241a4935a2 | ||
|
|
3577a6be31 | ||
|
|
2e540e4ec4 | ||
|
|
a4f7d7c594 | ||
|
|
55e953b383 | ||
|
|
d29723cb76 | ||
|
|
400dd16072 | ||
|
|
a3b96961a2 | ||
|
|
a3d32f3b70 | ||
|
|
4d14bcb02f | ||
|
|
9b4060f09b | ||
|
|
867bc86089 | ||
|
|
f48ee7a3d1 | ||
|
|
51afc2c291 | ||
|
|
02f7da2bf2 | ||
|
|
7631d4c73f | ||
|
|
ddae3036ca | ||
|
|
225e13c3cc | ||
|
|
3fa6320a39 | ||
|
|
1ae7e2164c | ||
|
|
877fb5b93a | ||
|
|
0e521788bc | ||
|
|
ffd6cf65e4 | ||
|
|
8b7b169043 | ||
|
|
533bc5115e | ||
|
|
99ab3e19d9 | ||
|
|
f4e19d3f1e | ||
|
|
06469b3391 | ||
|
|
303a10d27c | ||
|
|
4d85e7996d | ||
|
|
2da4f427ea | ||
|
|
a17cea8b8c | ||
|
|
6538970087 | ||
|
|
0399e64274 | ||
|
|
382f0f23f1 | ||
|
|
b83c9f5c6f | ||
|
|
d775686380 | ||
|
|
0dc531c4a7 | ||
|
|
0a7e2cb152 | ||
|
|
4f991610d0 | ||
|
|
ea852965ff | ||
|
|
260d8e1f71 | ||
|
|
642f394eb3 | ||
|
|
b15c2bfff6 | ||
|
|
da86db43d4 | ||
|
|
70ae99f521 | ||
|
|
a8eda7f978 | ||
|
|
8a8f394da7 | ||
|
|
51838fb5f5 | ||
|
|
85f874d10f | ||
|
|
9b3925009a | ||
|
|
3c128679ee | ||
|
|
e96b8ce4cc | ||
|
|
433b7881a3 | ||
|
|
ed05f14300 | ||
|
|
c62fb08da6 | ||
|
|
8ba20fcae1 | ||
|
|
ff97d18c4c | ||
|
|
5e8bb71785 | ||
|
|
b496e2c718 | ||
|
|
a41b8d5e97 | ||
|
|
8654029f86 | ||
|
|
a4e6c5d678 | ||
|
|
3a47c73f34 | ||
|
|
1f0fd79b91 | ||
|
|
d1a59ec39e | ||
|
|
4c987b20e2 | ||
|
|
2309270752 | ||
|
|
79b526a041 | ||
|
|
075bbecabd | ||
|
|
8aaffda969 | ||
|
|
10a335631e | ||
|
|
da2d7c3971 | ||
|
|
05eb0aa43d | ||
|
|
fc7223edc0 | ||
|
|
86c279d7d0 | ||
|
|
46b00a4a86 | ||
|
|
4a79eea6dc | ||
|
|
7374a023ef | ||
|
|
a46576afc3 | ||
|
|
10035a85cc | ||
|
|
c93140a5f1 | ||
|
|
5380cbcdda | ||
|
|
9ea76428b6 | ||
|
|
0cd04bd666 | ||
|
|
1c2b9a9ce3 | ||
|
|
cec084c178 | ||
|
|
c2ef8fcc00 | ||
|
|
3fc3521a97 | ||
|
|
9a67354fa2 | ||
|
|
f7ba86d1f3 | ||
|
|
f3db1b172c | ||
|
|
2a6d070774 | ||
|
|
aec69131cd | ||
|
|
4b968e5bc1 | ||
|
|
a852461c7d | ||
|
|
e4abf26069 | ||
|
|
006bd9eef5 | ||
|
|
5ee35f914f | ||
|
|
aa1bd647b1 | ||
|
|
fdb7ca6c8f | ||
|
|
6ab5a0befb | ||
|
|
6384f4acf4 | ||
|
|
4600043a49 | ||
|
|
279b06044c | ||
|
|
ccbdba7ee2 | ||
|
|
c7f0519faf | ||
|
|
7ea4fbf0ba | ||
|
|
f6ca4bac51 | ||
|
|
155eba57d8 | ||
|
|
7b10530a0d | ||
|
|
a25a214523 | ||
|
|
c8d80a2920 | ||
|
|
03385fc07f | ||
|
|
cca0f48b74 | ||
|
|
60edb376f2 | ||
|
|
6f74d8d7e9 | ||
|
|
ec4bea7901 | ||
|
|
9171db1984 | ||
|
|
5f60fc7d00 | ||
|
|
c4f46473df | ||
|
|
011d7ccb91 | ||
|
|
efc51eb7d1 | ||
|
|
c2835b6b0f | ||
|
|
d5d7f69d1e | ||
|
|
5cef2f44fe | ||
|
|
22154fa272 | ||
|
|
2ddd16ef28 | ||
|
|
d7382aa8a1 | ||
|
|
90306bdae6 | ||
|
|
b1ab0f7539 | ||
|
|
bf5e4bf116 | ||
|
|
4c471218c9 | ||
|
|
e59680481d | ||
|
|
f4315db50f | ||
|
|
3cc8e8c6be | ||
|
|
b37944605f | ||
|
|
f4995c1837 | ||
|
|
6ffde36466 | ||
|
|
c754d7963f | ||
|
|
8c97cb7858 | ||
|
|
e86d3a14e4 | ||
|
|
4b25fbe5fd | ||
|
|
81e93acba4 | ||
|
|
b21edb1a97 | ||
|
|
e4af4b5e2e | ||
|
|
d30cc19d25 | ||
|
|
f15b49e0fd | ||
|
|
c544c5115c | ||
|
|
b80b64cd6c | ||
|
|
4082e876d5 | ||
|
|
8ce1665fdb | ||
|
|
7753e8ea68 | ||
|
|
cb4230e1c2 | ||
|
|
7055d0c138 | ||
|
|
4435f5c546 | ||
|
|
7a84317f33 | ||
|
|
2433760786 | ||
|
|
b51ab182ae | ||
|
|
d7e7a29261 | ||
|
|
f1ef724a87 | ||
|
|
474bfcbccd | ||
|
|
905ca39bc9 | ||
|
|
3a21dd84b3 | ||
|
|
e6be4af21f | ||
|
|
2c78867a98 | ||
|
|
2acbb59bf2 | ||
|
|
11943f761e | ||
|
|
f148b96bea | ||
|
|
445337d03d | ||
|
|
34f2a4713e | ||
|
|
d5920bc5da | ||
|
|
aee9b8ac19 | ||
|
|
32a3d84d74 | ||
|
|
002cd91fbf | ||
|
|
01f4074421 | ||
|
|
6787fe8933 | ||
|
|
f0850905f0 | ||
|
|
d1ea18b492 | ||
|
|
73ae9790f9 | ||
|
|
3458d7ac93 | ||
|
|
e59464629f | ||
|
|
2e81648980 | ||
|
|
8f50460bfe | ||
|
|
f4b148df1e | ||
|
|
0e24f9c0d5 | ||
|
|
2cfa5d2408 | ||
|
|
fa246cb6ed | ||
|
|
6d25ef09cd | ||
|
|
0137a5f6cd | ||
|
|
3c1a2e9fca | ||
|
|
fb8eaba83f | ||
|
|
3352317ca8 | ||
|
|
e59623d1d5 | ||
|
|
d01f9943e1 | ||
|
|
59c615c321 | ||
|
|
e2a9271150 | ||
|
|
897ee276dc | ||
|
|
94a30889a7 | ||
|
|
9228116c9a | ||
|
|
410da2e46f | ||
|
|
7a6fde8414 | ||
|
|
3eb6cb1875 | ||
|
|
2f967037aa | ||
|
|
1309b59f2c | ||
|
|
fb36815b01 | ||
|
|
df3fba1572 | ||
|
|
40adb3dfb4 | ||
|
|
5d2b008294 | ||
|
|
208f94fe12 | ||
|
|
1789405163 | ||
|
|
68bb3e7f0a | ||
|
|
f83fe9986b | ||
|
|
f2d43e5f21 | ||
|
|
e1179b665b | ||
|
|
f261fb6fe0 | ||
|
|
3a43e7bb9a | ||
|
|
1f97643e83 | ||
|
|
56f6f61596 | ||
|
|
8e10ddb592 | ||
|
|
feb8ad48f0 | ||
|
|
f7fcbe32c9 | ||
|
|
a724332eb8 | ||
|
|
54441e0c4e | ||
|
|
acbcf0cf11 | ||
|
|
30b49c75bf | ||
|
|
ff9e059de6 | ||
|
|
f1e32cd122 | ||
|
|
868b2b544a | ||
|
|
8a6778f0a0 | ||
|
|
64591c85aa | ||
|
|
873bff390e | ||
|
|
84c9baecc6 | ||
|
|
3b99e906df | ||
|
|
5e7292434a | ||
|
|
70cfc7cc9c | ||
|
|
1da0b2c02e | ||
|
|
708d166360 | ||
|
|
44004abc01 | ||
|
|
31431a9271 | ||
|
|
70d94fec13 | ||
|
|
373108102c | ||
|
|
97a24ec6f3 | ||
|
|
64fefa3749 | ||
|
|
e380b6ed66 | ||
|
|
88adae73ba | ||
|
|
c6f672257b | ||
|
|
5b43c106bd | ||
|
|
d11d069715 | ||
|
|
ddf180fa30 | ||
|
|
a4b7d1c2d7 | ||
|
|
12b5034c99 | ||
|
|
9c38287410 | ||
|
|
ac5668192e | ||
|
|
7d51dee103 | ||
|
|
ea16b64ec1 | ||
|
|
e6a9cfab91 | ||
|
|
ef03f69116 | ||
|
|
32c0fa2f2f | ||
|
|
7d1c78f4a3 | ||
|
|
d462cc7fa1 | ||
|
|
09ec1cca51 | ||
|
|
6fc9c8e479 | ||
|
|
6131919715 | ||
|
|
aaa5573c73 | ||
|
|
344e32d71b | ||
|
|
d41135d07c | ||
|
|
b884f1f7c8 | ||
|
|
3d1dd6b5c7 | ||
|
|
1d3904c3e7 | ||
|
|
529ad4eaf4 | ||
|
|
d3042e5358 | ||
|
|
d2773d7a4e | ||
|
|
5fd90548dc | ||
|
|
25d5ce4833 | ||
|
|
e7a72de9b5 | ||
|
|
cb7ed4f62b | ||
|
|
2a478c30ca | ||
|
|
04ac46c543 | ||
|
|
2f55806d6f | ||
|
|
3b207d29bd | ||
|
|
6bd6c5512e | ||
|
|
bb5b09def0 | ||
|
|
efe29a2461 | ||
|
|
e951011503 | ||
|
|
16aeb24bc1 | ||
|
|
74d0f34cf3 | ||
|
|
4abf9155ee | ||
|
|
0a28e13787 | ||
|
|
3cd6e3960f | ||
|
|
8b1d6e3009 | ||
|
|
445acec2a2 | ||
|
|
45c3787e75 | ||
|
|
9199a9746d | ||
|
|
bce58d9d65 | ||
|
|
f3fc8d599a | ||
|
|
107723bdf4 | ||
|
|
065e89648b | ||
|
|
354d4594de | ||
|
|
089fdd1ea0 | ||
|
|
1815f9a2e5 | ||
|
|
d8f79d7678 | ||
|
|
80b2fd135b | ||
|
|
fda9790cde | ||
|
|
9b3f71390c | ||
|
|
0e5d03a557 | ||
|
|
57a39984dd | ||
|
|
944e36ea2e | ||
|
|
4a1b960cbe | ||
|
|
5d8261aee2 | ||
|
|
d075d1cab9 | ||
|
|
bb099e5733 | ||
|
|
dadb2e0949 | ||
|
|
a8c2d5a616 | ||
|
|
465cf66df1 | ||
|
|
1a0a22ad03 | ||
|
|
0a1ae48a9f | ||
|
|
ae403e6a05 | ||
|
|
ae4e38d9d5 | ||
|
|
ecae3c5e4b | ||
|
|
f1bd62806e | ||
|
|
fda5626594 | ||
|
|
c90dbfab6f | ||
|
|
d335c8f101 | ||
|
|
c8a0443adc | ||
|
|
ce48bc5408 | ||
|
|
da6e966313 | ||
|
|
a661203bb6 | ||
|
|
9e8d9791c7 | ||
|
|
2d82a92324 | ||
|
|
407453166c | ||
|
|
8dd2cd41fb | ||
|
|
0a0e56d99c | ||
|
|
086fd7ece8 | ||
|
|
4da9b7cc5b | ||
|
|
f56153a9c1 | ||
|
|
a36fa5c229 | ||
|
|
fdfcfc824e | ||
|
|
d01756c1f4 | ||
|
|
078e13f463 | ||
|
|
47d645d84a | ||
|
|
b65f8a8723 | ||
|
|
401a3bae61 | ||
|
|
76a899627e | ||
|
|
b7a3c45269 | ||
|
|
2bad73354a | ||
|
|
0dc7367a70 | ||
|
|
52b9ae592b | ||
|
|
25add26881 | ||
|
|
f16f170433 | ||
|
|
a6b263713a | ||
|
|
4f0f512cab | ||
|
|
a3a7499317 | ||
|
|
b117fae3b4 | ||
|
|
2671656a75 | ||
|
|
2778aff08f | ||
|
|
9e4f90aedf | ||
|
|
15dc024a39 | ||
|
|
3b85690aa6 | ||
|
|
cef09fbfe6 | ||
|
|
a8b568c6c4 | ||
|
|
b5fb6110ab | ||
|
|
da9252a23e | ||
|
|
8475a8ef99 | ||
|
|
f9c37ca43b | ||
|
|
9dc9366fc6 | ||
|
|
85aba23cbe | ||
|
|
2d1ebadb9b | ||
|
|
e66eab7b6a | ||
|
|
c9822b08f9 | ||
|
|
983bc067da | ||
|
|
b320bc2dc6 | ||
|
|
ad64726f5d | ||
|
|
5fa2594659 | ||
|
|
75727e7c17 | ||
|
|
67e1e46f9b | ||
|
|
308b1f3afb | ||
|
|
c143907857 | ||
|
|
830350a1f7 | ||
|
|
95542e4488 | ||
|
|
5642ed331d | ||
|
|
c7086f936a | ||
|
|
b9f110ef87 | ||
|
|
1bf4937b02 | ||
|
|
6a90b50545 | ||
|
|
602d6b7356 | ||
|
|
780e3dd542 | ||
|
|
f1a7a7497e | ||
|
|
f390f48a07 | ||
|
|
1b06d222cf | ||
|
|
391ff29110 | ||
|
|
a5c14370c1 | ||
|
|
b0bae15499 | ||
|
|
e8317ae34d | ||
|
|
a25d228840 | ||
|
|
60f069d540 | ||
|
|
2e6e0e9278 | ||
|
|
f69e72eca1 | ||
|
|
b0cd9972e8 | ||
|
|
f3c49c1295 | ||
|
|
4971725b69 | ||
|
|
1697171fc0 | ||
|
|
81721b8aa8 | ||
|
|
365caa49ff | ||
|
|
94381e5999 | ||
|
|
42fd366046 | ||
|
|
cbd2451570 | ||
|
|
dde3e082c9 | ||
|
|
9f3c9ac01a | ||
|
|
7f177fa1cf | ||
|
|
d64ac47202 | ||
|
|
4e93b2def5 | ||
|
|
aff34089c4 | ||
|
|
1989b0049f | ||
|
|
9f933da1c5 | ||
|
|
af301312d5 | ||
|
|
8c14c2a5f4 | ||
|
|
cb211d83f6 | ||
|
|
fde569db65 | ||
|
|
5b37d53992 | ||
|
|
deb077c346 | ||
|
|
3f40d6d936 | ||
|
|
a364e80425 | ||
|
|
2b01a5bcf6 | ||
|
|
8d4c18d723 | ||
|
|
c600e1aaff | ||
|
|
cca0adf6a3 | ||
|
|
534adad6b1 | ||
|
|
775111b603 | ||
|
|
85632e7c33 | ||
|
|
43ca66779b | ||
|
|
e75e2cdac7 | ||
|
|
2eaa4d80a0 | ||
|
|
dddb64dc35 | ||
|
|
1a3d17da91 | ||
|
|
2a24a61126 | ||
|
|
2e2e2e2cad | ||
|
|
68a5842f06 | ||
|
|
5f7ad767db | ||
|
|
a4a4fffffb | ||
|
|
1830296df3 | ||
|
|
e536b02248 | ||
|
|
1cc1a46c2e | ||
|
|
31422ae25d | ||
|
|
57921d7dbd | ||
|
|
8e8073c421 | ||
|
|
52ee7a8748 | ||
|
|
71dc9f6128 | ||
|
|
fd67ee9ecd | ||
|
|
bec18dc6f9 | ||
|
|
5b714f05f8 | ||
|
|
7c43eed2c1 | ||
|
|
23e7d8f6a7 | ||
|
|
df06cb4d71 | ||
|
|
0fec38fe72 | ||
|
|
80a4852266 | ||
|
|
4c4471c66d | ||
|
|
6378c8ed65 | ||
|
|
49e5f9c428 | ||
|
|
5f1df55fcb | ||
|
|
e2c78c00e5 | ||
|
|
bd7092a9fe | ||
|
|
c7d9719910 | ||
|
|
7ae7920572 | ||
|
|
4b6163aef3 | ||
|
|
788ae58897 | ||
|
|
bba2d9a197 | ||
|
|
e340e9f431 | ||
|
|
c2d14a2013 | ||
|
|
95cdedee04 | ||
|
|
0706c1a1f7 | ||
|
|
aecf1abddd | ||
|
|
b9f82e9968 | ||
|
|
e06b520427 | ||
|
|
dab50b3ef3 | ||
|
|
eaac5c7cbd | ||
|
|
a5234f26e4 | ||
|
|
de3ad245dc | ||
|
|
db24964877 | ||
|
|
9f7a96b997 | ||
|
|
3cba4ba44e | ||
|
|
8237627f3a | ||
|
|
35e134e570 | ||
|
|
452a7e6905 | ||
|
|
61a51bb4ef | ||
|
|
aefaeedf5e | ||
|
|
cef5e6dd7c | ||
|
|
7c03e9d376 | ||
|
|
df956a0f6f | ||
|
|
33f271c29a | ||
|
|
e892310953 | ||
|
|
4d05677e8d | ||
|
|
c16044a5c8 | ||
|
|
d94d8b4ab2 | ||
|
|
bb5c3f2702 | ||
|
|
0a27af8cd1 | ||
|
|
c106f454c1 | ||
|
|
875b598a33 | ||
|
|
8bbeee1173 | ||
|
|
b1e5cc66bd | ||
|
|
5ff02902ee | ||
|
|
cccca7c02e | ||
|
|
10a4365f7d | ||
|
|
a7a6eedc21 | ||
|
|
888bdf4e23 | ||
|
|
ceef4fb3a5 | ||
|
|
22f7d6f142 | ||
|
|
f9e4998a6d | ||
|
|
3c617ce33c | ||
|
|
f6ac755cf7 | ||
|
|
320144ae72 | ||
|
|
92186898c0 | ||
|
|
10a9fec7fc | ||
|
|
6d7544458d | ||
|
|
d26439a0fe | ||
|
|
ef6b0c81c9 | ||
|
|
8f83d29f00 | ||
|
|
22bf2853e6 | ||
|
|
5963970be5 | ||
|
|
8b51eeb7ae | ||
|
|
5329298b52 | ||
|
|
e9a7fb8f91 | ||
|
|
1fb720b62a | ||
|
|
2687788236 | ||
|
|
0ddb952d7a | ||
|
|
1930a95000 | ||
|
|
cc38e7e18f | ||
|
|
55ec8bd512 | ||
|
|
54f57797e9 | ||
|
|
65f66dcf0d | ||
|
|
451d7a41fc | ||
|
|
00d6261cc0 | ||
|
|
745a82ce8a | ||
|
|
a847bc67b1 | ||
|
|
b100344595 | ||
|
|
943b3d467b | ||
|
|
940f7aa990 | ||
|
|
e5fa017172 | ||
|
|
c4eda46d0e | ||
|
|
aa067a4cf1 | ||
|
|
67cee43006 | ||
|
|
47a1650c48 | ||
|
|
936dfedbad | ||
|
|
6113f4da7f | ||
|
|
cc923ad031 | ||
|
|
df9ff44899 | ||
|
|
97493511f9 | ||
|
|
505c1f8f4a | ||
|
|
6744bb57c6 | ||
|
|
2259a88551 | ||
|
|
1ba050d603 | ||
|
|
e8717a4fce | ||
|
|
9b03307653 | ||
|
|
b735295d2b | ||
|
|
8d5cdedbd3 | ||
|
|
4f591e807a | ||
|
|
fb91c2550f | ||
|
|
0ddbd1c3a4 | ||
|
|
af83c82513 | ||
|
|
9d37b1b073 | ||
|
|
cf18eca86d | ||
|
|
ec1e6be003 | ||
|
|
83be2480c4 | ||
|
|
7affc34ab4 | ||
|
|
098e491a43 | ||
|
|
967fe76a60 | ||
|
|
940ed3d525 | ||
|
|
6f7280a690 | ||
|
|
20031cea92 | ||
|
|
3fb47372b7 | ||
|
|
bb160cfe37 | ||
|
|
a29cfa7843 | ||
|
|
f5fa84554f | ||
|
|
b88e4a1a9a | ||
|
|
ff411658e8 | ||
|
|
943c7d18cc | ||
|
|
ccfae82ad1 | ||
|
|
430b5c302a | ||
|
|
8fa4cfb7df | ||
|
|
a551f85b91 | ||
|
|
07052a515b | ||
|
|
1fa0cd7a75 | ||
|
|
c10739e6e3 | ||
|
|
9e628067fc | ||
|
|
99b01c5d12 | ||
|
|
a8ff3a452c | ||
|
|
dca75db127 | ||
|
|
a425fbebe4 | ||
|
|
cca227a53e | ||
|
|
b9c439a55e | ||
|
|
726d697821 | ||
|
|
0ccc0ace88 | ||
|
|
f43d4a8638 | ||
|
|
4c7a2faf85 | ||
|
|
3b66351eeb | ||
|
|
e58e97b0a3 | ||
|
|
2dd0b2af71 | ||
|
|
2ec2b3bfb3 | ||
|
|
0ec128e5ed | ||
|
|
083a5cf3c1 | ||
|
|
8f42401aa8 | ||
|
|
97a309b784 | ||
|
|
3bf6f78dad | ||
|
|
e4ab28b1fb | ||
|
|
81ad218b8b | ||
|
|
64c46db087 | ||
|
|
0920572e70 | ||
|
|
55ccb1a8cf | ||
|
|
d1638a09ba | ||
|
|
e3882b23d0 | ||
|
|
88e9e03945 | ||
|
|
0fb9a04526 | ||
|
|
44899cd548 | ||
|
|
cd0d049126 | ||
|
|
180c26ada6 | ||
|
|
5833abbbd1 | ||
|
|
514e0ff509 | ||
|
|
40081cb330 | ||
|
|
32b18179dd | ||
|
|
29e7dc6428 | ||
|
|
3c0605c68e | ||
|
|
d8b865366a | ||
|
|
3852418d24 | ||
|
|
c4d214c42d | ||
|
|
93b4478e70 | ||
|
|
7c7a84ff60 | ||
|
|
a0b2169ed6 | ||
|
|
ee91df62f0 | ||
|
|
12c1bb936d | ||
|
|
5f721dce36 | ||
|
|
d679d20029 | ||
|
|
7188ee4f99 | ||
|
|
c7315617eb | ||
|
|
d49a1334a8 | ||
|
|
2c481202ef | ||
|
|
6cf193e166 | ||
|
|
b1120ec433 | ||
|
|
5d4b54b012 | ||
|
|
b6e226c320 | ||
|
|
f9b52203f5 | ||
|
|
a3d3b4fd64 | ||
|
|
f3f7d3629a | ||
|
|
c356e42500 | ||
|
|
0b29caf9ab | ||
|
|
3dd8db83f1 | ||
|
|
d5689bb539 | ||
|
|
e5384774a8 | ||
|
|
f0e023bff2 | ||
|
|
3cec45d821 | ||
|
|
7f46680ab1 | ||
|
|
f603a22af0 | ||
|
|
cdac64970e | ||
|
|
6e0aadc585 | ||
|
|
2b6ff6837e | ||
|
|
29997ef4ba | ||
|
|
5e96d738e6 | ||
|
|
9df0f0b66c | ||
|
|
4093b993a2 | ||
|
|
08cc063e17 | ||
|
|
a17850e41c | ||
|
|
6a5c342063 | ||
|
|
f044e4c951 | ||
|
|
ce3ba798df | ||
|
|
0eaf3581a3 | ||
|
|
62ee5cc273 | ||
|
|
48bf32c5de | ||
|
|
904f9b6aee | ||
|
|
e5d3a71263 | ||
|
|
0e630e9e74 | ||
|
|
5f30cb7753 | ||
|
|
495b92fb53 | ||
|
|
b57086aa43 | ||
|
|
09581d32fd | ||
|
|
86e9f69a69 | ||
|
|
781828a56e | ||
|
|
0baf166d39 | ||
|
|
ace803948a | ||
|
|
01c2ff34dd | ||
|
|
22b1370ae5 | ||
|
|
f309681d4a | ||
|
|
ce62521883 | ||
|
|
e7fd0f5aec | ||
|
|
abfd550ee2 | ||
|
|
8e51a36c7f | ||
|
|
5c3bd8e93d | ||
|
|
05a5e0b4f1 | ||
|
|
b61d4c3636 | ||
|
|
e79d3cd2ef | ||
|
|
1822707c7e | ||
|
|
c3f7c9bbb5 | ||
|
|
ee8116ac5d | ||
|
|
f5db483973 | ||
|
|
7564b26b7d | ||
|
|
178a300eea | ||
|
|
d655a10381 | ||
|
|
b65773bea9 | ||
|
|
c4eb194033 | ||
|
|
6ae89940c7 | ||
|
|
3d28879c26 | ||
|
|
223dcc8bac | ||
|
|
6ce07ee864 | ||
|
|
bc299928ad | ||
|
|
ac658500fb | ||
|
|
8cced091f5 | ||
|
|
91299f7039 | ||
|
|
60308a2bb5 | ||
|
|
613eac4603 | ||
|
|
e4a26f4f1d | ||
|
|
57b632ead8 | ||
|
|
1bf63dfdcd | ||
|
|
e0cfbec66b | ||
|
|
b3a7e3109b | ||
|
|
45e82199fb | ||
|
|
4711796d38 | ||
|
|
0d70c44253 | ||
|
|
a364df4c9e | ||
|
|
46d990f1b6 | ||
|
|
5bf7b1e1fa | ||
|
|
97444ed7a8 | ||
|
|
4e41cda27e | ||
|
|
da86aac0f5 | ||
|
|
0c7a7e2d56 | ||
|
|
0ec6072a29 | ||
|
|
3ca699debf | ||
|
|
52c0919621 | ||
|
|
6fbfeefc71 | ||
|
|
46bf87c8d1 | ||
|
|
595eb89f6e | ||
|
|
a815b14bf1 | ||
|
|
3a5052a714 | ||
|
|
8e237b006f | ||
|
|
1ed925b69c | ||
|
|
aed529f695 | ||
|
|
de68e065fe | ||
|
|
e2426942e5 | ||
|
|
5c6c300abf | ||
|
|
6bd3397141 | ||
|
|
68fd32c810 | ||
|
|
3ddb16bd5b | ||
|
|
f6387536f6 | ||
|
|
968f6a6013 | ||
|
|
488efab636 | ||
|
|
6649255d54 | ||
|
|
4b00cba319 | ||
|
|
9e418671e1 | ||
|
|
d73c14751a | ||
|
|
6f313de952 | ||
|
|
2cf6e7862a | ||
|
|
58669fef77 | ||
|
|
e20aef7d53 | ||
|
|
b2143a98e2 | ||
|
|
f75f8efb1b | ||
|
|
be96787ed0 | ||
|
|
89d945aabe | ||
|
|
27211c71e9 | ||
|
|
14942bca60 | ||
|
|
77f2a01304 | ||
|
|
7b56ce6521 | ||
|
|
32a8caf7e7 | ||
|
|
caaa9b11e4 | ||
|
|
b1ad2d8066 | ||
|
|
22746b3046 | ||
|
|
49713fab04 | ||
|
|
8b86ee8bf0 | ||
|
|
2a052c69f3 | ||
|
|
2320b2241c | ||
|
|
8f5188269b | ||
|
|
00c8626863 | ||
|
|
0a211f29f5 | ||
|
|
d279d7c4c6 | ||
|
|
6c78b03bb7 | ||
|
|
f79497087b | ||
|
|
508bde1f61 | ||
|
|
e5ff19ac0f | ||
|
|
8579066c7a | ||
|
|
9232bc2c00 | ||
|
|
db0b764a5a | ||
|
|
278583b8a1 | ||
|
|
4414cd07e2 | ||
|
|
9e98fb0167 | ||
|
|
9856378384 | ||
|
|
dfa1bd0cd4 | ||
|
|
92df6b0dce | ||
|
|
71963972bf | ||
|
|
1bc05b1f9f | ||
|
|
e6cf643f5a | ||
|
|
94140e886e | ||
|
|
b248d59713 | ||
|
|
cbc0ff6ec0 | ||
|
|
6b6554adb8 | ||
|
|
d936eb437b | ||
|
|
883d01084c | ||
|
|
0564b46a5e | ||
|
|
3c9716acfd | ||
|
|
581f6659f8 | ||
|
|
e72ae6b25f | ||
|
|
9e35656244 | ||
|
|
e87758529e | ||
|
|
eb97d949aa | ||
|
|
e74efd87e5 | ||
|
|
4dbdb556fe | ||
|
|
5ee4b19691 | ||
|
|
d35e70a8c6 | ||
|
|
c35ed8363f | ||
|
|
d505b33665 | ||
|
|
118be4dea0 | ||
|
|
73b9756b8d | ||
|
|
8b9e385943 | ||
|
|
e01da1fd7a | ||
|
|
7a8c013edc | ||
|
|
518399a95b | ||
|
|
155d44016d | ||
|
|
13f90bb87a | ||
|
|
c67b257e51 | ||
|
|
8237d7e1a4 | ||
|
|
85da1a17d8 | ||
|
|
9609b04ff9 | ||
|
|
04421063af | ||
|
|
43e1415e71 | ||
|
|
e1448732b3 | ||
|
|
7c4c402bd7 | ||
|
|
6179b17903 | ||
|
|
05b48d48d9 | ||
|
|
07a21fdfa9 | ||
|
|
0f594732b0 | ||
|
|
312411fc70 | ||
|
|
70add904c4 | ||
|
|
5ca4823128 | ||
|
|
0500213086 | ||
|
|
b0fca6eaf0 | ||
|
|
4988e00b1d | ||
|
|
0fad7a0bb0 | ||
|
|
727f1b54cd | ||
|
|
c80457be02 | ||
|
|
4a42c5ed20 | ||
|
|
bd6d6e7f33 | ||
|
|
027140b731 | ||
|
|
ea10592ad3 | ||
|
|
9b54342baa | ||
|
|
8f9887b0c9 | ||
|
|
fa39df4731 | ||
|
|
f7249bd331 | ||
|
|
6934e7aa2b | ||
|
|
8bbeee2041 | ||
|
|
7a24e564f4 | ||
|
|
4b5b8a7630 | ||
|
|
5b1375141b | ||
|
|
4af9410dc2 | ||
|
|
a6315b0af4 | ||
|
|
cac59fefec | ||
|
|
1ac2fc3f7e | ||
|
|
cf6a1716ae | ||
|
|
10d7219807 | ||
|
|
838ed87d6f | ||
|
|
76b82fdde7 | ||
|
|
c5fd577181 | ||
|
|
fbd6354393 | ||
|
|
fd8d8e122e | ||
|
|
1c9d56998d | ||
|
|
242e06b242 | ||
|
|
25e72949a1 | ||
|
|
259dcd838e | ||
|
|
ef33198e8f | ||
|
|
604eb21a7e | ||
|
|
92a0dd164e | ||
|
|
b9b8e6220f | ||
|
|
a95df6b57e | ||
|
|
9642311ac2 | ||
|
|
98e99cd03d | ||
|
|
8210a1d7ac | ||
|
|
d105c7403c | ||
|
|
00ee1cf98e | ||
|
|
7dd0f76e5a | ||
|
|
17ed4fc04c | ||
|
|
6a8824253c | ||
|
|
eb42adc4c0 | ||
|
|
09dbcabcc7 | ||
|
|
72c7818ae6 | ||
|
|
1ea47950f4 | ||
|
|
8d6c18076f | ||
|
|
9c5a37a797 | ||
|
|
ca85455a8e | ||
|
|
28f6c2df59 | ||
|
|
83ab3ae0af | ||
|
|
b672118f92 | ||
|
|
aac90d9279 | ||
|
|
66586c38f5 | ||
|
|
82c67e61a9 | ||
|
|
e45e606fbd | ||
|
|
688fe5c147 | ||
|
|
a3b75559b3 | ||
|
|
df4f222482 | ||
|
|
3b663f4afc | ||
|
|
f634b9e61a | ||
|
|
bdb296a83c | ||
|
|
4fa63104c9 | ||
|
|
a437e44a6a | ||
|
|
cae937c51b | ||
|
|
8162fae377 | ||
|
|
c5786be695 | ||
|
|
1b1ecf77e0 | ||
|
|
883463f9dd | ||
|
|
3e7325af57 | ||
|
|
946ed1f32a | ||
|
|
4eff224a7f | ||
|
|
c86db7bbb0 | ||
|
|
272d904870 | ||
|
|
01e3da4d51 | ||
|
|
33015546c6 | ||
|
|
83d88fa564 | ||
|
|
11dfb8397b | ||
|
|
f4045ab8d0 | ||
|
|
fa12efdd2a | ||
|
|
bf611fbbf3 | ||
|
|
5afc4dc42e | ||
|
|
50348a3ddb | ||
|
|
279ec1c291 | ||
|
|
1006663b6e | ||
|
|
b2a18aa80a | ||
|
|
d21a6b12b8 | ||
|
|
912e7ba82d | ||
|
|
92744b5b9a | ||
|
|
c5feee1e35 | ||
|
|
1840a907a8 | ||
|
|
682b30fba8 | ||
|
|
12d9901472 | ||
|
|
15f942000e | ||
|
|
520e91238f | ||
|
|
0c56be74a3 | ||
|
|
069faa4027 | ||
|
|
c30dfe92ee | ||
|
|
d85ae306c5 | ||
|
|
197f880790 | ||
|
|
3b4aabe04c | ||
|
|
c5ec079c6f | ||
|
|
4aec237ec0 | ||
|
|
39df1f4dbf | ||
|
|
77cf651825 | ||
|
|
c7b72790bd | ||
|
|
3fa6db1e7a | ||
|
|
d361fcbd85 | ||
|
|
df9d830117 | ||
|
|
118d4e1001 | ||
|
|
511eea71c6 | ||
|
|
01ff5fdf6a | ||
|
|
0bf9ceb53b | ||
|
|
4fdc0d55e4 | ||
|
|
8b37e81374 | ||
|
|
fd1d4e288e | ||
|
|
4b4971c06f | ||
|
|
83a334f97d |
208
.clang-tidy
Normal file
|
|
@ -0,0 +1,208 @@
|
||||||
|
WarningsAsErrors: >
|
||||||
|
-*,
|
||||||
|
bugprone-*,
|
||||||
|
-bugprone-multi-level-implicit-pointer-conversion,
|
||||||
|
-bugprone-empty-catch,
|
||||||
|
-bugprone-unused-return-value,
|
||||||
|
-bugprone-reserved-identifier,
|
||||||
|
-bugprone-switch-missing-default-case,
|
||||||
|
-bugprone-unused-local-non-trivial-variable,
|
||||||
|
-bugprone-easily-swappable-parameters,
|
||||||
|
-bugprone-forward-declararion-namespace,
|
||||||
|
-bugprone-forward-declararion-namespace,
|
||||||
|
-bugprone-macro-parentheses,
|
||||||
|
-bugprone-narrowing-conversions,
|
||||||
|
-bugprone-branch-clone,
|
||||||
|
-bugprone-assignment-in-if-condition,
|
||||||
|
concurrency-*,
|
||||||
|
-concurrency-mt-unsafe,
|
||||||
|
cppcoreguidelines-*,
|
||||||
|
-cppcoreguidelines-pro-type-const-cast,
|
||||||
|
-cppcoreguidelines-owning-memory,
|
||||||
|
-cppcoreguidelines-avoid-magic-numbers,
|
||||||
|
-cppcoreguidelines-pro-bounds-constant-array-index,
|
||||||
|
-cppcoreguidelines-avoid-const-or-ref-data-members,
|
||||||
|
-cppcoreguidelines-non-private-member-variables-in-classes,
|
||||||
|
-cppcoreguidelines-avoid-goto,
|
||||||
|
-cppcoreguidelines-pro-bounds-array-to-pointer-decay,
|
||||||
|
-cppcoreguidelines-avoid-do-while,
|
||||||
|
-cppcoreguidelines-avoid-non-const-global-variables,
|
||||||
|
-cppcoreguidelines-special-member-functions,
|
||||||
|
-cppcoreguidelines-explicit-virtual-functions,
|
||||||
|
-cppcoreguidelines-avoid-c-arrays,
|
||||||
|
-cppcoreguidelines-pro-bounds-pointer-arithmetic,
|
||||||
|
-cppcoreguidelines-narrowing-conversions,
|
||||||
|
-cppcoreguidelines-pro-type-union-access,
|
||||||
|
-cppcoreguidelines-pro-type-member-init,
|
||||||
|
-cppcoreguidelines-macro-usage,
|
||||||
|
-cppcoreguidelines-macro-to-enum,
|
||||||
|
-cppcoreguidelines-init-variables,
|
||||||
|
-cppcoreguidelines-pro-type-cstyle-cast,
|
||||||
|
-cppcoreguidelines-pro-type-vararg,
|
||||||
|
-cppcoreguidelines-pro-type-reinterpret-cast,
|
||||||
|
-google-global-names-in-headers,
|
||||||
|
-google-readability-casting,
|
||||||
|
google-runtime-operator,
|
||||||
|
misc-*,
|
||||||
|
-misc-use-internal-linkage,
|
||||||
|
-misc-unused-parameters,
|
||||||
|
-misc-no-recursion,
|
||||||
|
-misc-non-private-member-variables-in-classes,
|
||||||
|
-misc-include-cleaner,
|
||||||
|
-misc-use-anonymous-namespace,
|
||||||
|
-misc-const-correctness,
|
||||||
|
modernize-*,
|
||||||
|
-modernize-use-emplace,
|
||||||
|
-modernize-redundant-void-arg,
|
||||||
|
-modernize-use-starts-ends-with,
|
||||||
|
-modernize-use-designated-initializers,
|
||||||
|
-modernize-use-std-numbers,
|
||||||
|
-modernize-return-braced-init-list,
|
||||||
|
-modernize-use-trailing-return-type,
|
||||||
|
-modernize-use-using,
|
||||||
|
-modernize-use-override,
|
||||||
|
-modernize-avoid-c-arrays,
|
||||||
|
-modernize-macro-to-enum,
|
||||||
|
-modernize-loop-convert,
|
||||||
|
-modernize-use-nodiscard,
|
||||||
|
-modernize-pass-by-value,
|
||||||
|
-modernize-use-auto,
|
||||||
|
performance-*,
|
||||||
|
-performance-inefficient-vector-operation,
|
||||||
|
-performance-inefficient-string-concatenation,
|
||||||
|
-performance-enum-size,
|
||||||
|
-performance-move-const-arg,
|
||||||
|
-performance-avoid-endl,
|
||||||
|
-performance-unnecessary-value-param,
|
||||||
|
portability-std-allocator-const,
|
||||||
|
readability-*,
|
||||||
|
-readability-identifier-naming,
|
||||||
|
-readability-use-std-min-max,
|
||||||
|
-readability-math-missing-parentheses,
|
||||||
|
-readability-simplify-boolean-expr,
|
||||||
|
-readability-static-accessed-through-instance,
|
||||||
|
-readability-use-anyofallof,
|
||||||
|
-readability-enum-initial-value,
|
||||||
|
-readability-redundant-inline-specifier,
|
||||||
|
-readability-function-cognitive-complexity,
|
||||||
|
-readability-function-size,
|
||||||
|
-readability-identifier-length,
|
||||||
|
-readability-magic-numbers,
|
||||||
|
-readability-uppercase-literal-suffix,
|
||||||
|
-readability-braces-around-statements,
|
||||||
|
-readability-redundant-access-specifiers,
|
||||||
|
-readability-else-after-return,
|
||||||
|
-readability-container-data-pointer,
|
||||||
|
-readability-implicit-bool-conversion,
|
||||||
|
-readability-avoid-nested-conditional-operator,
|
||||||
|
-readability-redundant-member-init,
|
||||||
|
-readability-redundant-string-init,
|
||||||
|
-readability-avoid-const-params-in-decls,
|
||||||
|
-readability-named-parameter,
|
||||||
|
-readability-convert-member-functions-to-static,
|
||||||
|
-readability-qualified-auto,
|
||||||
|
-readability-make-member-function-const,
|
||||||
|
-readability-isolate-declaration,
|
||||||
|
-readability-inconsistent-declaration-parameter-name,
|
||||||
|
-clang-diagnostic-error,
|
||||||
|
|
||||||
|
HeaderFilterRegex: '.*\.hpp'
|
||||||
|
FormatStyle: file
|
||||||
|
Checks: >
|
||||||
|
-*,
|
||||||
|
bugprone-*,
|
||||||
|
-bugprone-easily-swappable-parameters,
|
||||||
|
-bugprone-forward-declararion-namespace,
|
||||||
|
-bugprone-forward-declararion-namespace,
|
||||||
|
-bugprone-macro-parentheses,
|
||||||
|
-bugprone-narrowing-conversions,
|
||||||
|
-bugprone-branch-clone,
|
||||||
|
-bugprone-assignment-in-if-condition,
|
||||||
|
concurrency-*,
|
||||||
|
-concurrency-mt-unsafe,
|
||||||
|
cppcoreguidelines-*,
|
||||||
|
-cppcoreguidelines-owning-memory,
|
||||||
|
-cppcoreguidelines-avoid-magic-numbers,
|
||||||
|
-cppcoreguidelines-pro-bounds-constant-array-index,
|
||||||
|
-cppcoreguidelines-avoid-const-or-ref-data-members,
|
||||||
|
-cppcoreguidelines-non-private-member-variables-in-classes,
|
||||||
|
-cppcoreguidelines-avoid-goto,
|
||||||
|
-cppcoreguidelines-pro-bounds-array-to-pointer-decay,
|
||||||
|
-cppcoreguidelines-avoid-do-while,
|
||||||
|
-cppcoreguidelines-avoid-non-const-global-variables,
|
||||||
|
-cppcoreguidelines-special-member-functions,
|
||||||
|
-cppcoreguidelines-explicit-virtual-functions,
|
||||||
|
-cppcoreguidelines-avoid-c-arrays,
|
||||||
|
-cppcoreguidelines-pro-bounds-pointer-arithmetic,
|
||||||
|
-cppcoreguidelines-narrowing-conversions,
|
||||||
|
-cppcoreguidelines-pro-type-union-access,
|
||||||
|
-cppcoreguidelines-pro-type-member-init,
|
||||||
|
-cppcoreguidelines-macro-usage,
|
||||||
|
-cppcoreguidelines-macro-to-enum,
|
||||||
|
-cppcoreguidelines-init-variables,
|
||||||
|
-cppcoreguidelines-pro-type-cstyle-cast,
|
||||||
|
-cppcoreguidelines-pro-type-vararg,
|
||||||
|
-cppcoreguidelines-pro-type-reinterpret-cast,
|
||||||
|
google-global-names-in-headers,
|
||||||
|
-google-readability-casting,
|
||||||
|
google-runtime-operator,
|
||||||
|
misc-*,
|
||||||
|
-misc-unused-parameters,
|
||||||
|
-misc-no-recursion,
|
||||||
|
-misc-non-private-member-variables-in-classes,
|
||||||
|
-misc-include-cleaner,
|
||||||
|
-misc-use-anonymous-namespace,
|
||||||
|
-misc-const-correctness,
|
||||||
|
modernize-*,
|
||||||
|
-modernize-return-braced-init-list,
|
||||||
|
-modernize-use-trailing-return-type,
|
||||||
|
-modernize-use-using,
|
||||||
|
-modernize-use-override,
|
||||||
|
-modernize-avoid-c-arrays,
|
||||||
|
-modernize-macro-to-enum,
|
||||||
|
-modernize-loop-convert,
|
||||||
|
-modernize-use-nodiscard,
|
||||||
|
-modernize-pass-by-value,
|
||||||
|
-modernize-use-auto,
|
||||||
|
performance-*,
|
||||||
|
-performance-avoid-endl,
|
||||||
|
-performance-unnecessary-value-param,
|
||||||
|
portability-std-allocator-const,
|
||||||
|
readability-*,
|
||||||
|
-readability-function-cognitive-complexity,
|
||||||
|
-readability-function-size,
|
||||||
|
-readability-identifier-length,
|
||||||
|
-readability-magic-numbers,
|
||||||
|
-readability-uppercase-literal-suffix,
|
||||||
|
-readability-braces-around-statements,
|
||||||
|
-readability-redundant-access-specifiers,
|
||||||
|
-readability-else-after-return,
|
||||||
|
-readability-container-data-pointer,
|
||||||
|
-readability-implicit-bool-conversion,
|
||||||
|
-readability-avoid-nested-conditional-operator,
|
||||||
|
-readability-redundant-member-init,
|
||||||
|
-readability-redundant-string-init,
|
||||||
|
-readability-avoid-const-params-in-decls,
|
||||||
|
-readability-named-parameter,
|
||||||
|
-readability-convert-member-functions-to-static,
|
||||||
|
-readability-qualified-auto,
|
||||||
|
-readability-make-member-function-const,
|
||||||
|
-readability-isolate-declaration,
|
||||||
|
-readability-inconsistent-declaration-parameter-name,
|
||||||
|
-clang-diagnostic-error,
|
||||||
|
|
||||||
|
CheckOptions:
|
||||||
|
performance-for-range-copy.WarnOnAllAutoCopies: true
|
||||||
|
performance-inefficient-string-concatenation.StrictMode: true
|
||||||
|
readability-braces-around-statements.ShortStatementLines: 0
|
||||||
|
readability-identifier-naming.ClassCase: CamelCase
|
||||||
|
readability-identifier-naming.ClassIgnoredRegexp: I.*
|
||||||
|
readability-identifier-naming.ClassPrefix: C # We can't use regex here?!?!?!?
|
||||||
|
readability-identifier-naming.EnumCase: CamelCase
|
||||||
|
readability-identifier-naming.EnumPrefix: e
|
||||||
|
readability-identifier-naming.EnumConstantCase: UPPER_CASE
|
||||||
|
readability-identifier-naming.FunctionCase: camelBack
|
||||||
|
readability-identifier-naming.NamespaceCase: CamelCase
|
||||||
|
readability-identifier-naming.NamespacePrefix: N
|
||||||
|
readability-identifier-naming.StructPrefix: S
|
||||||
|
readability-identifier-naming.StructCase: CamelCase
|
||||||
77
.github/ISSUE_TEMPLATE/bug.yml
vendored
|
|
@ -1,74 +1,15 @@
|
||||||
name: Bug Report
|
name: Do not open issues, go to discussions please!
|
||||||
description: Something is not working right
|
description: Do not open an issue
|
||||||
labels: ["bug"]
|
|
||||||
body:
|
body:
|
||||||
- type: markdown
|
- type: checkboxes
|
||||||
attributes:
|
attributes:
|
||||||
value: |
|
label: Please close this issue.
|
||||||
## Before opening a new issue, please take a moment to search through the current open and closed issues to check if it already exists.
|
description: Users cannot open issues. I want my issue to be closed.
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
- type: dropdown
|
|
||||||
id: type
|
|
||||||
attributes:
|
|
||||||
label: Regression?
|
|
||||||
description: |
|
|
||||||
Regression means that something used to work but no longer does.
|
|
||||||
**BEFORE CONTINUING**, please check if this bug is a regression or not, and if it is, we need you to bisect with the help of the wiki: https://wiki.hyprland.org/Crashes-and-Bugs/#bisecting-an-issue
|
|
||||||
multiple: true
|
|
||||||
options:
|
options:
|
||||||
- "Yes"
|
- label: Yes, I want this issue to be closed.
|
||||||
- "No"
|
required: true
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: textarea
|
- type: textarea
|
||||||
id: ver
|
id: body
|
||||||
attributes:
|
attributes:
|
||||||
label: System Info and Version
|
label: Issue body
|
||||||
description: |
|
|
||||||
Paste the output of `hyprctl systeminfo -c` here (If you are on a
|
|
||||||
version that shows you help menu, omit the `-c` and attach config files
|
|
||||||
to the issue). If you have configs outside of the main config shown
|
|
||||||
here, please attach.
|
|
||||||
value: "<details>
|
|
||||||
<summary>System/Version info</summary>
|
|
||||||
|
|
||||||
|
|
||||||
```sh
|
|
||||||
|
|
||||||
<Paste the output of the command here>
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
</details>"
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: textarea
|
|
||||||
id: desc
|
|
||||||
attributes:
|
|
||||||
label: Description
|
|
||||||
description: "What went wrong?"
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: textarea
|
|
||||||
id: repro
|
|
||||||
attributes:
|
|
||||||
label: How to reproduce
|
|
||||||
description: "How can someone else reproduce the issue?"
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: textarea
|
|
||||||
id: logs
|
|
||||||
attributes:
|
|
||||||
label: Crash reports, logs, images, videos
|
|
||||||
description: |
|
|
||||||
Anything that can help. Please always ATTACH and not paste them.
|
|
||||||
Logs can be found in $XDG_RUNTIME_DIR/hypr
|
|
||||||
Crash reports are stored in ~/.cache/hyprland or $XDG_CACHE_HOME/hyprland
|
|
||||||
|
|
||||||
|
|
|
||||||
19
.github/ISSUE_TEMPLATE/feature.yml
vendored
|
|
@ -1,19 +0,0 @@
|
||||||
name: Feature Request
|
|
||||||
description: I'd like to request additional functionality
|
|
||||||
labels: ["enhancement"]
|
|
||||||
body:
|
|
||||||
- type: markdown
|
|
||||||
attributes:
|
|
||||||
value: |
|
|
||||||
Before opening a new issue, take a moment to search through the current open ones.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
- type: textarea
|
|
||||||
id: desc
|
|
||||||
attributes:
|
|
||||||
label: Description
|
|
||||||
description: "Describe your idea"
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
23
.github/actions/setup_base/action.yml
vendored
|
|
@ -20,9 +20,11 @@ runs:
|
||||||
clang \
|
clang \
|
||||||
cmake \
|
cmake \
|
||||||
git \
|
git \
|
||||||
|
glaze \
|
||||||
glm \
|
glm \
|
||||||
glslang \
|
glslang \
|
||||||
go \
|
go \
|
||||||
|
gtest \
|
||||||
hyprlang \
|
hyprlang \
|
||||||
hyprcursor \
|
hyprcursor \
|
||||||
jq \
|
jq \
|
||||||
|
|
@ -33,7 +35,10 @@ runs:
|
||||||
libfontenc \
|
libfontenc \
|
||||||
libglvnd \
|
libglvnd \
|
||||||
libinput \
|
libinput \
|
||||||
|
libjxl \
|
||||||
libliftoff \
|
libliftoff \
|
||||||
|
libspng \
|
||||||
|
libwebp \
|
||||||
libxcursor \
|
libxcursor \
|
||||||
libxcvt \
|
libxcvt \
|
||||||
libxfont2 \
|
libxfont2 \
|
||||||
|
|
@ -41,6 +46,7 @@ runs:
|
||||||
libxkbfile \
|
libxkbfile \
|
||||||
lld \
|
lld \
|
||||||
meson \
|
meson \
|
||||||
|
muparser \
|
||||||
ninja \
|
ninja \
|
||||||
pango \
|
pango \
|
||||||
pixman \
|
pixman \
|
||||||
|
|
@ -58,7 +64,8 @@ runs:
|
||||||
xcb-util \
|
xcb-util \
|
||||||
xcb-util-image \
|
xcb-util-image \
|
||||||
libzip \
|
libzip \
|
||||||
librsvg
|
librsvg \
|
||||||
|
re2
|
||||||
|
|
||||||
- name: Get hyprwayland-scanner-git
|
- name: Get hyprwayland-scanner-git
|
||||||
shell: bash
|
shell: bash
|
||||||
|
|
@ -69,11 +76,25 @@ runs:
|
||||||
cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
|
cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
|
||||||
cmake --install build
|
cmake --install build
|
||||||
|
|
||||||
|
- name: Get hyprwire-git
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
git clone https://github.com/hyprwm/hyprwire --recursive
|
||||||
|
cd hyprwire
|
||||||
|
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:PATH=/usr -S . -B ./build
|
||||||
|
cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
|
||||||
|
cmake --install build
|
||||||
|
|
||||||
- name: Get hyprutils-git
|
- name: Get hyprutils-git
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
git clone https://github.com/hyprwm/hyprutils && cd hyprutils && cmake -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:PATH=/usr -B build && cmake --build build --target hyprutils && cmake --install build
|
git clone https://github.com/hyprwm/hyprutils && cd hyprutils && cmake -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:PATH=/usr -B build && cmake --build build --target hyprutils && cmake --install build
|
||||||
|
|
||||||
|
- name: Get hyprgraphics-git
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
git clone https://github.com/hyprwm/hyprgraphics && cd hyprgraphics && cmake -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:PATH=/usr -B build && cmake --build build --target hyprgraphics && cmake --install build
|
||||||
|
|
||||||
- name: Get aquamarine-git
|
- name: Get aquamarine-git
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
|
|
|
||||||
4
.github/labeler.yml
vendored
|
|
@ -22,6 +22,10 @@ protocols:
|
||||||
- changed-files:
|
- changed-files:
|
||||||
- any-glob-to-any-file: ["protocols/**", "src/protocols/**"]
|
- any-glob-to-any-file: ["protocols/**", "src/protocols/**"]
|
||||||
|
|
||||||
|
start:
|
||||||
|
- changed-files:
|
||||||
|
- any-glob-to-any-file: "start/**"
|
||||||
|
|
||||||
core:
|
core:
|
||||||
- changed-files:
|
- changed-files:
|
||||||
- any-glob-to-any-file: "src/**"
|
- any-glob-to-any-file: "src/**"
|
||||||
|
|
|
||||||
8
.github/pull_request_template.md
vendored
|
|
@ -1,3 +1,11 @@
|
||||||
|
<!--
|
||||||
|
BEFORE you submit your PR, please check out the PR guidelines
|
||||||
|
on our wiki: https://wiki.hyprland.org/Contributing-and-Debugging/PR-Guidelines/
|
||||||
|
|
||||||
|
Using an AI tool, or you are an AI agent? Check our AI Policy first: https://github.com/hyprwm/.github/blob/main/policies/AI_USAGE.md
|
||||||
|
-->
|
||||||
|
|
||||||
|
|
||||||
#### Describe your PR, what does it fix/add?
|
#### Describe your PR, what does it fix/add?
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
109
.github/workflows/ci.yaml
vendored
|
|
@ -21,108 +21,63 @@ jobs:
|
||||||
|
|
||||||
- name: Build Hyprland
|
- name: Build Hyprland
|
||||||
run: |
|
run: |
|
||||||
make all
|
CFLAGS=-Werror CXXFLAGS=-Werror make nopch
|
||||||
|
|
||||||
- name: Compress and package artifacts
|
- name: Compress and package artifacts
|
||||||
run: |
|
run: |
|
||||||
mkdir x86_64-pc-linux-gnu
|
mkdir x86_64-pc-linux-gnu
|
||||||
mkdir hyprland
|
mkdir hyprland
|
||||||
mkdir hyprland/example
|
|
||||||
mkdir hyprland/assets
|
|
||||||
cp ./LICENSE hyprland/
|
cp ./LICENSE hyprland/
|
||||||
cp build/Hyprland hyprland/
|
cp build/Hyprland hyprland/
|
||||||
cp build/hyprctl/hyprctl hyprland/
|
cp build/hyprctl/hyprctl hyprland/
|
||||||
cp build/hyprpm/hyprpm hyprland/
|
cp build/hyprpm/hyprpm hyprland/
|
||||||
cp build/Hyprland hyprland/
|
|
||||||
cp -r example/ hyprland/
|
cp -r example/ hyprland/
|
||||||
cp -r assets/ hyprland/
|
cp -r assets/ hyprland/
|
||||||
tar -cvf Hyprland.tar.xz hyprland
|
tar -cvJf Hyprland.tar.xz hyprland
|
||||||
|
|
||||||
- name: Release
|
- name: Release
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: Build archive
|
name: Build archive
|
||||||
path: Hyprland.tar.xz
|
path: Hyprland.tar.xz
|
||||||
|
|
||||||
meson:
|
|
||||||
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork
|
|
||||||
name: "Build Hyprland with Meson (Arch)"
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
container:
|
|
||||||
image: archlinux
|
|
||||||
steps:
|
|
||||||
- name: Checkout repository actions
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
sparse-checkout: .github/actions
|
|
||||||
|
|
||||||
- name: Setup base
|
|
||||||
uses: ./.github/actions/setup_base
|
|
||||||
|
|
||||||
- name: Configure
|
|
||||||
run: meson setup build -Ddefault_library=static
|
|
||||||
|
|
||||||
- name: Compile
|
|
||||||
run: ninja -C build
|
|
||||||
|
|
||||||
no-pch:
|
|
||||||
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork
|
|
||||||
name: "Build Hyprland without precompiled headers (Arch)"
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
container:
|
|
||||||
image: archlinux
|
|
||||||
steps:
|
|
||||||
- name: Checkout repository actions
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
sparse-checkout: .github/actions
|
|
||||||
|
|
||||||
- name: Setup base
|
|
||||||
uses: ./.github/actions/setup_base
|
|
||||||
with:
|
|
||||||
INSTALL_XORG_PKGS: true
|
|
||||||
|
|
||||||
- name: Compile
|
|
||||||
run: make nopch
|
|
||||||
|
|
||||||
noxwayland:
|
|
||||||
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork
|
|
||||||
name: "Build Hyprland in pure Wayland (Arch)"
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
container:
|
|
||||||
image: archlinux
|
|
||||||
steps:
|
|
||||||
- name: Checkout repository actions
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
sparse-checkout: .github/actions
|
|
||||||
|
|
||||||
- name: Setup base
|
|
||||||
uses: ./.github/actions/setup_base
|
|
||||||
|
|
||||||
- name: Configure
|
|
||||||
run: mkdir -p build && cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DNO_XWAYLAND:STRING=true -H./ -B./build -G Ninja
|
|
||||||
|
|
||||||
- name: Compile
|
|
||||||
run: make release
|
|
||||||
|
|
||||||
clang-format:
|
clang-format:
|
||||||
|
permissions: read-all
|
||||||
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork
|
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork
|
||||||
name: "Code Style (Arch)"
|
name: "Code Style"
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
container:
|
container:
|
||||||
image: archlinux
|
image: archlinux
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository actions
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
with:
|
|
||||||
sparse-checkout: .github/actions
|
|
||||||
|
|
||||||
- name: Setup base
|
# - name: clang-format check
|
||||||
uses: ./.github/actions/setup_base
|
# uses: jidicula/clang-format-action@v4.16.0
|
||||||
|
# with:
|
||||||
|
# exclude-regex: ^subprojects$
|
||||||
|
|
||||||
- name: Configure
|
- name: Install clang-format
|
||||||
run: meson setup build -Ddefault_library=static
|
run: |
|
||||||
|
pacman --noconfirm --noprogressbar -Syyu
|
||||||
|
pacman --noconfirm --noprogressbar -Sy clang
|
||||||
|
|
||||||
- name: clang-format check
|
- name: clang-format check
|
||||||
run: ninja -C build clang-format-check
|
run: .github/workflows/clang-format-check.sh "." "llvm" "^subprojects$" ""
|
||||||
|
|
||||||
|
- name: Save PR head commit SHA
|
||||||
|
if: failure() && github.event_name == 'pull_request'
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
SHA="${{ github.event.pull_request.head.sha }}"
|
||||||
|
echo "SHA=$SHA" >> $GITHUB_ENV
|
||||||
|
- name: Save latest commit SHA if not PR
|
||||||
|
if: failure() && github.event_name != 'pull_request'
|
||||||
|
shell: bash
|
||||||
|
run: echo "SHA=${{ github.sha }}" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Report failure in job summary
|
||||||
|
if: failure()
|
||||||
|
run: |
|
||||||
|
DEEPLINK="${{ github.server_url }}/${{ github.repository }}/commit/${{ env.SHA }}"
|
||||||
|
echo -e "Format check failed on commit [${GITHUB_SHA:0:8}]($DEEPLINK) with files:\n$(<$GITHUB_WORKSPACE/failing-files.txt)" >> $GITHUB_STEP_SUMMARY
|
||||||
|
|
|
||||||
92
.github/workflows/clang-format-check.sh
vendored
Executable file
|
|
@ -0,0 +1,92 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
#
|
||||||
|
# Adapted from https://github.com/jidicula/clang-format-action
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# check.sh #
|
||||||
|
###############################################################################
|
||||||
|
# USAGE: ./entrypoint.sh [<path>] [<fallback style>]
|
||||||
|
#
|
||||||
|
# Checks all C/C++/Protobuf/CUDA files (.h, .H, .hpp, .hh, .h++, .hxx and .c,
|
||||||
|
# .C, .cpp, .cc, .c++, .cxx, .proto, .cu) in the provided GitHub repository path
|
||||||
|
# (arg1) for conforming to clang-format. If no path is provided or provided path
|
||||||
|
# is not a directory, all C/C++/Protobuf/CUDA files are checked. If any files
|
||||||
|
# are incorrectly formatted, the script lists them and exits with 1.
|
||||||
|
#
|
||||||
|
# Define your own formatting rules in a .clang-format file at your repository
|
||||||
|
# root. Otherwise, the provided style guide (arg2) is used as a fallback.
|
||||||
|
|
||||||
|
# format_diff function
|
||||||
|
# Accepts a filepath argument. The filepath passed to this function must point
|
||||||
|
# to a C/C++/Protobuf/CUDA file.
|
||||||
|
format_diff() {
|
||||||
|
local filepath="$1"
|
||||||
|
|
||||||
|
# Invoke clang-format with dry run and formatting error output
|
||||||
|
local_format="$(clang-format \
|
||||||
|
--dry-run \
|
||||||
|
--Werror \
|
||||||
|
--style=file \
|
||||||
|
--fallback-style="$FALLBACK_STYLE" \
|
||||||
|
"${filepath}")"
|
||||||
|
|
||||||
|
local format_status="$?"
|
||||||
|
if [[ ${format_status} -ne 0 ]]; then
|
||||||
|
# Append Markdown-bulleted monospaced filepath of failing file to
|
||||||
|
# summary file.
|
||||||
|
echo "* \`$filepath\`" >>failing-files.txt
|
||||||
|
|
||||||
|
echo "Failed on file: $filepath" >&2
|
||||||
|
echo "$local_format" >&2
|
||||||
|
exit_code=1 # flip the global exit code
|
||||||
|
return "${format_status}"
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
CHECK_PATH="$1"
|
||||||
|
FALLBACK_STYLE="$2"
|
||||||
|
EXCLUDE_REGEX="$3"
|
||||||
|
INCLUDE_REGEX="$4"
|
||||||
|
|
||||||
|
# Set the regex to an empty string regex if nothing was provided
|
||||||
|
if [[ -z $EXCLUDE_REGEX ]]; then
|
||||||
|
EXCLUDE_REGEX="^$"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Set the filetype regex if nothing was provided.
|
||||||
|
# Find all C/C++/Protobuf/CUDA files:
|
||||||
|
# h, H, hpp, hh, h++, hxx
|
||||||
|
# c, C, cpp, cc, c++, cxx
|
||||||
|
# ino, pde
|
||||||
|
# proto
|
||||||
|
# cu
|
||||||
|
if [[ -z $INCLUDE_REGEX ]]; then
|
||||||
|
INCLUDE_REGEX='^.*\.((((c|C)(c|pp|xx|\+\+)?$)|((h|H)h?(pp|xx|\+\+)?$))|(ino|pde|proto|cu))$'
|
||||||
|
fi
|
||||||
|
|
||||||
|
cd "$GITHUB_WORKSPACE" || exit 2
|
||||||
|
|
||||||
|
if [[ ! -d $CHECK_PATH ]]; then
|
||||||
|
echo "Not a directory in the workspace, fallback to all files." >&2
|
||||||
|
CHECK_PATH="."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# initialize exit code
|
||||||
|
exit_code=0
|
||||||
|
|
||||||
|
# All files improperly formatted will be printed to the output.
|
||||||
|
src_files=$(find "$CHECK_PATH" -name .git -prune -o -regextype posix-egrep -regex "$INCLUDE_REGEX" -print)
|
||||||
|
|
||||||
|
# check formatting in each source file
|
||||||
|
IFS=$'\n' # Loop below should separate on new lines, not spaces.
|
||||||
|
for file in $src_files; do
|
||||||
|
# Only check formatting if the path doesn't match the regex
|
||||||
|
if ! [[ ${file} =~ $EXCLUDE_REGEX ]]; then
|
||||||
|
format_diff "${file}"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# global exit code is flipped to nonzero if any invocation of `format_diff` has
|
||||||
|
# a formatting difference.
|
||||||
|
exit "$exit_code"
|
||||||
28
.github/workflows/clang-format.yml
vendored
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
name: clang-format
|
||||||
|
on: pull_request_target
|
||||||
|
jobs:
|
||||||
|
clang-format:
|
||||||
|
permissions: write-all
|
||||||
|
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork
|
||||||
|
name: "Code Style"
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: clang-format check
|
||||||
|
uses: jidicula/clang-format-action@v4.16.0
|
||||||
|
with:
|
||||||
|
exclude-regex: ^subprojects$
|
||||||
|
|
||||||
|
- name: Create comment
|
||||||
|
if: ${{ failure() && github.event_name == 'pull_request' }}
|
||||||
|
run: |
|
||||||
|
echo 'Please fix the formatting issues by running [`clang-format`](https://wiki.hyprland.org/Contributing-and-Debugging/PR-Guidelines/#code-style).' > clang-format.patch
|
||||||
|
|
||||||
|
- name: Post comment
|
||||||
|
if: ${{ failure() && github.event_name == 'pull_request' }}
|
||||||
|
uses: mshick/add-pr-comment@v2
|
||||||
|
with:
|
||||||
|
message-path: |
|
||||||
|
clang-format.patch
|
||||||
101
.github/workflows/close-issues.yml
vendored
Normal file
|
|
@ -0,0 +1,101 @@
|
||||||
|
name: Close Unauthorized Issues
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
issues:
|
||||||
|
types: [opened]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
close-unauthorized-issues:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
issues: write
|
||||||
|
steps:
|
||||||
|
# XXX: This *could* be done in Bash by abusing GitHub's own tool to interact with its API
|
||||||
|
# but that's too much of a hack, and we'll be adding a layer of abstraction. github-script
|
||||||
|
# is a workflow that eases interaction with GitHub API in the workflow run context.
|
||||||
|
- name: "Close 'unauthorized' issues"
|
||||||
|
uses: actions/github-script@v7
|
||||||
|
with:
|
||||||
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
script: |
|
||||||
|
const ALLOWED_USERS = ['vaxerski', 'fufexan', 'NotAShelf'];
|
||||||
|
const CLOSING_COMMENT = 'Users are no longer allowed to open issues themselves, please open a discussion instead.\n\nPlease see the [wiki](https://wiki.hyprland.org/Contributing-and-Debugging/Issue-Guidelines/) on why this is the case.\n\nWe are volunteers, and we need your cooperation to make the best software we can. Thank you for understanding! ❤️\n\n[Open a discussion here](https://github.com/hyprwm/Hyprland/discussions)';
|
||||||
|
|
||||||
|
async function closeUnauthorizedIssue(issueNumber, userName) {
|
||||||
|
if (ALLOWED_USERS.includes(userName)) {
|
||||||
|
console.log(`Issue #${issueNumber} - Created by authorized user ${userName}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`Issue #${issueNumber} - Unauthorized, closing`);
|
||||||
|
|
||||||
|
await github.rest.issues.update({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
issue_number: issueNumber,
|
||||||
|
state: 'closed',
|
||||||
|
state_reason: 'not_planned'
|
||||||
|
});
|
||||||
|
|
||||||
|
await github.rest.issues.createComment({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
issue_number: issueNumber,
|
||||||
|
body: CLOSING_COMMENT
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (context.eventName === 'issues' && context.payload.action === 'opened') {
|
||||||
|
// Direct access to the issue that triggered the workflow
|
||||||
|
const issue = context.payload.issue;
|
||||||
|
|
||||||
|
// Skip if this is a PR
|
||||||
|
if (issue.pull_request) {
|
||||||
|
console.log(`Issue #${issue.number} - Skipping, this is a pull request`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process the single issue that triggered the workflow
|
||||||
|
await closeUnauthorizedIssue(issue.number, issue.user.login);
|
||||||
|
} else {
|
||||||
|
// For manual runs, we need to handle pagination
|
||||||
|
async function* fetchAllOpenIssues() {
|
||||||
|
let page = 1;
|
||||||
|
let hasNextPage = true;
|
||||||
|
|
||||||
|
while (hasNextPage) {
|
||||||
|
const response = await github.rest.issues.listForRepo({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
state: 'open',
|
||||||
|
per_page: 100,
|
||||||
|
page: page
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response.data.length === 0) {
|
||||||
|
hasNextPage = false;
|
||||||
|
} else {
|
||||||
|
for (const issue of response.data) {
|
||||||
|
yield issue;
|
||||||
|
}
|
||||||
|
page++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process issues one by one
|
||||||
|
for await (const issue of fetchAllOpenIssues()) {
|
||||||
|
try {
|
||||||
|
// Skip pull requests
|
||||||
|
if (issue.pull_request) {
|
||||||
|
console.log(`Issue #${issue.number} - Skipping, this is a pull request`);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
await closeUnauthorizedIssue(issue.number, issue.user.login);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Error processing issue #${issue.number}: ${error.message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
4
.github/workflows/man-update.yaml
vendored
|
|
@ -17,14 +17,14 @@ jobs:
|
||||||
run: sudo apt install pandoc
|
run: sudo apt install pandoc
|
||||||
|
|
||||||
- name: Clone repository
|
- name: Clone repository
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.PAT }}
|
token: ${{ secrets.PAT }}
|
||||||
|
|
||||||
- name: Build man pages
|
- name: Build man pages
|
||||||
run: make man
|
run: make man
|
||||||
|
|
||||||
- uses: stefanzweifel/git-auto-commit-action@v4
|
- uses: stefanzweifel/git-auto-commit-action@v5
|
||||||
name: Commit
|
name: Commit
|
||||||
with:
|
with:
|
||||||
commit_message: "[gha] build man pages"
|
commit_message: "[gha] build man pages"
|
||||||
|
|
|
||||||
45
.github/workflows/new-pr-comment.yml
vendored
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
name: "New MR welcome comment"
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request_target:
|
||||||
|
types:
|
||||||
|
- opened
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
comment:
|
||||||
|
if: >
|
||||||
|
github.event.pull_request.user.login != 'vaxerski' &&
|
||||||
|
github.event.pull_request.user.login != 'fufexan' &&
|
||||||
|
github.event.pull_request.user.login != 'gulafaran' &&
|
||||||
|
github.event.pull_request.user.login != 'ujint34' &&
|
||||||
|
github.event.pull_request.user.login != 'paideiadilemma' &&
|
||||||
|
github.event.pull_request.user.login != 'notashelf'
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
pull-requests: write
|
||||||
|
|
||||||
|
env:
|
||||||
|
PR_COMMENT: |
|
||||||
|
Hello and thank you for making a PR to Hyprland!
|
||||||
|
|
||||||
|
Please check the [PR Guidelines](https://wiki.hypr.land/Contributing-and-Debugging/PR-Guidelines/) and make sure your PR follows them.
|
||||||
|
It will make the entire review process faster. :)
|
||||||
|
|
||||||
|
If your code can be tested, please always add tests. See more [here](https://wiki.hypr.land/Contributing-and-Debugging/Tests/).
|
||||||
|
|
||||||
|
_beep boop, I'm just a bot. A real human will review your PR soon._
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Add comment to PR
|
||||||
|
uses: actions/github-script@v7
|
||||||
|
with:
|
||||||
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
script: |
|
||||||
|
const pr = context.payload.pull_request;
|
||||||
|
|
||||||
|
await github.rest.issues.createComment({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
issue_number: pr.number,
|
||||||
|
body: process.env.PR_COMMENT,
|
||||||
|
});
|
||||||
30
.github/workflows/nix-build.yml
vendored
|
|
@ -1,30 +0,0 @@
|
||||||
on:
|
|
||||||
workflow_call:
|
|
||||||
secrets:
|
|
||||||
CACHIX_AUTH_TOKEN:
|
|
||||||
required: false
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
package:
|
|
||||||
- hyprland
|
|
||||||
- xdg-desktop-portal-hyprland
|
|
||||||
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Clone repository
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
ref: ${{ github.ref }}
|
|
||||||
submodules: recursive
|
|
||||||
|
|
||||||
- uses: cachix/install-nix-action@v27
|
|
||||||
- uses: DeterminateSystems/magic-nix-cache-action@main
|
|
||||||
- uses: cachix/cachix-action@v15
|
|
||||||
with:
|
|
||||||
name: hyprland
|
|
||||||
authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'
|
|
||||||
|
|
||||||
- run: nix build '.?submodules=1#${{ matrix.package }}' -L --extra-substituters "https://hyprland.cachix.org"
|
|
||||||
24
.github/workflows/nix-ci.yml
vendored
|
|
@ -4,12 +4,26 @@ on: [push, pull_request, workflow_dispatch]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
update-inputs:
|
update-inputs:
|
||||||
if: github.event_name == 'push' || github.event_name == 'workflow_dispatch'
|
if: (github.event_name == 'push' || github.event_name == 'workflow_dispatch')
|
||||||
uses: ./.github/workflows/nix-update-inputs.yml
|
uses: ./.github/workflows/nix-update-inputs.yml
|
||||||
secrets: inherit
|
secrets: inherit
|
||||||
|
|
||||||
build:
|
hyprland:
|
||||||
if: (github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork) && !contains(needs.*.result, 'failure')
|
if: (github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork)
|
||||||
needs: update-inputs
|
uses: ./.github/workflows/nix.yml
|
||||||
uses: ./.github/workflows/nix-build.yml
|
secrets: inherit
|
||||||
|
with:
|
||||||
|
command: nix build 'github:${{ github.repository }}?ref=${{ github.ref }}' -L --extra-substituters "https://hyprland.cachix.org"
|
||||||
|
|
||||||
|
xdph:
|
||||||
|
if: (github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork)
|
||||||
|
needs: hyprland
|
||||||
|
uses: ./.github/workflows/nix.yml
|
||||||
|
secrets: inherit
|
||||||
|
with:
|
||||||
|
command: nix build 'github:${{ github.repository }}?ref=${{ github.ref }}#xdg-desktop-portal-hyprland' -L --extra-substituters "https://hyprland.cachix.org"
|
||||||
|
|
||||||
|
test:
|
||||||
|
if: (github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork)
|
||||||
|
uses: ./.github/workflows/nix-test.yml
|
||||||
secrets: inherit
|
secrets: inherit
|
||||||
|
|
|
||||||
47
.github/workflows/nix-test.yml
vendored
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
name: Nix (Test)
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_call:
|
||||||
|
secrets:
|
||||||
|
CACHIX_AUTH_TOKEN:
|
||||||
|
required: false
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Install Nix
|
||||||
|
uses: nixbuild/nix-quick-install-action@v31
|
||||||
|
with:
|
||||||
|
nix_conf: |
|
||||||
|
keep-env-derivations = true
|
||||||
|
keep-outputs = true
|
||||||
|
|
||||||
|
- name: Restore and save Nix store
|
||||||
|
uses: nix-community/cache-nix-action@v6
|
||||||
|
with:
|
||||||
|
# restore and save a cache using this key (per job)
|
||||||
|
primary-key: nix-${{ runner.os }}-${{ github.job }}
|
||||||
|
# if there's no cache hit, restore a cache by this prefix
|
||||||
|
restore-prefixes-first-match: nix-${{ runner.os }}
|
||||||
|
# collect garbage until the Nix store size (in bytes) is at most this number
|
||||||
|
# before trying to save a new cache
|
||||||
|
gc-max-store-size-linux: 5G
|
||||||
|
|
||||||
|
- uses: cachix/cachix-action@v15
|
||||||
|
with:
|
||||||
|
name: hyprland
|
||||||
|
authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}"
|
||||||
|
|
||||||
|
- name: Run test VM
|
||||||
|
run: nix build 'github:${{ github.repository }}?ref=${{ github.ref }}#checks.x86_64-linux.tests' -L --extra-substituters "https://hyprland.cachix.org"
|
||||||
|
|
||||||
|
- name: Check exit status
|
||||||
|
run: grep 0 result/exit_status
|
||||||
|
|
||||||
|
- name: Upload artifacts
|
||||||
|
if: always()
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: logs
|
||||||
|
path: result
|
||||||
26
.github/workflows/nix-update-inputs.yml
vendored
|
|
@ -1,4 +1,4 @@
|
||||||
name: Nix
|
name: Nix (Update Inputs)
|
||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_call:
|
workflow_call:
|
||||||
|
|
@ -8,19 +8,37 @@ on:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
update:
|
update:
|
||||||
|
if: github.repository == 'hyprwm/Hyprland'
|
||||||
name: inputs
|
name: inputs
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Clone repository
|
- name: Clone repository
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.PAT }}
|
token: ${{ secrets.PAT }}
|
||||||
|
|
||||||
- uses: DeterminateSystems/nix-installer-action@main
|
- name: Install Nix
|
||||||
|
uses: nixbuild/nix-quick-install-action@v31
|
||||||
|
with:
|
||||||
|
nix_conf: |
|
||||||
|
keep-env-derivations = true
|
||||||
|
keep-outputs = true
|
||||||
|
|
||||||
|
- name: Restore and save Nix store
|
||||||
|
uses: nix-community/cache-nix-action@v6
|
||||||
|
with:
|
||||||
|
# restore and save a cache using this key (per job)
|
||||||
|
primary-key: nix-${{ runner.os }}-${{ github.job }}
|
||||||
|
# if there's no cache hit, restore a cache by this prefix
|
||||||
|
restore-prefixes-first-match: nix-${{ runner.os }}
|
||||||
|
# collect garbage until the Nix store size (in bytes) is at most this number
|
||||||
|
# before trying to save a new cache
|
||||||
|
gc-max-store-size-linux: 5G
|
||||||
|
|
||||||
- name: Update inputs
|
- name: Update inputs
|
||||||
run: nix/update-inputs.sh
|
run: nix/update-inputs.sh
|
||||||
|
|
||||||
- name: Commit
|
- name: Commit
|
||||||
uses: stefanzweifel/git-auto-commit-action@v4
|
uses: stefanzweifel/git-auto-commit-action@v5
|
||||||
with:
|
with:
|
||||||
commit_message: "[gha] Nix: update inputs"
|
commit_message: "[gha] Nix: update inputs"
|
||||||
|
|
|
||||||
41
.github/workflows/nix.yml
vendored
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
name: Build
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_call:
|
||||||
|
inputs:
|
||||||
|
command:
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
description: Command to run
|
||||||
|
secrets:
|
||||||
|
CACHIX_AUTH_TOKEN:
|
||||||
|
required: false
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Install Nix
|
||||||
|
uses: nixbuild/nix-quick-install-action@v31
|
||||||
|
with:
|
||||||
|
nix_conf: |
|
||||||
|
keep-env-derivations = true
|
||||||
|
keep-outputs = true
|
||||||
|
|
||||||
|
- name: Restore and save Nix store
|
||||||
|
uses: nix-community/cache-nix-action@v6
|
||||||
|
with:
|
||||||
|
# restore and save a cache using this key (per job)
|
||||||
|
primary-key: nix-${{ runner.os }}-${{ github.job }}
|
||||||
|
# if there's no cache hit, restore a cache by this prefix
|
||||||
|
restore-prefixes-first-match: nix-${{ runner.os }}
|
||||||
|
# collect garbage until the Nix store size (in bytes) is at most this number
|
||||||
|
# before trying to save a new cache
|
||||||
|
gc-max-store-size-linux: 5G
|
||||||
|
|
||||||
|
- uses: cachix/cachix-action@v15
|
||||||
|
with:
|
||||||
|
name: hyprland
|
||||||
|
authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}"
|
||||||
|
|
||||||
|
- run: ${{ inputs.command }}
|
||||||
34
.github/workflows/release.yaml
vendored
|
|
@ -9,18 +9,36 @@ jobs:
|
||||||
source-tarball:
|
source-tarball:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout Hyprland
|
- name: Checkout repository
|
||||||
id: checkout
|
uses: actions/checkout@v5
|
||||||
uses: actions/checkout@v3
|
|
||||||
with:
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
submodules: recursive
|
submodules: recursive
|
||||||
|
|
||||||
- name: Generate version
|
- name: Populate git info in version.h.in
|
||||||
id: genversion
|
|
||||||
run: |
|
run: |
|
||||||
git fetch --unshallow || echo "failed unshallowing"
|
git fetch --tags --unshallow || true
|
||||||
bash -c scripts/generateVersion.sh
|
|
||||||
mv scripts/generateVersion.sh scripts/generateVersion.sh.bak
|
COMMIT_HASH=$(git rev-parse HEAD)
|
||||||
|
BRANCH="${GITHUB_REF_NAME:-$(git rev-parse --abbrev-ref HEAD)}"
|
||||||
|
COMMIT_MSG=$(git show -s --format=%s | sed 's/[&/]/\\&/g')
|
||||||
|
COMMIT_DATE=$(git show -s --format=%cd --date=local)
|
||||||
|
GIT_DIRTY=$(git diff-index --quiet HEAD -- && echo "clean" || echo "dirty")
|
||||||
|
GIT_TAG=$(git describe --tags --always || echo "unknown")
|
||||||
|
GIT_COMMITS=$(git rev-list --count HEAD)
|
||||||
|
|
||||||
|
echo "Branch: $BRANCH"
|
||||||
|
echo "Tag: $GIT_TAG"
|
||||||
|
|
||||||
|
sed -i \
|
||||||
|
-e "s|@GIT_COMMIT_HASH@|$COMMIT_HASH|" \
|
||||||
|
-e "s|@GIT_BRANCH@|$BRANCH|" \
|
||||||
|
-e "s|@GIT_COMMIT_MESSAGE@|$COMMIT_MSG|" \
|
||||||
|
-e "s|@GIT_COMMIT_DATE@|$COMMIT_DATE|" \
|
||||||
|
-e "s|@GIT_DIRTY@|$GIT_DIRTY|" \
|
||||||
|
-e "s|@GIT_TAG@|$GIT_TAG|" \
|
||||||
|
-e "s|@GIT_COMMITS@|$GIT_COMMITS|" \
|
||||||
|
src/version.h.in
|
||||||
|
|
||||||
- name: Create tarball with submodules
|
- name: Create tarball with submodules
|
||||||
id: tar
|
id: tar
|
||||||
|
|
|
||||||
2
.github/workflows/security-checks.yml
vendored
|
|
@ -13,7 +13,7 @@ jobs:
|
||||||
security-events: write
|
security-events: write
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Scan with Flawfinder
|
- name: Scan with Flawfinder
|
||||||
uses: david-a-wheeler/flawfinder@8e4a779ad59dbfaee5da586aa9210853b701959c
|
uses: david-a-wheeler/flawfinder@8e4a779ad59dbfaee5da586aa9210853b701959c
|
||||||
|
|
|
||||||
28
.github/workflows/stale.yml
vendored
|
|
@ -1,28 +0,0 @@
|
||||||
# This workflow warns and then closes issues and PRs that have had no activity for a specified amount of time.
|
|
||||||
#
|
|
||||||
# You can adjust the behavior by modifying this file.
|
|
||||||
# For more information, see:
|
|
||||||
# https://github.com/actions/stale
|
|
||||||
name: Mark stale issues and pull requests
|
|
||||||
|
|
||||||
on:
|
|
||||||
schedule:
|
|
||||||
- cron: '7 */4 * * *'
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
stale:
|
|
||||||
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
permissions:
|
|
||||||
issues: write
|
|
||||||
pull-requests: write
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/stale@v5
|
|
||||||
with:
|
|
||||||
repo-token: ${{ secrets.STALEBOT_PAT }}
|
|
||||||
stale-issue-label: 'stale'
|
|
||||||
stale-pr-label: 'stale'
|
|
||||||
operations-per-run: 40
|
|
||||||
days-before-close: -1
|
|
||||||
139
.github/workflows/translation-ai-check.yml
vendored
Normal file
|
|
@ -0,0 +1,139 @@
|
||||||
|
name: AI Translation Check
|
||||||
|
|
||||||
|
on:
|
||||||
|
# pull_request_target:
|
||||||
|
# types:
|
||||||
|
# - opened
|
||||||
|
issue_comment:
|
||||||
|
types:
|
||||||
|
- created
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
pull-requests: write
|
||||||
|
issues: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
review:
|
||||||
|
name: Review Translation
|
||||||
|
if: ${{ github.event_name == 'pull_request_target' || (github.event_name == 'issue_comment' && github.event.action == 'created' && github.event.issue.pull_request != null && github.event.comment.user.login == 'vaxerski' && github.event.comment.body == 'ai, please recheck' ) }}
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
env:
|
||||||
|
OPENAI_MODEL: gpt-5-mini
|
||||||
|
SYSTEM_PROMPT: |
|
||||||
|
You are a programmer and a translator. Your job is to review the attached patch for adding translation to a piece of software and make sure the submitted translation is not malicious, and that it makes sense. If the translation is not malicious, and doesn't contain obvious grammatical mistakes, say "Translation check OK". Otherwise, say "Translation check not ok" and list bad entries.
|
||||||
|
Examples of bad translations include obvious trolling (slurs, etc) or nonsense sentences. Meaningful improvements may be suggested, but if there are only minor improvements, just reply with "Translation check OK". Do not provide anything but the result and (if applicable) the bad entries or improvements.
|
||||||
|
|
||||||
|
AI_PROMPT: Translation patch below.
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout source code
|
||||||
|
uses: actions/checkout@v5
|
||||||
|
|
||||||
|
- uses: dorny/paths-filter@v3
|
||||||
|
id: changes
|
||||||
|
with:
|
||||||
|
filters: |
|
||||||
|
i18n:
|
||||||
|
- 'src/i18n/**'
|
||||||
|
|
||||||
|
- name: Stop if i18n not changed
|
||||||
|
if: steps.changes.outputs.i18n != 'true'
|
||||||
|
run: echo "No i18n changes in this PR; skipping." && exit 0
|
||||||
|
|
||||||
|
- name: Determine PR number
|
||||||
|
id: pr
|
||||||
|
run: |
|
||||||
|
if [ "${{ github.event_name }}" = "pull_request_target" ]; then
|
||||||
|
echo "number=${{ github.event.pull_request.number }}" >> "$GITHUB_OUTPUT"
|
||||||
|
else
|
||||||
|
echo "number=${{ github.event.issue.number }}" >> "$GITHUB_OUTPUT"
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Download combined PR diff
|
||||||
|
id: get_diff
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
PR_NUMBER: ${{ steps.pr.outputs.number }}
|
||||||
|
run: |
|
||||||
|
# Get the combined diff for the entire PR
|
||||||
|
curl -sSL \
|
||||||
|
-H "Authorization: token $GITHUB_TOKEN" \
|
||||||
|
-H "Accept: application/vnd.github.v3.diff" \
|
||||||
|
"https://api.github.com/repos/${{ github.repository }}/pulls/$PR_NUMBER" \
|
||||||
|
-o pr.diff
|
||||||
|
|
||||||
|
# Compute character length
|
||||||
|
LEN=$(wc -c < pr.diff | tr -d ' ')
|
||||||
|
echo "len=$LEN" >> "$GITHUB_OUTPUT"
|
||||||
|
if [ "$LEN" -gt 25000 ]; then
|
||||||
|
echo "too_long=true" >> "$GITHUB_OUTPUT"
|
||||||
|
else
|
||||||
|
echo "too_long=false" >> "$GITHUB_OUTPUT"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "got diff:"
|
||||||
|
cat pr.diff
|
||||||
|
|
||||||
|
- name: Comment when diff length exceeded
|
||||||
|
if: steps.get_diff.outputs.too_long == 'true'
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
PR_NUMBER: ${{ steps.pr.outputs.number }}
|
||||||
|
run: |
|
||||||
|
jq -n --arg body "Diff length exceeded, can't query API" '{body: ("AI translation check result:\n\n" + $body)}' > body.json
|
||||||
|
curl -sS -X POST \
|
||||||
|
-H "Authorization: token $GITHUB_TOKEN" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
"https://api.github.com/repos/${{ github.repository }}/issues/$PR_NUMBER/comments" \
|
||||||
|
--data @body.json
|
||||||
|
|
||||||
|
- name: Query OpenAI and post review
|
||||||
|
if: steps.get_diff.outputs.too_long == 'false'
|
||||||
|
env:
|
||||||
|
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
|
||||||
|
OPENAI_MODEL: ${{ env.OPENAI_MODEL }}
|
||||||
|
SYSTEM_PROMPT: ${{ env.SYSTEM_PROMPT }}
|
||||||
|
AI_PROMPT: ${{ env.AI_PROMPT }}
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
PR_NUMBER: ${{ steps.pr.outputs.number }}
|
||||||
|
run: |
|
||||||
|
# Prepare OpenAI chat request payload (embed diff safely)
|
||||||
|
jq -n \
|
||||||
|
--arg model "$OPENAI_MODEL" \
|
||||||
|
--arg sys "$SYSTEM_PROMPT" \
|
||||||
|
--arg prompt "$AI_PROMPT" \
|
||||||
|
--rawfile diff pr.diff \
|
||||||
|
'{model:$model,
|
||||||
|
messages:[
|
||||||
|
{role:"system", content:$sys},
|
||||||
|
{role:"user", content: ($prompt + "\n\n```diff\n" + $diff + "\n```")}
|
||||||
|
]
|
||||||
|
}' > payload.json
|
||||||
|
|
||||||
|
# Call OpenAI
|
||||||
|
curl -sS https://api.openai.com/v1/chat/completions \
|
||||||
|
-H "Authorization: Bearer $OPENAI_API_KEY" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d @payload.json > response.json
|
||||||
|
|
||||||
|
# Extract response text
|
||||||
|
COMMENT=$(jq -r '.choices[0].message.content // empty' response.json)
|
||||||
|
if [ -z "$COMMENT" ]; then
|
||||||
|
COMMENT="AI did not return a response."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# If failed, add a note
|
||||||
|
ADDITIONAL_NOTE=""
|
||||||
|
if [[ "$COMMENT" == *"not ok"* ]]; then
|
||||||
|
ADDITIONAL_NOTE=$(echo -ne "\n\nPlease note this check is a guideline, not a hard requirement. It is here to help you translate. If you disagree with some points, just state that. Any typos should be fixed.")
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Post the review as a PR comment
|
||||||
|
jq -n --arg body "$COMMENT" --arg note "$ADDITIONAL_NOTE" '{body: ("AI translation check result:\n\n" + $body + $note)}' > body.json
|
||||||
|
echo "CURLing https://api.github.com/repos/${{ github.repository }}/issues/$PR_NUMBER/comments"
|
||||||
|
curl -sS -X POST \
|
||||||
|
-H "Authorization: token $GITHUB_TOKEN" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
"https://api.github.com/repos/${{ github.repository }}/issues/$PR_NUMBER/comments" \
|
||||||
|
--data @body.json
|
||||||
11
.gitignore
vendored
|
|
@ -14,6 +14,7 @@ _deps
|
||||||
|
|
||||||
build/
|
build/
|
||||||
result*
|
result*
|
||||||
|
/.pre-commit-config.yaml
|
||||||
/.vscode/
|
/.vscode/
|
||||||
/.idea/
|
/.idea/
|
||||||
.envrc
|
.envrc
|
||||||
|
|
@ -27,8 +28,12 @@ protocols/*.c*
|
||||||
protocols/*.h*
|
protocols/*.h*
|
||||||
.ccls-cache
|
.ccls-cache
|
||||||
*.so
|
*.so
|
||||||
|
src/render/shaders/*.inc
|
||||||
|
src/render/shaders/Shaders.hpp
|
||||||
|
|
||||||
hyprctl/hyprctl
|
hyprctl/hyprctl
|
||||||
|
hyprctl/hw-protocols/*.c*
|
||||||
|
hyprctl/hw-protocols/*.h*
|
||||||
|
|
||||||
gmon.out
|
gmon.out
|
||||||
*.out
|
*.out
|
||||||
|
|
@ -37,3 +42,9 @@ gmon.out
|
||||||
PKGBUILD
|
PKGBUILD
|
||||||
|
|
||||||
src/version.h
|
src/version.h
|
||||||
|
hyprpm/Makefile
|
||||||
|
hyprctl/Makefile
|
||||||
|
example/hyprland.desktop
|
||||||
|
|
||||||
|
**/.#*.*
|
||||||
|
**/#*.*#
|
||||||
|
|
|
||||||
496
CMakeLists.txt
|
|
@ -1,4 +1,4 @@
|
||||||
cmake_minimum_required(VERSION 3.27)
|
cmake_minimum_required(VERSION 3.30)
|
||||||
|
|
||||||
# Get version
|
# Get version
|
||||||
file(READ "${CMAKE_SOURCE_DIR}/VERSION" VER_RAW)
|
file(READ "${CMAKE_SOURCE_DIR}/VERSION" VER_RAW)
|
||||||
|
|
@ -9,24 +9,54 @@ project(
|
||||||
DESCRIPTION "A Modern C++ Wayland Compositor"
|
DESCRIPTION "A Modern C++ Wayland Compositor"
|
||||||
VERSION ${VER})
|
VERSION ${VER})
|
||||||
|
|
||||||
|
include(CTest)
|
||||||
include(CheckIncludeFile)
|
include(CheckIncludeFile)
|
||||||
include(GNUInstallDirs)
|
include(GNUInstallDirs)
|
||||||
|
|
||||||
set(HYPRLAND_VERSION ${VER})
|
set(HYPRLAND_VERSION ${VER})
|
||||||
set(PREFIX ${CMAKE_INSTALL_PREFIX})
|
set(PREFIX ${CMAKE_INSTALL_PREFIX})
|
||||||
set(INCLUDEDIR ${CMAKE_INSTALL_INCLUDEDIR})
|
set(INCLUDEDIR ${CMAKE_INSTALL_INCLUDEDIR})
|
||||||
configure_file(hyprland.pc.in hyprland.pc @ONLY)
|
set(BINDIR ${CMAKE_INSTALL_BINDIR})
|
||||||
|
|
||||||
set(CMAKE_MESSAGE_LOG_LEVEL "STATUS")
|
set(CMAKE_MESSAGE_LOG_LEVEL "STATUS")
|
||||||
|
|
||||||
message(STATUS "Gathering git info")
|
message(STATUS "Gathering git info")
|
||||||
|
|
||||||
# Get git info hash and branch
|
# Make shader files includable
|
||||||
execute_process(COMMAND ./scripts/generateVersion.sh
|
execute_process(COMMAND ./scripts/generateShaderIncludes.sh
|
||||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
|
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||||
|
RESULT_VARIABLE HYPR_SHADER_GEN_RESULT)
|
||||||
|
if(NOT HYPR_SHADER_GEN_RESULT EQUAL 0)
|
||||||
|
message(
|
||||||
|
FATAL_ERROR
|
||||||
|
"Failed to generate shader includes (scripts/generateShaderIncludes.sh), exit code: ${HYPR_SHADER_GEN_RESULT}"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
# udis
|
find_package(PkgConfig REQUIRED)
|
||||||
add_subdirectory("subprojects/udis86")
|
|
||||||
|
# Try to find canihavesomecoffee's udis86 using pkgconfig vmd/udis86 does not
|
||||||
|
# provide a .pc file and won't be detected this way
|
||||||
|
pkg_check_modules(udis_dep IMPORTED_TARGET udis86>=1.7.2)
|
||||||
|
|
||||||
|
# Find non-pkgconfig udis86, otherwise fallback to subproject
|
||||||
|
if(NOT udis_dep_FOUND)
|
||||||
|
find_library(udis_nopc udis86)
|
||||||
|
if(NOT("${udis_nopc}" MATCHES "udis_nopc-NOTFOUND"))
|
||||||
|
message(STATUS "Found udis86 at ${udis_nopc}")
|
||||||
|
else()
|
||||||
|
add_subdirectory("subprojects/udis86")
|
||||||
|
include_directories("subprojects/udis86")
|
||||||
|
message(STATUS "udis86 dependency not found, falling back to subproject")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
find_library(librt rt)
|
||||||
|
if("${librt}" MATCHES "librt-NOTFOUND")
|
||||||
|
unset(LIBRT)
|
||||||
|
else()
|
||||||
|
set(LIBRT rt)
|
||||||
|
endif()
|
||||||
|
|
||||||
if(CMAKE_BUILD_TYPE)
|
if(CMAKE_BUILD_TYPE)
|
||||||
string(TOLOWER ${CMAKE_BUILD_TYPE} BUILDTYPE_LOWER)
|
string(TOLOWER ${CMAKE_BUILD_TYPE} BUILDTYPE_LOWER)
|
||||||
|
|
@ -47,32 +77,45 @@ else()
|
||||||
set(BUILDTYPE_LOWER "release")
|
set(BUILDTYPE_LOWER "release")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
find_package(PkgConfig REQUIRED)
|
|
||||||
|
|
||||||
pkg_get_variable(WAYLAND_PROTOCOLS_DIR wayland-protocols pkgdatadir)
|
pkg_get_variable(WAYLAND_PROTOCOLS_DIR wayland-protocols pkgdatadir)
|
||||||
message(STATUS "Found wayland-protocols at ${WAYLAND_PROTOCOLS_DIR}")
|
message(STATUS "Found wayland-protocols at ${WAYLAND_PROTOCOLS_DIR}")
|
||||||
pkg_get_variable(WAYLAND_SERVER_DIR wayland-server pkgdatadir)
|
pkg_get_variable(WAYLAND_SCANNER_PKGDATA_DIR wayland-scanner pkgdatadir)
|
||||||
|
message(
|
||||||
|
STATUS "Found wayland-scanner pkgdatadir at ${WAYLAND_SCANNER_PKGDATA_DIR}")
|
||||||
|
|
||||||
if(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG)
|
if(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG)
|
||||||
message(STATUS "Configuring Hyprland in Debug with CMake")
|
message(STATUS "Configuring Hyprland in Debug with CMake")
|
||||||
add_compile_definitions(HYPRLAND_DEBUG)
|
add_compile_definitions(HYPRLAND_DEBUG)
|
||||||
|
set(BUILD_TESTING ON)
|
||||||
else()
|
else()
|
||||||
add_compile_options(-O3)
|
add_compile_options(-O3)
|
||||||
message(STATUS "Configuring Hyprland in Release with CMake")
|
message(STATUS "Configuring Hyprland in Release with CMake")
|
||||||
|
set(BUILD_TESTING OFF)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
include_directories(. "src/" "subprojects/udis86/" "protocols/")
|
add_compile_definitions(HYPRLAND_VERSION="${HYPRLAND_VERSION}")
|
||||||
set(CMAKE_CXX_STANDARD 23)
|
|
||||||
|
include_directories(. "src/" "protocols/")
|
||||||
|
|
||||||
|
set(CMAKE_CXX_STANDARD 26)
|
||||||
|
set(CXX_STANDARD_REQUIRED ON)
|
||||||
add_compile_options(
|
add_compile_options(
|
||||||
-Wall
|
-Wall
|
||||||
-Wextra
|
-Wextra
|
||||||
|
-Wpedantic
|
||||||
-Wno-unused-parameter
|
-Wno-unused-parameter
|
||||||
-Wno-unused-value
|
-Wno-unused-value
|
||||||
-Wno-missing-field-initializers
|
-Wno-missing-field-initializers
|
||||||
|
-Wno-gnu-zero-variadic-macro-arguments
|
||||||
-Wno-narrowing
|
-Wno-narrowing
|
||||||
-Wno-pointer-arith
|
-Wno-pointer-arith
|
||||||
|
-Wno-clobbered
|
||||||
|
-frtti
|
||||||
-fmacro-prefix-map=${CMAKE_SOURCE_DIR}/=)
|
-fmacro-prefix-map=${CMAKE_SOURCE_DIR}/=)
|
||||||
|
|
||||||
|
# disable lto as it may break plugins
|
||||||
|
add_compile_options(-fno-lto)
|
||||||
|
|
||||||
set(CMAKE_EXECUTABLE_ENABLE_EXPORTS TRUE)
|
set(CMAKE_EXECUTABLE_ENABLE_EXPORTS TRUE)
|
||||||
set(CMAKE_EXPORT_COMPILE_COMMANDS TRUE)
|
set(CMAKE_EXPORT_COMPILE_COMMANDS TRUE)
|
||||||
|
|
||||||
|
|
@ -80,50 +123,158 @@ message(STATUS "Checking deps...")
|
||||||
|
|
||||||
find_package(Threads REQUIRED)
|
find_package(Threads REQUIRED)
|
||||||
|
|
||||||
if(LEGACY_RENDERER)
|
set(GLES_VERSION "GLES3")
|
||||||
set(GLES_VERSION "GLES2")
|
|
||||||
else()
|
|
||||||
set(GLES_VERSION "GLES3")
|
|
||||||
endif()
|
|
||||||
find_package(OpenGL REQUIRED COMPONENTS ${GLES_VERSION})
|
find_package(OpenGL REQUIRED COMPONENTS ${GLES_VERSION})
|
||||||
|
find_package(glslang CONFIG REQUIRED)
|
||||||
|
|
||||||
pkg_check_modules(
|
set(AQUAMARINE_MINIMUM_VERSION 0.9.3)
|
||||||
hyprctl_deps
|
set(HYPRLANG_MINIMUM_VERSION 0.6.7)
|
||||||
REQUIRED
|
set(HYPRCURSOR_MINIMUM_VERSION 0.1.7)
|
||||||
IMPORTED_TARGET
|
set(HYPRUTILS_MINIMUM_VERSION 0.11.0)
|
||||||
hyprutils>=0.2.1)
|
set(HYPRGRAPHICS_MINIMUM_VERSION 0.1.6)
|
||||||
|
|
||||||
|
pkg_check_modules(aquamarine_dep REQUIRED IMPORTED_TARGET aquamarine>=${AQUAMARINE_MINIMUM_VERSION})
|
||||||
|
pkg_check_modules(hyprlang_dep REQUIRED IMPORTED_TARGET hyprlang>=${HYPRLANG_MINIMUM_VERSION})
|
||||||
|
pkg_check_modules(hyprcursor_dep REQUIRED IMPORTED_TARGET hyprcursor>=${HYPRCURSOR_MINIMUM_VERSION})
|
||||||
|
pkg_check_modules(hyprutils_dep REQUIRED IMPORTED_TARGET hyprutils>=${HYPRUTILS_MINIMUM_VERSION})
|
||||||
|
pkg_check_modules(hyprgraphics_dep REQUIRED IMPORTED_TARGET hyprgraphics>=${HYPRGRAPHICS_MINIMUM_VERSION})
|
||||||
|
|
||||||
|
string(REPLACE "." ";" AQ_VERSION_LIST ${aquamarine_dep_VERSION})
|
||||||
|
list(GET AQ_VERSION_LIST 0 AQ_VERSION_MAJOR)
|
||||||
|
list(GET AQ_VERSION_LIST 1 AQ_VERSION_MINOR)
|
||||||
|
list(GET AQ_VERSION_LIST 2 AQ_VERSION_PATCH)
|
||||||
|
|
||||||
|
set(AQUAMARINE_VERSION "${aquamarine_dep_VERSION}")
|
||||||
|
set(AQUAMARINE_VERSION_MAJOR "${AQ_VERSION_MAJOR}")
|
||||||
|
set(AQUAMARINE_VERSION_MINOR "${AQ_VERSION_MINOR}")
|
||||||
|
set(AQUAMARINE_VERSION_PATCH "${AQ_VERSION_PATCH}")
|
||||||
|
set(HYPRLANG_VERSION "${hyprlang_dep_VERSION}")
|
||||||
|
set(HYPRUTILS_VERSION "${hyprutils_dep_VERSION}")
|
||||||
|
set(HYPRCURSOR_VERSION "${hyprcursor_dep_VERSION}")
|
||||||
|
set(HYPRGRAPHICS_VERSION "${hyprgraphics_dep_VERSION}")
|
||||||
|
|
||||||
|
|
||||||
|
find_package(Git QUIET)
|
||||||
|
|
||||||
|
# Populate variables with env vars if present
|
||||||
|
set(GIT_COMMIT_HASH "$ENV{GIT_COMMIT_HASH}")
|
||||||
|
if(NOT GIT_COMMIT_HASH)
|
||||||
|
set(GIT_COMMIT_HASH "unknown")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(GIT_BRANCH "$ENV{GIT_BRANCH}")
|
||||||
|
if(NOT GIT_BRANCH)
|
||||||
|
set(GIT_BRANCH "unknown")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(GIT_COMMIT_MESSAGE "$ENV{GIT_COMMIT_MESSAGE}")
|
||||||
|
if(NOT GIT_COMMIT_MESSAGE)
|
||||||
|
set(GIT_COMMIT_MESSAGE "unknown")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(GIT_COMMIT_DATE "$ENV{GIT_COMMIT_DATE}")
|
||||||
|
if(NOT GIT_COMMIT_DATE)
|
||||||
|
set(GIT_COMMIT_DATE "unknown")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(GIT_DIRTY "$ENV{GIT_DIRTY}")
|
||||||
|
if(NOT GIT_DIRTY)
|
||||||
|
set(GIT_DIRTY "unknown")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(GIT_TAG "$ENV{GIT_TAG}")
|
||||||
|
if(NOT GIT_TAG)
|
||||||
|
set(GIT_TAG "unknown")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(GIT_COMMITS "$ENV{GIT_COMMITS}")
|
||||||
|
if(NOT GIT_COMMITS)
|
||||||
|
set(GIT_COMMITS "0")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(Git_FOUND)
|
||||||
|
execute_process(
|
||||||
|
COMMAND ${GIT_EXECUTABLE} rev-parse --show-toplevel
|
||||||
|
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||||
|
OUTPUT_VARIABLE GIT_TOPLEVEL
|
||||||
|
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||||
|
ERROR_QUIET
|
||||||
|
RESULT_VARIABLE GIT_TOPLEVEL_RESULT
|
||||||
|
)
|
||||||
|
|
||||||
|
if(GIT_TOPLEVEL_RESULT EQUAL 0)
|
||||||
|
message(STATUS "Detected git repository root: ${GIT_TOPLEVEL}")
|
||||||
|
|
||||||
|
execute_process(COMMAND ${GIT_EXECUTABLE} rev-parse HEAD
|
||||||
|
WORKING_DIRECTORY ${GIT_TOPLEVEL}
|
||||||
|
OUTPUT_VARIABLE GIT_COMMIT_HASH OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||||
|
execute_process(COMMAND ${GIT_EXECUTABLE} branch --show-current
|
||||||
|
WORKING_DIRECTORY ${GIT_TOPLEVEL}
|
||||||
|
OUTPUT_VARIABLE GIT_BRANCH OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||||
|
execute_process(COMMAND sh "-c" "${GIT_EXECUTABLE} show -s --format=%s --no-show-signature | sed \"s/\\\"/\'/g\""
|
||||||
|
WORKING_DIRECTORY ${GIT_TOPLEVEL}
|
||||||
|
OUTPUT_VARIABLE GIT_COMMIT_MESSAGE OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||||
|
execute_process(COMMAND ${GIT_EXECUTABLE} show -s --format=%cd --date=local --no-show-signature
|
||||||
|
WORKING_DIRECTORY ${GIT_TOPLEVEL}
|
||||||
|
OUTPUT_VARIABLE GIT_COMMIT_DATE OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||||
|
execute_process(COMMAND ${GIT_EXECUTABLE} diff-index --quiet HEAD --
|
||||||
|
WORKING_DIRECTORY ${GIT_TOPLEVEL}
|
||||||
|
RESULT_VARIABLE GIT_DIRTY_RESULT)
|
||||||
|
if(NOT GIT_DIRTY_RESULT EQUAL 0)
|
||||||
|
set(GIT_DIRTY "dirty")
|
||||||
|
else()
|
||||||
|
set(GIT_DIRTY "clean")
|
||||||
|
endif()
|
||||||
|
execute_process(COMMAND ${GIT_EXECUTABLE} describe --tags
|
||||||
|
WORKING_DIRECTORY ${GIT_TOPLEVEL}
|
||||||
|
OUTPUT_VARIABLE GIT_TAG OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||||
|
execute_process(COMMAND ${GIT_EXECUTABLE} rev-list --count HEAD
|
||||||
|
WORKING_DIRECTORY ${GIT_TOPLEVEL}
|
||||||
|
OUTPUT_VARIABLE GIT_COMMITS OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||||
|
else()
|
||||||
|
message(WARNING "No Git repository detected in ${CMAKE_SOURCE_DIR}")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
configure_file(
|
||||||
|
${CMAKE_SOURCE_DIR}/src/version.h.in
|
||||||
|
${CMAKE_SOURCE_DIR}/src/version.h
|
||||||
|
@ONLY
|
||||||
|
)
|
||||||
|
|
||||||
|
set_source_files_properties(${CMAKE_SOURCE_DIR}/src/version.h PROPERTIES GENERATED TRUE)
|
||||||
|
|
||||||
|
set(XKBCOMMON_MINIMUM_VERSION 1.11.0)
|
||||||
|
set(WAYLAND_SERVER_MINIMUM_VERSION 1.22.91)
|
||||||
|
set(WAYLAND_SERVER_PROTOCOLS_MINIMUM_VERSION 1.45)
|
||||||
|
set(LIBINPUT_MINIMUM_VERSION 1.28)
|
||||||
|
|
||||||
pkg_check_modules(
|
pkg_check_modules(
|
||||||
deps
|
deps
|
||||||
REQUIRED
|
REQUIRED
|
||||||
IMPORTED_TARGET
|
IMPORTED_TARGET GLOBAL
|
||||||
aquamarine
|
xkbcommon>=${XKBCOMMON_MINIMUM_VERSION}
|
||||||
xkbcommon
|
|
||||||
uuid
|
uuid
|
||||||
wayland-server
|
wayland-server>=${WAYLAND_SERVER_MINIMUM_VERSION}
|
||||||
wayland-client
|
wayland-protocols>=${WAYLAND_SERVER_PROTOCOLS_MINIMUM_VERSION}
|
||||||
wayland-cursor
|
|
||||||
wayland-protocols
|
|
||||||
cairo
|
cairo
|
||||||
pango
|
pango
|
||||||
pangocairo
|
pangocairo
|
||||||
pixman-1
|
pixman-1
|
||||||
xcursor
|
xcursor
|
||||||
libdrm
|
libdrm
|
||||||
libinput
|
libinput>=${LIBINPUT_MINIMUM_VERSION}
|
||||||
hwdata
|
|
||||||
libseat
|
|
||||||
libdisplay-info
|
|
||||||
libliftoff
|
|
||||||
libudev
|
|
||||||
gbm
|
gbm
|
||||||
hyprlang>=0.3.2
|
gio-2.0
|
||||||
hyprcursor>=0.1.7
|
re2
|
||||||
hyprutils>=0.2.1)
|
muparser
|
||||||
|
lcms2)
|
||||||
|
|
||||||
find_package(hyprwayland-scanner 0.3.10 REQUIRED)
|
find_package(hyprwayland-scanner 0.3.10 REQUIRED)
|
||||||
|
|
||||||
file(GLOB_RECURSE SRCFILES "src/*.cpp")
|
file(GLOB_RECURSE SRCFILES "src/*.cpp")
|
||||||
|
get_filename_component(FULL_MAIN_PATH ${CMAKE_CURRENT_SOURCE_DIR}/src/main.cpp ABSOLUTE)
|
||||||
|
list(REMOVE_ITEM SRCFILES "${FULL_MAIN_PATH}")
|
||||||
|
|
||||||
set(TRACY_CPP_FILES "")
|
set(TRACY_CPP_FILES "")
|
||||||
if(USE_TRACY)
|
if(USE_TRACY)
|
||||||
|
|
@ -131,9 +282,14 @@ if(USE_TRACY)
|
||||||
message(STATUS "Tracy enabled, TRACY_CPP_FILES: " ${TRACY_CPP_FILES})
|
message(STATUS "Tracy enabled, TRACY_CPP_FILES: " ${TRACY_CPP_FILES})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_executable(Hyprland ${SRCFILES} ${TRACY_CPP_FILES})
|
add_library(hyprland_lib STATIC ${SRCFILES})
|
||||||
|
add_executable(Hyprland src/main.cpp ${TRACY_CPP_FILES})
|
||||||
|
target_link_libraries(Hyprland hyprland_lib)
|
||||||
|
|
||||||
set(USE_GPROF ON)
|
target_include_directories(hyprland_lib PUBLIC ${deps_INCLUDE_DIRS})
|
||||||
|
target_include_directories(Hyprland PUBLIC ${deps_INCLUDE_DIRS})
|
||||||
|
|
||||||
|
set(USE_GPROF OFF)
|
||||||
|
|
||||||
if(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG)
|
if(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG)
|
||||||
message(STATUS "Setting debug flags")
|
message(STATUS "Setting debug flags")
|
||||||
|
|
@ -141,23 +297,8 @@ if(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG)
|
||||||
if(WITH_ASAN)
|
if(WITH_ASAN)
|
||||||
message(STATUS "Enabling ASan")
|
message(STATUS "Enabling ASan")
|
||||||
|
|
||||||
target_link_libraries(Hyprland asan)
|
target_link_libraries(hyprland_lib PUBLIC asan)
|
||||||
target_compile_options(Hyprland PUBLIC -fsanitize=address)
|
target_compile_options(hyprland_lib PUBLIC -fsanitize=address)
|
||||||
endif()
|
|
||||||
|
|
||||||
if(USE_TRACY)
|
|
||||||
message(STATUS "Tracy is turned on")
|
|
||||||
|
|
||||||
option(TRACY_ENABLE "" ON)
|
|
||||||
option(TRACY_ON_DEMAND "" ON)
|
|
||||||
add_subdirectory(subprojects/tracy)
|
|
||||||
|
|
||||||
target_link_libraries(Hyprland Tracy::TracyClient)
|
|
||||||
|
|
||||||
if(USE_TRACY_GPU)
|
|
||||||
message(STATUS "Tracy GPU Profiling is turned on")
|
|
||||||
add_compile_definitions(USE_TRACY_GPU)
|
|
||||||
endif()
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_compile_options(-fno-pie -fno-builtin)
|
add_compile_options(-fno-pie -fno-builtin)
|
||||||
|
|
@ -168,6 +309,27 @@ if(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG)
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(USE_TRACY)
|
||||||
|
message(STATUS "Tracy is turned on")
|
||||||
|
|
||||||
|
option(TRACY_ENABLE "" ON)
|
||||||
|
option(TRACY_ON_DEMAND "" ON)
|
||||||
|
add_subdirectory(subprojects/tracy)
|
||||||
|
|
||||||
|
add_compile_options(-fno-omit-frame-pointer)
|
||||||
|
|
||||||
|
target_link_libraries(hyprland_lib PUBLIC Tracy::TracyClient)
|
||||||
|
|
||||||
|
if(USE_TRACY_GPU)
|
||||||
|
message(STATUS "Tracy GPU Profiling is turned on")
|
||||||
|
add_compile_definitions(USE_TRACY_GPU)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(BUILT_WITH_NIX)
|
||||||
|
add_compile_definitions(BUILT_WITH_NIX)
|
||||||
|
endif()
|
||||||
|
|
||||||
check_include_file("execinfo.h" EXECINFOH)
|
check_include_file("execinfo.h" EXECINFOH)
|
||||||
if(EXECINFOH)
|
if(EXECINFOH)
|
||||||
message(STATUS "Configuration supports execinfo")
|
message(STATUS "Configuration supports execinfo")
|
||||||
|
|
@ -177,18 +339,19 @@ endif()
|
||||||
include(CheckLibraryExists)
|
include(CheckLibraryExists)
|
||||||
check_library_exists(execinfo backtrace "" HAVE_LIBEXECINFO)
|
check_library_exists(execinfo backtrace "" HAVE_LIBEXECINFO)
|
||||||
if(HAVE_LIBEXECINFO)
|
if(HAVE_LIBEXECINFO)
|
||||||
target_link_libraries(Hyprland execinfo)
|
target_link_libraries(hyprland_lib PUBLIC execinfo)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
check_include_file("sys/timerfd.h" HAS_TIMERFD)
|
check_include_file("sys/timerfd.h" HAS_TIMERFD)
|
||||||
pkg_check_modules(epoll IMPORTED_TARGET epoll-shim)
|
pkg_check_modules(epoll IMPORTED_TARGET epoll-shim)
|
||||||
if(NOT HAS_TIMERFD AND epoll_FOUND)
|
if(NOT HAS_TIMERFD AND epoll_FOUND)
|
||||||
target_link_libraries(Hyprland PkgConfig::epoll)
|
target_link_libraries(hyprland_lib PUBLIC PkgConfig::epoll)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(LEGACY_RENDERER)
|
check_include_file("sys/inotify.h" HAS_INOTIFY)
|
||||||
message(STATUS "Using the legacy GLES2 renderer!")
|
pkg_check_modules(inotify IMPORTED_TARGET libinotify)
|
||||||
add_compile_definitions(LEGACY_RENDERER)
|
if(NOT HAS_INOTIFY AND inotify_FOUND)
|
||||||
|
target_link_libraries(hyprland_lib PUBLIC PkgConfig::inotify)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(NO_XWAYLAND)
|
if(NO_XWAYLAND)
|
||||||
|
|
@ -196,49 +359,89 @@ if(NO_XWAYLAND)
|
||||||
add_compile_definitions(NO_XWAYLAND)
|
add_compile_definitions(NO_XWAYLAND)
|
||||||
else()
|
else()
|
||||||
message(STATUS "XWAYLAND Enabled (NO_XWAYLAND not defined) checking deps...")
|
message(STATUS "XWAYLAND Enabled (NO_XWAYLAND not defined) checking deps...")
|
||||||
pkg_check_modules(
|
set(XWAYLAND_DEPENDENCIES
|
||||||
xdeps
|
|
||||||
REQUIRED
|
|
||||||
IMPORTED_TARGET
|
|
||||||
xcb
|
xcb
|
||||||
xwayland
|
|
||||||
xcb-util
|
|
||||||
xcb-render
|
xcb-render
|
||||||
xcb-xfixes
|
xcb-xfixes
|
||||||
xcb-icccm
|
xcb-icccm
|
||||||
xcb-composite
|
xcb-composite
|
||||||
xcb-res
|
xcb-res
|
||||||
xcb-ewmh
|
|
||||||
xcb-errors)
|
xcb-errors)
|
||||||
target_link_libraries(Hyprland PkgConfig::xdeps)
|
|
||||||
|
pkg_check_modules(
|
||||||
|
xdeps
|
||||||
|
REQUIRED
|
||||||
|
IMPORTED_TARGET
|
||||||
|
${XWAYLAND_DEPENDENCIES})
|
||||||
|
|
||||||
|
string(JOIN ", " PKGCONFIG_XWAYLAND_DEPENDENCIES ${XWAYLAND_DEPENDENCIES})
|
||||||
|
string(PREPEND PKGCONFIG_XWAYLAND_DEPENDENCIES ", ")
|
||||||
|
|
||||||
|
target_link_libraries(hyprland_lib PUBLIC PkgConfig::xdeps)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
configure_file(hyprland.pc.in hyprland.pc @ONLY)
|
||||||
|
|
||||||
if(NO_SYSTEMD)
|
if(NO_SYSTEMD)
|
||||||
message(STATUS "SYSTEMD support is disabled...")
|
message(STATUS "SYSTEMD support is disabled...")
|
||||||
else()
|
else()
|
||||||
message(STATUS "SYSTEMD support is requested (NO_SYSTEMD not defined)...")
|
message(STATUS "SYSTEMD support is requested (NO_SYSTEMD not defined)...")
|
||||||
add_compile_definitions(USES_SYSTEMD)
|
add_compile_definitions(USES_SYSTEMD)
|
||||||
|
|
||||||
|
# session file -uwsm
|
||||||
|
if(NO_UWSM)
|
||||||
|
message(STATUS "UWSM support is disabled...")
|
||||||
|
else()
|
||||||
|
message(STATUS "UWSM support is enabled (NO_UWSM not defined)...")
|
||||||
|
install(FILES ${CMAKE_SOURCE_DIR}/systemd/hyprland-uwsm.desktop
|
||||||
|
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/wayland-sessions)
|
||||||
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set(CPACK_PROJECT_NAME ${PROJECT_NAME})
|
set(CPACK_PROJECT_NAME ${PROJECT_NAME})
|
||||||
set(CPACK_PROJECT_VERSION ${PROJECT_VERSION})
|
set(CPACK_PROJECT_VERSION ${PROJECT_VERSION})
|
||||||
include(CPack)
|
include(CPack)
|
||||||
|
|
||||||
message(STATUS "Setting precompiled headers")
|
if(CMAKE_DISABLE_PRECOMPILE_HEADERS)
|
||||||
|
message(STATUS "Not using precompiled headers")
|
||||||
target_precompile_headers(Hyprland PRIVATE
|
else()
|
||||||
$<$<COMPILE_LANGUAGE:CXX>:src/pch/pch.hpp>)
|
message(STATUS "Setting precompiled headers")
|
||||||
|
target_precompile_headers(hyprland_lib PRIVATE
|
||||||
|
$<$<COMPILE_LANGUAGE:CXX>:src/pch/pch.hpp>)
|
||||||
|
endif()
|
||||||
|
|
||||||
message(STATUS "Setting link libraries")
|
message(STATUS "Setting link libraries")
|
||||||
|
|
||||||
target_link_libraries(Hyprland rt PkgConfig::deps)
|
target_link_libraries(
|
||||||
|
hyprland_lib
|
||||||
|
PUBLIC
|
||||||
|
PkgConfig::aquamarine_dep
|
||||||
|
PkgConfig::hyprlang_dep
|
||||||
|
PkgConfig::hyprutils_dep
|
||||||
|
PkgConfig::hyprcursor_dep
|
||||||
|
PkgConfig::hyprgraphics_dep
|
||||||
|
PkgConfig::deps
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(
|
||||||
|
Hyprland
|
||||||
|
${LIBRT}
|
||||||
|
hyprland_lib)
|
||||||
|
if(udis_dep_FOUND)
|
||||||
|
target_link_libraries(hyprland_lib PUBLIC PkgConfig::udis_dep)
|
||||||
|
elseif(NOT("${udis_nopc}" MATCHES "udis_nopc-NOTFOUND"))
|
||||||
|
target_link_libraries(hyprland_lib PUBLIC ${udis_nopc})
|
||||||
|
else()
|
||||||
|
target_link_libraries(hyprland_lib PUBLIC libudis86)
|
||||||
|
endif()
|
||||||
|
|
||||||
# used by `make installheaders`, to ensure the headers are generated
|
# used by `make installheaders`, to ensure the headers are generated
|
||||||
add_custom_target(generate-protocol-headers)
|
add_custom_target(generate-protocol-headers)
|
||||||
|
set(PROTOCOL_SOURCES "")
|
||||||
|
|
||||||
function(protocolnew protoPath protoName external)
|
function(protocolnew protoPath protoName external)
|
||||||
if(external)
|
if(external)
|
||||||
set(path ${CMAKE_SOURCE_DIR}/${protoPath})
|
set(path ${protoPath})
|
||||||
else()
|
else()
|
||||||
set(path ${WAYLAND_PROTOCOLS_DIR}/${protoPath})
|
set(path ${WAYLAND_PROTOCOLS_DIR}/${protoPath})
|
||||||
endif()
|
endif()
|
||||||
|
|
@ -248,31 +451,54 @@ function(protocolnew protoPath protoName external)
|
||||||
COMMAND hyprwayland-scanner ${path}/${protoName}.xml
|
COMMAND hyprwayland-scanner ${path}/${protoName}.xml
|
||||||
${CMAKE_SOURCE_DIR}/protocols/
|
${CMAKE_SOURCE_DIR}/protocols/
|
||||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
|
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
|
||||||
target_sources(Hyprland PRIVATE protocols/${protoName}.cpp
|
target_sources(hyprland_lib PRIVATE protocols/${protoName}.cpp
|
||||||
protocols/${protoName}.hpp)
|
protocols/${protoName}.hpp)
|
||||||
target_sources(generate-protocol-headers
|
target_sources(generate-protocol-headers
|
||||||
PRIVATE ${CMAKE_SOURCE_DIR}/protocols/${protoName}.hpp)
|
PRIVATE ${CMAKE_SOURCE_DIR}/protocols/${protoName}.hpp)
|
||||||
|
|
||||||
|
list(APPEND PROTOCOL_SOURCES "${CMAKE_SOURCE_DIR}/protocols/${protoName}.cpp")
|
||||||
|
set(PROTOCOL_SOURCES "${PROTOCOL_SOURCES}" PARENT_SCOPE)
|
||||||
|
list(APPEND PROTOCOL_SOURCES "${CMAKE_SOURCE_DIR}/protocols/${protoName}.hpp")
|
||||||
|
set(PROTOCOL_SOURCES "${PROTOCOL_SOURCES}" PARENT_SCOPE)
|
||||||
endfunction()
|
endfunction()
|
||||||
function(protocolWayland)
|
function(protocolWayland)
|
||||||
add_custom_command(
|
add_custom_command(
|
||||||
OUTPUT ${CMAKE_SOURCE_DIR}/protocols/wayland.cpp
|
OUTPUT ${CMAKE_SOURCE_DIR}/protocols/wayland.cpp
|
||||||
${CMAKE_SOURCE_DIR}/protocols/wayland.hpp
|
${CMAKE_SOURCE_DIR}/protocols/wayland.hpp
|
||||||
COMMAND hyprwayland-scanner --wayland-enums
|
COMMAND
|
||||||
${WAYLAND_SERVER_DIR}/wayland.xml ${CMAKE_SOURCE_DIR}/protocols/
|
hyprwayland-scanner --wayland-enums
|
||||||
|
${WAYLAND_SCANNER_PKGDATA_DIR}/wayland.xml ${CMAKE_SOURCE_DIR}/protocols/
|
||||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
|
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
|
||||||
target_sources(Hyprland PRIVATE protocols/wayland.cpp protocols/wayland.hpp)
|
target_sources(hyprland_lib PRIVATE protocols/wayland.cpp protocols/wayland.hpp)
|
||||||
target_sources(generate-protocol-headers
|
target_sources(generate-protocol-headers
|
||||||
PRIVATE ${CMAKE_SOURCE_DIR}/protocols/wayland.hpp)
|
PRIVATE ${CMAKE_SOURCE_DIR}/protocols/wayland.hpp)
|
||||||
|
|
||||||
|
list(APPEND PROTOCOL_SOURCES "${CMAKE_SOURCE_DIR}/protocols/wayland.hpp")
|
||||||
|
set(PROTOCOL_SOURCES "${PROTOCOL_SOURCES}" PARENT_SCOPE)
|
||||||
|
list(APPEND PROTOCOL_SOURCES "${CMAKE_SOURCE_DIR}/protocols/wayland.cpp")
|
||||||
|
set(PROTOCOL_SOURCES "${PROTOCOL_SOURCES}" PARENT_SCOPE)
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
target_link_libraries(Hyprland OpenGL::EGL OpenGL::GL Threads::Threads
|
if(TARGET OpenGL::GL)
|
||||||
libudis86 uuid)
|
target_link_libraries(hyprland_lib PUBLIC OpenGL::EGL OpenGL::GL glslang::glslang glslang::glslang-default-resource-limits glslang::SPIRV Threads::Threads)
|
||||||
|
else()
|
||||||
|
target_link_libraries(hyprland_lib PUBLIC OpenGL::EGL OpenGL::GLES3 glslang::glslang glslang::glslang-default-resource-limits glslang::SPIRV Threads::Threads)
|
||||||
|
endif()
|
||||||
|
|
||||||
protocolnew("subprojects/hyprland-protocols/protocols"
|
pkg_check_modules(hyprland_protocols_dep hyprland-protocols>=0.6.4)
|
||||||
"hyprland-global-shortcuts-v1" true)
|
if(hyprland_protocols_dep_FOUND)
|
||||||
|
pkg_get_variable(HYPRLAND_PROTOCOLS hyprland-protocols pkgdatadir)
|
||||||
|
message(STATUS "hyprland-protocols dependency set to ${HYPRLAND_PROTOCOLS}")
|
||||||
|
else()
|
||||||
|
set(HYPRLAND_PROTOCOLS "subprojects/hyprland-protocols")
|
||||||
|
message(STATUS "hyprland-protocols subproject set to ${HYPRLAND_PROTOCOLS}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
protocolnew("${HYPRLAND_PROTOCOLS}/protocols" "hyprland-global-shortcuts-v1"
|
||||||
|
true)
|
||||||
protocolnew("unstable/text-input" "text-input-unstable-v1" false)
|
protocolnew("unstable/text-input" "text-input-unstable-v1" false)
|
||||||
protocolnew("subprojects/hyprland-protocols/protocols"
|
protocolnew("${HYPRLAND_PROTOCOLS}/protocols" "hyprland-toplevel-export-v1"
|
||||||
"hyprland-toplevel-export-v1" true)
|
true)
|
||||||
protocolnew("protocols" "wlr-screencopy-unstable-v1" true)
|
protocolnew("protocols" "wlr-screencopy-unstable-v1" true)
|
||||||
protocolnew("protocols" "wlr-gamma-control-unstable-v1" true)
|
protocolnew("protocols" "wlr-gamma-control-unstable-v1" true)
|
||||||
protocolnew("protocols" "wlr-foreign-toplevel-management-unstable-v1" true)
|
protocolnew("protocols" "wlr-foreign-toplevel-management-unstable-v1" true)
|
||||||
|
|
@ -283,10 +509,15 @@ protocolnew("protocols" "input-method-unstable-v2" true)
|
||||||
protocolnew("protocols" "wlr-output-management-unstable-v1" true)
|
protocolnew("protocols" "wlr-output-management-unstable-v1" true)
|
||||||
protocolnew("protocols" "kde-server-decoration" true)
|
protocolnew("protocols" "kde-server-decoration" true)
|
||||||
protocolnew("protocols" "wlr-data-control-unstable-v1" true)
|
protocolnew("protocols" "wlr-data-control-unstable-v1" true)
|
||||||
protocolnew("subprojects/hyprland-protocols/protocols" "hyprland-focus-grab-v1"
|
protocolnew("${HYPRLAND_PROTOCOLS}/protocols" "hyprland-focus-grab-v1" true)
|
||||||
true)
|
|
||||||
protocolnew("protocols" "wlr-layer-shell-unstable-v1" true)
|
protocolnew("protocols" "wlr-layer-shell-unstable-v1" true)
|
||||||
protocolnew("protocols" "wayland-drm" true)
|
protocolnew("protocols" "wayland-drm" true)
|
||||||
|
protocolnew("${HYPRLAND_PROTOCOLS}/protocols" "hyprland-ctm-control-v1" true)
|
||||||
|
protocolnew("${HYPRLAND_PROTOCOLS}/protocols" "hyprland-surface-v1" true)
|
||||||
|
protocolnew("${HYPRLAND_PROTOCOLS}/protocols" "hyprland-lock-notify-v1" true)
|
||||||
|
protocolnew("${HYPRLAND_PROTOCOLS}/protocols" "hyprland-toplevel-mapping-v1"
|
||||||
|
true)
|
||||||
|
|
||||||
protocolnew("staging/tearing-control" "tearing-control-v1" false)
|
protocolnew("staging/tearing-control" "tearing-control-v1" false)
|
||||||
protocolnew("staging/fractional-scale" "fractional-scale-v1" false)
|
protocolnew("staging/fractional-scale" "fractional-scale-v1" false)
|
||||||
protocolnew("unstable/xdg-output" "xdg-output-unstable-v1" false)
|
protocolnew("unstable/xdg-output" "xdg-output-unstable-v1" false)
|
||||||
|
|
@ -315,12 +546,33 @@ protocolnew("stable/viewporter" "viewporter" false)
|
||||||
protocolnew("stable/linux-dmabuf" "linux-dmabuf-v1" false)
|
protocolnew("stable/linux-dmabuf" "linux-dmabuf-v1" false)
|
||||||
protocolnew("staging/drm-lease" "drm-lease-v1" false)
|
protocolnew("staging/drm-lease" "drm-lease-v1" false)
|
||||||
protocolnew("staging/linux-drm-syncobj" "linux-drm-syncobj-v1" false)
|
protocolnew("staging/linux-drm-syncobj" "linux-drm-syncobj-v1" false)
|
||||||
|
protocolnew("staging/xdg-dialog" "xdg-dialog-v1" false)
|
||||||
|
protocolnew("staging/single-pixel-buffer" "single-pixel-buffer-v1" false)
|
||||||
|
protocolnew("staging/security-context" "security-context-v1" false)
|
||||||
|
protocolnew("staging/content-type" "content-type-v1" false)
|
||||||
|
protocolnew("staging/color-management" "color-management-v1" false)
|
||||||
|
protocolnew("staging/xdg-toplevel-tag" "xdg-toplevel-tag-v1" false)
|
||||||
|
protocolnew("staging/xdg-system-bell" "xdg-system-bell-v1" false)
|
||||||
|
protocolnew("staging/ext-workspace" "ext-workspace-v1" false)
|
||||||
|
protocolnew("staging/ext-data-control" "ext-data-control-v1" false)
|
||||||
|
protocolnew("staging/pointer-warp" "pointer-warp-v1" false)
|
||||||
|
protocolnew("staging/fifo" "fifo-v1" false)
|
||||||
|
protocolnew("staging/commit-timing" "commit-timing-v1" false)
|
||||||
|
protocolnew("staging/ext-image-capture-source" "ext-image-capture-source-v1" false)
|
||||||
|
protocolnew("staging/ext-image-copy-capture" "ext-image-copy-capture-v1" false)
|
||||||
|
|
||||||
protocolwayland()
|
protocolwayland()
|
||||||
|
|
||||||
# tools
|
# tools
|
||||||
add_subdirectory(hyprctl)
|
add_subdirectory(hyprctl)
|
||||||
add_subdirectory(hyprpm)
|
add_subdirectory(start)
|
||||||
|
|
||||||
|
if(NO_HYPRPM)
|
||||||
|
message(STATUS "hyprpm is disabled")
|
||||||
|
else()
|
||||||
|
add_subdirectory(hyprpm)
|
||||||
|
message(STATUS "hyprpm is enabled (NO_HYPRPM not defined)")
|
||||||
|
endif()
|
||||||
|
|
||||||
# binary and symlink
|
# binary and symlink
|
||||||
install(TARGETS Hyprland)
|
install(TARGETS Hyprland)
|
||||||
|
|
@ -329,19 +581,24 @@ install(
|
||||||
CODE "execute_process( \
|
CODE "execute_process( \
|
||||||
COMMAND ${CMAKE_COMMAND} -E create_symlink \
|
COMMAND ${CMAKE_COMMAND} -E create_symlink \
|
||||||
${CMAKE_INSTALL_FULL_BINDIR}/Hyprland \
|
${CMAKE_INSTALL_FULL_BINDIR}/Hyprland \
|
||||||
${CMAKE_INSTALL_FULL_BINDIR}/hyprland
|
\"\$ENV{DESTDIR}${CMAKE_INSTALL_FULL_BINDIR}/hyprland\" \
|
||||||
)")
|
)")
|
||||||
|
|
||||||
# session file
|
# session file
|
||||||
|
configure_file(
|
||||||
|
${CMAKE_SOURCE_DIR}/example/hyprland.desktop.in
|
||||||
|
${CMAKE_SOURCE_DIR}/example/hyprland.desktop
|
||||||
|
@ONLY
|
||||||
|
)
|
||||||
install(FILES ${CMAKE_SOURCE_DIR}/example/hyprland.desktop
|
install(FILES ${CMAKE_SOURCE_DIR}/example/hyprland.desktop
|
||||||
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/wayland-sessions)
|
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/wayland-sessions)
|
||||||
|
|
||||||
# allow Hyprland to find wallpapers
|
# allow Hyprland to find assets
|
||||||
add_compile_definitions(DATAROOTDIR="${CMAKE_INSTALL_FULL_DATAROOTDIR}")
|
add_compile_definitions(DATAROOTDIR="${CMAKE_INSTALL_FULL_DATAROOTDIR}")
|
||||||
|
|
||||||
# wallpapers
|
# installable assets
|
||||||
file(GLOB_RECURSE WALLPAPERS "assets/wall*")
|
file(GLOB_RECURSE INSTALLABLE_ASSETS "assets/install/*")
|
||||||
install(FILES ${WALLPAPERS} DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/hypr)
|
install(FILES ${INSTALLABLE_ASSETS}
|
||||||
|
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/hypr)
|
||||||
|
|
||||||
# default config
|
# default config
|
||||||
install(FILES ${CMAKE_SOURCE_DIR}/example/hyprland.conf
|
install(FILES ${CMAKE_SOURCE_DIR}/example/hyprland.conf
|
||||||
|
|
@ -373,4 +630,51 @@ install(
|
||||||
DIRECTORY ${HEADERS_SRC}
|
DIRECTORY ${HEADERS_SRC}
|
||||||
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/hyprland
|
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/hyprland
|
||||||
FILES_MATCHING
|
FILES_MATCHING
|
||||||
PATTERN "*.h*")
|
PATTERN "*.h"
|
||||||
|
PATTERN "*.hpp"
|
||||||
|
PATTERN "*.inc")
|
||||||
|
|
||||||
|
if(BUILD_TESTING OR WITH_TESTS)
|
||||||
|
message(STATUS "Building tests")
|
||||||
|
|
||||||
|
# hyprtester
|
||||||
|
add_subdirectory(hyprtester)
|
||||||
|
|
||||||
|
# GTest
|
||||||
|
find_package(GTest CONFIG REQUIRED)
|
||||||
|
include(GoogleTest)
|
||||||
|
file(GLOB_RECURSE TESTFILES "tests/*.cpp")
|
||||||
|
add_executable(hyprland_gtests ${TESTFILES})
|
||||||
|
target_compile_options(hyprland_gtests PRIVATE --coverage)
|
||||||
|
target_link_options(hyprland_gtests PRIVATE --coverage)
|
||||||
|
target_include_directories(
|
||||||
|
hyprland_gtests
|
||||||
|
PUBLIC "./include"
|
||||||
|
PRIVATE "./src" "./src/include" "./protocols" "${CMAKE_BINARY_DIR}")
|
||||||
|
|
||||||
|
target_link_libraries(hyprland_gtests hyprland_lib GTest::gtest_main)
|
||||||
|
|
||||||
|
gtest_discover_tests(hyprland_gtests)
|
||||||
|
|
||||||
|
# Enable coverage in main hyprland lib
|
||||||
|
target_compile_options(hyprland_lib PRIVATE --coverage)
|
||||||
|
target_link_options(hyprland_lib PRIVATE --coverage)
|
||||||
|
target_link_libraries(hyprland_lib PUBLIC gcov)
|
||||||
|
|
||||||
|
# Enable coverage in hyprland exe
|
||||||
|
target_compile_options(Hyprland PRIVATE --coverage)
|
||||||
|
target_link_options(Hyprland PRIVATE --coverage)
|
||||||
|
target_link_libraries(Hyprland gcov)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(BUILD_TESTING)
|
||||||
|
message(STATUS "Testing is enabled")
|
||||||
|
|
||||||
|
enable_testing()
|
||||||
|
add_custom_target(tests)
|
||||||
|
|
||||||
|
add_dependencies(tests hyprland_gtests)
|
||||||
|
|
||||||
|
else()
|
||||||
|
message(STATUS "Testing is disabled")
|
||||||
|
endif()
|
||||||
|
|
|
||||||
2
LICENSE
|
|
@ -1,6 +1,6 @@
|
||||||
BSD 3-Clause License
|
BSD 3-Clause License
|
||||||
|
|
||||||
Copyright (c) 2022-2024, vaxerski
|
Copyright (c) 2022-2026, vaxerski
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
|
|
||||||
38
Makefile
|
|
@ -1,32 +1,24 @@
|
||||||
PREFIX = /usr/local
|
PREFIX = /usr/local
|
||||||
|
|
||||||
legacyrenderer:
|
stub:
|
||||||
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -DLEGACY_RENDERER:BOOL=true -S . -B ./build -G Ninja
|
@echo "Do not run $(MAKE) directly without any arguments. Please refer to the wiki on how to compile Hyprland."
|
||||||
cmake --build ./build --config Release --target all
|
|
||||||
chmod -R 777 ./build
|
|
||||||
|
|
||||||
legacyrendererdebug:
|
|
||||||
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Debug -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -DLEGACY_RENDERER:BOOL=true -S . -B ./build -G Ninja
|
|
||||||
cmake --build ./build --config Release --target all
|
|
||||||
chmod -R 777 ./build
|
|
||||||
|
|
||||||
release:
|
release:
|
||||||
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -S . -B ./build -G Ninja
|
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -S . -B ./build
|
||||||
cmake --build ./build --config Release --target all
|
cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
|
||||||
chmod -R 777 ./build
|
|
||||||
|
|
||||||
debug:
|
debug:
|
||||||
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Debug -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -S . -B ./build -G Ninja
|
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Debug -DTESTS=true -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -S . -B ./build
|
||||||
cmake --build ./build --config Debug --target all
|
cmake --build ./build --config Debug --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
|
||||||
chmod -R 777 ./build
|
|
||||||
|
|
||||||
nopch:
|
nopch:
|
||||||
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -DCMAKE_DISABLE_PRECOMPILE_HEADERS=ON -S . -B ./build -G Ninja
|
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -DCMAKE_DISABLE_PRECOMPILE_HEADERS=ON -S . -B ./build
|
||||||
cmake --build ./build --config Release --target all
|
cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
|
||||||
|
|
||||||
clear:
|
clear:
|
||||||
rm -rf build
|
rm -rf build
|
||||||
rm -f ./protocols/*.h ./protocols/*.c ./protocols/*.cpp ./protocols/*.hpp
|
rm -f ./protocols/*.h ./protocols/*.c ./protocols/*.cpp ./protocols/*.hpp
|
||||||
|
rm -f ./hyprctl/hw-protocols/*.cpp ./hyprctl/hw-protocols/*.hpp
|
||||||
|
|
||||||
all:
|
all:
|
||||||
$(MAKE) clear
|
$(MAKE) clear
|
||||||
|
|
@ -53,7 +45,7 @@ installheaders:
|
||||||
|
|
||||||
cmake --build ./build --config Release --target generate-protocol-headers
|
cmake --build ./build --config Release --target generate-protocol-headers
|
||||||
|
|
||||||
find src -name '*.h*' -print0 | cpio --quiet -0dump ${PREFIX}/include/hyprland
|
find src -type f \( -name '*.hpp' -o -name '*.h' -o -name '*.inc' \) -print0 | cpio --quiet -0dump ${PREFIX}/include/hyprland
|
||||||
cp ./protocols/*.h* ${PREFIX}/include/hyprland/protocols
|
cp ./protocols/*.h* ${PREFIX}/include/hyprland/protocols
|
||||||
cp ./build/hyprland.pc ${PREFIX}/share/pkgconfig
|
cp ./build/hyprland.pc ${PREFIX}/share/pkgconfig
|
||||||
if [ -d /usr/share/pkgconfig ]; then cp ./build/hyprland.pc /usr/share/pkgconfig 2>/dev/null || true; fi
|
if [ -d /usr/share/pkgconfig ]; then cp ./build/hyprland.pc /usr/share/pkgconfig 2>/dev/null || true; fi
|
||||||
|
|
@ -87,8 +79,8 @@ asan:
|
||||||
#git reset --hard
|
#git reset --hard
|
||||||
|
|
||||||
@echo -en "If you want to apply a patch, input its path (leave empty for none):\n"
|
@echo -en "If you want to apply a patch, input its path (leave empty for none):\n"
|
||||||
@read patchvar
|
@read patchvar; \
|
||||||
@if [-n "$patchvar"]; then patch -p1 < $patchvar || echo ""; else echo "No patch specified"; fi
|
if [ -n "$$patchvar" ]; then patch -p1 < "$$patchvar" || echo ""; else echo "No patch specified"; fi
|
||||||
|
|
||||||
git clone --recursive https://gitlab.freedesktop.org/wayland/wayland
|
git clone --recursive https://gitlab.freedesktop.org/wayland/wayland
|
||||||
cd wayland && patch -p1 < ../scripts/waylandStatic.diff && meson setup build --buildtype=debug -Db_sanitize=address -Ddocumentation=false && ninja -C build && cd ..
|
cd wayland && patch -p1 < ../scripts/waylandStatic.diff && meson setup build --buildtype=debug -Db_sanitize=address -Ddocumentation=false && ninja -C build && cd ..
|
||||||
|
|
@ -96,8 +88,12 @@ asan:
|
||||||
@echo "Wayland done"
|
@echo "Wayland done"
|
||||||
|
|
||||||
patch -p1 < ./scripts/hyprlandStaticAsan.diff
|
patch -p1 < ./scripts/hyprlandStaticAsan.diff
|
||||||
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Debug -DWITH_ASAN:STRING=True -DUSE_TRACY:STRING=False -DUSE_TRACY_GPU:STRING=False -S . -B ./build -G Ninja
|
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Debug -DWITH_ASAN:STRING=True -DUSE_TRACY:STRING=False -DUSE_TRACY_GPU:STRING=False -S . -B ./build
|
||||||
cmake --build ./build --config Debug --target all
|
cmake --build ./build --config Debug --target all
|
||||||
@echo "Hyprland done"
|
@echo "Hyprland done"
|
||||||
|
|
||||||
ASAN_OPTIONS="detect_odr_violation=0,log_path=asan.log" HYPRLAND_NO_CRASHREPORTER=1 ./build/Hyprland -c ~/.config/hypr/hyprland.conf
|
ASAN_OPTIONS="detect_odr_violation=0,log_path=asan.log" HYPRLAND_NO_CRASHREPORTER=1 ./build/Hyprland -c ~/.config/hypr/hyprland.conf
|
||||||
|
|
||||||
|
test:
|
||||||
|
$(MAKE) debug
|
||||||
|
./build/hyprtester/hyprtester -c hyprtester/test.conf -b ./build/Hyprland -p hyprtester/plugin/hyprtestplugin.so
|
||||||
|
|
|
||||||
20
README.md
|
|
@ -1,10 +1,10 @@
|
||||||
<div align = center>
|
<div align = center>
|
||||||
|
|
||||||
<img src="https://raw.githubusercontent.com/vaxerski/Hyprland/main/assets/header.svg" width="750" height="300" alt="banner">
|
<img src="https://raw.githubusercontent.com/hyprwm/Hyprland/main/assets/header.svg" width="750" height="300" alt="banner">
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
![Badge Workflow]
|
[![Badge Workflow]][Workflow]
|
||||||
[![Badge License]][License]
|
[![Badge License]][License]
|
||||||
![Badge Language]
|
![Badge Language]
|
||||||
[![Badge Pull Requests]][Pull Requests]
|
[![Badge Pull Requests]][Pull Requests]
|
||||||
|
|
@ -100,7 +100,7 @@ easy IPC, much more QoL stuff than other compositors and more...
|
||||||
|
|
||||||
<!----------------------------------------------------------------------------->
|
<!----------------------------------------------------------------------------->
|
||||||
|
|
||||||
[Configure]: https://wiki.hyprland.org/Configuring/Configuring-Hyprland/
|
[Configure]: https://wiki.hypr.land/Configuring/
|
||||||
[Stars]: https://starchart.cc/hyprwm/Hyprland
|
[Stars]: https://starchart.cc/hyprwm/Hyprland
|
||||||
[Hypr]: https://github.com/hyprwm/Hypr
|
[Hypr]: https://github.com/hyprwm/Hypr
|
||||||
|
|
||||||
|
|
@ -108,9 +108,10 @@ easy IPC, much more QoL stuff than other compositors and more...
|
||||||
[Issues]: https://github.com/hyprwm/Hyprland/issues
|
[Issues]: https://github.com/hyprwm/Hyprland/issues
|
||||||
[Todo]: https://github.com/hyprwm/Hyprland/projects?type=beta
|
[Todo]: https://github.com/hyprwm/Hyprland/projects?type=beta
|
||||||
|
|
||||||
[Contribute]: https://wiki.hyprland.org/Contributing-and-Debugging/
|
[Contribute]: https://wiki.hypr.land/Contributing-and-Debugging/
|
||||||
[Install]: https://wiki.hyprland.org/Getting-Started/Installation/
|
[Install]: https://wiki.hypr.land/Getting-Started/Installation/
|
||||||
[Quick Start]: https://wiki.hyprland.org/Getting-Started/Master-Tutorial/
|
[Quick Start]: https://wiki.hypr.land/Getting-Started/Master-Tutorial/
|
||||||
|
[Workflow]: https://github.com/hyprwm/Hyprland/actions/workflows/ci.yaml
|
||||||
[License]: LICENSE
|
[License]: LICENSE
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -125,10 +126,9 @@ easy IPC, much more QoL stuff than other compositors and more...
|
||||||
|
|
||||||
<!----------------------------------{ Images }--------------------------------->
|
<!----------------------------------{ Images }--------------------------------->
|
||||||
|
|
||||||
[Stars Preview]: https://starchart.cc/vaxerski/Hyprland.svg
|
[Preview A]: https://i.ibb.co/XxFY75Mk/greerggergerhtrytghjnyhjn.png
|
||||||
[Preview A]: https://i.ibb.co/C1yTb0r/falf.png
|
[Preview B]: https://i.ibb.co/C1yTb0r/falf.png
|
||||||
[Preview B]: https://linfindel.github.io/cdn/hyprland-preview-b.png
|
[Preview C]: https://i.ibb.co/2Yc4q835/hyprland-preview-b.png
|
||||||
[Preview C]: https://i.ibb.co/B3GJg28/20221126-20h53m26s-grim.png
|
|
||||||
|
|
||||||
|
|
||||||
<!----------------------------------{ Badges }--------------------------------->
|
<!----------------------------------{ Badges }--------------------------------->
|
||||||
|
|
|
||||||
32
SECURITY.md
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
# Hyprland Development Security Policy
|
||||||
|
|
||||||
|
If you have a bug that affects the security of your system, you may
|
||||||
|
want to privately disclose it instead of making it immediately public.
|
||||||
|
|
||||||
|
## Supported versions
|
||||||
|
|
||||||
|
_Only_ the most recent release on Github is supported. There are no LTS releases.
|
||||||
|
|
||||||
|
## What is not a security issue
|
||||||
|
|
||||||
|
Some examples of issues that should not be reported as security issues:
|
||||||
|
|
||||||
|
- An app can execute a command when ran outside of a sandbox
|
||||||
|
- An app can write / read hyprland sockets when ran outside of a sandbox
|
||||||
|
- Crashes
|
||||||
|
- Things that are protected via permissions when the permission system is disabled
|
||||||
|
|
||||||
|
## What is a security issue
|
||||||
|
|
||||||
|
Some examples of issues that should be reported as security issues:
|
||||||
|
|
||||||
|
- Sandboxed application executing arbitrary code via Hyprland
|
||||||
|
- Application being able to modify Hyprland's code on the fly
|
||||||
|
- Application being able to keylog / track user's activity beyond what the wayland protocols allow
|
||||||
|
|
||||||
|
## How to report security issues
|
||||||
|
|
||||||
|
Please report your security issues via either of these channels:
|
||||||
|
- Mail: `vaxry [at] vaxry [dot] net`
|
||||||
|
- Matrix: `@vaxry:matrix.vaxry.net`
|
||||||
|
- Discord: `@vaxry`
|
||||||
2
VERSION
|
|
@ -1 +1 @@
|
||||||
0.42.0
|
0.54.0
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 506 KiB After Width: | Height: | Size: 6.6 KiB |
BIN
assets/install/lockdead.png
Normal file
|
After Width: | Height: | Size: 110 KiB |
BIN
assets/install/lockdead2.png
Normal file
|
After Width: | Height: | Size: 48 KiB |
|
Before Width: | Height: | Size: 14 MiB After Width: | Height: | Size: 14 MiB |
|
Before Width: | Height: | Size: 5.9 MiB After Width: | Height: | Size: 5.9 MiB |
|
Before Width: | Height: | Size: 27 MiB After Width: | Height: | Size: 27 MiB |
|
|
@ -1,7 +0,0 @@
|
||||||
wallpapers = ['0', '1', '2']
|
|
||||||
|
|
||||||
foreach type : wallpapers
|
|
||||||
install_data(f'wall@type@.png', install_dir: join_paths(get_option('datadir'), 'hypr'), install_tag: 'runtime')
|
|
||||||
endforeach
|
|
||||||
|
|
||||||
install_data('hyprland-portals.conf', install_dir: join_paths(get_option('datadir'), 'xdg-desktop-portal'), install_tag: 'runtime')
|
|
||||||
|
|
@ -1,5 +1,19 @@
|
||||||
.\" Automatically generated by Pandoc 2.9.2.1
|
.\" Automatically generated by Pandoc 3.1.3
|
||||||
.\"
|
.\"
|
||||||
|
.\" Define V font for inline verbatim, using C font in formats
|
||||||
|
.\" that render this, and otherwise B font.
|
||||||
|
.ie "\f[CB]x\f[]"x" \{\
|
||||||
|
. ftr V B
|
||||||
|
. ftr VI BI
|
||||||
|
. ftr VB B
|
||||||
|
. ftr VBI BI
|
||||||
|
.\}
|
||||||
|
.el \{\
|
||||||
|
. ftr V CR
|
||||||
|
. ftr VI CI
|
||||||
|
. ftr VB CB
|
||||||
|
. ftr VBI CBI
|
||||||
|
.\}
|
||||||
.TH "Hyprland" "1" "" "" "Hyprland User Manual"
|
.TH "Hyprland" "1" "" "" "Hyprland User Manual"
|
||||||
.hy
|
.hy
|
||||||
.SH NAME
|
.SH NAME
|
||||||
|
|
@ -10,8 +24,8 @@ Hyprland - Dynamic tiling Wayland compositor
|
||||||
\f[B]Hyprland\f[R] [\f[I]arg [...]\f[R]].
|
\f[B]Hyprland\f[R] [\f[I]arg [...]\f[R]].
|
||||||
.SH DESCRIPTION
|
.SH DESCRIPTION
|
||||||
.PP
|
.PP
|
||||||
\f[B]Hyprland\f[R] is a dynamic tiling Wayland compositor based on
|
\f[B]Hyprland\f[R] is an independent, highly customizable, dynamic
|
||||||
wlroots that doesn\[aq]t sacrifice on its looks.
|
tiling Wayland compositor that doesn\[aq]t sacrifice on its looks.
|
||||||
.PP
|
.PP
|
||||||
You can launch Hyprland by either going into a TTY and executing
|
You can launch Hyprland by either going into a TTY and executing
|
||||||
\f[B]Hyprland\f[R], or with a login manager.
|
\f[B]Hyprland\f[R], or with a login manager.
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,8 @@ SYNOPSIS
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
===========
|
===========
|
||||||
|
|
||||||
**Hyprland** is a dynamic tiling Wayland compositor based on
|
**Hyprland** is an independent, highly customizable,
|
||||||
wlroots that doesn't sacrifice on its looks.
|
dynamic tiling Wayland compositor that doesn't sacrifice on its looks.
|
||||||
|
|
||||||
You can launch Hyprland by either going into a TTY and
|
You can launch Hyprland by either going into a TTY and
|
||||||
executing **Hyprland**, or with a login manager.
|
executing **Hyprland**, or with a login manager.
|
||||||
|
|
|
||||||
|
|
@ -2,15 +2,15 @@
|
||||||
|
|
||||||
First of all, please remember to:
|
First of all, please remember to:
|
||||||
- Check that your issue is not a duplicate
|
- Check that your issue is not a duplicate
|
||||||
- Read the [FAQ](https://wiki.hyprland.org/FAQ/)
|
- Read the [FAQ](https://wiki.hypr.land/FAQ/)
|
||||||
- Read the [Configuring Page](https://wiki.hyprland.org/Configuring/Configuring-Hyprland)
|
- Read the [Configuring Page](https://wiki.hypr.land/Configuring/)
|
||||||
|
|
||||||
<br/>
|
<br/>
|
||||||
|
|
||||||
# Reporting suggestions
|
# Reporting suggestions
|
||||||
Suggestions are welcome.
|
Suggestions are welcome.
|
||||||
|
|
||||||
Many features can be implemented using bash scripts and Hyprland sockets, read up on those [Here](https://wiki.hyprland.org/IPC). Please do not suggest features that can be implemented as such.
|
Many features can be implemented using bash scripts and Hyprland sockets, read up on those [Here](https://wiki.hypr.land/IPC). Please do not suggest features that can be implemented as such.
|
||||||
|
|
||||||
<br/>
|
<br/>
|
||||||
|
|
||||||
|
|
@ -70,7 +70,7 @@ A debug coredump provides more information for debugging and may speed up the pr
|
||||||
|
|
||||||
Make sure you're on latest git. Run `git pull --recurse-submodules` to sync everything.
|
Make sure you're on latest git. Run `git pull --recurse-submodules` to sync everything.
|
||||||
|
|
||||||
1. [Compile Hyprland with debug mode](http://wiki.hyprland.org/Contributing-and-Debugging/#build-in-debug-mode)
|
1. [Compile Hyprland with debug mode](http://wiki.hypr.land/Contributing-and-Debugging/#build-in-debug-mode)
|
||||||
> Note: The config file used will be `hyprlandd.conf` instead of `hyprland.conf`
|
> Note: The config file used will be `hyprlandd.conf` instead of `hyprland.conf`
|
||||||
|
|
||||||
2. `cd ~`
|
2. `cd ~`
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,19 @@
|
||||||
.\" Automatically generated by Pandoc 2.9.2.1
|
.\" Automatically generated by Pandoc 3.1.3
|
||||||
.\"
|
.\"
|
||||||
|
.\" Define V font for inline verbatim, using C font in formats
|
||||||
|
.\" that render this, and otherwise B font.
|
||||||
|
.ie "\f[CB]x\f[]"x" \{\
|
||||||
|
. ftr V B
|
||||||
|
. ftr VI BI
|
||||||
|
. ftr VB B
|
||||||
|
. ftr VBI BI
|
||||||
|
.\}
|
||||||
|
.el \{\
|
||||||
|
. ftr V CR
|
||||||
|
. ftr VI CI
|
||||||
|
. ftr VB CB
|
||||||
|
. ftr VBI CBI
|
||||||
|
.\}
|
||||||
.TH "hyprctl" "1" "" "" "hyprctl User Manual"
|
.TH "hyprctl" "1" "" "" "hyprctl User Manual"
|
||||||
.hy
|
.hy
|
||||||
.SH NAME
|
.SH NAME
|
||||||
|
|
|
||||||
|
|
@ -1,2 +0,0 @@
|
||||||
install_man ('Hyprland.1')
|
|
||||||
install_man ('hyprctl.1')
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
# This is an example Hyprland config file.
|
# This is an example Hyprland config file.
|
||||||
# Refer to the wiki for more information.
|
# Refer to the wiki for more information.
|
||||||
# https://wiki.hyprland.org/Configuring/Configuring-Hyprland/
|
# https://wiki.hypr.land/Configuring/
|
||||||
|
|
||||||
# Please note not all available settings / options are set here.
|
# Please note not all available settings / options are set here.
|
||||||
# For a full list, see the wiki
|
# For a full list, see the wiki
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
### MONITORS ###
|
### MONITORS ###
|
||||||
################
|
################
|
||||||
|
|
||||||
# See https://wiki.hyprland.org/Configuring/Monitors/
|
# See https://wiki.hypr.land/Configuring/Monitors/
|
||||||
monitor=,preferred,auto,auto
|
monitor=,preferred,auto,auto
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -22,12 +22,12 @@ monitor=,preferred,auto,auto
|
||||||
### MY PROGRAMS ###
|
### MY PROGRAMS ###
|
||||||
###################
|
###################
|
||||||
|
|
||||||
# See https://wiki.hyprland.org/Configuring/Keywords/
|
# See https://wiki.hypr.land/Configuring/Keywords/
|
||||||
|
|
||||||
# Set programs that you use
|
# Set programs that you use
|
||||||
$terminal = kitty
|
$terminal = kitty
|
||||||
$fileManager = dolphin
|
$fileManager = dolphin
|
||||||
$menu = wofi --show drun
|
$menu = hyprlauncher
|
||||||
|
|
||||||
|
|
||||||
#################
|
#################
|
||||||
|
|
@ -46,52 +46,72 @@ $menu = wofi --show drun
|
||||||
### ENVIRONMENT VARIABLES ###
|
### ENVIRONMENT VARIABLES ###
|
||||||
#############################
|
#############################
|
||||||
|
|
||||||
# See https://wiki.hyprland.org/Configuring/Environment-variables/
|
# See https://wiki.hypr.land/Configuring/Environment-variables/
|
||||||
|
|
||||||
env = XCURSOR_SIZE,24
|
env = XCURSOR_SIZE,24
|
||||||
env = HYPRCURSOR_SIZE,24
|
env = HYPRCURSOR_SIZE,24
|
||||||
|
|
||||||
|
|
||||||
|
###################
|
||||||
|
### PERMISSIONS ###
|
||||||
|
###################
|
||||||
|
|
||||||
|
# See https://wiki.hypr.land/Configuring/Permissions/
|
||||||
|
# Please note permission changes here require a Hyprland restart and are not applied on-the-fly
|
||||||
|
# for security reasons
|
||||||
|
|
||||||
|
# ecosystem {
|
||||||
|
# enforce_permissions = 1
|
||||||
|
# }
|
||||||
|
|
||||||
|
# permission = /usr/(bin|local/bin)/grim, screencopy, allow
|
||||||
|
# permission = /usr/(lib|libexec|lib64)/xdg-desktop-portal-hyprland, screencopy, allow
|
||||||
|
# permission = /usr/(bin|local/bin)/hyprpm, plugin, allow
|
||||||
|
|
||||||
|
|
||||||
#####################
|
#####################
|
||||||
### LOOK AND FEEL ###
|
### LOOK AND FEEL ###
|
||||||
#####################
|
#####################
|
||||||
|
|
||||||
# Refer to https://wiki.hyprland.org/Configuring/Variables/
|
# Refer to https://wiki.hypr.land/Configuring/Variables/
|
||||||
|
|
||||||
# https://wiki.hyprland.org/Configuring/Variables/#general
|
# https://wiki.hypr.land/Configuring/Variables/#general
|
||||||
general {
|
general {
|
||||||
gaps_in = 5
|
gaps_in = 5
|
||||||
gaps_out = 20
|
gaps_out = 20
|
||||||
|
|
||||||
border_size = 2
|
border_size = 2
|
||||||
|
|
||||||
# https://wiki.hyprland.org/Configuring/Variables/#variable-types for info about colors
|
# https://wiki.hypr.land/Configuring/Variables/#variable-types for info about colors
|
||||||
col.active_border = rgba(33ccffee) rgba(00ff99ee) 45deg
|
col.active_border = rgba(33ccffee) rgba(00ff99ee) 45deg
|
||||||
col.inactive_border = rgba(595959aa)
|
col.inactive_border = rgba(595959aa)
|
||||||
|
|
||||||
# Set to true enable resizing windows by clicking and dragging on borders and gaps
|
# Set to true enable resizing windows by clicking and dragging on borders and gaps
|
||||||
resize_on_border = false
|
resize_on_border = false
|
||||||
|
|
||||||
# Please see https://wiki.hyprland.org/Configuring/Tearing/ before you turn this on
|
# Please see https://wiki.hypr.land/Configuring/Tearing/ before you turn this on
|
||||||
allow_tearing = false
|
allow_tearing = false
|
||||||
|
|
||||||
layout = dwindle
|
layout = dwindle
|
||||||
}
|
}
|
||||||
|
|
||||||
# https://wiki.hyprland.org/Configuring/Variables/#decoration
|
# https://wiki.hypr.land/Configuring/Variables/#decoration
|
||||||
decoration {
|
decoration {
|
||||||
rounding = 10
|
rounding = 10
|
||||||
|
rounding_power = 2
|
||||||
|
|
||||||
# Change transparency of focused and unfocused windows
|
# Change transparency of focused and unfocused windows
|
||||||
active_opacity = 1.0
|
active_opacity = 1.0
|
||||||
inactive_opacity = 1.0
|
inactive_opacity = 1.0
|
||||||
|
|
||||||
drop_shadow = true
|
shadow {
|
||||||
shadow_range = 4
|
enabled = true
|
||||||
shadow_render_power = 3
|
range = 4
|
||||||
col.shadow = rgba(1a1a1aee)
|
render_power = 3
|
||||||
|
color = rgba(1a1a1aee)
|
||||||
|
}
|
||||||
|
|
||||||
# https://wiki.hyprland.org/Configuring/Variables/#blur
|
# https://wiki.hypr.land/Configuring/Variables/#blur
|
||||||
blur {
|
blur {
|
||||||
enabled = true
|
enabled = true
|
||||||
size = 3
|
size = 3
|
||||||
|
|
@ -101,34 +121,74 @@ decoration {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# https://wiki.hyprland.org/Configuring/Variables/#animations
|
# https://wiki.hypr.land/Configuring/Variables/#animations
|
||||||
animations {
|
animations {
|
||||||
enabled = true
|
enabled = yes, please :)
|
||||||
|
|
||||||
# Default animations, see https://wiki.hyprland.org/Configuring/Animations/ for more
|
# Default curves, see https://wiki.hypr.land/Configuring/Animations/#curves
|
||||||
|
# NAME, X0, Y0, X1, Y1
|
||||||
|
bezier = easeOutQuint, 0.23, 1, 0.32, 1
|
||||||
|
bezier = easeInOutCubic, 0.65, 0.05, 0.36, 1
|
||||||
|
bezier = linear, 0, 0, 1, 1
|
||||||
|
bezier = almostLinear, 0.5, 0.5, 0.75, 1
|
||||||
|
bezier = quick, 0.15, 0, 0.1, 1
|
||||||
|
|
||||||
bezier = myBezier, 0.05, 0.9, 0.1, 1.05
|
# Default animations, see https://wiki.hypr.land/Configuring/Animations/
|
||||||
|
# NAME, ONOFF, SPEED, CURVE, [STYLE]
|
||||||
animation = windows, 1, 7, myBezier
|
animation = global, 1, 10, default
|
||||||
animation = windowsOut, 1, 7, default, popin 80%
|
animation = border, 1, 5.39, easeOutQuint
|
||||||
animation = border, 1, 10, default
|
animation = windows, 1, 4.79, easeOutQuint
|
||||||
animation = borderangle, 1, 8, default
|
animation = windowsIn, 1, 4.1, easeOutQuint, popin 87%
|
||||||
animation = fade, 1, 7, default
|
animation = windowsOut, 1, 1.49, linear, popin 87%
|
||||||
animation = workspaces, 1, 6, default
|
animation = fadeIn, 1, 1.73, almostLinear
|
||||||
|
animation = fadeOut, 1, 1.46, almostLinear
|
||||||
|
animation = fade, 1, 3.03, quick
|
||||||
|
animation = layers, 1, 3.81, easeOutQuint
|
||||||
|
animation = layersIn, 1, 4, easeOutQuint, fade
|
||||||
|
animation = layersOut, 1, 1.5, linear, fade
|
||||||
|
animation = fadeLayersIn, 1, 1.79, almostLinear
|
||||||
|
animation = fadeLayersOut, 1, 1.39, almostLinear
|
||||||
|
animation = workspaces, 1, 1.94, almostLinear, fade
|
||||||
|
animation = workspacesIn, 1, 1.21, almostLinear, fade
|
||||||
|
animation = workspacesOut, 1, 1.94, almostLinear, fade
|
||||||
|
animation = zoomFactor, 1, 7, quick
|
||||||
}
|
}
|
||||||
|
|
||||||
# See https://wiki.hyprland.org/Configuring/Dwindle-Layout/ for more
|
# Ref https://wiki.hypr.land/Configuring/Workspace-Rules/
|
||||||
|
# "Smart gaps" / "No gaps when only"
|
||||||
|
# uncomment all if you wish to use that.
|
||||||
|
# workspace = w[tv1], gapsout:0, gapsin:0
|
||||||
|
# workspace = f[1], gapsout:0, gapsin:0
|
||||||
|
# windowrule {
|
||||||
|
# name = no-gaps-wtv1
|
||||||
|
# match:float = false
|
||||||
|
# match:workspace = w[tv1]
|
||||||
|
#
|
||||||
|
# border_size = 0
|
||||||
|
# rounding = 0
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# windowrule {
|
||||||
|
# name = no-gaps-f1
|
||||||
|
# match:float = false
|
||||||
|
# match:workspace = f[1]
|
||||||
|
#
|
||||||
|
# border_size = 0
|
||||||
|
# rounding = 0
|
||||||
|
# }
|
||||||
|
|
||||||
|
# See https://wiki.hypr.land/Configuring/Dwindle-Layout/ for more
|
||||||
dwindle {
|
dwindle {
|
||||||
pseudotile = true # Master switch for pseudotiling. Enabling is bound to mainMod + P in the keybinds section below
|
pseudotile = true # Master switch for pseudotiling. Enabling is bound to mainMod + P in the keybinds section below
|
||||||
preserve_split = true # You probably want this
|
preserve_split = true # You probably want this
|
||||||
}
|
}
|
||||||
|
|
||||||
# See https://wiki.hyprland.org/Configuring/Master-Layout/ for more
|
# See https://wiki.hypr.land/Configuring/Master-Layout/ for more
|
||||||
master {
|
master {
|
||||||
new_status = master
|
new_status = master
|
||||||
}
|
}
|
||||||
|
|
||||||
# https://wiki.hyprland.org/Configuring/Variables/#misc
|
# https://wiki.hypr.land/Configuring/Variables/#misc
|
||||||
misc {
|
misc {
|
||||||
force_default_wallpaper = -1 # Set to 0 or 1 to disable the anime mascot wallpapers
|
force_default_wallpaper = -1 # Set to 0 or 1 to disable the anime mascot wallpapers
|
||||||
disable_hyprland_logo = false # If true disables the random hyprland logo / anime girl background. :(
|
disable_hyprland_logo = false # If true disables the random hyprland logo / anime girl background. :(
|
||||||
|
|
@ -139,7 +199,7 @@ misc {
|
||||||
### INPUT ###
|
### INPUT ###
|
||||||
#############
|
#############
|
||||||
|
|
||||||
# https://wiki.hyprland.org/Configuring/Variables/#input
|
# https://wiki.hypr.land/Configuring/Variables/#input
|
||||||
input {
|
input {
|
||||||
kb_layout = us
|
kb_layout = us
|
||||||
kb_variant =
|
kb_variant =
|
||||||
|
|
@ -156,35 +216,33 @@ input {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# https://wiki.hyprland.org/Configuring/Variables/#gestures
|
# See https://wiki.hypr.land/Configuring/Gestures
|
||||||
gestures {
|
gesture = 3, horizontal, workspace
|
||||||
workspace_swipe = false
|
|
||||||
}
|
|
||||||
|
|
||||||
# Example per-device config
|
# Example per-device config
|
||||||
# See https://wiki.hyprland.org/Configuring/Keywords/#per-device-input-configs for more
|
# See https://wiki.hypr.land/Configuring/Keywords/#per-device-input-configs for more
|
||||||
device {
|
device {
|
||||||
name = epic-mouse-v1
|
name = epic-mouse-v1
|
||||||
sensitivity = -0.5
|
sensitivity = -0.5
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
####################
|
###################
|
||||||
### KEYBINDINGSS ###
|
### KEYBINDINGS ###
|
||||||
####################
|
###################
|
||||||
|
|
||||||
# See https://wiki.hyprland.org/Configuring/Keywords/
|
# See https://wiki.hypr.land/Configuring/Keywords/
|
||||||
$mainMod = SUPER # Sets "Windows" key as main modifier
|
$mainMod = SUPER # Sets "Windows" key as main modifier
|
||||||
|
|
||||||
# Example binds, see https://wiki.hyprland.org/Configuring/Binds/ for more
|
# Example binds, see https://wiki.hypr.land/Configuring/Binds/ for more
|
||||||
bind = $mainMod, Q, exec, $terminal
|
bind = $mainMod, Q, exec, $terminal
|
||||||
bind = $mainMod, C, killactive,
|
bind = $mainMod, C, killactive,
|
||||||
bind = $mainMod, M, exit,
|
bind = $mainMod, M, exec, command -v hyprshutdown >/dev/null 2>&1 && hyprshutdown || hyprctl dispatch exit
|
||||||
bind = $mainMod, E, exec, $fileManager
|
bind = $mainMod, E, exec, $fileManager
|
||||||
bind = $mainMod, V, togglefloating,
|
bind = $mainMod, V, togglefloating,
|
||||||
bind = $mainMod, R, exec, $menu
|
bind = $mainMod, R, exec, $menu
|
||||||
bind = $mainMod, P, pseudo, # dwindle
|
bind = $mainMod, P, pseudo, # dwindle
|
||||||
bind = $mainMod, J, togglesplit, # dwindle
|
bind = $mainMod, J, layoutmsg, togglesplit # dwindle
|
||||||
|
|
||||||
# Move focus with mainMod + arrow keys
|
# Move focus with mainMod + arrow keys
|
||||||
bind = $mainMod, left, movefocus, l
|
bind = $mainMod, left, movefocus, l
|
||||||
|
|
@ -228,18 +286,56 @@ bind = $mainMod, mouse_up, workspace, e-1
|
||||||
bindm = $mainMod, mouse:272, movewindow
|
bindm = $mainMod, mouse:272, movewindow
|
||||||
bindm = $mainMod, mouse:273, resizewindow
|
bindm = $mainMod, mouse:273, resizewindow
|
||||||
|
|
||||||
|
# Laptop multimedia keys for volume and LCD brightness
|
||||||
|
bindel = ,XF86AudioRaiseVolume, exec, wpctl set-volume -l 1 @DEFAULT_AUDIO_SINK@ 5%+
|
||||||
|
bindel = ,XF86AudioLowerVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-
|
||||||
|
bindel = ,XF86AudioMute, exec, wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle
|
||||||
|
bindel = ,XF86AudioMicMute, exec, wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle
|
||||||
|
bindel = ,XF86MonBrightnessUp, exec, brightnessctl -e4 -n2 set 5%+
|
||||||
|
bindel = ,XF86MonBrightnessDown, exec, brightnessctl -e4 -n2 set 5%-
|
||||||
|
|
||||||
|
# Requires playerctl
|
||||||
|
bindl = , XF86AudioNext, exec, playerctl next
|
||||||
|
bindl = , XF86AudioPause, exec, playerctl play-pause
|
||||||
|
bindl = , XF86AudioPlay, exec, playerctl play-pause
|
||||||
|
bindl = , XF86AudioPrev, exec, playerctl previous
|
||||||
|
|
||||||
##############################
|
##############################
|
||||||
### WINDOWS AND WORKSPACES ###
|
### WINDOWS AND WORKSPACES ###
|
||||||
##############################
|
##############################
|
||||||
|
|
||||||
# See https://wiki.hyprland.org/Configuring/Window-Rules/ for more
|
# See https://wiki.hypr.land/Configuring/Window-Rules/ for more
|
||||||
# See https://wiki.hyprland.org/Configuring/Workspace-Rules/ for workspace rules
|
# See https://wiki.hypr.land/Configuring/Workspace-Rules/ for workspace rules
|
||||||
|
|
||||||
# Example windowrule v1
|
# Example windowrules that are useful
|
||||||
# windowrule = float, ^(kitty)$
|
|
||||||
|
|
||||||
# Example windowrule v2
|
windowrule {
|
||||||
# windowrulev2 = float,class:^(kitty)$,title:^(kitty)$
|
# Ignore maximize requests from all apps. You'll probably like this.
|
||||||
|
name = suppress-maximize-events
|
||||||
|
match:class = .*
|
||||||
|
|
||||||
windowrulev2 = suppressevent maximize, class:.* # You'll probably like this.
|
suppress_event = maximize
|
||||||
|
}
|
||||||
|
|
||||||
|
windowrule {
|
||||||
|
# Fix some dragging issues with XWayland
|
||||||
|
name = fix-xwayland-drags
|
||||||
|
match:class = ^$
|
||||||
|
match:title = ^$
|
||||||
|
match:xwayland = true
|
||||||
|
match:float = true
|
||||||
|
match:fullscreen = false
|
||||||
|
match:pin = false
|
||||||
|
|
||||||
|
no_focus = true
|
||||||
|
}
|
||||||
|
|
||||||
|
# Hyprland-run windowrule
|
||||||
|
windowrule {
|
||||||
|
name = move-hyprland-run
|
||||||
|
|
||||||
|
match:class = hyprland-run
|
||||||
|
|
||||||
|
move = 20 monitor_h-120
|
||||||
|
float = yes
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
[Desktop Entry]
|
|
||||||
Name=Hyprland
|
|
||||||
Comment=An intelligent dynamic tiling Wayland compositor
|
|
||||||
Exec=Hyprland
|
|
||||||
Type=Application
|
|
||||||
7
example/hyprland.desktop.in
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
[Desktop Entry]
|
||||||
|
Name=Hyprland
|
||||||
|
Comment=An intelligent dynamic tiling Wayland compositor
|
||||||
|
Exec=@PREFIX@/@CMAKE_INSTALL_BINDIR@/start-hyprland
|
||||||
|
Type=Application
|
||||||
|
DesktopNames=Hyprland
|
||||||
|
Keywords=tiling;wayland;compositor;
|
||||||
|
|
@ -22,5 +22,6 @@
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
@ -1,2 +0,0 @@
|
||||||
install_data('hyprland.conf', install_dir: join_paths(get_option('datadir'), 'hypr'), install_tag: 'runtime')
|
|
||||||
install_data('hyprland.desktop', install_dir: join_paths(get_option('datadir'), 'wayland-sessions'), install_tag: 'runtime')
|
|
||||||
|
|
@ -2,15 +2,18 @@
|
||||||
// Example blue light filter shader.
|
// Example blue light filter shader.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#version 300 es
|
||||||
|
|
||||||
precision mediump float;
|
precision mediump float;
|
||||||
varying vec2 v_texcoord;
|
in vec2 v_texcoord;
|
||||||
|
layout(location = 0) out vec4 fragColor;
|
||||||
uniform sampler2D tex;
|
uniform sampler2D tex;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
|
|
||||||
vec4 pixColor = texture2D(tex, v_texcoord);
|
vec4 pixColor = texture(tex, v_texcoord);
|
||||||
|
|
||||||
pixColor[2] *= 0.8;
|
pixColor[2] *= 0.8;
|
||||||
|
|
||||||
gl_FragColor = pixColor;
|
fragColor = pixColor;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
262
flake.lock
generated
|
|
@ -16,11 +16,11 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1722347739,
|
"lastModified": 1772292445,
|
||||||
"narHash": "sha256-rAoh+K6KG+b1DwSWtqRVocdojnH6nGk6q07mNltoUSM=",
|
"narHash": "sha256-4F1Q7U313TKUDDovCC96m/Za4wZcJ3yqtu4eSrj8lk8=",
|
||||||
"owner": "hyprwm",
|
"owner": "hyprwm",
|
||||||
"repo": "aquamarine",
|
"repo": "aquamarine",
|
||||||
"rev": "7c3565f9bedc7cb601cc0baa14792247e4dc1d5a",
|
"rev": "1dbbba659c1cef0b0202ce92cadfe13bae550e8f",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|
@ -29,6 +29,43 @@
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"flake-compat": {
|
||||||
|
"flake": false,
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1767039857,
|
||||||
|
"narHash": "sha256-vNpUSpF5Nuw8xvDLj2KCwwksIbjua2LZCqhV1LNRDns=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "flake-compat",
|
||||||
|
"rev": "5edf11c44bc78a0d334f6334cdaf7d60d732daab",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "flake-compat",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"gitignore": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": [
|
||||||
|
"pre-commit-hooks",
|
||||||
|
"nixpkgs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1709087332,
|
||||||
|
"narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=",
|
||||||
|
"owner": "hercules-ci",
|
||||||
|
"repo": "gitignore.nix",
|
||||||
|
"rev": "637db329424fd7e46cf4185293b9cc8c88c95394",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "hercules-ci",
|
||||||
|
"repo": "gitignore.nix",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
"hyprcursor": {
|
"hyprcursor": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"hyprlang": [
|
"hyprlang": [
|
||||||
|
|
@ -42,11 +79,11 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1721330371,
|
"lastModified": 1753964049,
|
||||||
"narHash": "sha256-aYlHTWylczLt6ERJyg6E66Y/XSCbVL7leVcRuJmVbpI=",
|
"narHash": "sha256-lIqabfBY7z/OANxHoPeIrDJrFyYy9jAM4GQLzZ2feCM=",
|
||||||
"owner": "hyprwm",
|
"owner": "hyprwm",
|
||||||
"repo": "hyprcursor",
|
"repo": "hyprcursor",
|
||||||
"rev": "4493a972b48f9c3014befbbf381ed5fff91a65dc",
|
"rev": "44e91d467bdad8dcf8bbd2ac7cf49972540980a5",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|
@ -55,23 +92,86 @@
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"hyprland-protocols": {
|
"hyprgraphics": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
|
"hyprutils": [
|
||||||
|
"hyprutils"
|
||||||
|
],
|
||||||
"nixpkgs": [
|
"nixpkgs": [
|
||||||
"xdph",
|
|
||||||
"nixpkgs"
|
"nixpkgs"
|
||||||
],
|
],
|
||||||
"systems": [
|
"systems": [
|
||||||
"xdph",
|
|
||||||
"systems"
|
"systems"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1721326555,
|
"lastModified": 1770511807,
|
||||||
"narHash": "sha256-zCu4R0CSHEactW9JqYki26gy8h9f6rHmSwj4XJmlHgg=",
|
"narHash": "sha256-suKmSbSk34uPOJDTg/GbPrKEJutzK08vj0VoTvAFBCA=",
|
||||||
|
"owner": "hyprwm",
|
||||||
|
"repo": "hyprgraphics",
|
||||||
|
"rev": "7c75487edd43a71b61adb01cae8326d277aab683",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "hyprwm",
|
||||||
|
"repo": "hyprgraphics",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"hyprland-guiutils": {
|
||||||
|
"inputs": {
|
||||||
|
"aquamarine": [
|
||||||
|
"aquamarine"
|
||||||
|
],
|
||||||
|
"hyprgraphics": [
|
||||||
|
"hyprgraphics"
|
||||||
|
],
|
||||||
|
"hyprlang": [
|
||||||
|
"hyprlang"
|
||||||
|
],
|
||||||
|
"hyprtoolkit": "hyprtoolkit",
|
||||||
|
"hyprutils": [
|
||||||
|
"hyprutils"
|
||||||
|
],
|
||||||
|
"hyprwayland-scanner": [
|
||||||
|
"hyprwayland-scanner"
|
||||||
|
],
|
||||||
|
"nixpkgs": [
|
||||||
|
"nixpkgs"
|
||||||
|
],
|
||||||
|
"systems": [
|
||||||
|
"systems"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1767023960,
|
||||||
|
"narHash": "sha256-R2HgtVS1G3KSIKAQ77aOZ+Q0HituOmPgXW9nBNkpp3Q=",
|
||||||
|
"owner": "hyprwm",
|
||||||
|
"repo": "hyprland-guiutils",
|
||||||
|
"rev": "c2e906261142f5dd1ee0bfc44abba23e2754c660",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "hyprwm",
|
||||||
|
"repo": "hyprland-guiutils",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"hyprland-protocols": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": [
|
||||||
|
"nixpkgs"
|
||||||
|
],
|
||||||
|
"systems": [
|
||||||
|
"systems"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1765214753,
|
||||||
|
"narHash": "sha256-P9zdGXOzToJJgu5sVjv7oeOGPIIwrd9hAUAP3PsmBBs=",
|
||||||
"owner": "hyprwm",
|
"owner": "hyprwm",
|
||||||
"repo": "hyprland-protocols",
|
"repo": "hyprland-protocols",
|
||||||
"rev": "5a11232266bf1a1f5952d5b179c3f4b2facaaa84",
|
"rev": "3f3860b869014c00e8b9e0528c7b4ddc335c21ab",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|
@ -93,11 +193,11 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1721324361,
|
"lastModified": 1771866172,
|
||||||
"narHash": "sha256-BiJKO0IIdnSwHQBSrEJlKlFr753urkLE48wtt0UhNG4=",
|
"narHash": "sha256-fYFoXhQLrm1rD8vSFKQBOEX4OGCuJdLt1amKfHd5GAw=",
|
||||||
"owner": "hyprwm",
|
"owner": "hyprwm",
|
||||||
"repo": "hyprlang",
|
"repo": "hyprlang",
|
||||||
"rev": "adbefbf49664a6c2c8bf36b6487fd31e3eb68086",
|
"rev": "0b219224910e7642eb0ed49f0db5ec3d008e3e41",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|
@ -106,6 +206,51 @@
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"hyprtoolkit": {
|
||||||
|
"inputs": {
|
||||||
|
"aquamarine": [
|
||||||
|
"hyprland-guiutils",
|
||||||
|
"aquamarine"
|
||||||
|
],
|
||||||
|
"hyprgraphics": [
|
||||||
|
"hyprland-guiutils",
|
||||||
|
"hyprgraphics"
|
||||||
|
],
|
||||||
|
"hyprlang": [
|
||||||
|
"hyprland-guiutils",
|
||||||
|
"hyprlang"
|
||||||
|
],
|
||||||
|
"hyprutils": [
|
||||||
|
"hyprland-guiutils",
|
||||||
|
"hyprutils"
|
||||||
|
],
|
||||||
|
"hyprwayland-scanner": [
|
||||||
|
"hyprland-guiutils",
|
||||||
|
"hyprwayland-scanner"
|
||||||
|
],
|
||||||
|
"nixpkgs": [
|
||||||
|
"hyprland-guiutils",
|
||||||
|
"nixpkgs"
|
||||||
|
],
|
||||||
|
"systems": [
|
||||||
|
"hyprland-guiutils",
|
||||||
|
"systems"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1764592794,
|
||||||
|
"narHash": "sha256-7CcO+wbTJ1L1NBQHierHzheQGPWwkIQug/w+fhTAVuU=",
|
||||||
|
"owner": "hyprwm",
|
||||||
|
"repo": "hyprtoolkit",
|
||||||
|
"rev": "5cfe0743f0e608e1462972303778d8a0859ee63e",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "hyprwm",
|
||||||
|
"repo": "hyprtoolkit",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
"hyprutils": {
|
"hyprutils": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"nixpkgs": [
|
"nixpkgs": [
|
||||||
|
|
@ -116,11 +261,11 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1722098849,
|
"lastModified": 1771271487,
|
||||||
"narHash": "sha256-D3wIZlBNh7LuZ0NaoCpY/Pvu+xHxIVtSN+KkWZYvvVs=",
|
"narHash": "sha256-41gEiUS0Pyw3L/ge1l8MXn61cK14VAhgWB/JV8s/oNI=",
|
||||||
"owner": "hyprwm",
|
"owner": "hyprwm",
|
||||||
"repo": "hyprutils",
|
"repo": "hyprutils",
|
||||||
"rev": "5dcbbc1e3de40b2cecfd2007434d86e924468f1f",
|
"rev": "340a792e3b3d482c4ae5f66d27a9096bdee6d76d",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|
@ -139,11 +284,11 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1721324119,
|
"lastModified": 1770501770,
|
||||||
"narHash": "sha256-SOOqIT27/X792+vsLSeFdrNTF+OSRp5qXv6Te+fb2Qg=",
|
"narHash": "sha256-NWRM6+YxTRv+bT9yvlhhJ2iLae1B1pNH3mAL5wi2rlQ=",
|
||||||
"owner": "hyprwm",
|
"owner": "hyprwm",
|
||||||
"repo": "hyprwayland-scanner",
|
"repo": "hyprwayland-scanner",
|
||||||
"rev": "a048a6cb015340bd82f97c1f40a4b595ca85cc30",
|
"rev": "0bd8b6cde9ec27d48aad9e5b4deefb3746909d40",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|
@ -152,13 +297,39 @@
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"hyprwire": {
|
||||||
|
"inputs": {
|
||||||
|
"hyprutils": [
|
||||||
|
"hyprutils"
|
||||||
|
],
|
||||||
|
"nixpkgs": [
|
||||||
|
"nixpkgs"
|
||||||
|
],
|
||||||
|
"systems": [
|
||||||
|
"systems"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1771606233,
|
||||||
|
"narHash": "sha256-F3PLUqQ/TwgR70U+UeOqJnihJZ2EuunzojYC4g5xHr0=",
|
||||||
|
"owner": "hyprwm",
|
||||||
|
"repo": "hyprwire",
|
||||||
|
"rev": "06c7f1f8c4194786c8400653c4efc49dc14c0f3a",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "hyprwm",
|
||||||
|
"repo": "hyprwire",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1722185531,
|
"lastModified": 1772198003,
|
||||||
"narHash": "sha256-veKR07psFoJjINLC8RK4DiLniGGMgF3QMlS4tb74S6k=",
|
"narHash": "sha256-I45esRSssFtJ8p/gLHUZ1OUaaTaVLluNkABkk6arQwE=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "52ec9ac3b12395ad677e8b62106f0b98c1f8569d",
|
"rev": "dd9b079222d43e1943b6ebd802f04fd959dc8e61",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|
@ -168,14 +339,41 @@
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"pre-commit-hooks": {
|
||||||
|
"inputs": {
|
||||||
|
"flake-compat": "flake-compat",
|
||||||
|
"gitignore": "gitignore",
|
||||||
|
"nixpkgs": [
|
||||||
|
"nixpkgs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1772024342,
|
||||||
|
"narHash": "sha256-+eXlIc4/7dE6EcPs9a2DaSY3fTA9AE526hGqkNID3Wg=",
|
||||||
|
"owner": "cachix",
|
||||||
|
"repo": "git-hooks.nix",
|
||||||
|
"rev": "6e34e97ed9788b17796ee43ccdbaf871a5c2b476",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "cachix",
|
||||||
|
"repo": "git-hooks.nix",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
"root": {
|
"root": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"aquamarine": "aquamarine",
|
"aquamarine": "aquamarine",
|
||||||
"hyprcursor": "hyprcursor",
|
"hyprcursor": "hyprcursor",
|
||||||
|
"hyprgraphics": "hyprgraphics",
|
||||||
|
"hyprland-guiutils": "hyprland-guiutils",
|
||||||
|
"hyprland-protocols": "hyprland-protocols",
|
||||||
"hyprlang": "hyprlang",
|
"hyprlang": "hyprlang",
|
||||||
"hyprutils": "hyprutils",
|
"hyprutils": "hyprutils",
|
||||||
"hyprwayland-scanner": "hyprwayland-scanner",
|
"hyprwayland-scanner": "hyprwayland-scanner",
|
||||||
|
"hyprwire": "hyprwire",
|
||||||
"nixpkgs": "nixpkgs",
|
"nixpkgs": "nixpkgs",
|
||||||
|
"pre-commit-hooks": "pre-commit-hooks",
|
||||||
"systems": "systems",
|
"systems": "systems",
|
||||||
"xdph": "xdph"
|
"xdph": "xdph"
|
||||||
}
|
}
|
||||||
|
|
@ -197,10 +395,18 @@
|
||||||
},
|
},
|
||||||
"xdph": {
|
"xdph": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"hyprland-protocols": "hyprland-protocols",
|
"hyprland-protocols": [
|
||||||
|
"hyprland-protocols"
|
||||||
|
],
|
||||||
"hyprlang": [
|
"hyprlang": [
|
||||||
"hyprlang"
|
"hyprlang"
|
||||||
],
|
],
|
||||||
|
"hyprutils": [
|
||||||
|
"hyprutils"
|
||||||
|
],
|
||||||
|
"hyprwayland-scanner": [
|
||||||
|
"hyprwayland-scanner"
|
||||||
|
],
|
||||||
"nixpkgs": [
|
"nixpkgs": [
|
||||||
"nixpkgs"
|
"nixpkgs"
|
||||||
],
|
],
|
||||||
|
|
@ -209,11 +415,11 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1722365976,
|
"lastModified": 1761431178,
|
||||||
"narHash": "sha256-Khdm+mDzYA//XaU0M+hftod+rKr5q9SSHSEuiQ0/9ow=",
|
"narHash": "sha256-xzjC1CV3+wpUQKNF+GnadnkeGUCJX+vgaWIZsnz9tzI=",
|
||||||
"owner": "hyprwm",
|
"owner": "hyprwm",
|
||||||
"repo": "xdg-desktop-portal-hyprland",
|
"repo": "xdg-desktop-portal-hyprland",
|
||||||
"rev": "7f2a77ddf60390248e2a3de2261d7102a13e5341",
|
"rev": "4b8801228ff958d028f588f0c2b911dbf32297f9",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|
|
||||||
215
flake.nix
|
|
@ -22,6 +22,30 @@
|
||||||
inputs.hyprlang.follows = "hyprlang";
|
inputs.hyprlang.follows = "hyprlang";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
hyprgraphics = {
|
||||||
|
url = "github:hyprwm/hyprgraphics";
|
||||||
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
|
inputs.systems.follows = "systems";
|
||||||
|
inputs.hyprutils.follows = "hyprutils";
|
||||||
|
};
|
||||||
|
|
||||||
|
hyprland-protocols = {
|
||||||
|
url = "github:hyprwm/hyprland-protocols";
|
||||||
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
|
inputs.systems.follows = "systems";
|
||||||
|
};
|
||||||
|
|
||||||
|
hyprland-guiutils = {
|
||||||
|
url = "github:hyprwm/hyprland-guiutils";
|
||||||
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
|
inputs.systems.follows = "systems";
|
||||||
|
inputs.aquamarine.follows = "aquamarine";
|
||||||
|
inputs.hyprgraphics.follows = "hyprgraphics";
|
||||||
|
inputs.hyprutils.follows = "hyprutils";
|
||||||
|
inputs.hyprlang.follows = "hyprlang";
|
||||||
|
inputs.hyprwayland-scanner.follows = "hyprwayland-scanner";
|
||||||
|
};
|
||||||
|
|
||||||
hyprlang = {
|
hyprlang = {
|
||||||
url = "github:hyprwm/hyprlang";
|
url = "github:hyprwm/hyprlang";
|
||||||
inputs.nixpkgs.follows = "nixpkgs";
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
|
|
@ -41,76 +65,145 @@
|
||||||
inputs.systems.follows = "systems";
|
inputs.systems.follows = "systems";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
hyprwire = {
|
||||||
|
url = "github:hyprwm/hyprwire";
|
||||||
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
|
inputs.systems.follows = "systems";
|
||||||
|
inputs.hyprutils.follows = "hyprutils";
|
||||||
|
};
|
||||||
|
|
||||||
xdph = {
|
xdph = {
|
||||||
url = "github:hyprwm/xdg-desktop-portal-hyprland";
|
url = "github:hyprwm/xdg-desktop-portal-hyprland";
|
||||||
inputs.nixpkgs.follows = "nixpkgs";
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
inputs.systems.follows = "systems";
|
inputs.systems.follows = "systems";
|
||||||
|
inputs.hyprland-protocols.follows = "hyprland-protocols";
|
||||||
inputs.hyprlang.follows = "hyprlang";
|
inputs.hyprlang.follows = "hyprlang";
|
||||||
|
inputs.hyprutils.follows = "hyprutils";
|
||||||
|
inputs.hyprwayland-scanner.follows = "hyprwayland-scanner";
|
||||||
|
};
|
||||||
|
|
||||||
|
pre-commit-hooks = {
|
||||||
|
url = "github:cachix/git-hooks.nix";
|
||||||
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
outputs = inputs @ {
|
outputs =
|
||||||
self,
|
inputs@{
|
||||||
nixpkgs,
|
self,
|
||||||
systems,
|
nixpkgs,
|
||||||
...
|
systems,
|
||||||
}: let
|
...
|
||||||
inherit (nixpkgs) lib;
|
}:
|
||||||
eachSystem = lib.genAttrs (import systems);
|
let
|
||||||
pkgsFor = eachSystem (system:
|
inherit (nixpkgs) lib;
|
||||||
import nixpkgs {
|
eachSystem = lib.genAttrs (import systems);
|
||||||
localSystem = system;
|
pkgsFor = eachSystem (
|
||||||
overlays = with self.overlays; [
|
system:
|
||||||
hyprland-packages
|
import nixpkgs {
|
||||||
hyprland-extras
|
localSystem = system;
|
||||||
];
|
overlays = with self.overlays; [
|
||||||
});
|
hyprland-packages
|
||||||
in {
|
hyprland-extras
|
||||||
overlays = import ./nix/overlays.nix {inherit self lib inputs;};
|
|
||||||
|
|
||||||
checks = eachSystem (system:
|
|
||||||
(lib.filterAttrs
|
|
||||||
(n: _: (lib.hasPrefix "hyprland" n) && !(lib.hasSuffix "debug" n))
|
|
||||||
self.packages.${system})
|
|
||||||
// {
|
|
||||||
inherit (self.packages.${system}) xdg-desktop-portal-hyprland;
|
|
||||||
});
|
|
||||||
|
|
||||||
packages = eachSystem (system: {
|
|
||||||
default = self.packages.${system}.hyprland;
|
|
||||||
inherit
|
|
||||||
(pkgsFor.${system})
|
|
||||||
# hyprland-packages
|
|
||||||
|
|
||||||
hyprland
|
|
||||||
hyprland-debug
|
|
||||||
hyprland-legacy-renderer
|
|
||||||
hyprland-unwrapped
|
|
||||||
# hyprland-extras
|
|
||||||
|
|
||||||
xdg-desktop-portal-hyprland
|
|
||||||
;
|
|
||||||
});
|
|
||||||
|
|
||||||
devShells = eachSystem (system: {
|
|
||||||
default =
|
|
||||||
pkgsFor.${system}.mkShell.override {
|
|
||||||
stdenv = pkgsFor.${system}.gcc13Stdenv;
|
|
||||||
} {
|
|
||||||
name = "hyprland-shell";
|
|
||||||
nativeBuildInputs = with pkgsFor.${system}; [
|
|
||||||
expat
|
|
||||||
libxml2
|
|
||||||
];
|
];
|
||||||
hardeningDisable = ["fortify"];
|
}
|
||||||
inputsFrom = [pkgsFor.${system}.hyprland];
|
);
|
||||||
packages = [pkgsFor.${system}.clang-tools];
|
pkgsCrossFor = eachSystem (
|
||||||
};
|
system: crossSystem:
|
||||||
});
|
import nixpkgs {
|
||||||
|
localSystem = system;
|
||||||
|
inherit crossSystem;
|
||||||
|
overlays = with self.overlays; [
|
||||||
|
hyprland-packages
|
||||||
|
hyprland-extras
|
||||||
|
];
|
||||||
|
}
|
||||||
|
);
|
||||||
|
pkgsDebugFor = eachSystem (
|
||||||
|
system:
|
||||||
|
import nixpkgs {
|
||||||
|
localSystem = system;
|
||||||
|
overlays = with self.overlays; [
|
||||||
|
hyprland-debug
|
||||||
|
];
|
||||||
|
}
|
||||||
|
);
|
||||||
|
pkgsDebugCrossFor = eachSystem (
|
||||||
|
system: crossSystem:
|
||||||
|
import nixpkgs {
|
||||||
|
localSystem = system;
|
||||||
|
inherit crossSystem;
|
||||||
|
overlays = with self.overlays; [
|
||||||
|
hyprland-debug
|
||||||
|
];
|
||||||
|
}
|
||||||
|
);
|
||||||
|
in
|
||||||
|
{
|
||||||
|
overlays = import ./nix/overlays.nix { inherit self lib inputs; };
|
||||||
|
|
||||||
formatter = eachSystem (system: nixpkgs.legacyPackages.${system}.alejandra);
|
checks = eachSystem (
|
||||||
|
system:
|
||||||
|
(lib.filterAttrs (
|
||||||
|
n: _: (lib.hasPrefix "hyprland" n) && !(lib.hasSuffix "debug" n)
|
||||||
|
) self.packages.${system})
|
||||||
|
// {
|
||||||
|
inherit (self.packages.${system}) xdg-desktop-portal-hyprland;
|
||||||
|
pre-commit-check = inputs.pre-commit-hooks.lib.${system}.run {
|
||||||
|
src = ./.;
|
||||||
|
hooks = {
|
||||||
|
hyprland-treewide-formatter = {
|
||||||
|
enable = true;
|
||||||
|
entry = "${self.formatter.${system}}/bin/hyprland-treewide-formatter";
|
||||||
|
pass_filenames = false;
|
||||||
|
excludes = [ "subprojects" ];
|
||||||
|
always_run = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// (import ./nix/tests inputs pkgsFor.${system})
|
||||||
|
);
|
||||||
|
|
||||||
nixosModules.default = import ./nix/module.nix inputs;
|
packages = eachSystem (system: {
|
||||||
homeManagerModules.default = import ./nix/hm-module.nix self;
|
default = self.packages.${system}.hyprland;
|
||||||
};
|
inherit (pkgsFor.${system})
|
||||||
|
# hyprland-packages
|
||||||
|
hyprland
|
||||||
|
hyprland-unwrapped
|
||||||
|
hyprland-with-tests
|
||||||
|
# hyprland-extras
|
||||||
|
xdg-desktop-portal-hyprland
|
||||||
|
;
|
||||||
|
inherit (pkgsDebugFor.${system}) hyprland-debug;
|
||||||
|
hyprland-cross = (pkgsCrossFor.${system} "aarch64-linux").hyprland;
|
||||||
|
hyprland-debug-cross = (pkgsDebugCrossFor.${system} "aarch64-linux").hyprland-debug;
|
||||||
|
});
|
||||||
|
|
||||||
|
devShells = eachSystem (system: {
|
||||||
|
default =
|
||||||
|
pkgsFor.${system}.mkShell.override
|
||||||
|
{
|
||||||
|
inherit (self.packages.${system}.default) stdenv;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
name = "hyprland-shell";
|
||||||
|
hardeningDisable = [ "fortify" ];
|
||||||
|
inputsFrom = [ pkgsFor.${system}.hyprland ];
|
||||||
|
packages = [ pkgsFor.${system}.clang-tools ];
|
||||||
|
inherit (self.checks.${system}.pre-commit-check) shellHook;
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
formatter = eachSystem (system: pkgsFor.${system}.callPackage ./nix/formatter.nix { });
|
||||||
|
|
||||||
|
nixosModules.default = import ./nix/module.nix inputs;
|
||||||
|
homeManagerModules.default = import ./nix/hm-module.nix self;
|
||||||
|
|
||||||
|
# Hydra build jobs
|
||||||
|
# Recent versions of Hydra can aggregate jobsets from 'hydraJobs' instead of a release.nix
|
||||||
|
# or similar. Remember to filter large or incompatible attributes here. More eval jobs can
|
||||||
|
# be added by merging, e.g., self.packages // self.devShells.
|
||||||
|
hydraJobs = self.packages;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,11 +5,32 @@ project(
|
||||||
DESCRIPTION "Control utility for Hyprland"
|
DESCRIPTION "Control utility for Hyprland"
|
||||||
)
|
)
|
||||||
|
|
||||||
pkg_check_modules(deps REQUIRED IMPORTED_TARGET hyprutils>=0.1.1)
|
pkg_check_modules(hyprctl_deps REQUIRED IMPORTED_TARGET hyprutils>=0.2.4 hyprwire re2)
|
||||||
|
|
||||||
add_executable(hyprctl "main.cpp")
|
file(GLOB_RECURSE HYPRCTL_SRCFILES CONFIGURE_DEPENDS "src/*.cpp" "hw-protocols/*.cpp" "include/*.hpp")
|
||||||
|
|
||||||
|
add_executable(hyprctl ${HYPRCTL_SRCFILES})
|
||||||
|
|
||||||
target_link_libraries(hyprctl PUBLIC PkgConfig::hyprctl_deps)
|
target_link_libraries(hyprctl PUBLIC PkgConfig::hyprctl_deps)
|
||||||
|
target_include_directories(hyprctl PRIVATE "hw-protocols")
|
||||||
|
|
||||||
|
# Hyprwire
|
||||||
|
|
||||||
|
function(hyprprotocol protoPath protoName)
|
||||||
|
set(path ${CMAKE_CURRENT_SOURCE_DIR}/${protoPath})
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/hw-protocols/${protoName}-client.cpp
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/hw-protocols/${protoName}-client.hpp
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/hw-protocols/${protoName}-spec.hpp
|
||||||
|
COMMAND hyprwire-scanner --client ${path}/${protoName}.xml
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/hw-protocols/
|
||||||
|
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
|
target_sources(hyprctl PRIVATE hw-protocols/${protoName}-client.cpp
|
||||||
|
hw-protocols/${protoName}-client.hpp
|
||||||
|
hw-protocols/${protoName}-spec.hpp)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
hyprprotocol(hw-protocols hyprpaper_core)
|
||||||
|
|
||||||
# binary
|
# binary
|
||||||
install(TARGETS hyprctl)
|
install(TARGETS hyprctl)
|
||||||
|
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
all:
|
|
||||||
$(CXX) $(CXXFLAGS) -std=c++2b ./main.cpp -o ./hyprctl
|
|
||||||
clean:
|
|
||||||
rm ./hyprctl
|
|
||||||
172
hyprctl/hw-protocols/hyprpaper_core.xml
Normal file
|
|
@ -0,0 +1,172 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<protocol name="hyprpaper_core" version="2">
|
||||||
|
<copyright>
|
||||||
|
BSD 3-Clause License
|
||||||
|
|
||||||
|
Copyright (c) 2025, Hypr Development
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation
|
||||||
|
and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
3. Neither the name of the copyright holder nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived from
|
||||||
|
this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||||
|
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
</copyright>
|
||||||
|
|
||||||
|
<object name="hyprpaper_core_manager" version="2">
|
||||||
|
<description summary="manager object">
|
||||||
|
This is the core manager object for hyprpaper operations
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<c2s name="get_wallpaper_object">
|
||||||
|
<description summary="Get a wallpaper object">
|
||||||
|
Creates a wallpaper object
|
||||||
|
</description>
|
||||||
|
<returns iface="hyprpaper_wallpaper"/>
|
||||||
|
</c2s>
|
||||||
|
|
||||||
|
<s2c name="add_monitor">
|
||||||
|
<description summary="New monitor added">
|
||||||
|
Emitted when a new monitor is added.
|
||||||
|
</description>
|
||||||
|
<arg name="monitor_name" type="varchar" summary="the monitor's name"/>
|
||||||
|
</s2c>
|
||||||
|
|
||||||
|
<s2c name="remove_monitor">
|
||||||
|
<description summary="A monitor was removed">
|
||||||
|
Emitted when a monitor is removed.
|
||||||
|
</description>
|
||||||
|
<arg name="monitor_name" type="varchar" summary="the monitor's name"/>
|
||||||
|
</s2c>
|
||||||
|
|
||||||
|
<c2s name="destroy" destructor="true">
|
||||||
|
<description summary="Destroy this object">
|
||||||
|
Destroys this object. Children remain alive until destroyed.
|
||||||
|
</description>
|
||||||
|
</c2s>
|
||||||
|
|
||||||
|
<c2s name="get_status_object" since="2">
|
||||||
|
<description summary="Get a status object">
|
||||||
|
Creates a status object
|
||||||
|
</description>
|
||||||
|
<returns iface="hyprpaper_status"/>
|
||||||
|
</c2s>
|
||||||
|
</object>
|
||||||
|
|
||||||
|
<enum name="wallpaper_fit_mode">
|
||||||
|
<value idx="0" name="stretch"/>
|
||||||
|
<value idx="1" name="cover"/>
|
||||||
|
<value idx="2" name="contain"/>
|
||||||
|
<value idx="3" name="tile"/>
|
||||||
|
</enum>
|
||||||
|
|
||||||
|
<enum name="wallpaper_errors">
|
||||||
|
<value idx="0" name="inert_wallpaper_object" description="attempted to use an inert wallpaper object"/>
|
||||||
|
</enum>
|
||||||
|
|
||||||
|
<enum name="applying_error">
|
||||||
|
<value idx="0" name="invalid_path" description="path provided was invalid"/>
|
||||||
|
<value idx="1" name="invalid_monitor" description="monitor provided was invalid"/>
|
||||||
|
<value idx="2" name="unknown_error" description="unknown error"/>
|
||||||
|
</enum>
|
||||||
|
|
||||||
|
<object name="hyprpaper_wallpaper" version="1">
|
||||||
|
<description summary="wallpaper object">
|
||||||
|
This is an object describing a wallpaper
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<c2s name="path">
|
||||||
|
<description summary="Set a path">
|
||||||
|
Set a file path for the wallpaper. This has to be an absolute path from the fs root.
|
||||||
|
This is required.
|
||||||
|
</description>
|
||||||
|
<arg name="wallpaper" type="varchar" summary="path"/>
|
||||||
|
</c2s>
|
||||||
|
|
||||||
|
<c2s name="fit_mode">
|
||||||
|
<description summary="Set a fit mode">
|
||||||
|
Set a fit mode for the wallpaper. This is set to cover by default.
|
||||||
|
</description>
|
||||||
|
<arg name="fit_mode" type="enum" interface="wallpaper_fit_mode" summary="path"/>
|
||||||
|
</c2s>
|
||||||
|
|
||||||
|
<c2s name="monitor_name">
|
||||||
|
<description summary="Set the monitor name">
|
||||||
|
Set a monitor for the wallpaper. Setting this to empty (or not setting at all) will
|
||||||
|
treat this as a wildcard fallback.
|
||||||
|
|
||||||
|
See hyprpaper_core_manager.add_monitor and hyprpaper_core_manager.remove_monitor
|
||||||
|
for tracking monitor names.
|
||||||
|
</description>
|
||||||
|
<arg name="monitor_name" type="varchar" summary="monitor name"/>
|
||||||
|
</c2s>
|
||||||
|
|
||||||
|
<c2s name="apply">
|
||||||
|
<description summary="Apply this wallpaper">
|
||||||
|
Applies this object's state to the wallpaper state. Will emit .success on success,
|
||||||
|
and .failed on failure.
|
||||||
|
|
||||||
|
This object becomes inert after .succeess or .failed, the only valid operation
|
||||||
|
is to destroy it afterwards.
|
||||||
|
</description>
|
||||||
|
</c2s>
|
||||||
|
|
||||||
|
<s2c name="success">
|
||||||
|
<description summary="Operation succeeded">
|
||||||
|
Wallpaper was applied successfully.
|
||||||
|
</description>
|
||||||
|
</s2c>
|
||||||
|
|
||||||
|
<s2c name="failed">
|
||||||
|
<description summary="Operation failed">
|
||||||
|
Wallpaper was not applied. See the error field for more information.
|
||||||
|
</description>
|
||||||
|
<arg name="error" type="enum" interface="hyprpaper_wallpaper_application_error" summary="path"/>
|
||||||
|
</s2c>
|
||||||
|
|
||||||
|
<c2s name="destroy" destructor="true">
|
||||||
|
<description summary="Destroy this object">
|
||||||
|
Destroys this object.
|
||||||
|
</description>
|
||||||
|
</c2s>
|
||||||
|
</object>
|
||||||
|
|
||||||
|
<object name="hyprpaper_status" version="2">
|
||||||
|
<description summary="status object">
|
||||||
|
This is an object which will emit various status updates.
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<s2c name="active_wallpaper">
|
||||||
|
<description summary="Active wallpaper state">
|
||||||
|
Sends the active wallpaper for a given monitor. This will be emitted
|
||||||
|
immediately after binding, and then every time the path changes.
|
||||||
|
</description>
|
||||||
|
<arg name="monitor" type="varchar" summary="monitor name"/>
|
||||||
|
<arg name="path" type="varchar" summary="wallpaper path"/>
|
||||||
|
</s2c>
|
||||||
|
|
||||||
|
<c2s name="destroy" destructor="true">
|
||||||
|
<description summary="Destroy this object">
|
||||||
|
Destroys this object.
|
||||||
|
</description>
|
||||||
|
</c2s>
|
||||||
|
</object>
|
||||||
|
</protocol>
|
||||||
|
|
@ -1,17 +1,17 @@
|
||||||
_hyprctl_cmd_2 () {
|
_hyprctl_cmd_1 () {
|
||||||
hyprctl monitors | awk '/Monitor/{ print $2 }'
|
hyprctl monitors | awk '/Monitor/{ print $2 }'
|
||||||
}
|
}
|
||||||
|
|
||||||
_hyprctl_cmd_3 () {
|
_hyprctl_cmd_3 () {
|
||||||
hyprpm list | awk '/Plugin/{ print $4 }'
|
hyprctl clients | awk '/class/{print $2}'
|
||||||
|
}
|
||||||
|
|
||||||
|
_hyprctl_cmd_2 () {
|
||||||
|
hyprctl devices | sed -n '/Keyboard at/{n; s/^\s\+//; p}'
|
||||||
}
|
}
|
||||||
|
|
||||||
_hyprctl_cmd_0 () {
|
_hyprctl_cmd_0 () {
|
||||||
hyprctl clients | awk '/class/{ print $2 }'
|
hyprpm list | awk '/Plugin/{print $4}'
|
||||||
}
|
|
||||||
|
|
||||||
_hyprctl_cmd_1 () {
|
|
||||||
hyprctl devices | sed -n '/Keyboard at/{n; s/^\s\+//; p}'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_hyprctl () {
|
_hyprctl () {
|
||||||
|
|
@ -23,25 +23,25 @@ _hyprctl () {
|
||||||
local words cword
|
local words cword
|
||||||
_get_comp_words_by_ref -n "$COMP_WORDBREAKS" words cword
|
_get_comp_words_by_ref -n "$COMP_WORDBREAKS" words cword
|
||||||
|
|
||||||
local -a literals=("cyclenext" "globalshortcuts" "cursorpos" "bordersize" "renameworkspace" "animationstyle" "focuswindow" "0" "auto" "swapnext" "forceallowsinput" "moveactive" "activebordercolor" "alphafullscreen" "wayland" "layers" "minsize" "monitors" "1" "kill" "settiled" "3" "focusmonitor" "swapwindow" "moveoutofgroup" "notify" "movecursor" "setcursor" "seterror" "movecurrentworkspacetomonitor" "4" "nomaxsize" "forcenoanims" "setprop" "-i" "-q" "togglefloating" "workspacerules" "movetoworkspace" "disable" "setignoregrouplock" "workspaces" "movegroupwindow" "closewindow" "0" "--instance" "binds" "movewindow" "splitratio" "alpha" "denywindowfromgroup" "workspace" "configerrors" "togglegroup" "getoption" "forceopaque" "keepaspectratio" "killactive" "pass" "decorations" "devices" "focuscurrentorlast" "submap" "global" "alphafullscreenoverride" "forcerendererreload" "movewindowpixel" "headless" "version" "dpms" "resizeactive" "moveintogroup" "5" "alphaoverride" "setfloating" "rollinglog" "::=" "rounding" "layouts" "moveworkspacetomonitor" "exec" "alphainactiveoverride" "alterzorder" "fakefullscreen" "nofocus" "keyword" "forcenoborder" "forcenodim" "--quiet" "pin" "output" "forcenoblur" "togglespecialworkspace" "fullscreen" "toggleopaque" "focusworkspaceoncurrentmonitor" "next" "changegroupactive" "-j" "instances" "execr" "exit" "clients" "all" "--batch" "dismissnotify" "inactivebordercolor" "switchxkblayout" "movetoworkspacesilent" "tagwindow" "movewindoworgroup" "-r" "movefocus" "focusurgentorlast" "remove" "activeworkspace" "dispatch" "create" "centerwindow" "2" "hyprpaper" "-1" "reload" "alphainactive" "systeminfo" "plugin" "dimaround" "activewindow" "swapactiveworkspaces" "splash" "sendshortcut" "maxsize" "lockactivegroup" "windowdancecompat" "forceopaqueoverriden" "lockgroups" "movecursortocorner" "x11" "prev" "1" "resizewindowpixel" "forcenoshadow")
|
declare -a literals=(resizeactive 2 changegroupactive -r moveintogroup forceallowsinput 4 ::= systeminfo all layouts setprop animationstyle switchxkblayout create denywindowfromgroup headless activebordercolor exec setcursor wayland focusurgentorlast workspacerules movecurrentworkspacetomonitor movetoworkspacesilent hyprpaper alpha inactivebordercolor movegroupwindow movecursortocorner movewindowpixel prev movewindow globalshortcuts clients dimaround setignoregrouplock splash execr monitors 0 forcenoborder -q animations 1 nomaxsize splitratio moveactive pass swapnext devices layers rounding lockactivegroup 5 moveworkspacetomonitor -f -i --quiet forcenodim pin 0 1 forceopaque forcenoshadow setfloating minsize alphaoverride sendshortcut workspaces cyclenext alterzorder togglegroup lockgroups bordersize dpms focuscurrentorlast -1 --batch notify remove instances 1 3 moveoutofgroup killactive 2 movetoworkspace movecursor configerrors closewindow swapwindow tagwindow forcerendererreload centerwindow auto focuswindow seterror nofocus alphafullscreen binds version -h togglespecialworkspace fullscreen windowdancecompat 0 keyword toggleopaque 3 --instance togglefloating renameworkspace alphafullscreenoverride activeworkspace x11 kill forceopaqueoverriden output global dispatch reload forcenoblur -j event --help disable -1 activewindow keepaspectratio dismissnotify focusmonitor movefocus plugin exit workspace fullscreenstate getoption alphainactiveoverride alphainactive decorations settiled config-only descriptions resizewindowpixel fakefullscreen rollinglog swapactiveworkspaces submap next movewindoworgroup cursorpos forcenoanims focusworkspaceoncurrentmonitor maxsize sendkeystate)
|
||||||
|
|
||||||
declare -A literal_transitions
|
declare -A literal_transitions
|
||||||
literal_transitions[0]="([105]=1 [75]=2 [33]=3 [35]=4 [1]=2 [2]=2 [78]=2 [107]=5 [37]=2 [111]=4 [41]=2 [46]=2 [115]=2 [85]=6 [116]=8 [52]=2 [88]=4 [54]=2 [90]=9 [120]=2 [122]=2 [124]=2 [15]=2 [59]=10 [60]=2 [17]=11 [125]=12 [19]=2 [127]=2 [129]=2 [25]=13 [68]=2 [98]=4 [99]=2 [27]=2 [28]=14 [102]=2 [104]=4)"
|
literal_transitions[0]="([120]=14 [43]=2 [125]=21 [81]=2 [3]=21 [51]=2 [50]=2 [128]=2 [89]=2 [58]=21 [8]=2 [10]=2 [11]=3 [130]=4 [13]=5 [97]=6 [101]=2 [102]=21 [133]=7 [100]=2 [137]=2 [22]=2 [19]=2 [140]=8 [25]=2 [143]=2 [107]=9 [146]=10 [69]=2 [33]=2 [34]=2 [78]=21 [114]=2 [37]=2 [151]=2 [116]=2 [121]=13 [123]=21 [39]=11 [42]=21 [79]=15 [118]=12)"
|
||||||
literal_transitions[3]="([73]=17 [13]=2 [32]=17 [55]=17 [56]=17 [91]=17 [106]=2 [123]=2 [77]=1 [16]=2 [126]=17 [3]=1 [5]=2 [64]=17 [131]=2 [133]=17 [81]=17 [134]=17 [84]=17 [31]=17 [49]=2 [12]=2 [86]=17 [10]=17 [87]=17 [141]=17)"
|
literal_transitions[1]="([81]=2 [51]=2 [50]=2 [128]=2 [8]=2 [89]=2 [10]=2 [11]=3 [130]=4 [13]=5 [97]=6 [101]=2 [133]=7 [100]=2 [22]=2 [19]=2 [137]=2 [140]=8 [25]=2 [143]=2 [107]=9 [146]=10 [69]=2 [33]=2 [34]=2 [114]=2 [37]=2 [151]=2 [116]=2 [39]=11 [118]=12 [121]=13 [120]=14 [79]=15 [43]=2)"
|
||||||
literal_transitions[7]="([105]=1 [75]=2 [33]=3 [1]=2 [2]=2 [78]=2 [107]=5 [37]=2 [41]=2 [46]=2 [115]=2 [85]=6 [116]=8 [52]=2 [54]=2 [90]=9 [120]=2 [122]=2 [124]=2 [15]=2 [59]=10 [60]=2 [17]=11 [125]=12 [19]=2 [127]=2 [129]=2 [25]=13 [68]=2 [99]=2 [27]=2 [28]=14 [102]=2)"
|
literal_transitions[3]="([139]=2 [63]=16 [64]=16 [45]=16 [105]=16 [27]=2 [26]=2 [52]=4 [5]=16 [66]=2 [67]=16 [129]=16 [113]=16 [12]=2 [74]=4 [99]=2 [35]=16 [152]=16 [98]=16 [59]=16 [117]=16 [41]=16 [17]=2 [138]=16 [154]=2 [122]=16)"
|
||||||
literal_transitions[8]="([101]=2 [130]=2 [132]=2 [0]=2 [74]=2 [36]=2 [108]=2 [109]=2 [38]=2 [110]=2 [4]=2 [79]=2 [40]=2 [80]=2 [113]=2 [6]=2 [42]=2 [43]=2 [82]=2 [83]=2 [47]=2 [48]=2 [9]=2 [50]=2 [51]=2 [53]=2 [11]=2 [112]=2 [89]=2 [118]=2 [57]=2 [92]=2 [58]=2 [93]=2 [94]=2 [61]=2 [62]=2 [128]=2 [95]=2 [63]=2 [20]=2 [97]=2 [22]=2 [23]=2 [65]=2 [66]=2 [135]=2 [136]=2 [24]=2 [26]=2 [69]=2 [100]=2 [70]=2 [140]=2 [29]=2 [71]=2)"
|
literal_transitions[6]="([126]=2)"
|
||||||
literal_transitions[9]="([117]=20 [114]=16)"
|
literal_transitions[10]="([56]=2)"
|
||||||
literal_transitions[11]="([103]=2)"
|
literal_transitions[11]="([9]=2)"
|
||||||
literal_transitions[13]="([21]=1 [119]=1 [30]=1 [139]=1 [121]=1 [44]=1 [72]=1)"
|
literal_transitions[12]="([14]=19 [80]=22)"
|
||||||
literal_transitions[14]="([39]=2)"
|
literal_transitions[13]="([142]=2)"
|
||||||
literal_transitions[15]="([138]=2 [96]=2)"
|
literal_transitions[14]="([0]=2 [84]=2 [2]=2 [85]=2 [4]=2 [87]=2 [88]=2 [90]=2 [91]=2 [92]=2 [93]=2 [94]=2 [96]=2 [15]=2 [18]=2 [103]=2 [21]=2 [104]=2 [23]=2 [24]=2 [28]=2 [29]=2 [30]=2 [108]=2 [111]=2 [32]=2 [112]=2 [36]=2 [38]=2 [119]=2 [124]=2 [46]=2 [47]=2 [48]=2 [49]=2 [53]=2 [55]=2 [131]=2 [132]=2 [134]=2 [135]=2 [60]=2 [136]=20 [141]=2 [65]=2 [144]=2 [145]=2 [68]=2 [147]=2 [70]=2 [71]=2 [72]=2 [73]=2 [148]=2 [75]=2 [76]=2 [150]=2 [153]=2)"
|
||||||
literal_transitions[17]="([18]=2 [7]=2)"
|
literal_transitions[15]="([86]=4 [6]=4 [109]=4 [61]=4 [77]=4 [54]=4 [62]=4)"
|
||||||
literal_transitions[18]="([76]=19)"
|
literal_transitions[16]="([40]=2 [44]=2)"
|
||||||
literal_transitions[19]="([34]=4 [45]=4)"
|
literal_transitions[17]="([7]=23)"
|
||||||
literal_transitions[20]="([8]=2 [67]=2 [14]=2 [137]=2)"
|
literal_transitions[18]="([31]=2 [149]=2)"
|
||||||
|
literal_transitions[19]="([95]=2 [16]=2 [115]=2 [20]=2)"
|
||||||
declare -A match_anything_transitions
|
literal_transitions[20]="([106]=2 [82]=2 [127]=2 [1]=2 [83]=2)"
|
||||||
match_anything_transitions=([1]=2 [0]=7 [6]=2 [15]=2 [10]=2 [5]=15 [14]=18 [7]=7 [2]=18 [16]=2 [12]=2 [11]=18)
|
literal_transitions[23]="([57]=21 [110]=21)"
|
||||||
|
declare -A match_anything_transitions=([6]=17 [7]=2 [0]=1 [22]=2 [5]=18 [4]=2 [2]=17 [18]=2 [11]=17 [8]=2 [9]=2 [13]=17 [10]=17 [1]=1)
|
||||||
declare -A subword_transitions
|
declare -A subword_transitions
|
||||||
|
|
||||||
local state=0
|
local state=0
|
||||||
|
|
@ -79,21 +79,9 @@ _hyprctl () {
|
||||||
done
|
done
|
||||||
|
|
||||||
|
|
||||||
|
local -a matches=()
|
||||||
|
|
||||||
local prefix="${words[$cword]}"
|
local prefix="${words[$cword]}"
|
||||||
|
|
||||||
local shortest_suffix="$word"
|
|
||||||
for ((i=0; i < ${#COMP_WORDBREAKS}; i++)); do
|
|
||||||
local char="${COMP_WORDBREAKS:$i:1}"
|
|
||||||
local candidate="${word##*$char}"
|
|
||||||
if [[ ${#candidate} -lt ${#shortest_suffix} ]]; then
|
|
||||||
shortest_suffix=$candidate
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
local superfluous_prefix=""
|
|
||||||
if [[ "$shortest_suffix" != "$word" ]]; then
|
|
||||||
local superfluous_prefix=${word%$shortest_suffix}
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ -v "literal_transitions[$state]" ]]; then
|
if [[ -v "literal_transitions[$state]" ]]; then
|
||||||
local state_transitions_initializer=${literal_transitions[$state]}
|
local state_transitions_initializer=${literal_transitions[$state]}
|
||||||
declare -A state_transitions
|
declare -A state_transitions
|
||||||
|
|
@ -102,25 +90,38 @@ _hyprctl () {
|
||||||
for literal_id in "${!state_transitions[@]}"; do
|
for literal_id in "${!state_transitions[@]}"; do
|
||||||
local literal="${literals[$literal_id]}"
|
local literal="${literals[$literal_id]}"
|
||||||
if [[ $literal = "${prefix}"* ]]; then
|
if [[ $literal = "${prefix}"* ]]; then
|
||||||
local completion=${literal#"$superfluous_prefix"}
|
matches+=("$literal ")
|
||||||
COMPREPLY+=("$completion ")
|
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
declare -A commands
|
declare -A commands
|
||||||
commands=([5]=1 [16]=2 [12]=3 [10]=0)
|
commands=([7]=0 [22]=1 [8]=3 [5]=2)
|
||||||
if [[ -v "commands[$state]" ]]; then
|
if [[ -v "commands[$state]" ]]; then
|
||||||
local command_id=${commands[$state]}
|
local command_id=${commands[$state]}
|
||||||
local completions=()
|
local completions=()
|
||||||
mapfile -t completions < <(_hyprctl_cmd_${command_id} "$prefix" | cut -f1)
|
readarray -t completions < <(_hyprctl_cmd_${command_id} "$prefix" | cut -f1)
|
||||||
for item in "${completions[@]}"; do
|
for item in "${completions[@]}"; do
|
||||||
if [[ $item = "${prefix}"* ]]; then
|
if [[ $item = "${prefix}"* ]]; then
|
||||||
COMPREPLY+=("$item")
|
matches+=("$item")
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
local shortest_suffix="$prefix"
|
||||||
|
for ((i=0; i < ${#COMP_WORDBREAKS}; i++)); do
|
||||||
|
local char="${COMP_WORDBREAKS:$i:1}"
|
||||||
|
local candidate=${prefix##*$char}
|
||||||
|
if [[ ${#candidate} -lt ${#shortest_suffix} ]]; then
|
||||||
|
shortest_suffix=$candidate
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
local superfluous_prefix=""
|
||||||
|
if [[ "$shortest_suffix" != "$prefix" ]]; then
|
||||||
|
local superfluous_prefix=${prefix%$shortest_suffix}
|
||||||
|
fi
|
||||||
|
COMPREPLY=("${matches[@]#$superfluous_prefix}")
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,21 @@
|
||||||
function _hyprctl_3
|
function _hyprctl_2
|
||||||
set 1 $argv[1]
|
set 1 $argv[1]
|
||||||
hyprctl monitors | awk '/Monitor/{ print $2 }'
|
hyprctl monitors | awk '/Monitor/{ print $2 }'
|
||||||
end
|
end
|
||||||
|
|
||||||
function _hyprctl_4
|
function _hyprctl_4
|
||||||
set 1 $argv[1]
|
set 1 $argv[1]
|
||||||
hyprpm list | awk '/Plugin/{ print $4 }'
|
hyprctl clients | awk '/class/{print $2}'
|
||||||
|
end
|
||||||
|
|
||||||
|
function _hyprctl_3
|
||||||
|
set 1 $argv[1]
|
||||||
|
hyprctl devices | sed -n '/Keyboard at/{n; s/^\s\+//; p}'
|
||||||
end
|
end
|
||||||
|
|
||||||
function _hyprctl_1
|
function _hyprctl_1
|
||||||
set 1 $argv[1]
|
set 1 $argv[1]
|
||||||
hyprctl clients | awk '/class/{ print $2 }'
|
hyprpm list | awk '/Plugin/{print $4}'
|
||||||
end
|
|
||||||
|
|
||||||
function _hyprctl_2
|
|
||||||
set 1 $argv[1]
|
|
||||||
hyprctl devices | sed -n '/Keyboard at/{n; s/^\s\+//; p}'
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function _hyprctl
|
function _hyprctl
|
||||||
|
|
@ -29,145 +29,160 @@ function _hyprctl
|
||||||
set COMP_CWORD (count $COMP_WORDS)
|
set COMP_CWORD (count $COMP_WORDS)
|
||||||
end
|
end
|
||||||
|
|
||||||
set --local literals "cyclenext" "globalshortcuts" "cursorpos" "bordersize" "renameworkspace" "animationstyle" "focuswindow" "0" "auto" "swapnext" "forceallowsinput" "moveactive" "activebordercolor" "alphafullscreen" "wayland" "layers" "minsize" "monitors" "1" "kill" "settiled" "3" "focusmonitor" "swapwindow" "moveoutofgroup" "notify" "movecursor" "setcursor" "seterror" "movecurrentworkspacetomonitor" "4" "nomaxsize" "forcenoanims" "setprop" "-i" "-q" "togglefloating" "workspacerules" "movetoworkspace" "disable" "setignoregrouplock" "workspaces" "movegroupwindow" "closewindow" "0" "--instance" "binds" "movewindow" "splitratio" "alpha" "denywindowfromgroup" "workspace" "configerrors" "togglegroup" "getoption" "forceopaque" "keepaspectratio" "killactive" "pass" "decorations" "devices" "focuscurrentorlast" "submap" "global" "alphafullscreenoverride" "forcerendererreload" "movewindowpixel" "headless" "version" "dpms" "resizeactive" "moveintogroup" "5" "alphaoverride" "setfloating" "rollinglog" "::=" "rounding" "layouts" "moveworkspacetomonitor" "exec" "alphainactiveoverride" "alterzorder" "fakefullscreen" "nofocus" "keyword" "forcenoborder" "forcenodim" "--quiet" "pin" "output" "forcenoblur" "togglespecialworkspace" "fullscreen" "toggleopaque" "focusworkspaceoncurrentmonitor" "next" "changegroupactive" "-j" "instances" "execr" "exit" "clients" "all" "--batch" "dismissnotify" "inactivebordercolor" "switchxkblayout" "movetoworkspacesilent" "tagwindow" "movewindoworgroup" "-r" "movefocus" "focusurgentorlast" "remove" "activeworkspace" "dispatch" "create" "centerwindow" "2" "hyprpaper" "-1" "reload" "alphainactive" "systeminfo" "plugin" "dimaround" "activewindow" "swapactiveworkspaces" "splash" "sendshortcut" "maxsize" "lockactivegroup" "windowdancecompat" "forceopaqueoverriden" "lockgroups" "movecursortocorner" "x11" "prev" "1" "resizewindowpixel" "forcenoshadow"
|
set literals "resizeactive" "2" "changegroupactive" "-r" "moveintogroup" "forceallowsinput" "4" "::=" "systeminfo" "all" "layouts" "setprop" "animationstyle" "switchxkblayout" "create" "denywindowfromgroup" "headless" "activebordercolor" "exec" "setcursor" "wayland" "focusurgentorlast" "workspacerules" "movecurrentworkspacetomonitor" "movetoworkspacesilent" "hyprpaper" "alpha" "inactivebordercolor" "movegroupwindow" "movecursortocorner" "movewindowpixel" "prev" "movewindow" "globalshortcuts" "clients" "dimaround" "setignoregrouplock" "splash" "execr" "monitors" "0" "forcenoborder" "-q" "animations" "1" "nomaxsize" "splitratio" "moveactive" "pass" "swapnext" "devices" "layers" "rounding" "lockactivegroup" "5" "moveworkspacetomonitor" "-f" "-i" "--quiet" "forcenodim" "pin" "0" "1" "forceopaque" "forcenoshadow" "setfloating" "minsize" "alphaoverride" "sendshortcut" "workspaces" "cyclenext" "alterzorder" "togglegroup" "lockgroups" "bordersize" "dpms" "focuscurrentorlast" "-1" "--batch" "notify" "remove" "instances" "1" "3" "moveoutofgroup" "killactive" "2" "movetoworkspace" "movecursor" "configerrors" "closewindow" "swapwindow" "tagwindow" "forcerendererreload" "centerwindow" "auto" "focuswindow" "seterror" "nofocus" "alphafullscreen" "binds" "version" "-h" "togglespecialworkspace" "fullscreen" "windowdancecompat" "0" "keyword" "toggleopaque" "3" "--instance" "togglefloating" "renameworkspace" "alphafullscreenoverride" "activeworkspace" "x11" "kill" "forceopaqueoverriden" "output" "global" "dispatch" "reload" "forcenoblur" "-j" "event" "--help" "disable" "-1" "activewindow" "keepaspectratio" "dismissnotify" "focusmonitor" "movefocus" "plugin" "exit" "workspace" "fullscreenstate" "getoption" "alphainactiveoverride" "alphainactive" "decorations" "settiled" "config-only" "descriptions" "resizewindowpixel" "fakefullscreen" "rollinglog" "swapactiveworkspaces" "submap" "next" "movewindoworgroup" "cursorpos" "forcenoanims" "focusworkspaceoncurrentmonitor" "maxsize" "sendkeystate"
|
||||||
|
|
||||||
set --local descriptions
|
set descriptions
|
||||||
set descriptions[1] "Focus the next window on a workspace"
|
set descriptions[1] "Resize the active window"
|
||||||
set descriptions[3] "Get the current cursor pos in global layout coordinates"
|
set descriptions[2] "Fullscreen"
|
||||||
set descriptions[5] "Rename a workspace"
|
set descriptions[3] "Switch to the next window in a group"
|
||||||
set descriptions[7] "Focus the first window matching"
|
set descriptions[4] "Refresh state after issuing the command"
|
||||||
set descriptions[10] "Swap the focused window with the next window"
|
set descriptions[5] "Move the active window into a group"
|
||||||
set descriptions[12] "Move the active window"
|
set descriptions[7] "CONFUSED"
|
||||||
set descriptions[16] "List the layers"
|
set descriptions[9] "Print system info"
|
||||||
set descriptions[18] "List active outputs with their properties"
|
set descriptions[11] "List all layouts available (including plugin ones)"
|
||||||
set descriptions[20] "Get into a kill mode, where you can kill an app by clicking on it"
|
set descriptions[12] "Set a property of a window"
|
||||||
set descriptions[21] "Set the current window's floating state to false"
|
set descriptions[14] "Set the xkb layout index for a keyboard"
|
||||||
set descriptions[22] "ERROR"
|
set descriptions[16] "Prohibit the active window from becoming or being inserted into group"
|
||||||
set descriptions[23] "Focus a monitor"
|
set descriptions[19] "Execute a shell command"
|
||||||
set descriptions[24] "Swap the active window with another window"
|
set descriptions[20] "Set the cursor theme and reloads the cursor manager"
|
||||||
set descriptions[25] "Move the active window out of a group"
|
set descriptions[22] "Focus the urgent window or the last window"
|
||||||
set descriptions[26] "Send a notification using the built-in Hyprland notification system"
|
set descriptions[23] "Get the list of defined workspace rules"
|
||||||
set descriptions[27] "Move the cursor to a specified position"
|
set descriptions[24] "Move the active workspace to a monitor"
|
||||||
set descriptions[28] "Set the cursor theme and reloads the cursor manager"
|
set descriptions[25] "Move window doesn't switch to the workspace"
|
||||||
set descriptions[29] "Set the hyprctl error string"
|
set descriptions[26] "Interact with hyprpaper if present"
|
||||||
set descriptions[30] "Move the active workspace to a monitor"
|
set descriptions[29] "Swap the active window with the next or previous in a group"
|
||||||
set descriptions[31] "CONFUSED"
|
set descriptions[30] "Move the cursor to the corner of the active window"
|
||||||
set descriptions[34] "Set a property of a window"
|
set descriptions[31] "Move a selected window"
|
||||||
set descriptions[35] "Specify the Hyprland instance"
|
set descriptions[33] "Move the active window in a direction or to a monitor"
|
||||||
set descriptions[36] "Disable output"
|
set descriptions[34] "Lists all global shortcuts"
|
||||||
set descriptions[37] "Toggle the current window's floating state"
|
set descriptions[35] "List all windows with their properties"
|
||||||
set descriptions[38] "Get the list of defined workspace rules"
|
set descriptions[37] "Temporarily enable or disable binds:ignore_group_lock"
|
||||||
set descriptions[39] "Move the focused window to a workspace"
|
set descriptions[38] "Print the current random splash"
|
||||||
set descriptions[41] "Temporarily enable or disable binds:ignore_group_lock"
|
set descriptions[39] "Execute a raw shell command"
|
||||||
set descriptions[42] "List all workspaces with their properties"
|
set descriptions[40] "List active outputs with their properties"
|
||||||
set descriptions[43] "Swap the active window with the next or previous in a group"
|
set descriptions[43] "Disable output"
|
||||||
set descriptions[44] "Close a specified window"
|
set descriptions[44] "Gets the current config info about animations and beziers"
|
||||||
set descriptions[45] "WARNING"
|
set descriptions[47] "Change the split ratio"
|
||||||
set descriptions[46] "Specify the Hyprland instance"
|
set descriptions[48] "Move the active window"
|
||||||
set descriptions[47] "List all registered binds"
|
set descriptions[49] "Pass the key to a specified window"
|
||||||
set descriptions[48] "Move the active window in a direction or to a monitor"
|
set descriptions[50] "Swap the focused window with the next window"
|
||||||
set descriptions[49] "Change the split ratio"
|
set descriptions[51] "List all connected keyboards and mice"
|
||||||
set descriptions[51] "Prohibit the active window from becoming or being inserted into group"
|
set descriptions[52] "List the layers"
|
||||||
set descriptions[52] "Change the workspace"
|
set descriptions[54] "Lock the focused group"
|
||||||
set descriptions[53] "List all current config parsing errors"
|
set descriptions[55] "OK"
|
||||||
set descriptions[54] "Toggle the current active window into a group"
|
set descriptions[56] "Move a workspace to a monitor"
|
||||||
set descriptions[55] "Get the config option status (values)"
|
set descriptions[58] "Specify the Hyprland instance"
|
||||||
set descriptions[58] "Close the active window"
|
set descriptions[59] "Disable output"
|
||||||
set descriptions[59] "Pass the key to a specified window"
|
set descriptions[61] "Pin a window"
|
||||||
set descriptions[60] "List all decorations and their info"
|
set descriptions[62] "WARNING"
|
||||||
set descriptions[61] "List all connected keyboards and mice"
|
set descriptions[63] "INFO"
|
||||||
set descriptions[62] "Switch focus from current to previously focused window"
|
set descriptions[66] "Set the current window's floating state to true"
|
||||||
set descriptions[63] "Change the current mapping group"
|
set descriptions[69] "On shortcut X sends shortcut Y to a specified window"
|
||||||
set descriptions[64] "Execute a Global Shortcut using the GlobalShortcuts portal"
|
set descriptions[70] "List all workspaces with their properties"
|
||||||
set descriptions[66] "Force the renderer to reload all resources and outputs"
|
set descriptions[71] "Focus the next window on a workspace"
|
||||||
set descriptions[67] "Move a selected window"
|
set descriptions[72] "Modify the window stack order of the active or specified window"
|
||||||
set descriptions[69] "Print the Hyprland version: flags, commit and branch of build"
|
set descriptions[73] "Toggle the current active window into a group"
|
||||||
set descriptions[70] "Set all monitors' DPMS status"
|
set descriptions[74] "Lock the groups"
|
||||||
set descriptions[71] "Resize the active window"
|
set descriptions[76] "Set all monitors' DPMS status"
|
||||||
set descriptions[72] "Move the active window into a group"
|
set descriptions[77] "Switch focus from current to previously focused window"
|
||||||
set descriptions[73] "OK"
|
set descriptions[78] "No Icon"
|
||||||
set descriptions[75] "Set the current window's floating state to true"
|
set descriptions[79] "Execute a batch of commands separated by ;"
|
||||||
set descriptions[76] "Print tail of the log"
|
set descriptions[80] "Send a notification using the built-in Hyprland notification system"
|
||||||
set descriptions[79] "List all layouts available (including plugin ones)"
|
set descriptions[82] "List all running Hyprland instances and their info"
|
||||||
set descriptions[80] "Move a workspace to a monitor"
|
set descriptions[83] "Maximize no fullscreen"
|
||||||
set descriptions[81] "Execute a shell command"
|
set descriptions[84] "Maximize and fullscreen"
|
||||||
set descriptions[83] "Modify the window stack order of the active or specified window"
|
set descriptions[85] "Move the active window out of a group"
|
||||||
set descriptions[84] "Toggle the focused window's internal fullscreen state"
|
set descriptions[86] "Close the active window"
|
||||||
set descriptions[86] "Issue a keyword to call a config keyword dynamically"
|
set descriptions[87] "HINT"
|
||||||
set descriptions[89] "Disable output"
|
set descriptions[88] "Move the focused window to a workspace"
|
||||||
set descriptions[90] "Pin a window"
|
set descriptions[89] "Move the cursor to a specified position"
|
||||||
set descriptions[91] "Allows adding/removing fake outputs to a specific backend"
|
set descriptions[90] "List all current config parsing errors"
|
||||||
set descriptions[93] "Toggle a special workspace on/off"
|
set descriptions[91] "Close a specified window"
|
||||||
set descriptions[94] "Toggle the focused window's fullscreen state"
|
set descriptions[92] "Swap the active window with another window"
|
||||||
set descriptions[95] "Toggle the current window to always be opaque"
|
set descriptions[93] "Apply a tag to the window"
|
||||||
set descriptions[96] "Focus the requested workspace"
|
set descriptions[94] "Force the renderer to reload all resources and outputs"
|
||||||
set descriptions[98] "Switch to the next window in a group"
|
set descriptions[95] "Center the active window"
|
||||||
set descriptions[99] "Output in JSON format"
|
set descriptions[97] "Focus the first window matching"
|
||||||
set descriptions[100] "List all running Hyprland instances and their info"
|
set descriptions[98] "Set the hyprctl error string"
|
||||||
set descriptions[101] "Execute a raw shell command"
|
set descriptions[101] "List all registered binds"
|
||||||
set descriptions[102] "Exit the compositor with no questions asked"
|
set descriptions[102] "Print the Hyprland version: flags, commit and branch of build"
|
||||||
set descriptions[103] "List all windows with their properties"
|
set descriptions[103] "Prints the help message"
|
||||||
set descriptions[105] "Execute a batch of commands separated by ;"
|
set descriptions[104] "Toggle a special workspace on/off"
|
||||||
set descriptions[106] "Dismiss all or up to amount of notifications"
|
set descriptions[105] "Toggle the focused window's fullscreen state"
|
||||||
set descriptions[108] "Set the xkb layout index for a keyboard"
|
set descriptions[107] "None"
|
||||||
set descriptions[109] "Move window doesnt switch to the workspace"
|
set descriptions[108] "Issue a keyword to call a config keyword dynamically"
|
||||||
set descriptions[110] "Apply a tag to the window"
|
set descriptions[109] "Toggle the current window to always be opaque"
|
||||||
set descriptions[111] "Behave as moveintogroup"
|
set descriptions[110] "ERROR"
|
||||||
set descriptions[112] "Refresh state after issuing the command"
|
set descriptions[111] "Specify the Hyprland instance"
|
||||||
set descriptions[113] "Move the focus in a direction"
|
set descriptions[112] "Toggle the current window's floating state"
|
||||||
set descriptions[114] "Focus the urgent window or the last window"
|
set descriptions[113] "Rename a workspace"
|
||||||
set descriptions[116] "Get the active workspace name and its properties"
|
set descriptions[115] "Get the active workspace name and its properties"
|
||||||
set descriptions[117] "Issue a dispatch to call a keybind dispatcher with an arg"
|
set descriptions[117] "Get into a kill mode, where you can kill an app by clicking on it"
|
||||||
set descriptions[119] "Center the active window"
|
set descriptions[119] "Allows adding/removing fake outputs to a specific backend"
|
||||||
set descriptions[120] "HINT"
|
set descriptions[120] "Execute a Global Shortcut using the GlobalShortcuts portal"
|
||||||
set descriptions[121] "Interact with hyprpaper if present"
|
set descriptions[121] "Issue a dispatch to call a keybind dispatcher with an arg"
|
||||||
set descriptions[122] "No Icon"
|
set descriptions[122] "Force reload the config"
|
||||||
set descriptions[123] "Force reload the config"
|
set descriptions[124] "Output in JSON format"
|
||||||
set descriptions[125] "Print system info"
|
set descriptions[125] "Emits a custom event to socket2"
|
||||||
set descriptions[126] "Interact with a plugin"
|
set descriptions[126] "Prints the help message"
|
||||||
set descriptions[128] "Get the active window name and its properties"
|
set descriptions[128] "Current"
|
||||||
set descriptions[129] "Swap the active workspaces between two monitors"
|
set descriptions[129] "Get the active window name and its properties"
|
||||||
set descriptions[130] "Print the current random splash"
|
set descriptions[131] "Dismiss all or up to amount of notifications"
|
||||||
set descriptions[131] "On shortcut X sends shortcut Y to a specified window"
|
set descriptions[132] "Focus a monitor"
|
||||||
set descriptions[133] "Lock the focused group"
|
set descriptions[133] "Move the focus in a direction"
|
||||||
set descriptions[136] "Lock the groups"
|
set descriptions[134] "Interact with a plugin"
|
||||||
set descriptions[137] "Move the cursor to the corner of the active window"
|
set descriptions[135] "Exit the compositor with no questions asked"
|
||||||
set descriptions[140] "INFO"
|
set descriptions[136] "Change the workspace"
|
||||||
set descriptions[141] "Resize a selected window"
|
set descriptions[137] "Sets the focused window’s fullscreen mode and the one sent to the client"
|
||||||
|
set descriptions[138] "Get the config option status (values)"
|
||||||
|
set descriptions[141] "List all decorations and their info"
|
||||||
|
set descriptions[142] "Set the current window's floating state to false"
|
||||||
|
set descriptions[144] "Return a parsable JSON with all the config options, descriptions, value types and ranges"
|
||||||
|
set descriptions[145] "Resize a selected window"
|
||||||
|
set descriptions[146] "Toggle the focused window's internal fullscreen state"
|
||||||
|
set descriptions[147] "Print tail of the log"
|
||||||
|
set descriptions[148] "Swap the active workspaces between two monitors"
|
||||||
|
set descriptions[149] "Change the current mapping group"
|
||||||
|
set descriptions[151] "Behave as moveintogroup"
|
||||||
|
set descriptions[152] "Get the current cursor pos in global layout coordinates"
|
||||||
|
set descriptions[154] "Focus the requested workspace"
|
||||||
|
|
||||||
set --local literal_transitions
|
set literal_transitions
|
||||||
set literal_transitions[1] "set inputs 106 76 34 36 2 3 79 108 38 112 42 47 116 86 117 53 89 55 91 121 123 125 16 60 61 18 126 20 128 130 26 69 99 100 28 29 103 105; set tos 2 3 4 5 3 3 3 6 3 5 3 3 3 7 9 3 5 3 10 3 3 3 3 11 3 12 13 3 3 3 14 3 5 3 3 15 3 5"
|
set literal_transitions[1] "set inputs 121 44 126 82 4 52 51 129 90 59 9 11 12 131 14 98 102 103 134 101 138 23 20 141 26 144 108 147 70 34 35 79 115 38 152 117 122 124 40 43 80 119; set tos 15 3 22 3 22 3 3 3 3 22 3 3 4 5 6 7 3 22 8 3 3 3 3 9 3 3 10 11 3 3 3 22 3 3 3 3 14 22 12 22 16 13"
|
||||||
set literal_transitions[4] "set inputs 74 14 33 56 57 92 107 124 78 17 127 4 6 65 132 134 82 135 85 32 50 13 87 11 88 142; set tos 18 3 18 18 18 18 3 3 2 3 18 2 3 18 3 18 18 18 18 18 3 3 18 18 18 18"
|
set literal_transitions[2] "set inputs 82 52 51 129 9 90 11 12 131 14 98 102 134 101 23 20 138 141 26 144 108 147 70 34 35 115 38 152 117 40 119 122 121 80 44; set tos 3 3 3 3 3 3 3 4 5 6 7 3 8 3 3 3 3 9 3 3 10 11 3 3 3 3 3 3 3 12 13 14 15 16 3"
|
||||||
set literal_transitions[8] "set inputs 106 76 34 2 3 79 108 38 42 47 116 86 117 53 55 91 121 123 125 16 60 61 18 126 20 128 130 26 69 100 28 29 103; set tos 2 3 4 3 3 3 6 3 3 3 3 7 9 3 3 10 3 3 3 3 11 3 12 13 3 3 3 14 3 3 3 15 3"
|
set literal_transitions[4] "set inputs 140 64 65 46 106 28 27 53 6 67 68 130 114 13 75 100 36 153 99 60 118 42 18 139 155 123; set tos 3 17 17 17 17 3 3 5 17 3 17 17 17 3 5 3 17 17 17 17 17 17 3 17 3 17"
|
||||||
set literal_transitions[9] "set inputs 102 131 133 1 75 37 109 110 39 111 5 80 41 81 114 7 43 44 83 84 48 49 10 51 52 54 12 113 90 119 58 93 59 94 95 62 63 129 96 64 21 98 23 24 66 67 136 137 25 27 70 101 71 141 30 72; set tos 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3"
|
set literal_transitions[7] "set inputs 127; set tos 3"
|
||||||
set literal_transitions[10] "set inputs 118 115; set tos 21 17"
|
set literal_transitions[11] "set inputs 57; set tos 3"
|
||||||
set literal_transitions[12] "set inputs 104; set tos 3"
|
set literal_transitions[12] "set inputs 10; set tos 3"
|
||||||
set literal_transitions[14] "set inputs 22 120 31 140 122 45 73; set tos 2 2 2 2 2 2 2"
|
set literal_transitions[13] "set inputs 15 81; set tos 20 23"
|
||||||
set literal_transitions[15] "set inputs 40; set tos 3"
|
set literal_transitions[14] "set inputs 143; set tos 3"
|
||||||
set literal_transitions[16] "set inputs 139 97; set tos 3 3"
|
set literal_transitions[15] "set inputs 1 85 3 86 5 88 89 91 92 93 94 95 97 16 19 104 22 105 24 25 29 30 31 109 112 33 113 37 39 120 125 47 48 49 50 54 56 132 133 135 136 61 137 142 66 145 146 69 148 71 72 73 74 149 76 77 151 154; set tos 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 21 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3"
|
||||||
set literal_transitions[18] "set inputs 19 8; set tos 3 3"
|
set literal_transitions[16] "set inputs 87 7 110 62 78 55 63; set tos 5 5 5 5 5 5 5"
|
||||||
set literal_transitions[19] "set inputs 77; set tos 20"
|
set literal_transitions[17] "set inputs 41 45; set tos 3 3"
|
||||||
set literal_transitions[20] "set inputs 35 46; set tos 5 5"
|
set literal_transitions[18] "set inputs 8; set tos 24"
|
||||||
set literal_transitions[21] "set inputs 9 68 15 138; set tos 3 3 3 3"
|
set literal_transitions[19] "set inputs 32 150; set tos 3 3"
|
||||||
|
set literal_transitions[20] "set inputs 96 17 116 21; set tos 3 3 3 3"
|
||||||
|
set literal_transitions[21] "set inputs 107 83 128 2 84; set tos 3 3 3 3 3"
|
||||||
|
set literal_transitions[24] "set inputs 58 111; set tos 22 22"
|
||||||
|
|
||||||
set --local match_anything_transitions_from 2 1 7 16 11 6 15 8 3 17 13 12
|
set match_anything_transitions_from 7 8 1 23 6 5 3 19 12 9 10 14 11 2
|
||||||
set --local match_anything_transitions_to 3 8 3 3 3 16 19 8 19 3 3 19
|
set match_anything_transitions_to 18 3 2 3 19 3 18 3 18 3 3 18 18 2
|
||||||
|
|
||||||
set --local state 1
|
set state 1
|
||||||
set --local word_index 2
|
set word_index 2
|
||||||
while test $word_index -lt $COMP_CWORD
|
while test $word_index -lt $COMP_CWORD
|
||||||
set --local -- word $COMP_WORDS[$word_index]
|
set -- word $COMP_WORDS[$word_index]
|
||||||
|
|
||||||
if set --query literal_transitions[$state] && test -n $literal_transitions[$state]
|
if set --query literal_transitions[$state] && test -n $literal_transitions[$state]
|
||||||
set --local --erase inputs
|
set --erase inputs
|
||||||
set --local --erase tos
|
set --erase tos
|
||||||
eval $literal_transitions[$state]
|
eval $literal_transitions[$state]
|
||||||
|
|
||||||
if contains -- $word $literals
|
if contains -- $word $literals
|
||||||
set --local literal_matched 0
|
set literal_matched 0
|
||||||
for literal_id in (seq 1 (count $literals))
|
for literal_id in (seq 1 (count $literals))
|
||||||
if test $literals[$literal_id] = $word
|
if test $literals[$literal_id] = $word
|
||||||
set --local index (contains --index -- $literal_id $inputs)
|
set index (contains --index -- $literal_id $inputs)
|
||||||
set state $tos[$index]
|
set state $tos[$index]
|
||||||
set word_index (math $word_index + 1)
|
set word_index (math $word_index + 1)
|
||||||
set literal_matched 1
|
set literal_matched 1
|
||||||
|
|
@ -181,7 +196,7 @@ function _hyprctl
|
||||||
end
|
end
|
||||||
|
|
||||||
if set --query match_anything_transitions_from[$state] && test -n $match_anything_transitions_from[$state]
|
if set --query match_anything_transitions_from[$state] && test -n $match_anything_transitions_from[$state]
|
||||||
set --local index (contains --index -- $state $match_anything_transitions_from)
|
set index (contains --index -- $state $match_anything_transitions_from)
|
||||||
set state $match_anything_transitions_to[$index]
|
set state $match_anything_transitions_to[$index]
|
||||||
set word_index (math $word_index + 1)
|
set word_index (math $word_index + 1)
|
||||||
continue
|
continue
|
||||||
|
|
@ -191,8 +206,8 @@ function _hyprctl
|
||||||
end
|
end
|
||||||
|
|
||||||
if set --query literal_transitions[$state] && test -n $literal_transitions[$state]
|
if set --query literal_transitions[$state] && test -n $literal_transitions[$state]
|
||||||
set --local --erase inputs
|
set --erase inputs
|
||||||
set --local --erase tos
|
set --erase tos
|
||||||
eval $literal_transitions[$state]
|
eval $literal_transitions[$state]
|
||||||
for literal_id in $inputs
|
for literal_id in $inputs
|
||||||
if test -n $descriptions[$literal_id]
|
if test -n $descriptions[$literal_id]
|
||||||
|
|
@ -203,14 +218,14 @@ function _hyprctl
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
set command_states 6 17 13 11
|
set command_states 8 23 9 6
|
||||||
set command_ids 2 3 4 1
|
set command_ids 1 2 4 3
|
||||||
if contains $state $command_states
|
if contains $state $command_states
|
||||||
set --local index (contains --index $state $command_states)
|
set index (contains --index $state $command_states)
|
||||||
set --local function_id $command_ids[$index]
|
set function_id $command_ids[$index]
|
||||||
set --local function_name _hyprctl_$function_id
|
set function_name _hyprctl_$function_id
|
||||||
set --local --erase inputs
|
set --erase inputs
|
||||||
set --local --erase tos
|
set --erase tos
|
||||||
$function_name "$COMP_WORDS[$COMP_CWORD]"
|
$function_name "$COMP_WORDS[$COMP_CWORD]"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
# This is a file feeded to complgen to generate bash/fish/zsh completions
|
# This is a file fed to complgen to generate bash/fish/zsh completions
|
||||||
# Repo: https://github.com/adaszko/complgen
|
# Repo: https://github.com/adaszko/complgen
|
||||||
# Generate completion scripts: "complgen aot --bash-script hyprctl.bash --fish-script hyprctl.fish --zsh-script hyprctl.zsh ./hyprctl.usage"
|
# Generate completion scripts: "complgen aot --bash-script hyprctl.bash --fish-script hyprctl.fish --zsh-script hyprctl.zsh ./hyprctl.usage"
|
||||||
|
|
||||||
|
|
@ -9,6 +9,7 @@ hyprctl [<OPTIONS>]... <ARGUMENTS>
|
||||||
| (-r) "Refresh state after issuing the command"
|
| (-r) "Refresh state after issuing the command"
|
||||||
| (--batch) "Execute a batch of commands separated by ;"
|
| (--batch) "Execute a batch of commands separated by ;"
|
||||||
| (-q | --quiet) "Disable output"
|
| (-q | --quiet) "Disable output"
|
||||||
|
| (-h | --help) "Prints the help message"
|
||||||
;
|
;
|
||||||
|
|
||||||
<WINDOWS> ::= {{{ hyprctl clients | awk '/class/{print $2}' }}};
|
<WINDOWS> ::= {{{ hyprctl clients | awk '/class/{print $2}' }}};
|
||||||
|
|
@ -59,16 +60,18 @@ hyprctl [<OPTIONS>]... <ARGUMENTS>
|
||||||
|
|
||||||
<ARGUMENTS> ::= (activewindow) "Get the active window name and its properties"
|
<ARGUMENTS> ::= (activewindow) "Get the active window name and its properties"
|
||||||
| (activeworkspace) "Get the active workspace name and its properties"
|
| (activeworkspace) "Get the active workspace name and its properties"
|
||||||
|
| (animations) "Gets the current config info about animations and beziers"
|
||||||
| (binds) "List all registered binds"
|
| (binds) "List all registered binds"
|
||||||
| (clients) "List all windows with their properties"
|
| (clients) "List all windows with their properties"
|
||||||
| (configerrors) "List all current config parsing errors"
|
| (configerrors) "List all current config parsing errors"
|
||||||
| (cursorpos) "Get the current cursor pos in global layout coordinates"
|
| (cursorpos) "Get the current cursor pos in global layout coordinates"
|
||||||
| (decorations <WINDOWS>) "List all decorations and their info"
|
| (decorations <WINDOWS>) "List all decorations and their info"
|
||||||
|
| (descriptions) "Return a parsable JSON with all the config options, descriptions, value types and ranges"
|
||||||
| (devices) "List all connected keyboards and mice"
|
| (devices) "List all connected keyboards and mice"
|
||||||
| (dismissnotify <NUM>) "Dismiss all or up to amount of notifications"
|
| (dismissnotify <NUM>) "Dismiss all or up to amount of notifications"
|
||||||
| (dispatch <DISPATCHERS>) "Issue a dispatch to call a keybind dispatcher with an arg"
|
| (dispatch <DISPATCHERS>) "Issue a dispatch to call a keybind dispatcher with an arg"
|
||||||
| (getoption) "Get the config option status (values)"
|
| (getoption) "Get the config option status (values)"
|
||||||
| (globalshortcuts) ""
|
| (globalshortcuts) "Lists all global shortcuts"
|
||||||
| (hyprpaper) "Interact with hyprpaper if present"
|
| (hyprpaper) "Interact with hyprpaper if present"
|
||||||
| (instances) "List all running Hyprland instances and their info"
|
| (instances) "List all running Hyprland instances and their info"
|
||||||
| (keyword <KEYWORDS>) "Issue a keyword to call a config keyword dynamically"
|
| (keyword <KEYWORDS>) "Issue a keyword to call a config keyword dynamically"
|
||||||
|
|
@ -79,8 +82,8 @@ hyprctl [<OPTIONS>]... <ARGUMENTS>
|
||||||
| (notify <NOTIFICATION_TYPES> <NUM>) "Send a notification using the built-in Hyprland notification system"
|
| (notify <NOTIFICATION_TYPES> <NUM>) "Send a notification using the built-in Hyprland notification system"
|
||||||
| (output (create (wayland | x11 | headless | auto) | remove <MONITORS>)) "Allows adding/removing fake outputs to a specific backend"
|
| (output (create (wayland | x11 | headless | auto) | remove <MONITORS>)) "Allows adding/removing fake outputs to a specific backend"
|
||||||
| (plugin <AVAILABLE_PLUGINS>) "Interact with a plugin"
|
| (plugin <AVAILABLE_PLUGINS>) "Interact with a plugin"
|
||||||
| (reload) "Force reload the config"
|
| (reload [config-only]) "Force reload the config"
|
||||||
| (rollinglog) "Print tail of the log"
|
| (rollinglog [-f]) "Print tail of the log"
|
||||||
| (setcursor) "Set the cursor theme and reloads the cursor manager"
|
| (setcursor) "Set the cursor theme and reloads the cursor manager"
|
||||||
| (seterror [disable]) "Set the hyprctl error string"
|
| (seterror [disable]) "Set the hyprctl error string"
|
||||||
| (setprop <PROPS>) "Set a property of a window"
|
| (setprop <PROPS>) "Set a property of a window"
|
||||||
|
|
@ -92,20 +95,29 @@ hyprctl [<OPTIONS>]... <ARGUMENTS>
|
||||||
| (workspaces) "List all workspaces with their properties"
|
| (workspaces) "List all workspaces with their properties"
|
||||||
;
|
;
|
||||||
|
|
||||||
|
<WINDOW_STATE> ::= (-1) "Current"
|
||||||
|
| (0) "None"
|
||||||
|
| (1) "Maximize no fullscreen"
|
||||||
|
| (2) "Fullscreen"
|
||||||
|
| (3) "Maximize and fullscreen"
|
||||||
|
;
|
||||||
|
|
||||||
<DISPATCHERS> ::= (exec) "Execute a shell command"
|
<DISPATCHERS> ::= (exec) "Execute a shell command"
|
||||||
| (execr) "Execute a raw shell command"
|
| (execr) "Execute a raw shell command"
|
||||||
| (pass) "Pass the key to a specified window"
|
| (pass) "Pass the key to a specified window"
|
||||||
| (sendshortcut) "On shortcut X sends shortcut Y to a specified window"
|
| (sendshortcut) "On shortcut X sends shortcut Y to a specified window"
|
||||||
|
| (sendkeystate) "Send a key with specific state (down/repeat/up) to a specified window (window must keep focus for events to continue)"
|
||||||
| (killactive) "Close the active window"
|
| (killactive) "Close the active window"
|
||||||
| (closewindow) "Close a specified window"
|
| (closewindow) "Close a specified window"
|
||||||
| (workspace) "Change the workspace"
|
| (workspace) "Change the workspace"
|
||||||
| (movetoworkspace) "Move the focused window to a workspace"
|
| (movetoworkspace) "Move the focused window to a workspace"
|
||||||
| (movetoworkspacesilent) "Move window doesnt switch to the workspace"
|
| (movetoworkspacesilent) "Move window doesn't switch to the workspace"
|
||||||
| (togglefloating) "Toggle the current window's floating state"
|
| (togglefloating) "Toggle the current window's floating state"
|
||||||
| (setfloating) "Set the current window's floating state to true"
|
| (setfloating) "Set the current window's floating state to true"
|
||||||
| (settiled) "Set the current window's floating state to false"
|
| (settiled) "Set the current window's floating state to false"
|
||||||
| (fullscreen) "Toggle the focused window's fullscreen state"
|
| (fullscreen) "Toggle the focused window's fullscreen state"
|
||||||
| (fakefullscreen) "Toggle the focused window's internal fullscreen state"
|
| (fakefullscreen) "Toggle the focused window's internal fullscreen state"
|
||||||
|
| (fullscreenstate <WINDOW_STATE>) "Sets the focused window’s fullscreen mode and the one sent to the client"
|
||||||
| (dpms) "Set all monitors' DPMS status"
|
| (dpms) "Set all monitors' DPMS status"
|
||||||
| (pin) "Pin a window"
|
| (pin) "Pin a window"
|
||||||
| (movefocus) "Move the focus in a direction"
|
| (movefocus) "Move the focus in a direction"
|
||||||
|
|
@ -148,4 +160,5 @@ hyprctl [<OPTIONS>]... <ARGUMENTS>
|
||||||
| (setignoregrouplock) "Temporarily enable or disable binds:ignore_group_lock"
|
| (setignoregrouplock) "Temporarily enable or disable binds:ignore_group_lock"
|
||||||
| (global) "Execute a Global Shortcut using the GlobalShortcuts portal"
|
| (global) "Execute a Global Shortcut using the GlobalShortcuts portal"
|
||||||
| (submap) "Change the current mapping group"
|
| (submap) "Change the current mapping group"
|
||||||
|
| (event) "Emits a custom event to socket2"
|
||||||
;
|
;
|
||||||
|
|
|
||||||
|
|
@ -1,145 +1,160 @@
|
||||||
#compdef hyprctl
|
#compdef hyprctl
|
||||||
|
|
||||||
_hyprctl_cmd_2 () {
|
_hyprctl_cmd_1 () {
|
||||||
hyprctl monitors | awk '/Monitor/{ print $2 }'
|
hyprctl monitors | awk '/Monitor/{ print $2 }'
|
||||||
}
|
}
|
||||||
|
|
||||||
_hyprctl_cmd_3 () {
|
_hyprctl_cmd_3 () {
|
||||||
hyprpm list | awk '/Plugin/{ print $4 }'
|
hyprctl clients | awk '/class/{print $2}'
|
||||||
}
|
}
|
||||||
|
|
||||||
_hyprctl_cmd_0 () {
|
_hyprctl_cmd_2 () {
|
||||||
hyprctl clients | awk '/class/{ print $2 }'
|
|
||||||
}
|
|
||||||
|
|
||||||
_hyprctl_cmd_1 () {
|
|
||||||
hyprctl devices | sed -n '/Keyboard at/{n; s/^\s\+//; p}'
|
hyprctl devices | sed -n '/Keyboard at/{n; s/^\s\+//; p}'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_hyprctl_cmd_0 () {
|
||||||
|
hyprpm list | awk '/Plugin/{print $4}'
|
||||||
|
}
|
||||||
|
|
||||||
_hyprctl () {
|
_hyprctl () {
|
||||||
local -a literals=("cyclenext" "globalshortcuts" "cursorpos" "bordersize" "renameworkspace" "animationstyle" "focuswindow" "0" "auto" "swapnext" "forceallowsinput" "moveactive" "activebordercolor" "alphafullscreen" "wayland" "layers" "minsize" "monitors" "1" "kill" "settiled" "3" "focusmonitor" "swapwindow" "moveoutofgroup" "notify" "movecursor" "setcursor" "seterror" "movecurrentworkspacetomonitor" "4" "nomaxsize" "forcenoanims" "setprop" "-i" "-q" "togglefloating" "workspacerules" "movetoworkspace" "disable" "setignoregrouplock" "workspaces" "movegroupwindow" "closewindow" "0" "--instance" "binds" "movewindow" "splitratio" "alpha" "denywindowfromgroup" "workspace" "configerrors" "togglegroup" "getoption" "forceopaque" "keepaspectratio" "killactive" "pass" "decorations" "devices" "focuscurrentorlast" "submap" "global" "alphafullscreenoverride" "forcerendererreload" "movewindowpixel" "headless" "version" "dpms" "resizeactive" "moveintogroup" "5" "alphaoverride" "setfloating" "rollinglog" "::=" "rounding" "layouts" "moveworkspacetomonitor" "exec" "alphainactiveoverride" "alterzorder" "fakefullscreen" "nofocus" "keyword" "forcenoborder" "forcenodim" "--quiet" "pin" "output" "forcenoblur" "togglespecialworkspace" "fullscreen" "toggleopaque" "focusworkspaceoncurrentmonitor" "next" "changegroupactive" "-j" "instances" "execr" "exit" "clients" "all" "--batch" "dismissnotify" "inactivebordercolor" "switchxkblayout" "movetoworkspacesilent" "tagwindow" "movewindoworgroup" "-r" "movefocus" "focusurgentorlast" "remove" "activeworkspace" "dispatch" "create" "centerwindow" "2" "hyprpaper" "-1" "reload" "alphainactive" "systeminfo" "plugin" "dimaround" "activewindow" "swapactiveworkspaces" "splash" "sendshortcut" "maxsize" "lockactivegroup" "windowdancecompat" "forceopaqueoverriden" "lockgroups" "movecursortocorner" "x11" "prev" "1" "resizewindowpixel" "forcenoshadow")
|
local -a literals=("resizeactive" "2" "changegroupactive" "-r" "moveintogroup" "forceallowsinput" "4" "::=" "systeminfo" "all" "layouts" "setprop" "animationstyle" "switchxkblayout" "create" "denywindowfromgroup" "headless" "activebordercolor" "exec" "setcursor" "wayland" "focusurgentorlast" "workspacerules" "movecurrentworkspacetomonitor" "movetoworkspacesilent" "hyprpaper" "alpha" "inactivebordercolor" "movegroupwindow" "movecursortocorner" "movewindowpixel" "prev" "movewindow" "globalshortcuts" "clients" "dimaround" "setignoregrouplock" "splash" "execr" "monitors" "0" "forcenoborder" "-q" "animations" "1" "nomaxsize" "splitratio" "moveactive" "pass" "swapnext" "devices" "layers" "rounding" "lockactivegroup" "5" "moveworkspacetomonitor" "-f" "-i" "--quiet" "forcenodim" "pin" "0" "1" "forceopaque" "forcenoshadow" "setfloating" "minsize" "alphaoverride" "sendshortcut" "workspaces" "cyclenext" "alterzorder" "togglegroup" "lockgroups" "bordersize" "dpms" "focuscurrentorlast" "-1" "--batch" "notify" "remove" "instances" "1" "3" "moveoutofgroup" "killactive" "2" "movetoworkspace" "movecursor" "configerrors" "closewindow" "swapwindow" "tagwindow" "forcerendererreload" "centerwindow" "auto" "focuswindow" "seterror" "nofocus" "alphafullscreen" "binds" "version" "-h" "togglespecialworkspace" "fullscreen" "windowdancecompat" "0" "keyword" "toggleopaque" "3" "--instance" "togglefloating" "renameworkspace" "alphafullscreenoverride" "activeworkspace" "x11" "kill" "forceopaqueoverriden" "output" "global" "dispatch" "reload" "forcenoblur" "-j" "event" "--help" "disable" "-1" "activewindow" "keepaspectratio" "dismissnotify" "focusmonitor" "movefocus" "plugin" "exit" "workspace" "fullscreenstate" "getoption" "alphainactiveoverride" "alphainactive" "decorations" "settiled" "config-only" "descriptions" "resizewindowpixel" "fakefullscreen" "rollinglog" "swapactiveworkspaces" "submap" "next" "movewindoworgroup" "cursorpos" "forcenoanims" "focusworkspaceoncurrentmonitor" "maxsize" "sendkeystate")
|
||||||
|
|
||||||
local -A descriptions
|
local -A descriptions
|
||||||
descriptions[1]="Focus the next window on a workspace"
|
descriptions[1]="Resize the active window"
|
||||||
descriptions[3]="Get the current cursor pos in global layout coordinates"
|
descriptions[2]="Fullscreen"
|
||||||
descriptions[5]="Rename a workspace"
|
descriptions[3]="Switch to the next window in a group"
|
||||||
descriptions[7]="Focus the first window matching"
|
descriptions[4]="Refresh state after issuing the command"
|
||||||
descriptions[10]="Swap the focused window with the next window"
|
descriptions[5]="Move the active window into a group"
|
||||||
descriptions[12]="Move the active window"
|
descriptions[7]="CONFUSED"
|
||||||
descriptions[16]="List the layers"
|
descriptions[9]="Print system info"
|
||||||
descriptions[18]="List active outputs with their properties"
|
descriptions[11]="List all layouts available (including plugin ones)"
|
||||||
descriptions[20]="Get into a kill mode, where you can kill an app by clicking on it"
|
descriptions[12]="Set a property of a window"
|
||||||
descriptions[21]="Set the current window's floating state to false"
|
descriptions[14]="Set the xkb layout index for a keyboard"
|
||||||
descriptions[22]="ERROR"
|
descriptions[16]="Prohibit the active window from becoming or being inserted into group"
|
||||||
descriptions[23]="Focus a monitor"
|
descriptions[19]="Execute a shell command"
|
||||||
descriptions[24]="Swap the active window with another window"
|
descriptions[20]="Set the cursor theme and reloads the cursor manager"
|
||||||
descriptions[25]="Move the active window out of a group"
|
descriptions[22]="Focus the urgent window or the last window"
|
||||||
descriptions[26]="Send a notification using the built-in Hyprland notification system"
|
descriptions[23]="Get the list of defined workspace rules"
|
||||||
descriptions[27]="Move the cursor to a specified position"
|
descriptions[24]="Move the active workspace to a monitor"
|
||||||
descriptions[28]="Set the cursor theme and reloads the cursor manager"
|
descriptions[25]="Move window doesn't switch to the workspace"
|
||||||
descriptions[29]="Set the hyprctl error string"
|
descriptions[26]="Interact with hyprpaper if present"
|
||||||
descriptions[30]="Move the active workspace to a monitor"
|
descriptions[29]="Swap the active window with the next or previous in a group"
|
||||||
descriptions[31]="CONFUSED"
|
descriptions[30]="Move the cursor to the corner of the active window"
|
||||||
descriptions[34]="Set a property of a window"
|
descriptions[31]="Move a selected window"
|
||||||
descriptions[35]="Specify the Hyprland instance"
|
descriptions[33]="Move the active window in a direction or to a monitor"
|
||||||
descriptions[36]="Disable output"
|
descriptions[34]="Lists all global shortcuts"
|
||||||
descriptions[37]="Toggle the current window's floating state"
|
descriptions[35]="List all windows with their properties"
|
||||||
descriptions[38]="Get the list of defined workspace rules"
|
descriptions[37]="Temporarily enable or disable binds:ignore_group_lock"
|
||||||
descriptions[39]="Move the focused window to a workspace"
|
descriptions[38]="Print the current random splash"
|
||||||
descriptions[41]="Temporarily enable or disable binds:ignore_group_lock"
|
descriptions[39]="Execute a raw shell command"
|
||||||
descriptions[42]="List all workspaces with their properties"
|
descriptions[40]="List active outputs with their properties"
|
||||||
descriptions[43]="Swap the active window with the next or previous in a group"
|
descriptions[43]="Disable output"
|
||||||
descriptions[44]="Close a specified window"
|
descriptions[44]="Gets the current config info about animations and beziers"
|
||||||
descriptions[45]="WARNING"
|
descriptions[47]="Change the split ratio"
|
||||||
descriptions[46]="Specify the Hyprland instance"
|
descriptions[48]="Move the active window"
|
||||||
descriptions[47]="List all registered binds"
|
descriptions[49]="Pass the key to a specified window"
|
||||||
descriptions[48]="Move the active window in a direction or to a monitor"
|
descriptions[50]="Swap the focused window with the next window"
|
||||||
descriptions[49]="Change the split ratio"
|
descriptions[51]="List all connected keyboards and mice"
|
||||||
descriptions[51]="Prohibit the active window from becoming or being inserted into group"
|
descriptions[52]="List the layers"
|
||||||
descriptions[52]="Change the workspace"
|
descriptions[54]="Lock the focused group"
|
||||||
descriptions[53]="List all current config parsing errors"
|
descriptions[55]="OK"
|
||||||
descriptions[54]="Toggle the current active window into a group"
|
descriptions[56]="Move a workspace to a monitor"
|
||||||
descriptions[55]="Get the config option status (values)"
|
descriptions[58]="Specify the Hyprland instance"
|
||||||
descriptions[58]="Close the active window"
|
descriptions[59]="Disable output"
|
||||||
descriptions[59]="Pass the key to a specified window"
|
descriptions[61]="Pin a window"
|
||||||
descriptions[60]="List all decorations and their info"
|
descriptions[62]="WARNING"
|
||||||
descriptions[61]="List all connected keyboards and mice"
|
descriptions[63]="INFO"
|
||||||
descriptions[62]="Switch focus from current to previously focused window"
|
descriptions[66]="Set the current window's floating state to true"
|
||||||
descriptions[63]="Change the current mapping group"
|
descriptions[69]="On shortcut X sends shortcut Y to a specified window"
|
||||||
descriptions[64]="Execute a Global Shortcut using the GlobalShortcuts portal"
|
descriptions[70]="List all workspaces with their properties"
|
||||||
descriptions[66]="Force the renderer to reload all resources and outputs"
|
descriptions[71]="Focus the next window on a workspace"
|
||||||
descriptions[67]="Move a selected window"
|
descriptions[72]="Modify the window stack order of the active or specified window"
|
||||||
descriptions[69]="Print the Hyprland version: flags, commit and branch of build"
|
descriptions[73]="Toggle the current active window into a group"
|
||||||
descriptions[70]="Set all monitors' DPMS status"
|
descriptions[74]="Lock the groups"
|
||||||
descriptions[71]="Resize the active window"
|
descriptions[76]="Set all monitors' DPMS status"
|
||||||
descriptions[72]="Move the active window into a group"
|
descriptions[77]="Switch focus from current to previously focused window"
|
||||||
descriptions[73]="OK"
|
descriptions[78]="No Icon"
|
||||||
descriptions[75]="Set the current window's floating state to true"
|
descriptions[79]="Execute a batch of commands separated by ;"
|
||||||
descriptions[76]="Print tail of the log"
|
descriptions[80]="Send a notification using the built-in Hyprland notification system"
|
||||||
descriptions[79]="List all layouts available (including plugin ones)"
|
descriptions[82]="List all running Hyprland instances and their info"
|
||||||
descriptions[80]="Move a workspace to a monitor"
|
descriptions[83]="Maximize no fullscreen"
|
||||||
descriptions[81]="Execute a shell command"
|
descriptions[84]="Maximize and fullscreen"
|
||||||
descriptions[83]="Modify the window stack order of the active or specified window"
|
descriptions[85]="Move the active window out of a group"
|
||||||
descriptions[84]="Toggle the focused window's internal fullscreen state"
|
descriptions[86]="Close the active window"
|
||||||
descriptions[86]="Issue a keyword to call a config keyword dynamically"
|
descriptions[87]="HINT"
|
||||||
descriptions[89]="Disable output"
|
descriptions[88]="Move the focused window to a workspace"
|
||||||
descriptions[90]="Pin a window"
|
descriptions[89]="Move the cursor to a specified position"
|
||||||
descriptions[91]="Allows adding/removing fake outputs to a specific backend"
|
descriptions[90]="List all current config parsing errors"
|
||||||
descriptions[93]="Toggle a special workspace on/off"
|
descriptions[91]="Close a specified window"
|
||||||
descriptions[94]="Toggle the focused window's fullscreen state"
|
descriptions[92]="Swap the active window with another window"
|
||||||
descriptions[95]="Toggle the current window to always be opaque"
|
descriptions[93]="Apply a tag to the window"
|
||||||
descriptions[96]="Focus the requested workspace"
|
descriptions[94]="Force the renderer to reload all resources and outputs"
|
||||||
descriptions[98]="Switch to the next window in a group"
|
descriptions[95]="Center the active window"
|
||||||
descriptions[99]="Output in JSON format"
|
descriptions[97]="Focus the first window matching"
|
||||||
descriptions[100]="List all running Hyprland instances and their info"
|
descriptions[98]="Set the hyprctl error string"
|
||||||
descriptions[101]="Execute a raw shell command"
|
descriptions[101]="List all registered binds"
|
||||||
descriptions[102]="Exit the compositor with no questions asked"
|
descriptions[102]="Print the Hyprland version: flags, commit and branch of build"
|
||||||
descriptions[103]="List all windows with their properties"
|
descriptions[103]="Prints the help message"
|
||||||
descriptions[105]="Execute a batch of commands separated by ;"
|
descriptions[104]="Toggle a special workspace on/off"
|
||||||
descriptions[106]="Dismiss all or up to amount of notifications"
|
descriptions[105]="Toggle the focused window's fullscreen state"
|
||||||
descriptions[108]="Set the xkb layout index for a keyboard"
|
descriptions[107]="None"
|
||||||
descriptions[109]="Move window doesnt switch to the workspace"
|
descriptions[108]="Issue a keyword to call a config keyword dynamically"
|
||||||
descriptions[110]="Apply a tag to the window"
|
descriptions[109]="Toggle the current window to always be opaque"
|
||||||
descriptions[111]="Behave as moveintogroup"
|
descriptions[110]="ERROR"
|
||||||
descriptions[112]="Refresh state after issuing the command"
|
descriptions[111]="Specify the Hyprland instance"
|
||||||
descriptions[113]="Move the focus in a direction"
|
descriptions[112]="Toggle the current window's floating state"
|
||||||
descriptions[114]="Focus the urgent window or the last window"
|
descriptions[113]="Rename a workspace"
|
||||||
descriptions[116]="Get the active workspace name and its properties"
|
descriptions[115]="Get the active workspace name and its properties"
|
||||||
descriptions[117]="Issue a dispatch to call a keybind dispatcher with an arg"
|
descriptions[117]="Get into a kill mode, where you can kill an app by clicking on it"
|
||||||
descriptions[119]="Center the active window"
|
descriptions[119]="Allows adding/removing fake outputs to a specific backend"
|
||||||
descriptions[120]="HINT"
|
descriptions[120]="Execute a Global Shortcut using the GlobalShortcuts portal"
|
||||||
descriptions[121]="Interact with hyprpaper if present"
|
descriptions[121]="Issue a dispatch to call a keybind dispatcher with an arg"
|
||||||
descriptions[122]="No Icon"
|
descriptions[122]="Force reload the config"
|
||||||
descriptions[123]="Force reload the config"
|
descriptions[124]="Output in JSON format"
|
||||||
descriptions[125]="Print system info"
|
descriptions[125]="Emits a custom event to socket2"
|
||||||
descriptions[126]="Interact with a plugin"
|
descriptions[126]="Prints the help message"
|
||||||
descriptions[128]="Get the active window name and its properties"
|
descriptions[128]="Current"
|
||||||
descriptions[129]="Swap the active workspaces between two monitors"
|
descriptions[129]="Get the active window name and its properties"
|
||||||
descriptions[130]="Print the current random splash"
|
descriptions[131]="Dismiss all or up to amount of notifications"
|
||||||
descriptions[131]="On shortcut X sends shortcut Y to a specified window"
|
descriptions[132]="Focus a monitor"
|
||||||
descriptions[133]="Lock the focused group"
|
descriptions[133]="Move the focus in a direction"
|
||||||
descriptions[136]="Lock the groups"
|
descriptions[134]="Interact with a plugin"
|
||||||
descriptions[137]="Move the cursor to the corner of the active window"
|
descriptions[135]="Exit the compositor with no questions asked"
|
||||||
descriptions[140]="INFO"
|
descriptions[136]="Change the workspace"
|
||||||
descriptions[141]="Resize a selected window"
|
descriptions[137]="Sets the focused window’s fullscreen mode and the one sent to the client"
|
||||||
|
descriptions[138]="Get the config option status (values)"
|
||||||
|
descriptions[141]="List all decorations and their info"
|
||||||
|
descriptions[142]="Set the current window's floating state to false"
|
||||||
|
descriptions[144]="Return a parsable JSON with all the config options, descriptions, value types and ranges"
|
||||||
|
descriptions[145]="Resize a selected window"
|
||||||
|
descriptions[146]="Toggle the focused window's internal fullscreen state"
|
||||||
|
descriptions[147]="Print tail of the log"
|
||||||
|
descriptions[148]="Swap the active workspaces between two monitors"
|
||||||
|
descriptions[149]="Change the current mapping group"
|
||||||
|
descriptions[151]="Behave as moveintogroup"
|
||||||
|
descriptions[152]="Get the current cursor pos in global layout coordinates"
|
||||||
|
descriptions[154]="Focus the requested workspace"
|
||||||
|
|
||||||
local -A literal_transitions
|
local -A literal_transitions
|
||||||
literal_transitions[1]="([106]=2 [76]=3 [34]=4 [36]=5 [2]=3 [3]=3 [79]=3 [108]=6 [38]=3 [112]=5 [42]=3 [47]=3 [116]=3 [86]=7 [117]=9 [53]=3 [89]=5 [55]=3 [91]=10 [121]=3 [123]=3 [125]=3 [16]=3 [60]=11 [61]=3 [18]=12 [126]=13 [20]=3 [128]=3 [130]=3 [26]=14 [69]=3 [99]=5 [100]=3 [28]=3 [29]=15 [103]=3 [105]=5)"
|
literal_transitions[1]="([121]=15 [44]=3 [126]=22 [82]=3 [4]=22 [52]=3 [51]=3 [129]=3 [90]=3 [59]=22 [9]=3 [11]=3 [12]=4 [131]=5 [14]=6 [98]=7 [102]=3 [103]=22 [134]=8 [101]=3 [138]=3 [23]=3 [20]=3 [141]=9 [26]=3 [144]=3 [108]=10 [147]=11 [70]=3 [34]=3 [35]=3 [79]=22 [115]=3 [38]=3 [152]=3 [117]=3 [122]=14 [124]=22 [40]=12 [43]=22 [80]=16 [119]=13)"
|
||||||
literal_transitions[4]="([74]=18 [14]=3 [33]=18 [56]=18 [57]=18 [92]=18 [107]=3 [124]=3 [78]=2 [17]=3 [127]=18 [4]=2 [6]=3 [65]=18 [132]=3 [134]=18 [82]=18 [135]=18 [85]=18 [32]=18 [50]=3 [13]=3 [87]=18 [11]=18 [88]=18 [142]=18)"
|
literal_transitions[2]="([82]=3 [52]=3 [51]=3 [129]=3 [9]=3 [90]=3 [11]=3 [12]=4 [131]=5 [14]=6 [98]=7 [102]=3 [134]=8 [101]=3 [23]=3 [20]=3 [138]=3 [141]=9 [26]=3 [144]=3 [108]=10 [147]=11 [70]=3 [34]=3 [35]=3 [115]=3 [38]=3 [152]=3 [117]=3 [40]=12 [119]=13 [122]=14 [121]=15 [80]=16 [44]=3)"
|
||||||
literal_transitions[8]="([106]=2 [76]=3 [34]=4 [2]=3 [3]=3 [79]=3 [108]=6 [38]=3 [42]=3 [47]=3 [116]=3 [86]=7 [117]=9 [53]=3 [55]=3 [91]=10 [121]=3 [123]=3 [125]=3 [16]=3 [60]=11 [61]=3 [18]=12 [126]=13 [20]=3 [128]=3 [130]=3 [26]=14 [69]=3 [100]=3 [28]=3 [29]=15 [103]=3)"
|
literal_transitions[4]="([140]=3 [64]=17 [65]=17 [46]=17 [106]=17 [28]=3 [27]=3 [53]=5 [6]=17 [67]=3 [68]=17 [130]=17 [114]=17 [13]=3 [75]=5 [100]=3 [36]=17 [153]=17 [99]=17 [60]=17 [118]=17 [42]=17 [18]=3 [139]=17 [155]=3 [123]=17)"
|
||||||
literal_transitions[9]="([102]=3 [131]=3 [133]=3 [1]=3 [75]=3 [37]=3 [109]=3 [110]=3 [39]=3 [111]=3 [5]=3 [80]=3 [41]=3 [81]=3 [114]=3 [7]=3 [43]=3 [44]=3 [83]=3 [84]=3 [48]=3 [49]=3 [10]=3 [51]=3 [52]=3 [54]=3 [12]=3 [113]=3 [90]=3 [119]=3 [58]=3 [93]=3 [59]=3 [94]=3 [95]=3 [62]=3 [63]=3 [129]=3 [96]=3 [64]=3 [21]=3 [98]=3 [23]=3 [24]=3 [66]=3 [67]=3 [136]=3 [137]=3 [25]=3 [27]=3 [70]=3 [101]=3 [71]=3 [141]=3 [30]=3 [72]=3)"
|
literal_transitions[7]="([127]=3)"
|
||||||
literal_transitions[10]="([118]=21 [115]=17)"
|
literal_transitions[11]="([57]=3)"
|
||||||
literal_transitions[12]="([104]=3)"
|
literal_transitions[12]="([10]=3)"
|
||||||
literal_transitions[14]="([22]=2 [120]=2 [31]=2 [140]=2 [122]=2 [45]=2 [73]=2)"
|
literal_transitions[13]="([15]=20 [81]=23)"
|
||||||
literal_transitions[15]="([40]=3)"
|
literal_transitions[14]="([143]=3)"
|
||||||
literal_transitions[16]="([139]=3 [97]=3)"
|
literal_transitions[15]="([1]=3 [85]=3 [3]=3 [86]=3 [5]=3 [88]=3 [89]=3 [91]=3 [92]=3 [93]=3 [94]=3 [95]=3 [97]=3 [16]=3 [19]=3 [104]=3 [22]=3 [105]=3 [24]=3 [25]=3 [29]=3 [30]=3 [31]=3 [109]=3 [112]=3 [33]=3 [113]=3 [37]=3 [39]=3 [120]=3 [125]=3 [47]=3 [48]=3 [49]=3 [50]=3 [54]=3 [56]=3 [132]=3 [133]=3 [135]=3 [136]=3 [61]=3 [137]=21 [142]=3 [66]=3 [145]=3 [146]=3 [69]=3 [148]=3 [71]=3 [72]=3 [73]=3 [74]=3 [149]=3 [76]=3 [77]=3 [151]=3 [154]=3)"
|
||||||
literal_transitions[18]="([19]=3 [8]=3)"
|
literal_transitions[16]="([87]=5 [7]=5 [110]=5 [62]=5 [78]=5 [55]=5 [63]=5)"
|
||||||
literal_transitions[19]="([77]=20)"
|
literal_transitions[17]="([41]=3 [45]=3)"
|
||||||
literal_transitions[20]="([35]=5 [46]=5)"
|
literal_transitions[18]="([8]=24)"
|
||||||
literal_transitions[21]="([9]=3 [68]=3 [15]=3 [138]=3)"
|
literal_transitions[19]="([32]=3 [150]=3)"
|
||||||
|
literal_transitions[20]="([96]=3 [17]=3 [116]=3 [21]=3)"
|
||||||
|
literal_transitions[21]="([107]=3 [83]=3 [128]=3 [2]=3 [84]=3)"
|
||||||
|
literal_transitions[24]="([58]=22 [111]=22)"
|
||||||
|
|
||||||
local -A match_anything_transitions
|
local -A match_anything_transitions
|
||||||
match_anything_transitions=([2]=3 [1]=8 [7]=3 [16]=3 [11]=3 [6]=16 [15]=19 [8]=8 [3]=19 [17]=3 [13]=3 [12]=19)
|
match_anything_transitions=([7]=18 [8]=3 [1]=2 [23]=3 [6]=19 [5]=3 [3]=18 [19]=3 [12]=18 [9]=3 [10]=3 [14]=18 [11]=18 [2]=2)
|
||||||
|
|
||||||
declare -A subword_transitions
|
declare -A subword_transitions
|
||||||
|
|
||||||
|
|
@ -199,7 +214,7 @@ _hyprctl () {
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
local -A commands=([6]=1 [17]=2 [13]=3 [11]=0)
|
local -A commands=([8]=0 [23]=1 [9]=3 [6]=2)
|
||||||
|
|
||||||
if [[ -v "commands[$state]" ]]; then
|
if [[ -v "commands[$state]" ]]; then
|
||||||
local command_id=${commands[$state]}
|
local command_id=${commands[$state]}
|
||||||
|
|
@ -252,4 +267,8 @@ _hyprctl () {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
compdef _hyprctl hyprctl
|
if [[ $ZSH_EVAL_CONTEXT =~ :file$ ]]; then
|
||||||
|
compdef _hyprctl hyprctl
|
||||||
|
else
|
||||||
|
_hyprctl
|
||||||
|
fi
|
||||||
|
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
executable('hyprctl', 'main.cpp',
|
|
||||||
dependencies: [
|
|
||||||
dependency('hyprutils', version: '>= 0.1.1'),
|
|
||||||
],
|
|
||||||
install: true
|
|
||||||
)
|
|
||||||
|
|
||||||
install_data('hyprctl.bash', install_dir: join_paths(get_option('datadir'), 'bash-completion/completions'), install_tag: 'runtime', rename: 'hyprctl')
|
|
||||||
install_data('hyprctl.fish', install_dir: join_paths(get_option('datadir'), 'fish/vendor_completions.d'), install_tag: 'runtime')
|
|
||||||
install_data('hyprctl.zsh', install_dir: join_paths(get_option('datadir'), 'zsh/site-functions'), install_tag: 'runtime', rename: '_hyprctl')
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
const std::string_view USAGE = R"#(usage: hyprctl [flags] <command> [args...|--help]
|
const std::string_view USAGE = R"#(usage: hyprctl [flags] <command> [args...|--help]
|
||||||
|
|
||||||
commands:
|
commands:
|
||||||
|
|
@ -20,6 +22,7 @@ commands:
|
||||||
getoption <option> → Gets the config option status (values)
|
getoption <option> → Gets the config option status (values)
|
||||||
globalshortcuts → Lists all global shortcuts
|
globalshortcuts → Lists all global shortcuts
|
||||||
hyprpaper ... → Issue a hyprpaper request
|
hyprpaper ... → Issue a hyprpaper request
|
||||||
|
hyprsunset ... → Issue a hyprsunset request
|
||||||
instances → Lists all running instances of Hyprland with
|
instances → Lists all running instances of Hyprland with
|
||||||
their info
|
their info
|
||||||
keyword <name> <value> → Issue a keyword to call a config keyword
|
keyword <name> <value> → Issue a keyword to call a config keyword
|
||||||
|
|
@ -46,6 +49,7 @@ commands:
|
||||||
the same format as in colors in config. Will reset
|
the same format as in colors in config. Will reset
|
||||||
when Hyprland's config is reloaded
|
when Hyprland's config is reloaded
|
||||||
setprop ... → Sets a window property
|
setprop ... → Sets a window property
|
||||||
|
getprop ... → Gets a window property
|
||||||
splash → Get the current splash
|
splash → Get the current splash
|
||||||
switchxkblayout ... → Sets the xkb layout index for a keyboard
|
switchxkblayout ... → Sets the xkb layout index for a keyboard
|
||||||
systeminfo → Get system info
|
systeminfo → Get system info
|
||||||
|
|
@ -70,11 +74,18 @@ flags:
|
||||||
const std::string_view HYPRPAPER_HELP = R"#(usage: hyprctl [flags] hyprpaper <request>
|
const std::string_view HYPRPAPER_HELP = R"#(usage: hyprctl [flags] hyprpaper <request>
|
||||||
|
|
||||||
requests:
|
requests:
|
||||||
listactive → Lists all active images
|
wallpaper → Issue a wallpaper to call a config wallpaper dynamically.
|
||||||
listloaded → Lists all loaded images
|
Arguments are [mon],[path],[fit_mode]. Fit mode is optional.
|
||||||
preload <path> → Preloads image
|
|
||||||
unload <path> → Unloads image. Pass 'all' as path to unload all images
|
flags:
|
||||||
wallpaper → Issue a wallpaper to call a config wallpaper dynamically
|
See 'hyprctl --help')#";
|
||||||
|
|
||||||
|
const std::string_view HYPRSUNSET_HELP = R"#(usage: hyprctl [flags] hyprsunset <request>
|
||||||
|
|
||||||
|
requests:
|
||||||
|
temperature <temp> → Enable blue-light filter
|
||||||
|
identity → Disable blue-light filter
|
||||||
|
gamma <gamma> → Enable gamma filter
|
||||||
|
|
||||||
flags:
|
flags:
|
||||||
See 'hyprctl --help')#";
|
See 'hyprctl --help')#";
|
||||||
|
|
@ -133,7 +144,7 @@ regex:
|
||||||
Regular expression by which a window will be searched
|
Regular expression by which a window will be searched
|
||||||
|
|
||||||
property:
|
property:
|
||||||
See https://wiki.hyprland.org/Configuring/Using-hyprctl/#setprop for list
|
See https://wiki.hypr.land/Configuring/Using-hyprctl/#setprop for list
|
||||||
of properties
|
of properties
|
||||||
|
|
||||||
value:
|
value:
|
||||||
|
|
@ -146,6 +157,18 @@ lock:
|
||||||
flags:
|
flags:
|
||||||
See 'hyprctl --help')#";
|
See 'hyprctl --help')#";
|
||||||
|
|
||||||
|
const std::string_view GETPROP_HELP = R"#(usage: hyprctl [flags] getprop <regex> <property>
|
||||||
|
|
||||||
|
regex:
|
||||||
|
Regular expression by which a window will be searched
|
||||||
|
|
||||||
|
property:
|
||||||
|
See https://wiki.hypr.land/Configuring/Using-hyprctl/#setprop for list
|
||||||
|
of properties
|
||||||
|
|
||||||
|
flags:
|
||||||
|
See 'hyprctl --help')#";
|
||||||
|
|
||||||
const std::string_view SWITCHXKBLAYOUT_HELP = R"#(usage: [flags] switchxkblayout <device> <cmd>
|
const std::string_view SWITCHXKBLAYOUT_HELP = R"#(usage: [flags] switchxkblayout <device> <cmd>
|
||||||
|
|
||||||
device:
|
device:
|
||||||
11
hyprctl/src/helpers/Memory.hpp
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <hyprutils/memory/SharedPtr.hpp>
|
||||||
|
#include <hyprutils/memory/UniquePtr.hpp>
|
||||||
|
#include <hyprutils/memory/Atomic.hpp>
|
||||||
|
|
||||||
|
using namespace Hyprutils::Memory;
|
||||||
|
|
||||||
|
#define SP CSharedPointer
|
||||||
|
#define WP CWeakPointer
|
||||||
|
#define UP CUniquePointer
|
||||||
208
hyprctl/src/hyprpaper/Hyprpaper.cpp
Normal file
|
|
@ -0,0 +1,208 @@
|
||||||
|
#include "Hyprpaper.hpp"
|
||||||
|
#include "../helpers/Memory.hpp"
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
|
#include <format>
|
||||||
|
#include <filesystem>
|
||||||
|
#include <print>
|
||||||
|
|
||||||
|
#include <hyprpaper_core-client.hpp>
|
||||||
|
|
||||||
|
#include <hyprutils/string/VarList2.hpp>
|
||||||
|
using namespace Hyprutils::String;
|
||||||
|
|
||||||
|
using namespace std::string_literals;
|
||||||
|
|
||||||
|
constexpr const char* SOCKET_NAME = ".hyprpaper.sock";
|
||||||
|
static SP<CCHyprpaperCoreImpl> g_coreImpl;
|
||||||
|
|
||||||
|
constexpr const uint32_t PROTOCOL_VERSION_SUPPORTED = 2;
|
||||||
|
|
||||||
|
//
|
||||||
|
static hyprpaperCoreWallpaperFitMode fitFromString(const std::string_view& sv) {
|
||||||
|
if (sv == "contain")
|
||||||
|
return HYPRPAPER_CORE_WALLPAPER_FIT_MODE_CONTAIN;
|
||||||
|
if (sv == "fit" || sv == "stretch")
|
||||||
|
return HYPRPAPER_CORE_WALLPAPER_FIT_MODE_STRETCH;
|
||||||
|
if (sv == "tile")
|
||||||
|
return HYPRPAPER_CORE_WALLPAPER_FIT_MODE_TILE;
|
||||||
|
return HYPRPAPER_CORE_WALLPAPER_FIT_MODE_COVER;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::expected<std::string, std::string> resolvePath(const std::string_view& sv) {
|
||||||
|
std::error_code ec;
|
||||||
|
auto can = std::filesystem::canonical(sv, ec);
|
||||||
|
|
||||||
|
if (ec)
|
||||||
|
return std::unexpected(std::format("invalid path: {}", ec.message()));
|
||||||
|
|
||||||
|
return can;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::expected<std::string, std::string> getFullPath(const std::string_view& sv) {
|
||||||
|
if (sv.empty())
|
||||||
|
return std::unexpected("empty path");
|
||||||
|
|
||||||
|
if (sv[0] == '~') {
|
||||||
|
static auto HOME = getenv("HOME");
|
||||||
|
if (!HOME || HOME[0] == '\0')
|
||||||
|
return std::unexpected("home path but no $HOME");
|
||||||
|
|
||||||
|
return resolvePath(std::string{HOME} + "/"s + std::string{sv.substr(1)});
|
||||||
|
}
|
||||||
|
|
||||||
|
return resolvePath(sv);
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::expected<void, std::string> doWallpaper(const std::string_view& RHS) {
|
||||||
|
CVarList2 args(std::string{RHS}, 0, ',');
|
||||||
|
|
||||||
|
const std::string MONITOR = std::string{args[0]};
|
||||||
|
const auto& PATH_RAW = args[1];
|
||||||
|
const auto& FIT = args[2];
|
||||||
|
|
||||||
|
if (PATH_RAW.empty())
|
||||||
|
return std::unexpected("not enough args");
|
||||||
|
|
||||||
|
const auto RTDIR = getenv("XDG_RUNTIME_DIR");
|
||||||
|
|
||||||
|
if (!RTDIR || RTDIR[0] == '\0')
|
||||||
|
return std::unexpected("can't send: no XDG_RUNTIME_DIR");
|
||||||
|
|
||||||
|
const auto HIS = getenv("HYPRLAND_INSTANCE_SIGNATURE");
|
||||||
|
|
||||||
|
if (!HIS || HIS[0] == '\0')
|
||||||
|
return std::unexpected("can't send: no HYPRLAND_INSTANCE_SIGNATURE (not running under hyprland)");
|
||||||
|
|
||||||
|
const auto PATH = getFullPath(PATH_RAW);
|
||||||
|
|
||||||
|
if (!PATH)
|
||||||
|
return std::unexpected(std::format("bad path: {}", PATH_RAW));
|
||||||
|
|
||||||
|
auto socketPath = RTDIR + "/hypr/"s + HIS + "/"s + SOCKET_NAME;
|
||||||
|
|
||||||
|
auto socket = Hyprwire::IClientSocket::open(socketPath);
|
||||||
|
|
||||||
|
if (!socket)
|
||||||
|
return std::unexpected("can't send: failed to connect to hyprpaper (is it running?)");
|
||||||
|
|
||||||
|
g_coreImpl = makeShared<CCHyprpaperCoreImpl>(PROTOCOL_VERSION_SUPPORTED);
|
||||||
|
|
||||||
|
socket->addImplementation(g_coreImpl);
|
||||||
|
|
||||||
|
if (!socket->waitForHandshake())
|
||||||
|
return std::unexpected("can't send: wire handshake failed");
|
||||||
|
|
||||||
|
auto spec = socket->getSpec(g_coreImpl->protocol()->specName());
|
||||||
|
|
||||||
|
if (!spec)
|
||||||
|
return std::unexpected("can't send: hyprpaper doesn't have the spec?!");
|
||||||
|
|
||||||
|
auto manager = makeShared<CCHyprpaperCoreManagerObject>(socket->bindProtocol(g_coreImpl->protocol(), std::min(PROTOCOL_VERSION_SUPPORTED, spec->specVer())));
|
||||||
|
|
||||||
|
if (!manager)
|
||||||
|
return std::unexpected("wire error: couldn't create manager");
|
||||||
|
|
||||||
|
auto wallpaper = makeShared<CCHyprpaperWallpaperObject>(manager->sendGetWallpaperObject());
|
||||||
|
|
||||||
|
if (!wallpaper)
|
||||||
|
return std::unexpected("wire error: couldn't create wallpaper object");
|
||||||
|
|
||||||
|
bool canExit = false;
|
||||||
|
std::optional<std::string> err;
|
||||||
|
|
||||||
|
wallpaper->setFailed([&canExit, &err](uint32_t code) {
|
||||||
|
canExit = true;
|
||||||
|
switch (code) {
|
||||||
|
case HYPRPAPER_CORE_APPLYING_ERROR_INVALID_PATH: err = std::format("failed to set wallpaper: Invalid path", code); break;
|
||||||
|
case HYPRPAPER_CORE_APPLYING_ERROR_INVALID_MONITOR: err = std::format("failed to set wallpaper: Invalid monitor", code); break;
|
||||||
|
default: err = std::format("failed to set wallpaper: unknown error, code {}", code); break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
wallpaper->setSuccess([&canExit]() { canExit = true; });
|
||||||
|
|
||||||
|
wallpaper->sendPath(PATH->c_str());
|
||||||
|
wallpaper->sendMonitorName(MONITOR.c_str());
|
||||||
|
if (!FIT.empty())
|
||||||
|
wallpaper->sendFitMode(fitFromString(FIT));
|
||||||
|
|
||||||
|
wallpaper->sendApply();
|
||||||
|
|
||||||
|
while (!canExit) {
|
||||||
|
socket->dispatchEvents(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (err)
|
||||||
|
return std::unexpected(*err);
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::expected<void, std::string> doListActive() {
|
||||||
|
const auto RTDIR = getenv("XDG_RUNTIME_DIR");
|
||||||
|
|
||||||
|
if (!RTDIR || RTDIR[0] == '\0')
|
||||||
|
return std::unexpected("can't send: no XDG_RUNTIME_DIR");
|
||||||
|
|
||||||
|
const auto HIS = getenv("HYPRLAND_INSTANCE_SIGNATURE");
|
||||||
|
|
||||||
|
if (!HIS || HIS[0] == '\0')
|
||||||
|
return std::unexpected("can't send: no HYPRLAND_INSTANCE_SIGNATURE (not running under hyprland)");
|
||||||
|
|
||||||
|
auto socketPath = RTDIR + "/hypr/"s + HIS + "/"s + SOCKET_NAME;
|
||||||
|
|
||||||
|
auto socket = Hyprwire::IClientSocket::open(socketPath);
|
||||||
|
|
||||||
|
if (!socket)
|
||||||
|
return std::unexpected("can't send: failed to connect to hyprpaper (is it running?)");
|
||||||
|
|
||||||
|
g_coreImpl = makeShared<CCHyprpaperCoreImpl>(PROTOCOL_VERSION_SUPPORTED);
|
||||||
|
|
||||||
|
socket->addImplementation(g_coreImpl);
|
||||||
|
|
||||||
|
if (!socket->waitForHandshake())
|
||||||
|
return std::unexpected("can't send: wire handshake failed");
|
||||||
|
|
||||||
|
auto spec = socket->getSpec(g_coreImpl->protocol()->specName());
|
||||||
|
|
||||||
|
if (!spec)
|
||||||
|
return std::unexpected("can't send: hyprpaper doesn't have the spec?!");
|
||||||
|
|
||||||
|
if (spec->specVer() < 2)
|
||||||
|
return std::unexpected("can't send: hyprpaper protocol version too low (hyprpaper too old)");
|
||||||
|
|
||||||
|
auto manager = makeShared<CCHyprpaperCoreManagerObject>(socket->bindProtocol(g_coreImpl->protocol(), std::min(PROTOCOL_VERSION_SUPPORTED, spec->specVer())));
|
||||||
|
|
||||||
|
if (!manager)
|
||||||
|
return std::unexpected("wire error: couldn't create manager");
|
||||||
|
|
||||||
|
auto status = makeShared<CCHyprpaperStatusObject>(manager->sendGetStatusObject());
|
||||||
|
|
||||||
|
status->setActiveWallpaper([](const char* mon, const char* wp) { std::println("{}: {}", mon, wp); });
|
||||||
|
|
||||||
|
socket->roundtrip();
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::expected<void, std::string> Hyprpaper::makeHyprpaperRequest(const std::string_view& rq) {
|
||||||
|
if (!rq.contains(' '))
|
||||||
|
return std::unexpected("Invalid request");
|
||||||
|
|
||||||
|
if (!rq.starts_with("/hyprpaper "))
|
||||||
|
return std::unexpected("Invalid request");
|
||||||
|
|
||||||
|
std::string_view LHS, RHS;
|
||||||
|
auto spacePos = rq.find(' ', 12);
|
||||||
|
LHS = rq.substr(11, spacePos - 11);
|
||||||
|
RHS = rq.substr(spacePos + 1);
|
||||||
|
|
||||||
|
if (LHS == "wallpaper")
|
||||||
|
return doWallpaper(RHS);
|
||||||
|
else if (LHS == "listactive")
|
||||||
|
return doListActive();
|
||||||
|
else
|
||||||
|
return std::unexpected("invalid hyprpaper request");
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
8
hyprctl/src/hyprpaper/Hyprpaper.hpp
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <expected>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace Hyprpaper {
|
||||||
|
std::expected<void, std::string> makeHyprpaperRequest(const std::string_view& rq);
|
||||||
|
};
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
#include <re2/re2.h>
|
||||||
|
|
||||||
#include <cctype>
|
#include <cctype>
|
||||||
#include <netdb.h>
|
#include <netdb.h>
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
|
|
@ -10,27 +12,26 @@
|
||||||
#include <sys/un.h>
|
#include <sys/un.h>
|
||||||
#include <pwd.h>
|
#include <pwd.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <ranges>
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <csignal>
|
#include <csignal>
|
||||||
#include <format>
|
#include <ranges>
|
||||||
|
#include <optional>
|
||||||
|
#include <charconv>
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <print>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <deque>
|
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <cstdarg>
|
#include <cstdarg>
|
||||||
#include <regex>
|
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <hyprutils/string/String.hpp>
|
#include <hyprutils/string/String.hpp>
|
||||||
|
#include <hyprutils/memory/Casts.hpp>
|
||||||
using namespace Hyprutils::String;
|
using namespace Hyprutils::String;
|
||||||
|
using namespace Hyprutils::Memory;
|
||||||
|
|
||||||
#include "Strings.hpp"
|
#include "Strings.hpp"
|
||||||
|
#include "hyprpaper/Hyprpaper.hpp"
|
||||||
#define PAD
|
|
||||||
|
|
||||||
std::string instanceSignature;
|
std::string instanceSignature;
|
||||||
bool quiet = false;
|
bool quiet = false;
|
||||||
|
|
@ -40,63 +41,100 @@ struct SInstanceData {
|
||||||
uint64_t time;
|
uint64_t time;
|
||||||
uint64_t pid;
|
uint64_t pid;
|
||||||
std::string wlSocket;
|
std::string wlSocket;
|
||||||
bool valid = true;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void log(std::string str) {
|
void log(const std::string_view str) {
|
||||||
if (quiet)
|
if (quiet)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
std::cout << str << "\n";
|
std::println("{}", str);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int getUID() {
|
||||||
|
const auto UID = getuid();
|
||||||
|
const auto PWUID = getpwuid(UID);
|
||||||
|
return PWUID ? PWUID->pw_uid : UID;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string getRuntimeDir() {
|
std::string getRuntimeDir() {
|
||||||
const auto XDG = getenv("XDG_RUNTIME_DIR");
|
const auto XDG = getenv("XDG_RUNTIME_DIR");
|
||||||
|
|
||||||
if (!XDG) {
|
if (!XDG) {
|
||||||
const std::string USERID = std::to_string(getpwuid(getuid())->pw_uid);
|
const std::string USERID = std::to_string(getUID());
|
||||||
return "/run/user/" + USERID + "/hypr";
|
return "/run/user/" + USERID + "/hypr";
|
||||||
}
|
}
|
||||||
|
|
||||||
return std::string{XDG} + "/hypr";
|
return std::string{XDG} + "/hypr";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static std::optional<uint64_t> toUInt64(const std::string_view str) {
|
||||||
|
uint64_t value = 0;
|
||||||
|
const auto [ptr, ec] = std::from_chars(str.data(), str.data() + str.size(), value);
|
||||||
|
if (ec != std::errc() || ptr != str.data() + str.size())
|
||||||
|
return std::nullopt;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::optional<SInstanceData> parseInstance(const std::filesystem::directory_entry& entry) {
|
||||||
|
if (!entry.is_directory())
|
||||||
|
return std::nullopt;
|
||||||
|
|
||||||
|
const auto lockPath = entry.path() / "hyprland.lock";
|
||||||
|
std::ifstream ifs(lockPath);
|
||||||
|
if (!ifs.is_open())
|
||||||
|
return std::nullopt;
|
||||||
|
|
||||||
|
SInstanceData data;
|
||||||
|
data.id = entry.path().filename().string();
|
||||||
|
|
||||||
|
const auto first = std::string_view{data.id}.find_first_of('_');
|
||||||
|
const auto last = std::string_view{data.id}.find_last_of('_');
|
||||||
|
if (first == std::string_view::npos || last == std::string_view::npos || last <= first)
|
||||||
|
return std::nullopt;
|
||||||
|
|
||||||
|
auto time = toUInt64(std::string_view{data.id}.substr(first + 1, last - first - 1));
|
||||||
|
if (!time)
|
||||||
|
return std::nullopt;
|
||||||
|
data.time = *time;
|
||||||
|
|
||||||
|
std::string line;
|
||||||
|
if (!std::getline(ifs, line))
|
||||||
|
return std::nullopt;
|
||||||
|
|
||||||
|
auto pid = toUInt64(std::string_view{line});
|
||||||
|
if (!pid)
|
||||||
|
return std::nullopt;
|
||||||
|
data.pid = *pid;
|
||||||
|
|
||||||
|
if (!std::getline(ifs, data.wlSocket))
|
||||||
|
return std::nullopt;
|
||||||
|
|
||||||
|
if (std::getline(ifs, line) && !line.empty())
|
||||||
|
return std::nullopt; // more lines than expected
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<SInstanceData> instances() {
|
std::vector<SInstanceData> instances() {
|
||||||
std::vector<SInstanceData> result;
|
std::vector<SInstanceData> result;
|
||||||
|
|
||||||
for (const auto& el : std::filesystem::directory_iterator(getRuntimeDir())) {
|
std::error_code ec;
|
||||||
if (!el.is_directory() || !std::filesystem::exists(el.path().string() + "/hyprland.lock"))
|
const auto runtimeDir = getRuntimeDir();
|
||||||
continue;
|
if (!std::filesystem::exists(runtimeDir, ec) || ec)
|
||||||
|
return result;
|
||||||
|
|
||||||
// read lock
|
std::filesystem::directory_iterator it(runtimeDir, std::filesystem::directory_options::skip_permission_denied, ec);
|
||||||
SInstanceData* data = &result.emplace_back();
|
if (ec)
|
||||||
data->id = el.path().filename().string();
|
return result;
|
||||||
|
|
||||||
try {
|
for (const auto& el : it) {
|
||||||
data->time = std::stoull(data->id.substr(data->id.find_first_of('_') + 1, data->id.find_last_of('_') - (data->id.find_first_of('_') + 1)));
|
if (auto instance = parseInstance(el))
|
||||||
} catch (std::exception& e) { continue; }
|
result.emplace_back(std::move(*instance));
|
||||||
|
|
||||||
// read file
|
|
||||||
std::ifstream ifs(el.path().string() + "/hyprland.lock");
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
for (std::string line; std::getline(ifs, line); ++i) {
|
|
||||||
if (i == 0) {
|
|
||||||
try {
|
|
||||||
data->pid = std::stoull(line);
|
|
||||||
} catch (std::exception& e) { continue; }
|
|
||||||
} else if (i == 1) {
|
|
||||||
data->wlSocket = line;
|
|
||||||
} else
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
ifs.close();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::erase_if(result, [&](const auto& el) { return kill(el.pid, 0) != 0 && errno == ESRCH; });
|
std::erase_if(result, [](const auto& el) { return kill(el.pid, 0) != 0 && errno == ESRCH; });
|
||||||
|
|
||||||
std::sort(result.begin(), result.end(), [&](const auto& a, const auto& b) { return a.time < b.time; });
|
std::ranges::sort(result, {}, &SInstanceData::time);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
@ -104,7 +142,7 @@ std::vector<SInstanceData> instances() {
|
||||||
static volatile bool sigintReceived = false;
|
static volatile bool sigintReceived = false;
|
||||||
void intHandler(int sig) {
|
void intHandler(int sig) {
|
||||||
sigintReceived = true;
|
sigintReceived = true;
|
||||||
std::cout << "[hyprctl] SIGINT received, closing connection" << std::endl;
|
std::println("[hyprctl] SIGINT received, closing connection");
|
||||||
}
|
}
|
||||||
|
|
||||||
int rollingRead(const int socket) {
|
int rollingRead(const int socket) {
|
||||||
|
|
@ -113,13 +151,13 @@ int rollingRead(const int socket) {
|
||||||
|
|
||||||
constexpr size_t BUFFER_SIZE = 8192;
|
constexpr size_t BUFFER_SIZE = 8192;
|
||||||
std::array<char, BUFFER_SIZE> buffer = {0};
|
std::array<char, BUFFER_SIZE> buffer = {0};
|
||||||
int sizeWritten = 0;
|
long sizeWritten = 0;
|
||||||
std::cout << "[hyprctl] reading from socket following up log:" << std::endl;
|
std::println("[hyprctl] reading from socket following up log:");
|
||||||
while (!sigintReceived) {
|
while (!sigintReceived) {
|
||||||
sizeWritten = read(socket, buffer.data(), BUFFER_SIZE);
|
sizeWritten = read(socket, buffer.data(), BUFFER_SIZE);
|
||||||
if (sizeWritten < 0 && errno != EAGAIN) {
|
if (sizeWritten < 0 && errno != EAGAIN) {
|
||||||
if (errno != EINTR)
|
if (errno != EINTR)
|
||||||
std::cout << "Couldn't read (5) " << strerror(errno) << ":" << errno << std::endl;
|
std::println("Couldn't read (5): {}: {}", strerror(errno), errno);
|
||||||
close(socket);
|
close(socket);
|
||||||
return 5;
|
return 5;
|
||||||
}
|
}
|
||||||
|
|
@ -128,7 +166,7 @@ int rollingRead(const int socket) {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (sizeWritten > 0) {
|
if (sizeWritten > 0) {
|
||||||
std::cout << std::string(buffer.data(), sizeWritten);
|
std::println("{}", std::string(buffer.data(), sizeWritten));
|
||||||
buffer.fill('\0');
|
buffer.fill('\0');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -138,11 +176,19 @@ int rollingRead(const int socket) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int request(std::string arg, int minArgs = 0, bool needRoll = false) {
|
int request(std::string_view arg, int minArgs = 0, bool needRoll = false) {
|
||||||
const auto SERVERSOCKET = socket(AF_UNIX, SOCK_STREAM, 0);
|
const auto SERVERSOCKET = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||||
|
|
||||||
auto t = timeval{.tv_sec = 5, .tv_usec = 0};
|
if (SERVERSOCKET < 0) {
|
||||||
setsockopt(SERVERSOCKET, SOL_SOCKET, SO_RCVTIMEO, &t, sizeof(struct timeval));
|
log("Couldn't open a socket (1)");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto t = timeval{.tv_sec = 5, .tv_usec = 0};
|
||||||
|
if (setsockopt(SERVERSOCKET, SOL_SOCKET, SO_RCVTIMEO, &t, sizeof(struct timeval)) < 0) {
|
||||||
|
log("Couldn't set socket timeout (2)");
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
const auto ARGS = std::count(arg.begin(), arg.end(), ' ');
|
const auto ARGS = std::count(arg.begin(), arg.end(), ' ');
|
||||||
|
|
||||||
|
|
@ -151,60 +197,54 @@ int request(std::string arg, int minArgs = 0, bool needRoll = false) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SERVERSOCKET < 0) {
|
|
||||||
log("Couldn't open a socket (1)");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (instanceSignature.empty()) {
|
if (instanceSignature.empty()) {
|
||||||
log("HYPRLAND_INSTANCE_SIGNATURE was not set! (Is Hyprland running?)");
|
log("HYPRLAND_INSTANCE_SIGNATURE was not set! (Is Hyprland running?) (3)");
|
||||||
return 2;
|
return 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string USERID = std::to_string(getpwuid(getuid())->pw_uid);
|
sockaddr_un serverAddress = {0};
|
||||||
|
serverAddress.sun_family = AF_UNIX;
|
||||||
sockaddr_un serverAddress = {0};
|
|
||||||
serverAddress.sun_family = AF_UNIX;
|
|
||||||
|
|
||||||
std::string socketPath = getRuntimeDir() + "/" + instanceSignature + "/.socket.sock";
|
std::string socketPath = getRuntimeDir() + "/" + instanceSignature + "/.socket.sock";
|
||||||
|
|
||||||
strncpy(serverAddress.sun_path, socketPath.c_str(), sizeof(serverAddress.sun_path) - 1);
|
strncpy(serverAddress.sun_path, socketPath.c_str(), sizeof(serverAddress.sun_path) - 1);
|
||||||
|
|
||||||
if (connect(SERVERSOCKET, (sockaddr*)&serverAddress, SUN_LEN(&serverAddress)) < 0) {
|
if (connect(SERVERSOCKET, rc<sockaddr*>(&serverAddress), SUN_LEN(&serverAddress)) < 0) {
|
||||||
log("Couldn't connect to " + socketPath + ". (3)");
|
log("Couldn't connect to " + socketPath + ". (4)");
|
||||||
return 3;
|
return 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto sizeWritten = write(SERVERSOCKET, arg.c_str(), arg.length());
|
auto sizeWritten = write(SERVERSOCKET, arg.data(), arg.size());
|
||||||
|
|
||||||
if (sizeWritten < 0) {
|
if (sizeWritten < 0) {
|
||||||
log("Couldn't write (4)");
|
log("Couldn't write (5)");
|
||||||
return 4;
|
return 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (needRoll)
|
if (needRoll)
|
||||||
return rollingRead(SERVERSOCKET);
|
return rollingRead(SERVERSOCKET);
|
||||||
|
|
||||||
std::string reply = "";
|
std::string reply = "";
|
||||||
char buffer[8192] = {0};
|
constexpr size_t BUFFER_SIZE = 8192;
|
||||||
|
char buffer[BUFFER_SIZE] = {0};
|
||||||
|
|
||||||
sizeWritten = read(SERVERSOCKET, buffer, 8192);
|
// read all data until server closes the connection
|
||||||
|
// this handles partial writes on the server side under high load
|
||||||
|
while (true) {
|
||||||
|
sizeWritten = read(SERVERSOCKET, buffer, BUFFER_SIZE);
|
||||||
|
|
||||||
if (sizeWritten < 0) {
|
|
||||||
if (errno == EWOULDBLOCK)
|
|
||||||
log("Hyprland IPC didn't respond in time\n");
|
|
||||||
log("Couldn't read (5)");
|
|
||||||
return 5;
|
|
||||||
}
|
|
||||||
|
|
||||||
reply += std::string(buffer, sizeWritten);
|
|
||||||
|
|
||||||
while (sizeWritten == 8192) {
|
|
||||||
sizeWritten = read(SERVERSOCKET, buffer, 8192);
|
|
||||||
if (sizeWritten < 0) {
|
if (sizeWritten < 0) {
|
||||||
log("Couldn't read (5)");
|
if (errno == EWOULDBLOCK)
|
||||||
return 5;
|
log("Hyprland IPC didn't respond in time\n");
|
||||||
|
log("Couldn't read (6)");
|
||||||
|
return 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (sizeWritten == 0) {
|
||||||
|
// server closed connection, we're done
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
reply += std::string(buffer, sizeWritten);
|
reply += std::string(buffer, sizeWritten);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -215,7 +255,7 @@ int request(std::string arg, int minArgs = 0, bool needRoll = false) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int requestHyprpaper(std::string arg) {
|
int requestIPC(std::string_view filename, std::string_view arg) {
|
||||||
const auto SERVERSOCKET = socket(AF_UNIX, SOCK_STREAM, 0);
|
const auto SERVERSOCKET = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||||
|
|
||||||
if (SERVERSOCKET < 0) {
|
if (SERVERSOCKET < 0) {
|
||||||
|
|
@ -231,13 +271,11 @@ int requestHyprpaper(std::string arg) {
|
||||||
sockaddr_un serverAddress = {0};
|
sockaddr_un serverAddress = {0};
|
||||||
serverAddress.sun_family = AF_UNIX;
|
serverAddress.sun_family = AF_UNIX;
|
||||||
|
|
||||||
const std::string USERID = std::to_string(getpwuid(getuid())->pw_uid);
|
std::string socketPath = getRuntimeDir() + "/" + instanceSignature + "/" + filename;
|
||||||
|
|
||||||
std::string socketPath = getRuntimeDir() + "/" + instanceSignature + "/.hyprpaper.sock";
|
|
||||||
|
|
||||||
strncpy(serverAddress.sun_path, socketPath.c_str(), sizeof(serverAddress.sun_path) - 1);
|
strncpy(serverAddress.sun_path, socketPath.c_str(), sizeof(serverAddress.sun_path) - 1);
|
||||||
|
|
||||||
if (connect(SERVERSOCKET, (sockaddr*)&serverAddress, SUN_LEN(&serverAddress)) < 0) {
|
if (connect(SERVERSOCKET, rc<sockaddr*>(&serverAddress), SUN_LEN(&serverAddress)) < 0) {
|
||||||
log("Couldn't connect to " + socketPath + ". (3)");
|
log("Couldn't connect to " + socketPath + ". (3)");
|
||||||
return 3;
|
return 3;
|
||||||
}
|
}
|
||||||
|
|
@ -245,16 +283,16 @@ int requestHyprpaper(std::string arg) {
|
||||||
arg = arg.substr(arg.find_first_of('/') + 1); // strip flags
|
arg = arg.substr(arg.find_first_of('/') + 1); // strip flags
|
||||||
arg = arg.substr(arg.find_first_of(' ') + 1); // strip "hyprpaper"
|
arg = arg.substr(arg.find_first_of(' ') + 1); // strip "hyprpaper"
|
||||||
|
|
||||||
auto sizeWritten = write(SERVERSOCKET, arg.c_str(), arg.length());
|
auto sizeWritten = write(SERVERSOCKET, arg.data(), arg.size());
|
||||||
|
|
||||||
if (sizeWritten < 0) {
|
if (sizeWritten < 0) {
|
||||||
log("Couldn't write (4)");
|
log("Couldn't write (4)");
|
||||||
return 4;
|
return 4;
|
||||||
}
|
}
|
||||||
|
constexpr size_t BUFFER_SIZE = 8192;
|
||||||
|
char buffer[BUFFER_SIZE] = {0};
|
||||||
|
|
||||||
char buffer[8192] = {0};
|
sizeWritten = read(SERVERSOCKET, buffer, BUFFER_SIZE);
|
||||||
|
|
||||||
sizeWritten = read(SERVERSOCKET, buffer, 8192);
|
|
||||||
|
|
||||||
if (sizeWritten < 0) {
|
if (sizeWritten < 0) {
|
||||||
log("Couldn't read (5)");
|
log("Couldn't read (5)");
|
||||||
|
|
@ -268,11 +306,16 @@ int requestHyprpaper(std::string arg) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void batchRequest(std::string arg, bool json) {
|
int requestHyprsunset(std::string_view arg) {
|
||||||
std::string commands = arg.substr(arg.find_first_of(" ") + 1);
|
return requestIPC(".hyprsunset.sock", arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void batchRequest(std::string_view arg, bool json) {
|
||||||
|
std::string commands(arg.substr(arg.find_first_of(' ') + 1));
|
||||||
|
|
||||||
if (json) {
|
if (json) {
|
||||||
commands = "j/" + std::regex_replace(commands, std::regex(";\\s*"), ";j/");
|
RE2::GlobalReplace(&commands, ";\\s*", ";j/");
|
||||||
|
commands.insert(0, "j/");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string rq = "[[BATCH]]" + commands;
|
std::string rq = "[[BATCH]]" + commands;
|
||||||
|
|
@ -286,12 +329,12 @@ void instancesRequest(bool json) {
|
||||||
std::vector<SInstanceData> inst = instances();
|
std::vector<SInstanceData> inst = instances();
|
||||||
|
|
||||||
if (!json) {
|
if (!json) {
|
||||||
for (auto& el : inst) {
|
for (auto const& el : inst) {
|
||||||
result += std::format("instance {}:\n\ttime: {}\n\tpid: {}\n\twl socket: {}\n\n", el.id, el.time, el.pid, el.wlSocket);
|
result += std::format("instance {}:\n\ttime: {}\n\tpid: {}\n\twl socket: {}\n\n", el.id, el.time, el.pid, el.wlSocket);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
result += '[';
|
result += '[';
|
||||||
for (auto& el : inst) {
|
for (auto const& el : inst) {
|
||||||
result += std::format(R"#(
|
result += std::format(R"#(
|
||||||
{{
|
{{
|
||||||
"instance": "{}",
|
"instance": "{}",
|
||||||
|
|
@ -309,11 +352,11 @@ void instancesRequest(bool json) {
|
||||||
log(result + "\n");
|
log(result + "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::deque<std::string> splitArgs(int argc, char** argv) {
|
std::vector<std::string> splitArgs(int argc, char** argv) {
|
||||||
std::deque<std::string> result;
|
std::vector<std::string> result;
|
||||||
|
|
||||||
for (auto i = 1 /* skip the executable */; i < argc; ++i)
|
for (auto i = 1 /* skip the executable */; i < argc; ++i)
|
||||||
result.push_back(std::string(argv[i]));
|
result.emplace_back(argv[i]);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
@ -322,7 +365,7 @@ int main(int argc, char** argv) {
|
||||||
bool parseArgs = true;
|
bool parseArgs = true;
|
||||||
|
|
||||||
if (argc < 2) {
|
if (argc < 2) {
|
||||||
std::cout << USAGE << std::endl;
|
std::println("{}", USAGE);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -339,7 +382,7 @@ int main(int argc, char** argv) {
|
||||||
parseArgs = false;
|
parseArgs = false;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (parseArgs && (ARGS[i][0] == '-') && !isNumber(ARGS[i], true) /* For stuff like -2 */) {
|
if (parseArgs && (ARGS[i][0] == '-') && !(isNumber(ARGS[i], true) || isNumber(ARGS[i].substr(0, ARGS[i].length() - 1), true)) /* For stuff like -2 or -2, */) {
|
||||||
// parse
|
// parse
|
||||||
if (ARGS[i] == "-j" && !fullArgs.contains("j")) {
|
if (ARGS[i] == "-j" && !fullArgs.contains("j")) {
|
||||||
fullArgs += "j";
|
fullArgs += "j";
|
||||||
|
|
@ -359,7 +402,7 @@ int main(int argc, char** argv) {
|
||||||
++i;
|
++i;
|
||||||
|
|
||||||
if (i >= ARGS.size()) {
|
if (i >= ARGS.size()) {
|
||||||
std::cout << USAGE << std::endl;
|
std::println("{}", USAGE);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -370,24 +413,28 @@ int main(int argc, char** argv) {
|
||||||
const std::string& cmd = ARGS[0];
|
const std::string& cmd = ARGS[0];
|
||||||
|
|
||||||
if (cmd == "hyprpaper") {
|
if (cmd == "hyprpaper") {
|
||||||
std::cout << HYPRPAPER_HELP << std::endl;
|
std::println("{}", HYPRPAPER_HELP);
|
||||||
|
} else if (cmd == "hyprsunset") {
|
||||||
|
std::println("{}", HYPRSUNSET_HELP);
|
||||||
} else if (cmd == "notify") {
|
} else if (cmd == "notify") {
|
||||||
std::cout << NOTIFY_HELP << std::endl;
|
std::println("{}", NOTIFY_HELP);
|
||||||
} else if (cmd == "output") {
|
} else if (cmd == "output") {
|
||||||
std::cout << OUTPUT_HELP << std::endl;
|
std::println("{}", OUTPUT_HELP);
|
||||||
} else if (cmd == "plugin") {
|
} else if (cmd == "plugin") {
|
||||||
std::cout << PLUGIN_HELP << std::endl;
|
std::println("{}", PLUGIN_HELP);
|
||||||
} else if (cmd == "setprop") {
|
} else if (cmd == "setprop") {
|
||||||
std::cout << SETPROP_HELP << std::endl;
|
std::println("{}", SETPROP_HELP);
|
||||||
|
} else if (cmd == "getprop") {
|
||||||
|
std::println("{}", GETPROP_HELP);
|
||||||
} else if (cmd == "switchxkblayout") {
|
} else if (cmd == "switchxkblayout") {
|
||||||
std::cout << SWITCHXKBLAYOUT_HELP << std::endl;
|
std::println("{}", SWITCHXKBLAYOUT_HELP);
|
||||||
} else {
|
} else {
|
||||||
std::cout << USAGE << std::endl;
|
std::println("{}", USAGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
} else {
|
} else {
|
||||||
std::cout << USAGE << std::endl;
|
std::println("{}", USAGE);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -398,7 +445,7 @@ int main(int argc, char** argv) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fullRequest.empty()) {
|
if (fullRequest.empty()) {
|
||||||
std::cout << USAGE << std::endl;
|
std::println("{}", USAGE);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -429,7 +476,7 @@ int main(int argc, char** argv) {
|
||||||
|
|
||||||
const auto INSTANCES = instances();
|
const auto INSTANCES = instances();
|
||||||
|
|
||||||
if (INSTANCENO < 0 || static_cast<std::size_t>(INSTANCENO) >= INSTANCES.size()) {
|
if (INSTANCENO < 0 || sc<std::size_t>(INSTANCENO) >= INSTANCES.size()) {
|
||||||
log("no such instance\n");
|
log("no such instance\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
@ -450,8 +497,13 @@ int main(int argc, char** argv) {
|
||||||
|
|
||||||
if (fullRequest.contains("/--batch"))
|
if (fullRequest.contains("/--batch"))
|
||||||
batchRequest(fullRequest, json);
|
batchRequest(fullRequest, json);
|
||||||
else if (fullRequest.contains("/hyprpaper"))
|
else if (fullRequest.contains("/hyprpaper")) {
|
||||||
exitStatus = requestHyprpaper(fullRequest);
|
auto result = Hyprpaper::makeHyprpaperRequest(fullRequest);
|
||||||
|
if (!result)
|
||||||
|
log(std::format("error: {}", result.error()));
|
||||||
|
exitStatus = !result;
|
||||||
|
} else if (fullRequest.contains("/hyprsunset"))
|
||||||
|
exitStatus = requestHyprsunset(fullRequest);
|
||||||
else if (fullRequest.contains("/switchxkblayout"))
|
else if (fullRequest.contains("/switchxkblayout"))
|
||||||
exitStatus = request(fullRequest, 2);
|
exitStatus = request(fullRequest, 2);
|
||||||
else if (fullRequest.contains("/seterror"))
|
else if (fullRequest.contains("/seterror"))
|
||||||
|
|
@ -475,7 +527,7 @@ int main(int argc, char** argv) {
|
||||||
else if (fullRequest.contains("/decorations"))
|
else if (fullRequest.contains("/decorations"))
|
||||||
exitStatus = request(fullRequest, 1);
|
exitStatus = request(fullRequest, 1);
|
||||||
else if (fullRequest.contains("/--help"))
|
else if (fullRequest.contains("/--help"))
|
||||||
std::cout << USAGE << std::endl;
|
std::println("{}", USAGE);
|
||||||
else if (fullRequest.contains("/rollinglog") && needRoll)
|
else if (fullRequest.contains("/rollinglog") && needRoll)
|
||||||
exitStatus = request(fullRequest, 0, true);
|
exitStatus = request(fullRequest, 0, true);
|
||||||
else {
|
else {
|
||||||
|
|
@ -4,4 +4,5 @@ Name: Hyprland
|
||||||
URL: https://github.com/hyprwm/Hyprland
|
URL: https://github.com/hyprwm/Hyprland
|
||||||
Description: Hyprland header files
|
Description: Hyprland header files
|
||||||
Version: @HYPRLAND_VERSION@
|
Version: @HYPRLAND_VERSION@
|
||||||
|
Requires: aquamarine >= @AQUAMARINE_MINIMUM_VERSION@, hyprcursor >= @HYPRCURSOR_MINIMUM_VERSION@, hyprgraphics >= @HYPRGRAPHICS_MINIMUM_VERSION@, hyprlang >= @HYPRLANG_MINIMUM_VERSION@, hyprutils >= @HYPRUTILS_MINIMUM_VERSION@, libdrm, egl, cairo, xkbcommon >= @XKBCOMMON_MINIMUM_VERSION@, libinput >= @LIBINPUT_MINIMUM_VERSION@, wayland-server >= @WAYLAND_SERVER_MINIMUM_VERSION@@PKGCONFIG_XWAYLAND_DEPENDENCIES@
|
||||||
Cflags: -I${prefix} -I${prefix}/hyprland/protocols -I${prefix}/hyprland
|
Cflags: -I${prefix} -I${prefix}/hyprland/protocols -I${prefix}/hyprland
|
||||||
|
|
|
||||||
|
|
@ -9,11 +9,26 @@ file(GLOB_RECURSE SRCFILES CONFIGURE_DEPENDS "src/*.cpp")
|
||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 23)
|
set(CMAKE_CXX_STANDARD 23)
|
||||||
|
|
||||||
pkg_check_modules(deps REQUIRED IMPORTED_TARGET tomlplusplus hyprutils>=0.1.1)
|
pkg_check_modules(hyprpm_deps REQUIRED IMPORTED_TARGET tomlplusplus hyprutils>=0.7.0)
|
||||||
|
|
||||||
|
find_package(glaze 6.0.1 QUIET)
|
||||||
|
if (NOT glaze_FOUND)
|
||||||
|
set(GLAZE_VERSION v6.0.1)
|
||||||
|
message(STATUS "glaze dependency not found, retrieving ${GLAZE_VERSION} with FetchContent")
|
||||||
|
include(FetchContent)
|
||||||
|
FetchContent_Declare(
|
||||||
|
glaze
|
||||||
|
GIT_REPOSITORY https://github.com/stephenberry/glaze.git
|
||||||
|
GIT_TAG ${GLAZE_VERSION}
|
||||||
|
GIT_SHALLOW TRUE
|
||||||
|
EXCLUDE_FROM_ALL
|
||||||
|
)
|
||||||
|
FetchContent_MakeAvailable(glaze)
|
||||||
|
endif()
|
||||||
|
|
||||||
add_executable(hyprpm ${SRCFILES})
|
add_executable(hyprpm ${SRCFILES})
|
||||||
|
|
||||||
target_link_libraries(hyprpm PUBLIC PkgConfig::deps)
|
target_link_libraries(hyprpm PUBLIC PkgConfig::hyprpm_deps glaze::glaze)
|
||||||
|
|
||||||
# binary
|
# binary
|
||||||
install(TARGETS hyprpm)
|
install(TARGETS hyprpm)
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,10 @@ _hyprpm_cmd_0 () {
|
||||||
hyprpm list | awk '/Plugin/{print $4}'
|
hyprpm list | awk '/Plugin/{print $4}'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_hyprpm_cmd_1 () {
|
||||||
|
hyprpm list | awk '/Repository/{print $4}' | sed 's/:$//'
|
||||||
|
}
|
||||||
|
|
||||||
_hyprpm () {
|
_hyprpm () {
|
||||||
if [[ $(type -t _get_comp_words_by_ref) != function ]]; then
|
if [[ $(type -t _get_comp_words_by_ref) != function ]]; then
|
||||||
echo _get_comp_words_by_ref: function not defined. Make sure the bash-completions system package is installed
|
echo _get_comp_words_by_ref: function not defined. Make sure the bash-completions system package is installed
|
||||||
|
|
@ -11,16 +15,13 @@ _hyprpm () {
|
||||||
local words cword
|
local words cword
|
||||||
_get_comp_words_by_ref -n "$COMP_WORDBREAKS" words cword
|
_get_comp_words_by_ref -n "$COMP_WORDBREAKS" words cword
|
||||||
|
|
||||||
local -a literals=("-n" "::=" "list" "disable" "--help" "update" "add" "--verbose" "-v" "--force" "remove" "enable" "--notify" "-h" "reload" "-f")
|
declare -a literals=(--no-shallow -n ::= disable list --help update add --verbose -v --force -s remove enable --notify -h reload -f)
|
||||||
|
|
||||||
declare -A literal_transitions
|
declare -A literal_transitions
|
||||||
literal_transitions[0]="([9]=6 [2]=2 [7]=6 [8]=6 [4]=6 [10]=2 [11]=3 [5]=2 [13]=6 [3]=3 [14]=2 [15]=6 [6]=2)"
|
literal_transitions[0]="([0]=7 [3]=3 [4]=4 [8]=7 [9]=7 [6]=4 [7]=4 [11]=7 [5]=7 [10]=7 [12]=2 [13]=3 [15]=7 [16]=4 [17]=7)"
|
||||||
literal_transitions[1]="([10]=2 [11]=3 [3]=3 [2]=2 [14]=2 [5]=2 [6]=2)"
|
literal_transitions[1]="([12]=2 [13]=3 [3]=3 [4]=4 [16]=4 [6]=4 [7]=4)"
|
||||||
literal_transitions[4]="([1]=5)"
|
literal_transitions[5]="([2]=6)"
|
||||||
literal_transitions[5]="([0]=6 [12]=6)"
|
literal_transitions[6]="([1]=7 [14]=7)"
|
||||||
|
declare -A match_anything_transitions=([1]=1 [4]=5 [3]=4 [2]=4 [0]=1)
|
||||||
declare -A match_anything_transitions
|
|
||||||
match_anything_transitions=([3]=2 [2]=4 [0]=1 [1]=1)
|
|
||||||
declare -A subword_transitions
|
declare -A subword_transitions
|
||||||
|
|
||||||
local state=0
|
local state=0
|
||||||
|
|
@ -58,21 +59,9 @@ _hyprpm () {
|
||||||
done
|
done
|
||||||
|
|
||||||
|
|
||||||
|
local -a matches=()
|
||||||
|
|
||||||
local prefix="${words[$cword]}"
|
local prefix="${words[$cword]}"
|
||||||
|
|
||||||
local shortest_suffix="$word"
|
|
||||||
for ((i=0; i < ${#COMP_WORDBREAKS}; i++)); do
|
|
||||||
local char="${COMP_WORDBREAKS:$i:1}"
|
|
||||||
local candidate="${word##*$char}"
|
|
||||||
if [[ ${#candidate} -lt ${#shortest_suffix} ]]; then
|
|
||||||
shortest_suffix=$candidate
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
local superfluous_prefix=""
|
|
||||||
if [[ "$shortest_suffix" != "$word" ]]; then
|
|
||||||
local superfluous_prefix=${word%$shortest_suffix}
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ -v "literal_transitions[$state]" ]]; then
|
if [[ -v "literal_transitions[$state]" ]]; then
|
||||||
local state_transitions_initializer=${literal_transitions[$state]}
|
local state_transitions_initializer=${literal_transitions[$state]}
|
||||||
declare -A state_transitions
|
declare -A state_transitions
|
||||||
|
|
@ -81,25 +70,38 @@ _hyprpm () {
|
||||||
for literal_id in "${!state_transitions[@]}"; do
|
for literal_id in "${!state_transitions[@]}"; do
|
||||||
local literal="${literals[$literal_id]}"
|
local literal="${literals[$literal_id]}"
|
||||||
if [[ $literal = "${prefix}"* ]]; then
|
if [[ $literal = "${prefix}"* ]]; then
|
||||||
local completion=${literal#"$superfluous_prefix"}
|
matches+=("$literal ")
|
||||||
COMPREPLY+=("$completion ")
|
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
declare -A commands
|
declare -A commands
|
||||||
commands=([3]=0)
|
commands=([3]=0 [2]=1)
|
||||||
if [[ -v "commands[$state]" ]]; then
|
if [[ -v "commands[$state]" ]]; then
|
||||||
local command_id=${commands[$state]}
|
local command_id=${commands[$state]}
|
||||||
local completions=()
|
local completions=()
|
||||||
mapfile -t completions < <(_hyprpm_cmd_${command_id} "$prefix" | cut -f1)
|
readarray -t completions < <(_hyprpm_cmd_${command_id} "$prefix" | cut -f1)
|
||||||
for item in "${completions[@]}"; do
|
for item in "${completions[@]}"; do
|
||||||
if [[ $item = "${prefix}"* ]]; then
|
if [[ $item = "${prefix}"* ]]; then
|
||||||
COMPREPLY+=("$item")
|
matches+=("$item")
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
local shortest_suffix="$prefix"
|
||||||
|
for ((i=0; i < ${#COMP_WORDBREAKS}; i++)); do
|
||||||
|
local char="${COMP_WORDBREAKS:$i:1}"
|
||||||
|
local candidate=${prefix##*$char}
|
||||||
|
if [[ ${#candidate} -lt ${#shortest_suffix} ]]; then
|
||||||
|
shortest_suffix=$candidate
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
local superfluous_prefix=""
|
||||||
|
if [[ "$shortest_suffix" != "$prefix" ]]; then
|
||||||
|
local superfluous_prefix=${prefix%$shortest_suffix}
|
||||||
|
fi
|
||||||
|
COMPREPLY=("${matches[@]#$superfluous_prefix}")
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,11 @@ function _hyprpm_1
|
||||||
hyprpm list | awk '/Plugin/{print $4}'
|
hyprpm list | awk '/Plugin/{print $4}'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function _hyprpm_2
|
||||||
|
set 1 $argv[1]
|
||||||
|
hyprpm list | awk '/Repository/{print $4}' | sed 's/:$//'
|
||||||
|
end
|
||||||
|
|
||||||
function _hyprpm
|
function _hyprpm
|
||||||
set COMP_LINE (commandline --cut-at-cursor)
|
set COMP_LINE (commandline --cut-at-cursor)
|
||||||
|
|
||||||
|
|
@ -14,49 +19,51 @@ function _hyprpm
|
||||||
set COMP_CWORD (count $COMP_WORDS)
|
set COMP_CWORD (count $COMP_WORDS)
|
||||||
end
|
end
|
||||||
|
|
||||||
set --local literals "-n" "::=" "list" "disable" "--help" "update" "add" "--verbose" "-v" "--force" "remove" "enable" "--notify" "-h" "reload" "-f"
|
set literals "--no-shallow" "-n" "::=" "disable" "list" "--help" "update" "add" "--verbose" "-v" "--force" "-s" "remove" "enable" "--notify" "-h" "reload" "-f"
|
||||||
|
|
||||||
set --local descriptions
|
set descriptions
|
||||||
set descriptions[1] "Send a hyprland notification for important events (e.g. load fail)"
|
set descriptions[1] "Disable shallow cloning of Hyprland sources"
|
||||||
set descriptions[3] "List all installed plugins"
|
set descriptions[2] "Send a hyprland notification for important events (e.g. load fail)"
|
||||||
set descriptions[4] "Unload a plugin"
|
set descriptions[4] "Unload a plugin"
|
||||||
set descriptions[5] "Show help menu"
|
set descriptions[5] "List all installed plugins"
|
||||||
set descriptions[6] "Check and update all plugins if needed"
|
set descriptions[6] "Show help menu"
|
||||||
set descriptions[7] "Install a new plugin repository from git"
|
set descriptions[7] "Check and update all plugins if needed"
|
||||||
set descriptions[8] "Enable too much loggin"
|
set descriptions[8] "Install a new plugin repository from git"
|
||||||
set descriptions[9] "Enable too much loggin"
|
set descriptions[9] "Enable too much logging"
|
||||||
set descriptions[10] "Force an operation ignoring checks (e.g. update -f)"
|
set descriptions[10] "Enable too much logging"
|
||||||
set descriptions[11] "Remove a plugin repository"
|
set descriptions[11] "Force an operation ignoring checks (e.g. update -f)"
|
||||||
set descriptions[12] "Load a plugin"
|
set descriptions[12] "Disable shallow cloning of Hyprland sources"
|
||||||
set descriptions[13] "Send a hyprland notification for important events (e.g. load fail)"
|
set descriptions[13] "Remove a plugin repository"
|
||||||
set descriptions[14] "Show help menu"
|
set descriptions[14] "Load a plugin"
|
||||||
set descriptions[15] "Reload all plugins"
|
set descriptions[15] "Send a hyprland notification for important events (e.g. load fail)"
|
||||||
set descriptions[16] "Force an operation ignoring checks (e.g. update -f)"
|
set descriptions[16] "Show help menu"
|
||||||
|
set descriptions[17] "Reload all plugins"
|
||||||
|
set descriptions[18] "Force an operation ignoring checks (e.g. update -f)"
|
||||||
|
|
||||||
set --local literal_transitions
|
set literal_transitions
|
||||||
set literal_transitions[1] "set inputs 10 3 8 9 5 11 12 6 14 4 15 16 7; set tos 7 3 7 7 7 3 4 3 7 4 3 7 3"
|
set literal_transitions[1] "set inputs 1 4 5 9 10 7 8 12 6 11 13 14 16 17 18; set tos 8 4 5 8 8 5 5 8 8 8 3 4 8 5 8"
|
||||||
set literal_transitions[2] "set inputs 11 12 4 3 15 6 7; set tos 3 4 4 3 3 3 3"
|
set literal_transitions[2] "set inputs 13 14 4 5 17 7 8; set tos 3 4 4 5 5 5 5"
|
||||||
set literal_transitions[5] "set inputs 2; set tos 6"
|
set literal_transitions[6] "set inputs 3; set tos 7"
|
||||||
set literal_transitions[6] "set inputs 1 13; set tos 7 7"
|
set literal_transitions[7] "set inputs 2 15; set tos 8 8"
|
||||||
|
|
||||||
set --local match_anything_transitions_from 4 3 1 2
|
set match_anything_transitions_from 2 5 4 3 1
|
||||||
set --local match_anything_transitions_to 3 5 2 2
|
set match_anything_transitions_to 2 6 5 5 2
|
||||||
|
|
||||||
set --local state 1
|
set state 1
|
||||||
set --local word_index 2
|
set word_index 2
|
||||||
while test $word_index -lt $COMP_CWORD
|
while test $word_index -lt $COMP_CWORD
|
||||||
set --local -- word $COMP_WORDS[$word_index]
|
set -- word $COMP_WORDS[$word_index]
|
||||||
|
|
||||||
if set --query literal_transitions[$state] && test -n $literal_transitions[$state]
|
if set --query literal_transitions[$state] && test -n $literal_transitions[$state]
|
||||||
set --local --erase inputs
|
set --erase inputs
|
||||||
set --local --erase tos
|
set --erase tos
|
||||||
eval $literal_transitions[$state]
|
eval $literal_transitions[$state]
|
||||||
|
|
||||||
if contains -- $word $literals
|
if contains -- $word $literals
|
||||||
set --local literal_matched 0
|
set literal_matched 0
|
||||||
for literal_id in (seq 1 (count $literals))
|
for literal_id in (seq 1 (count $literals))
|
||||||
if test $literals[$literal_id] = $word
|
if test $literals[$literal_id] = $word
|
||||||
set --local index (contains --index -- $literal_id $inputs)
|
set index (contains --index -- $literal_id $inputs)
|
||||||
set state $tos[$index]
|
set state $tos[$index]
|
||||||
set word_index (math $word_index + 1)
|
set word_index (math $word_index + 1)
|
||||||
set literal_matched 1
|
set literal_matched 1
|
||||||
|
|
@ -70,7 +77,7 @@ function _hyprpm
|
||||||
end
|
end
|
||||||
|
|
||||||
if set --query match_anything_transitions_from[$state] && test -n $match_anything_transitions_from[$state]
|
if set --query match_anything_transitions_from[$state] && test -n $match_anything_transitions_from[$state]
|
||||||
set --local index (contains --index -- $state $match_anything_transitions_from)
|
set index (contains --index -- $state $match_anything_transitions_from)
|
||||||
set state $match_anything_transitions_to[$index]
|
set state $match_anything_transitions_to[$index]
|
||||||
set word_index (math $word_index + 1)
|
set word_index (math $word_index + 1)
|
||||||
continue
|
continue
|
||||||
|
|
@ -80,8 +87,8 @@ function _hyprpm
|
||||||
end
|
end
|
||||||
|
|
||||||
if set --query literal_transitions[$state] && test -n $literal_transitions[$state]
|
if set --query literal_transitions[$state] && test -n $literal_transitions[$state]
|
||||||
set --local --erase inputs
|
set --erase inputs
|
||||||
set --local --erase tos
|
set --erase tos
|
||||||
eval $literal_transitions[$state]
|
eval $literal_transitions[$state]
|
||||||
for literal_id in $inputs
|
for literal_id in $inputs
|
||||||
if test -n $descriptions[$literal_id]
|
if test -n $descriptions[$literal_id]
|
||||||
|
|
@ -92,14 +99,14 @@ function _hyprpm
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
set command_states 4
|
set command_states 4 3
|
||||||
set command_ids 1
|
set command_ids 1 2
|
||||||
if contains $state $command_states
|
if contains $state $command_states
|
||||||
set --local index (contains --index $state $command_states)
|
set index (contains --index $state $command_states)
|
||||||
set --local function_id $command_ids[$index]
|
set function_id $command_ids[$index]
|
||||||
set --local function_name _hyprpm_$function_id
|
set function_name _hyprpm_$function_id
|
||||||
set --local --erase inputs
|
set --erase inputs
|
||||||
set --local --erase tos
|
set --erase tos
|
||||||
$function_name "$COMP_WORDS[$COMP_CWORD]"
|
$function_name "$COMP_WORDS[$COMP_CWORD]"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,17 +3,19 @@ hyprpm [<FLAGS>]... <ARGUMENT>
|
||||||
|
|
||||||
<FLAGS> ::= (--notify | -n) "Send a hyprland notification for important events (e.g. load fail)"
|
<FLAGS> ::= (--notify | -n) "Send a hyprland notification for important events (e.g. load fail)"
|
||||||
| (--help | -h) "Show help menu"
|
| (--help | -h) "Show help menu"
|
||||||
| (--verbose | -v) "Enable too much loggin"
|
| (--verbose | -v) "Enable too much logging"
|
||||||
| (--force | -f) "Force an operation ignoring checks (e.g. update -f)"
|
| (--force | -f) "Force an operation ignoring checks (e.g. update -f)"
|
||||||
|
| (--no-shallow | -s) "Disable shallow cloning of Hyprland sources"
|
||||||
;
|
;
|
||||||
|
|
||||||
<ARGUMENT> ::= (add) "Install a new plugin repository from git"
|
<ARGUMENT> ::= (add) "Install a new plugin repository from git"
|
||||||
| (remove) "Remove a plugin repository"
|
| (remove <PLUGIN_REPOS>) "Remove a plugin repository"
|
||||||
| (update) "Check and update all plugins if needed"
|
| (update) "Check and update all plugins if needed"
|
||||||
| (list) "List all installed plugins"
|
| (list) "List all installed plugins"
|
||||||
| (enable <PLUGINS>) "Load a plugin"
|
| (enable <PLUGINS>) "Load a plugin"
|
||||||
| (disable <PLUGINS>) "Unload a plugin"
|
| (disable <PLUGINS>) "Unload a plugin"
|
||||||
| (reload) "Reload all plugins"
|
| (reload) "Reload plugins to match the enabled/disabled state. Use -f to force reload."
|
||||||
;
|
;
|
||||||
|
|
||||||
<PLUGINS> ::= {{{ hyprpm list | awk '/Plugin/{print $4}' }}};
|
<PLUGINS> ::= {{{ hyprpm list | awk '/Plugin/{print $4}' }}};
|
||||||
|
<PLUGIN_REPOS> ::= {{{ hyprpm list | awk '/Repository/{print $4}' | sed 's/:$//' }}};
|
||||||
|
|
|
||||||
|
|
@ -4,34 +4,40 @@ _hyprpm_cmd_0 () {
|
||||||
hyprpm list | awk '/Plugin/{print $4}'
|
hyprpm list | awk '/Plugin/{print $4}'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_hyprpm_cmd_1 () {
|
||||||
|
hyprpm list | awk '/Repository/{print $4}' | sed 's/:$//'
|
||||||
|
}
|
||||||
|
|
||||||
_hyprpm () {
|
_hyprpm () {
|
||||||
local -a literals=("-n" "::=" "list" "disable" "--help" "update" "add" "--verbose" "-v" "--force" "remove" "enable" "--notify" "-h" "reload" "-f")
|
local -a literals=("--no-shallow" "-n" "::=" "disable" "list" "--help" "update" "add" "--verbose" "-v" "--force" "-s" "remove" "enable" "--notify" "-h" "reload" "-f")
|
||||||
|
|
||||||
local -A descriptions
|
local -A descriptions
|
||||||
descriptions[1]="Send a hyprland notification for important events (e.g. load fail)"
|
descriptions[1]="Disable shallow cloning of Hyprland sources"
|
||||||
descriptions[3]="List all installed plugins"
|
descriptions[2]="Send a hyprland notification for important events (e.g. load fail)"
|
||||||
descriptions[4]="Unload a plugin"
|
descriptions[4]="Unload a plugin"
|
||||||
descriptions[5]="Show help menu"
|
descriptions[5]="List all installed plugins"
|
||||||
descriptions[6]="Check and update all plugins if needed"
|
descriptions[6]="Show help menu"
|
||||||
descriptions[7]="Install a new plugin repository from git"
|
descriptions[7]="Check and update all plugins if needed"
|
||||||
descriptions[8]="Enable too much loggin"
|
descriptions[8]="Install a new plugin repository from git"
|
||||||
descriptions[9]="Enable too much loggin"
|
descriptions[9]="Enable too much logging"
|
||||||
descriptions[10]="Force an operation ignoring checks (e.g. update -f)"
|
descriptions[10]="Enable too much logging"
|
||||||
descriptions[11]="Remove a plugin repository"
|
descriptions[11]="Force an operation ignoring checks (e.g. update -f)"
|
||||||
descriptions[12]="Load a plugin"
|
descriptions[12]="Disable shallow cloning of Hyprland sources"
|
||||||
descriptions[13]="Send a hyprland notification for important events (e.g. load fail)"
|
descriptions[13]="Remove a plugin repository"
|
||||||
descriptions[14]="Show help menu"
|
descriptions[14]="Load a plugin"
|
||||||
descriptions[15]="Reload all plugins"
|
descriptions[15]="Send a hyprland notification for important events (e.g. load fail)"
|
||||||
descriptions[16]="Force an operation ignoring checks (e.g. update -f)"
|
descriptions[16]="Show help menu"
|
||||||
|
descriptions[17]="Reload all plugins"
|
||||||
|
descriptions[18]="Force an operation ignoring checks (e.g. update -f)"
|
||||||
|
|
||||||
local -A literal_transitions
|
local -A literal_transitions
|
||||||
literal_transitions[1]="([10]=7 [3]=3 [8]=7 [9]=7 [5]=7 [11]=3 [12]=4 [6]=3 [14]=7 [4]=4 [15]=3 [16]=7 [7]=3)"
|
literal_transitions[1]="([1]=8 [4]=4 [5]=5 [9]=8 [10]=8 [7]=5 [8]=5 [12]=8 [6]=8 [11]=8 [13]=3 [14]=4 [16]=8 [17]=5 [18]=8)"
|
||||||
literal_transitions[2]="([11]=3 [12]=4 [4]=4 [3]=3 [15]=3 [6]=3 [7]=3)"
|
literal_transitions[2]="([13]=3 [14]=4 [4]=4 [5]=5 [17]=5 [7]=5 [8]=5)"
|
||||||
literal_transitions[5]="([2]=6)"
|
literal_transitions[6]="([3]=7)"
|
||||||
literal_transitions[6]="([1]=7 [13]=7)"
|
literal_transitions[7]="([2]=8 [15]=8)"
|
||||||
|
|
||||||
local -A match_anything_transitions
|
local -A match_anything_transitions
|
||||||
match_anything_transitions=([4]=3 [3]=5 [1]=2 [2]=2)
|
match_anything_transitions=([2]=2 [5]=6 [4]=5 [3]=5 [1]=2)
|
||||||
|
|
||||||
declare -A subword_transitions
|
declare -A subword_transitions
|
||||||
|
|
||||||
|
|
@ -91,7 +97,7 @@ _hyprpm () {
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
local -A commands=([4]=0)
|
local -A commands=([4]=0 [3]=1)
|
||||||
|
|
||||||
if [[ -v "commands[$state]" ]]; then
|
if [[ -v "commands[$state]" ]]; then
|
||||||
local command_id=${commands[$state]}
|
local command_id=${commands[$state]}
|
||||||
|
|
|
||||||
|
|
@ -1,124 +1,170 @@
|
||||||
#include "DataState.hpp"
|
#include "DataState.hpp"
|
||||||
|
#include <sys/stat.h>
|
||||||
#include <toml++/toml.hpp>
|
#include <toml++/toml.hpp>
|
||||||
#include <iostream>
|
#include <print>
|
||||||
#include <filesystem>
|
#include <sstream>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include "PluginManager.hpp"
|
#include "PluginManager.hpp"
|
||||||
|
#include "../helpers/Die.hpp"
|
||||||
|
#include "../helpers/Sys.hpp"
|
||||||
|
#include "../helpers/StringUtils.hpp"
|
||||||
|
|
||||||
std::string DataState::getDataStatePath() {
|
static std::string getTempRoot() {
|
||||||
const auto HOME = getenv("HOME");
|
static auto ENV = getenv("XDG_RUNTIME_DIR");
|
||||||
if (!HOME) {
|
if (!ENV) {
|
||||||
std::cerr << "DataState: no $HOME\n";
|
std::cerr << "\nERROR: XDG_RUNTIME_DIR not set!\n";
|
||||||
throw std::runtime_error("no $HOME");
|
exit(1);
|
||||||
return "";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto XDG_DATA_HOME = getenv("XDG_DATA_HOME");
|
const auto STR = ENV + std::string{"/hyprpm/"};
|
||||||
|
|
||||||
if (XDG_DATA_HOME)
|
if (!std::filesystem::exists(STR))
|
||||||
return std::string{XDG_DATA_HOME} + "/hyprpm";
|
mkdir(STR.c_str(), S_IRWXU);
|
||||||
return std::string{HOME} + "/.local/share/hyprpm";
|
|
||||||
|
return STR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// write the state to a file
|
||||||
|
static bool writeState(const std::string& str, const std::string& to) {
|
||||||
|
// create temp file in a safe temp root
|
||||||
|
std::ofstream of(getTempRoot() + ".temp-state", std::ios::trunc);
|
||||||
|
if (!of.good())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
of << str;
|
||||||
|
of.close();
|
||||||
|
|
||||||
|
return NSys::root::install(getTempRoot() + ".temp-state", to, "644");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::filesystem::path DataState::getDataStatePath() {
|
||||||
|
return std::filesystem::path("/var/cache/hyprpm/" + g_pPluginManager->m_szUsername);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string DataState::getHeadersPath() {
|
std::string DataState::getHeadersPath() {
|
||||||
return getDataStatePath() + "/headersRoot";
|
return getDataStatePath() / "headersRoot";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::filesystem::path> DataState::getPluginStates() {
|
||||||
|
ensureStateStoreExists();
|
||||||
|
|
||||||
|
std::vector<std::filesystem::path> states;
|
||||||
|
for (const auto& entry : std::filesystem::directory_iterator(getDataStatePath())) {
|
||||||
|
if (!entry.is_directory() || entry.path().stem() == "headersRoot")
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const auto stateFile = entry.path() / "state.toml";
|
||||||
|
if (!std::filesystem::exists(stateFile))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
states.emplace_back(stateFile);
|
||||||
|
}
|
||||||
|
return states;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DataState::ensureStateStoreExists() {
|
void DataState::ensureStateStoreExists() {
|
||||||
const auto PATH = getDataStatePath();
|
std::error_code ec;
|
||||||
|
if (!std::filesystem::exists(getHeadersPath(), ec) || ec) {
|
||||||
if (!std::filesystem::exists(PATH))
|
std::println("{}", infoString("The hyprpm state store doesn't exist. Creating now..."));
|
||||||
std::filesystem::create_directories(PATH);
|
if (!std::filesystem::exists("/var/cache/hyprpm/", ec) || ec) {
|
||||||
|
if (!NSys::root::createDirectory("/var/cache/hyprpm", "755"))
|
||||||
if (!std::filesystem::exists(getHeadersPath()))
|
Debug::die("ensureStateStoreExists: Failed to run a superuser cmd");
|
||||||
std::filesystem::create_directories(getHeadersPath());
|
}
|
||||||
|
if (!std::filesystem::exists(getDataStatePath(), ec) || ec) {
|
||||||
|
if (!NSys::root::createDirectory(getDataStatePath().string(), "755"))
|
||||||
|
Debug::die("ensureStateStoreExists: Failed to run a superuser cmd");
|
||||||
|
}
|
||||||
|
if (!NSys::root::createDirectory(getHeadersPath(), "755"))
|
||||||
|
Debug::die("ensureStateStoreExists: Failed to run a superuser cmd");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DataState::addNewPluginRepo(const SPluginRepository& repo) {
|
void DataState::addNewPluginRepo(const SPluginRepository& repo) {
|
||||||
ensureStateStoreExists();
|
ensureStateStoreExists();
|
||||||
|
|
||||||
const auto PATH = getDataStatePath() + "/" + repo.name;
|
const auto PATH = getDataStatePath() / repo.name;
|
||||||
|
|
||||||
std::filesystem::create_directories(PATH);
|
std::error_code ec;
|
||||||
|
if (!std::filesystem::exists(PATH, ec) || ec) {
|
||||||
|
if (!NSys::root::createDirectory(PATH.string(), "755"))
|
||||||
|
Debug::die("addNewPluginRepo: failed to create cache dir");
|
||||||
|
}
|
||||||
// clang-format off
|
// clang-format off
|
||||||
auto DATA = toml::table{
|
auto DATA = toml::table{
|
||||||
{"repository", toml::table{
|
{"repository", toml::table{
|
||||||
{"name", repo.name},
|
{"name", repo.name},
|
||||||
|
{"author", repo.author},
|
||||||
{"hash", repo.hash},
|
{"hash", repo.hash},
|
||||||
{"url", repo.url},
|
{"url", repo.url},
|
||||||
{"rev", repo.rev}
|
{"rev", repo.rev}
|
||||||
}}
|
}}
|
||||||
};
|
};
|
||||||
for (auto& p : repo.plugins) {
|
for (auto const& p : repo.plugins) {
|
||||||
// copy .so to the good place
|
const auto filename = p.name + ".so";
|
||||||
if (std::filesystem::exists(p.filename))
|
|
||||||
std::filesystem::copy_file(p.filename, PATH + "/" + p.name + ".so");
|
// copy .so to the good place and chmod 755
|
||||||
|
if (std::filesystem::exists(p.filename)) {
|
||||||
|
if (!NSys::root::install(p.filename, (PATH / filename).string(), "0755"))
|
||||||
|
Debug::die("addNewPluginRepo: failed to install so file");
|
||||||
|
}
|
||||||
|
|
||||||
DATA.emplace(p.name, toml::table{
|
DATA.emplace(p.name, toml::table{
|
||||||
{"filename", p.name + ".so"},
|
{"filename", filename},
|
||||||
{"enabled", p.enabled},
|
{"enabled", p.enabled},
|
||||||
{"failed", p.failed}
|
{"failed", p.failed}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
std::ofstream ofs(PATH + "/state.toml", std::ios::trunc);
|
std::stringstream ss;
|
||||||
ofs << DATA;
|
ss << DATA;
|
||||||
ofs.close();
|
|
||||||
|
if (!writeState(ss.str(), (PATH / "state.toml").string()))
|
||||||
|
Debug::die("{}", failureString("Failed to write plugin state"));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DataState::pluginRepoExists(const std::string& urlOrName) {
|
bool DataState::pluginRepoExists(const SPluginRepoIdentifier identifier) {
|
||||||
ensureStateStoreExists();
|
ensureStateStoreExists();
|
||||||
|
|
||||||
const auto PATH = getDataStatePath();
|
for (const auto& stateFile : getPluginStates()) {
|
||||||
|
const auto STATE = toml::parse_file(stateFile.c_str());
|
||||||
|
const auto NAME = STATE["repository"]["name"].value_or("");
|
||||||
|
const auto AUTHOR = STATE["repository"]["author"].value_or("");
|
||||||
|
const auto URL = STATE["repository"]["url"].value_or("");
|
||||||
|
|
||||||
for (const auto& entry : std::filesystem::directory_iterator(PATH)) {
|
if (identifier.matches(URL, NAME, AUTHOR))
|
||||||
if (!entry.is_directory() || entry.path().stem() == "headersRoot")
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (!std::filesystem::exists(entry.path().string() + "/state.toml"))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
auto STATE = toml::parse_file(entry.path().string() + "/state.toml");
|
|
||||||
|
|
||||||
const auto NAME = STATE["repository"]["name"].value_or("");
|
|
||||||
const auto URL = STATE["repository"]["url"].value_or("");
|
|
||||||
|
|
||||||
if (URL == urlOrName || NAME == urlOrName)
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DataState::removePluginRepo(const std::string& urlOrName) {
|
void DataState::removePluginRepo(const SPluginRepoIdentifier identifier) {
|
||||||
ensureStateStoreExists();
|
ensureStateStoreExists();
|
||||||
|
|
||||||
const auto PATH = getDataStatePath();
|
for (const auto& stateFile : getPluginStates()) {
|
||||||
|
const auto STATE = toml::parse_file(stateFile.c_str());
|
||||||
for (const auto& entry : std::filesystem::directory_iterator(PATH)) {
|
const auto NAME = STATE["repository"]["name"].value_or("");
|
||||||
if (!entry.is_directory() || entry.path().stem() == "headersRoot")
|
const auto AUTHOR = STATE["repository"]["author"].value_or("");
|
||||||
continue;
|
const auto URL = STATE["repository"]["url"].value_or("");
|
||||||
|
|
||||||
if (!std::filesystem::exists(entry.path().string() + "/state.toml"))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
auto STATE = toml::parse_file(entry.path().string() + "/state.toml");
|
|
||||||
|
|
||||||
const auto NAME = STATE["repository"]["name"].value_or("");
|
|
||||||
const auto URL = STATE["repository"]["url"].value_or("");
|
|
||||||
|
|
||||||
if (URL == urlOrName || NAME == urlOrName) {
|
|
||||||
|
|
||||||
|
if (identifier.matches(URL, NAME, AUTHOR)) {
|
||||||
// unload the plugins!!
|
// unload the plugins!!
|
||||||
for (const auto& file : std::filesystem::directory_iterator(entry.path())) {
|
for (const auto& file : std::filesystem::directory_iterator(stateFile.parent_path())) {
|
||||||
if (!file.path().string().ends_with(".so"))
|
if (!file.path().string().ends_with(".so"))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
g_pPluginManager->loadUnloadPlugin(std::filesystem::absolute(file.path()), false);
|
g_pPluginManager->loadUnloadPlugin(std::filesystem::absolute(file.path()), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::filesystem::remove_all(entry.path());
|
const auto PATH = stateFile.parent_path().string();
|
||||||
|
|
||||||
|
if (!PATH.starts_with("/var/cache/hyprpm") || PATH.contains('\''))
|
||||||
|
return; // WTF?
|
||||||
|
|
||||||
|
// scary!
|
||||||
|
if (!NSys::root::removeRecursive(PATH))
|
||||||
|
Debug::die("removePluginRepo: failed to remove dir");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -127,36 +173,43 @@ void DataState::removePluginRepo(const std::string& urlOrName) {
|
||||||
void DataState::updateGlobalState(const SGlobalState& state) {
|
void DataState::updateGlobalState(const SGlobalState& state) {
|
||||||
ensureStateStoreExists();
|
ensureStateStoreExists();
|
||||||
|
|
||||||
const auto PATH = getDataStatePath();
|
const auto PATH = getDataStatePath();
|
||||||
|
|
||||||
std::filesystem::create_directories(PATH);
|
std::error_code ec;
|
||||||
|
if (!std::filesystem::exists(PATH, ec) || ec) {
|
||||||
|
if (!NSys::root::createDirectory(PATH.string(), "755"))
|
||||||
|
Debug::die("updateGlobalState: failed to create dir");
|
||||||
|
}
|
||||||
// clang-format off
|
// clang-format off
|
||||||
auto DATA = toml::table{
|
auto DATA = toml::table{
|
||||||
{"state", toml::table{
|
{"state", toml::table{
|
||||||
{"hash", state.headersHashCompiled},
|
{"hash", state.headersAbiCompiled},
|
||||||
{"dont_warn_install", state.dontWarnInstall}
|
{"dont_warn_install", state.dontWarnInstall}
|
||||||
}}
|
}}
|
||||||
};
|
};
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
std::ofstream ofs(PATH + "/state.toml", std::ios::trunc);
|
std::stringstream ss;
|
||||||
ofs << DATA;
|
ss << DATA;
|
||||||
ofs.close();
|
|
||||||
|
if (!writeState(ss.str(), (PATH / "state.toml").string()))
|
||||||
|
Debug::die("{}", failureString("Failed to write plugin state"));
|
||||||
}
|
}
|
||||||
|
|
||||||
SGlobalState DataState::getGlobalState() {
|
SGlobalState DataState::getGlobalState() {
|
||||||
ensureStateStoreExists();
|
ensureStateStoreExists();
|
||||||
|
|
||||||
const auto PATH = getDataStatePath();
|
const auto stateFile = getDataStatePath() / "state.toml";
|
||||||
|
|
||||||
if (!std::filesystem::exists(PATH + "/state.toml"))
|
std::error_code ec;
|
||||||
|
if (!std::filesystem::exists(stateFile, ec) || ec)
|
||||||
return SGlobalState{};
|
return SGlobalState{};
|
||||||
|
|
||||||
auto DATA = toml::parse_file(PATH + "/state.toml");
|
auto DATA = toml::parse_file(stateFile.c_str());
|
||||||
|
|
||||||
SGlobalState state;
|
SGlobalState state;
|
||||||
state.headersHashCompiled = DATA["state"]["hash"].value_or("");
|
state.headersAbiCompiled = DATA["state"]["hash"].value_or("");
|
||||||
state.dontWarnInstall = DATA["state"]["dont_warn_install"].value_or(false);
|
state.dontWarnInstall = DATA["state"]["dont_warn_install"].value_or(false);
|
||||||
|
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
@ -164,29 +217,22 @@ SGlobalState DataState::getGlobalState() {
|
||||||
std::vector<SPluginRepository> DataState::getAllRepositories() {
|
std::vector<SPluginRepository> DataState::getAllRepositories() {
|
||||||
ensureStateStoreExists();
|
ensureStateStoreExists();
|
||||||
|
|
||||||
const auto PATH = getDataStatePath();
|
|
||||||
|
|
||||||
std::vector<SPluginRepository> repos;
|
std::vector<SPluginRepository> repos;
|
||||||
|
for (const auto& stateFile : getPluginStates()) {
|
||||||
|
const auto STATE = toml::parse_file(stateFile.c_str());
|
||||||
|
|
||||||
for (const auto& entry : std::filesystem::directory_iterator(PATH)) {
|
const auto NAME = STATE["repository"]["name"].value_or("");
|
||||||
if (!entry.is_directory() || entry.path().stem() == "headersRoot")
|
const auto AUTHOR = STATE["repository"]["author"].value_or("");
|
||||||
continue;
|
const auto URL = STATE["repository"]["url"].value_or("");
|
||||||
|
const auto REV = STATE["repository"]["rev"].value_or("");
|
||||||
if (!std::filesystem::exists(entry.path().string() + "/state.toml"))
|
const auto HASH = STATE["repository"]["hash"].value_or("");
|
||||||
continue;
|
|
||||||
|
|
||||||
auto STATE = toml::parse_file(entry.path().string() + "/state.toml");
|
|
||||||
|
|
||||||
const auto NAME = STATE["repository"]["name"].value_or("");
|
|
||||||
const auto URL = STATE["repository"]["url"].value_or("");
|
|
||||||
const auto REV = STATE["repository"]["rev"].value_or("");
|
|
||||||
const auto HASH = STATE["repository"]["hash"].value_or("");
|
|
||||||
|
|
||||||
SPluginRepository repo;
|
SPluginRepository repo;
|
||||||
repo.hash = HASH;
|
repo.hash = HASH;
|
||||||
repo.name = NAME;
|
repo.name = NAME;
|
||||||
repo.url = URL;
|
repo.author = AUTHOR;
|
||||||
repo.rev = REV;
|
repo.url = URL;
|
||||||
|
repo.rev = REV;
|
||||||
|
|
||||||
for (const auto& [key, val] : STATE) {
|
for (const auto& [key, val] : STATE) {
|
||||||
if (key == "repository")
|
if (key == "repository")
|
||||||
|
|
@ -205,37 +251,40 @@ std::vector<SPluginRepository> DataState::getAllRepositories() {
|
||||||
return repos;
|
return repos;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DataState::setPluginEnabled(const std::string& name, bool enabled) {
|
bool DataState::setPluginEnabled(const SPluginRepoIdentifier identifier, bool enabled) {
|
||||||
ensureStateStoreExists();
|
ensureStateStoreExists();
|
||||||
|
|
||||||
const auto PATH = getDataStatePath();
|
for (const auto& stateFile : getPluginStates()) {
|
||||||
|
const auto STATE = toml::parse_file(stateFile.c_str());
|
||||||
for (const auto& entry : std::filesystem::directory_iterator(PATH)) {
|
|
||||||
if (!entry.is_directory() || entry.path().stem() == "headersRoot")
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (!std::filesystem::exists(entry.path().string() + "/state.toml"))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
auto STATE = toml::parse_file(entry.path().string() + "/state.toml");
|
|
||||||
|
|
||||||
for (const auto& [key, val] : STATE) {
|
for (const auto& [key, val] : STATE) {
|
||||||
if (key == "repository")
|
if (key == "repository")
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (key.str() != name)
|
switch (identifier.type) {
|
||||||
continue;
|
case IDENTIFIER_NAME:
|
||||||
|
if (key.str() != identifier.name)
|
||||||
|
continue;
|
||||||
|
break;
|
||||||
|
case IDENTIFIER_AUTHOR_NAME:
|
||||||
|
if (STATE["repository"]["author"] != identifier.author || key.str() != identifier.name)
|
||||||
|
continue;
|
||||||
|
break;
|
||||||
|
default: return false;
|
||||||
|
}
|
||||||
|
|
||||||
const auto FAILED = STATE[key]["failed"].value_or(false);
|
const auto FAILED = STATE[key]["failed"].value_or(false);
|
||||||
|
|
||||||
if (FAILED)
|
if (FAILED)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
(*STATE[key].as_table()).insert_or_assign("enabled", enabled);
|
auto modifiedState = STATE;
|
||||||
|
(*modifiedState[key].as_table()).insert_or_assign("enabled", enabled);
|
||||||
|
|
||||||
std::ofstream state(entry.path().string() + "/state.toml", std::ios::trunc);
|
std::stringstream ss;
|
||||||
state << STATE;
|
ss << modifiedState;
|
||||||
state.close();
|
|
||||||
|
if (!writeState(ss.str(), stateFile.string()))
|
||||||
|
Debug::die("{}", failureString("Failed to write plugin state"));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -243,3 +292,18 @@ bool DataState::setPluginEnabled(const std::string& name, bool enabled) {
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DataState::purgeAllCache() {
|
||||||
|
std::error_code ec;
|
||||||
|
if (!std::filesystem::exists(getDataStatePath()) && !ec) {
|
||||||
|
std::println("{}", infoString("Nothing to do"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto PATH = getDataStatePath().string();
|
||||||
|
if (PATH.contains('\''))
|
||||||
|
return;
|
||||||
|
// scary!
|
||||||
|
if (!NSys::root::removeRecursive(PATH))
|
||||||
|
Debug::die("Failed to run a superuser cmd");
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,25 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
#include <filesystem>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "Plugin.hpp"
|
#include "Plugin.hpp"
|
||||||
|
|
||||||
struct SGlobalState {
|
struct SGlobalState {
|
||||||
std::string headersHashCompiled = "";
|
std::string headersAbiCompiled = "";
|
||||||
bool dontWarnInstall = false;
|
bool dontWarnInstall = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace DataState {
|
namespace DataState {
|
||||||
std::string getDataStatePath();
|
std::filesystem::path getDataStatePath();
|
||||||
std::string getHeadersPath();
|
std::string getHeadersPath();
|
||||||
void ensureStateStoreExists();
|
std::vector<std::filesystem::path> getPluginStates();
|
||||||
void addNewPluginRepo(const SPluginRepository& repo);
|
void ensureStateStoreExists();
|
||||||
void removePluginRepo(const std::string& urlOrName);
|
void addNewPluginRepo(const SPluginRepository& repo);
|
||||||
bool pluginRepoExists(const std::string& urlOrName);
|
void removePluginRepo(const SPluginRepoIdentifier identifier);
|
||||||
void updateGlobalState(const SGlobalState& state);
|
bool pluginRepoExists(const SPluginRepoIdentifier identifier);
|
||||||
SGlobalState getGlobalState();
|
void updateGlobalState(const SGlobalState& state);
|
||||||
bool setPluginEnabled(const std::string& name, bool enabled);
|
void purgeAllCache();
|
||||||
std::vector<SPluginRepository> getAllRepositories();
|
SGlobalState getGlobalState();
|
||||||
|
bool setPluginEnabled(const SPluginRepoIdentifier identifier, bool enabled);
|
||||||
|
std::vector<SPluginRepository> getAllRepositories();
|
||||||
};
|
};
|
||||||
89
hyprpm/src/core/HyprlandSocket.cpp
Normal file
|
|
@ -0,0 +1,89 @@
|
||||||
|
#include "HyprlandSocket.hpp"
|
||||||
|
#include <pwd.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include "../helpers/StringUtils.hpp"
|
||||||
|
#include <print>
|
||||||
|
#include <sys/un.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <cstring>
|
||||||
|
#include <hyprutils/memory/Casts.hpp>
|
||||||
|
|
||||||
|
using namespace Hyprutils::Memory;
|
||||||
|
|
||||||
|
static int getUID() {
|
||||||
|
const auto UID = getuid();
|
||||||
|
const auto PWUID = getpwuid(UID);
|
||||||
|
return PWUID ? PWUID->pw_uid : UID;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string getRuntimeDir() {
|
||||||
|
const auto XDG = getenv("XDG_RUNTIME_DIR");
|
||||||
|
|
||||||
|
if (!XDG) {
|
||||||
|
const std::string USERID = std::to_string(getUID());
|
||||||
|
return "/run/user/" + USERID + "/hypr";
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::string{XDG} + "/hypr";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string NHyprlandSocket::send(const std::string& cmd) {
|
||||||
|
const auto SERVERSOCKET = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||||
|
|
||||||
|
if (SERVERSOCKET < 0) {
|
||||||
|
std::println("{}", failureString("Couldn't open a socket (1)"));
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto HIS = getenv("HYPRLAND_INSTANCE_SIGNATURE");
|
||||||
|
|
||||||
|
if (!HIS) {
|
||||||
|
std::println("{}", failureString("HYPRLAND_INSTANCE_SIGNATURE was not set! (Is Hyprland running?) (3)"));
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
sockaddr_un serverAddress = {0};
|
||||||
|
serverAddress.sun_family = AF_UNIX;
|
||||||
|
|
||||||
|
std::string socketPath = getRuntimeDir() + "/" + HIS + "/.socket.sock";
|
||||||
|
|
||||||
|
strncpy(serverAddress.sun_path, socketPath.c_str(), sizeof(serverAddress.sun_path) - 1);
|
||||||
|
|
||||||
|
if (connect(SERVERSOCKET, rc<sockaddr*>(&serverAddress), SUN_LEN(&serverAddress)) < 0) {
|
||||||
|
std::println("{}", failureString("Couldn't connect to " + socketPath + ". (4)"));
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
auto sizeWritten = write(SERVERSOCKET, cmd.c_str(), cmd.length());
|
||||||
|
|
||||||
|
if (sizeWritten < 0) {
|
||||||
|
std::println("{}", failureString("Couldn't write (5)"));
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string reply = "";
|
||||||
|
constexpr size_t BUFFER_SIZE = 8192;
|
||||||
|
char buffer[BUFFER_SIZE] = {0};
|
||||||
|
|
||||||
|
sizeWritten = read(SERVERSOCKET, buffer, BUFFER_SIZE);
|
||||||
|
|
||||||
|
if (sizeWritten < 0) {
|
||||||
|
std::println("{}", failureString("Couldn't read (6)"));
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
reply += std::string(buffer, sizeWritten);
|
||||||
|
|
||||||
|
while (sizeWritten == BUFFER_SIZE) {
|
||||||
|
sizeWritten = read(SERVERSOCKET, buffer, BUFFER_SIZE);
|
||||||
|
if (sizeWritten < 0) {
|
||||||
|
std::println("{}", failureString("Couldn't read (7)"));
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
reply += std::string(buffer, sizeWritten);
|
||||||
|
}
|
||||||
|
|
||||||
|
close(SERVERSOCKET);
|
||||||
|
|
||||||
|
return reply;
|
||||||
|
}
|
||||||
7
hyprpm/src/core/HyprlandSocket.hpp
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace NHyprlandSocket {
|
||||||
|
std::string send(const std::string& cmd);
|
||||||
|
};
|
||||||
|
|
@ -1,21 +1,33 @@
|
||||||
#include "Manifest.hpp"
|
#include "Manifest.hpp"
|
||||||
#include <toml++/toml.hpp>
|
#include <toml++/toml.hpp>
|
||||||
#include <iostream>
|
#include <algorithm>
|
||||||
|
|
||||||
|
// Alphanumerics and -_ allowed for plugin names. No magic names.
|
||||||
|
// [A-Za-z0-9\-_]*
|
||||||
|
static bool validManifestName(const std::string_view& n) {
|
||||||
|
return std::ranges::all_of(n, [](const char& c) { return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '-' || c == '_' || c == '=' || (c >= '0' && c <= '9'); });
|
||||||
|
}
|
||||||
|
|
||||||
CManifest::CManifest(const eManifestType type, const std::string& path) {
|
CManifest::CManifest(const eManifestType type, const std::string& path) {
|
||||||
auto manifest = toml::parse_file(path);
|
auto manifest = toml::parse_file(path);
|
||||||
|
|
||||||
if (type == MANIFEST_HYPRLOAD) {
|
if (type == MANIFEST_HYPRLOAD) {
|
||||||
for (auto& [key, val] : manifest) {
|
for (auto const& [key, val] : manifest) {
|
||||||
if (key.str().ends_with(".build"))
|
if (key.str().ends_with(".build"))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
CManifest::SManifestPlugin plugin;
|
CManifest::SManifestPlugin plugin;
|
||||||
|
|
||||||
|
if (!validManifestName(key.str())) {
|
||||||
|
m_good = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
plugin.name = key;
|
plugin.name = key;
|
||||||
m_vPlugins.push_back(plugin);
|
m_plugins.push_back(plugin);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto& plugin : m_vPlugins) {
|
for (auto& plugin : m_plugins) {
|
||||||
plugin.description = manifest[plugin.name]["description"].value_or("?");
|
plugin.description = manifest[plugin.name]["description"].value_or("?");
|
||||||
plugin.version = manifest[plugin.name]["version"].value_or("?");
|
plugin.version = manifest[plugin.name]["version"].value_or("?");
|
||||||
plugin.output = manifest[plugin.name]["build"]["output"].value_or("?");
|
plugin.output = manifest[plugin.name]["build"]["output"].value_or("?");
|
||||||
|
|
@ -37,21 +49,21 @@ CManifest::CManifest(const eManifestType type, const std::string& path) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (plugin.output.empty() || plugin.buildSteps.empty()) {
|
if (plugin.output.empty() || plugin.buildSteps.empty()) {
|
||||||
m_bGood = false;
|
m_good = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (type == MANIFEST_HYPRPM) {
|
} else if (type == MANIFEST_HYPRPM) {
|
||||||
m_sRepository.name = manifest["repository"]["name"].value_or("");
|
m_repository.name = manifest["repository"]["name"].value_or("");
|
||||||
auto authors = manifest["repository"]["authors"].as_array();
|
auto authors = manifest["repository"]["authors"].as_array();
|
||||||
if (authors) {
|
if (authors) {
|
||||||
for (auto&& a : *authors) {
|
for (auto&& a : *authors) {
|
||||||
m_sRepository.authors.push_back(a.as_string()->value_or("?"));
|
m_repository.authors.push_back(a.as_string()->value_or("?"));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
auto author = manifest["repository"]["author"].value_or("");
|
auto author = manifest["repository"]["author"].value_or("");
|
||||||
if (!std::string{author}.empty())
|
if (!std::string{author}.empty())
|
||||||
m_sRepository.authors.push_back(author);
|
m_repository.authors.push_back(author);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto pins = manifest["repository"]["commit_pins"].as_array();
|
auto pins = manifest["repository"]["commit_pins"].as_array();
|
||||||
|
|
@ -59,20 +71,26 @@ CManifest::CManifest(const eManifestType type, const std::string& path) {
|
||||||
for (auto&& pin : *pins) {
|
for (auto&& pin : *pins) {
|
||||||
auto pinArr = pin.as_array();
|
auto pinArr = pin.as_array();
|
||||||
if (pinArr && pinArr->get(1))
|
if (pinArr && pinArr->get(1))
|
||||||
m_sRepository.commitPins.push_back(std::make_pair<>(pinArr->get(0)->as_string()->get(), pinArr->get(1)->as_string()->get()));
|
m_repository.commitPins.push_back(std::make_pair<>(pinArr->get(0)->as_string()->get(), pinArr->get(1)->as_string()->get()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto& [key, val] : manifest) {
|
for (auto const& [key, val] : manifest) {
|
||||||
if (key.str() == "repository")
|
if (key.str() == "repository")
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
CManifest::SManifestPlugin plugin;
|
CManifest::SManifestPlugin plugin;
|
||||||
|
|
||||||
|
if (!validManifestName(key.str())) {
|
||||||
|
m_good = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
plugin.name = key;
|
plugin.name = key;
|
||||||
m_vPlugins.push_back(plugin);
|
m_plugins.push_back(plugin);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto& plugin : m_vPlugins) {
|
for (auto& plugin : m_plugins) {
|
||||||
plugin.description = manifest[plugin.name]["description"].value_or("?");
|
plugin.description = manifest[plugin.name]["description"].value_or("?");
|
||||||
plugin.output = manifest[plugin.name]["output"].value_or("?");
|
plugin.output = manifest[plugin.name]["output"].value_or("?");
|
||||||
plugin.since = manifest[plugin.name]["since_hyprland"].value_or(0);
|
plugin.since = manifest[plugin.name]["since_hyprland"].value_or(0);
|
||||||
|
|
@ -94,12 +112,12 @@ CManifest::CManifest(const eManifestType type, const std::string& path) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (plugin.output.empty() || plugin.buildSteps.empty()) {
|
if (plugin.output.empty() || plugin.buildSteps.empty()) {
|
||||||
m_bGood = false;
|
m_good = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// ???
|
// ???
|
||||||
m_bGood = false;
|
m_good = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -27,8 +27,8 @@ class CManifest {
|
||||||
std::string name;
|
std::string name;
|
||||||
std::vector<std::string> authors;
|
std::vector<std::string> authors;
|
||||||
std::vector<std::pair<std::string, std::string>> commitPins;
|
std::vector<std::pair<std::string, std::string>> commitPins;
|
||||||
} m_sRepository;
|
} m_repository;
|
||||||
|
|
||||||
std::vector<SManifestPlugin> m_vPlugins;
|
std::vector<SManifestPlugin> m_plugins;
|
||||||
bool m_bGood = true;
|
bool m_good = true;
|
||||||
};
|
};
|
||||||
48
hyprpm/src/core/Plugin.cpp
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
#include "Plugin.hpp"
|
||||||
|
|
||||||
|
SPluginRepoIdentifier SPluginRepoIdentifier::fromUrl(const std::string& url) {
|
||||||
|
return SPluginRepoIdentifier{.type = IDENTIFIER_URL, .url = url};
|
||||||
|
}
|
||||||
|
|
||||||
|
SPluginRepoIdentifier SPluginRepoIdentifier::fromName(const std::string& name) {
|
||||||
|
return SPluginRepoIdentifier{.type = IDENTIFIER_NAME, .name = name};
|
||||||
|
}
|
||||||
|
|
||||||
|
SPluginRepoIdentifier SPluginRepoIdentifier::fromAuthorName(const std::string& author, const std::string& name) {
|
||||||
|
return SPluginRepoIdentifier{.type = IDENTIFIER_AUTHOR_NAME, .name = name, .author = author};
|
||||||
|
}
|
||||||
|
|
||||||
|
SPluginRepoIdentifier SPluginRepoIdentifier::fromString(const std::string& string) {
|
||||||
|
if (string.find(':') != std::string::npos) {
|
||||||
|
return SPluginRepoIdentifier{.type = IDENTIFIER_URL, .url = string};
|
||||||
|
} else {
|
||||||
|
auto slashPos = string.find('/');
|
||||||
|
if (slashPos != std::string::npos) {
|
||||||
|
std::string author = string.substr(0, slashPos);
|
||||||
|
std::string name = string.substr(slashPos + 1, string.size() - slashPos - 1);
|
||||||
|
return SPluginRepoIdentifier{.type = IDENTIFIER_AUTHOR_NAME, .name = name, .author = author};
|
||||||
|
} else {
|
||||||
|
return SPluginRepoIdentifier{.type = IDENTIFIER_NAME, .name = string};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string SPluginRepoIdentifier::toString() const {
|
||||||
|
switch (type) {
|
||||||
|
case IDENTIFIER_NAME: return name;
|
||||||
|
case IDENTIFIER_AUTHOR_NAME: return author + '/' + name;
|
||||||
|
case IDENTIFIER_URL: return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SPluginRepoIdentifier::matches(const std::string& url, const std::string& name, const std::string& author) const {
|
||||||
|
switch (type) {
|
||||||
|
case IDENTIFIER_URL: return this->url == url;
|
||||||
|
case IDENTIFIER_NAME: return this->name == name;
|
||||||
|
case IDENTIFIER_AUTHOR_NAME: return this->author == author && this->name == name;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
@ -14,6 +14,27 @@ struct SPluginRepository {
|
||||||
std::string url;
|
std::string url;
|
||||||
std::string rev;
|
std::string rev;
|
||||||
std::string name;
|
std::string name;
|
||||||
|
std::string author;
|
||||||
std::vector<SPlugin> plugins;
|
std::vector<SPlugin> plugins;
|
||||||
std::string hash;
|
std::string hash;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum ePluginRepoIdentifierType {
|
||||||
|
IDENTIFIER_URL,
|
||||||
|
IDENTIFIER_NAME,
|
||||||
|
IDENTIFIER_AUTHOR_NAME
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SPluginRepoIdentifier {
|
||||||
|
ePluginRepoIdentifierType type;
|
||||||
|
std::string url = "";
|
||||||
|
std::string name = "";
|
||||||
|
std::string author = "";
|
||||||
|
|
||||||
|
static SPluginRepoIdentifier fromString(const std::string& string);
|
||||||
|
static SPluginRepoIdentifier fromUrl(const std::string& Url);
|
||||||
|
static SPluginRepoIdentifier fromName(const std::string& name);
|
||||||
|
static SPluginRepoIdentifier fromAuthorName(const std::string& author, const std::string& name);
|
||||||
|
std::string toString() const;
|
||||||
|
bool matches(const std::string& url, const std::string& name, const std::string& author) const;
|
||||||
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,11 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <optional>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <expected>
|
||||||
|
#include "Plugin.hpp"
|
||||||
|
|
||||||
enum eHeadersErrors {
|
enum eHeadersErrors {
|
||||||
HEADERS_OK = 0,
|
HEADERS_OK = 0,
|
||||||
|
|
@ -9,6 +13,7 @@ enum eHeadersErrors {
|
||||||
HEADERS_MISSING,
|
HEADERS_MISSING,
|
||||||
HEADERS_CORRUPTED,
|
HEADERS_CORRUPTED,
|
||||||
HEADERS_MISMATCHED,
|
HEADERS_MISMATCHED,
|
||||||
|
HEADERS_ABI_MISMATCH,
|
||||||
HEADERS_DUPLICATED
|
HEADERS_DUPLICATED
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -26,20 +31,25 @@ enum ePluginLoadStateReturn {
|
||||||
LOADSTATE_OK = 0,
|
LOADSTATE_OK = 0,
|
||||||
LOADSTATE_FAIL,
|
LOADSTATE_FAIL,
|
||||||
LOADSTATE_PARTIAL_FAIL,
|
LOADSTATE_PARTIAL_FAIL,
|
||||||
LOADSTATE_HEADERS_OUTDATED
|
LOADSTATE_HEADERS_OUTDATED,
|
||||||
|
LOADSTATE_HYPRLAND_UPDATED
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SHyprlandVersion {
|
struct SHyprlandVersion {
|
||||||
std::string branch;
|
std::string branch;
|
||||||
std::string hash;
|
std::string hash;
|
||||||
std::string date;
|
std::string date;
|
||||||
|
std::string abiHash;
|
||||||
int commits = 0;
|
int commits = 0;
|
||||||
|
bool isNix = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
class CPluginManager {
|
class CPluginManager {
|
||||||
public:
|
public:
|
||||||
|
CPluginManager();
|
||||||
|
|
||||||
bool addNewPluginRepo(const std::string& url, const std::string& rev);
|
bool addNewPluginRepo(const std::string& url, const std::string& rev);
|
||||||
bool removePluginRepo(const std::string& urlOrName);
|
bool removePluginRepo(const SPluginRepoIdentifier identifier);
|
||||||
|
|
||||||
eHeadersErrors headersValid();
|
eHeadersErrors headersValid();
|
||||||
bool updateHeaders(bool force = false);
|
bool updateHeaders(bool force = false);
|
||||||
|
|
@ -47,28 +57,35 @@ class CPluginManager {
|
||||||
|
|
||||||
void listAllPlugins();
|
void listAllPlugins();
|
||||||
|
|
||||||
bool enablePlugin(const std::string& name);
|
bool enablePlugin(const SPluginRepoIdentifier identifier);
|
||||||
bool disablePlugin(const std::string& name);
|
bool disablePlugin(const SPluginRepoIdentifier identifier);
|
||||||
ePluginLoadStateReturn ensurePluginsLoadState();
|
ePluginLoadStateReturn ensurePluginsLoadState(bool forceReload = false);
|
||||||
|
|
||||||
bool loadUnloadPlugin(const std::string& path, bool load);
|
bool loadUnloadPlugin(const std::string& path, bool load);
|
||||||
SHyprlandVersion getHyprlandVersion();
|
SHyprlandVersion getHyprlandVersion(bool running = true);
|
||||||
|
|
||||||
void notify(const eNotifyIcons icon, uint32_t color, int durationMs, const std::string& message);
|
void notify(const eNotifyIcons icon, uint32_t color, int durationMs, const std::string& message);
|
||||||
|
|
||||||
|
const std::string& getPkgConfigPath();
|
||||||
|
|
||||||
bool hasDeps();
|
bool hasDeps();
|
||||||
|
|
||||||
bool m_bVerbose = false;
|
bool m_bVerbose = false;
|
||||||
bool m_bNoShallow = false;
|
bool m_bNoShallow = false;
|
||||||
|
bool m_bNoNix = false;
|
||||||
|
std::string m_szCustomHlUrl, m_szUsername, m_szArgv0;
|
||||||
|
|
||||||
// will delete recursively if exists!!
|
// will delete recursively if exists!!
|
||||||
bool createSafeDirectory(const std::string& path);
|
bool createSafeDirectory(const std::string& path);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string headerError(const eHeadersErrors err);
|
std::string headerError(const eHeadersErrors err);
|
||||||
std::string headerErrorShort(const eHeadersErrors err);
|
std::string headerErrorShort(const eHeadersErrors err);
|
||||||
|
bool validArg(const std::string& s);
|
||||||
|
|
||||||
std::string m_szWorkingPluginDirectory = "";
|
std::expected<std::string, std::string> nixDevelopIfNeeded(const std::string& cmd, const SHyprlandVersion& ver);
|
||||||
|
|
||||||
|
std::string m_szWorkingPluginDirectory;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline std::unique_ptr<CPluginManager> g_pPluginManager;
|
inline std::unique_ptr<CPluginManager> g_pPluginManager;
|
||||||
|
|
|
||||||
15
hyprpm/src/helpers/Die.hpp
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <format>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
// NOLINTNEXTLINE
|
||||||
|
namespace Debug {
|
||||||
|
template <typename... Args>
|
||||||
|
void die(std::format_string<Args...> fmt, Args&&... args) {
|
||||||
|
const std::string logMsg = std::vformat(fmt.get(), std::make_format_args(args...));
|
||||||
|
|
||||||
|
std::cout << "\n[ERR] " << logMsg << "\n";
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
};
|
||||||
32
hyprpm/src/helpers/StringUtils.hpp
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <format>
|
||||||
|
#include <string>
|
||||||
|
#include "Colors.hpp"
|
||||||
|
|
||||||
|
template <typename... Args>
|
||||||
|
std::string statusString(const std::string_view emoji, const std::string_view color, const std::string_view fmt, Args&&... args) {
|
||||||
|
std::string ret = std::format("{}{}{} ", color, emoji, Colors::RESET);
|
||||||
|
ret += std::vformat(fmt, std::make_format_args(args...));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename... Args>
|
||||||
|
std::string successString(const std::string_view fmt, Args&&... args) {
|
||||||
|
return statusString("✔", Colors::GREEN, fmt, args...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename... Args>
|
||||||
|
std::string failureString(const std::string_view fmt, Args&&... args) {
|
||||||
|
return statusString("✖", Colors::RED, fmt, args...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename... Args>
|
||||||
|
std::string verboseString(const std::string_view fmt, Args&&... args) {
|
||||||
|
return statusString("[v]", Colors::BLUE, fmt, args...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename... Args>
|
||||||
|
std::string infoString(const std::string_view fmt, Args&&... args) {
|
||||||
|
return statusString("→", Colors::RESET, fmt, args...);
|
||||||
|
}
|
||||||
173
hyprpm/src/helpers/Sys.cpp
Normal file
|
|
@ -0,0 +1,173 @@
|
||||||
|
#include "Sys.hpp"
|
||||||
|
#include "Die.hpp"
|
||||||
|
#include "StringUtils.hpp"
|
||||||
|
|
||||||
|
#include <pwd.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sstream>
|
||||||
|
#include <print>
|
||||||
|
#include <filesystem>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
#include <hyprutils/os/Process.hpp>
|
||||||
|
#include <hyprutils/string/VarList.hpp>
|
||||||
|
|
||||||
|
using namespace Hyprutils::OS;
|
||||||
|
using namespace Hyprutils::String;
|
||||||
|
|
||||||
|
inline constexpr std::array<std::string_view, 3> SUPERUSER_BINARIES = {
|
||||||
|
"sudo",
|
||||||
|
"doas",
|
||||||
|
"run0",
|
||||||
|
};
|
||||||
|
|
||||||
|
static std::string validSubinsAsStr() {
|
||||||
|
std::ostringstream oss;
|
||||||
|
auto it = SUPERUSER_BINARIES.begin();
|
||||||
|
if (it != SUPERUSER_BINARIES.end()) {
|
||||||
|
oss << *it++;
|
||||||
|
for (; it != SUPERUSER_BINARIES.end(); ++it)
|
||||||
|
oss << ", " << *it;
|
||||||
|
}
|
||||||
|
|
||||||
|
return oss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool executableExistsInPath(const std::string& exe) {
|
||||||
|
return NSys::findInPath(exe).has_value();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<std::string> NSys::findInPath(const std::string& exe) {
|
||||||
|
const char* PATHENV = std::getenv("PATH");
|
||||||
|
if (!PATHENV)
|
||||||
|
return std::nullopt;
|
||||||
|
|
||||||
|
CVarList paths(PATHENV, 0, ':', true);
|
||||||
|
std::error_code ec;
|
||||||
|
|
||||||
|
for (const auto& PATH : paths) {
|
||||||
|
std::filesystem::path candidate = std::filesystem::path(PATH) / exe;
|
||||||
|
if (!std::filesystem::exists(candidate, ec) || ec)
|
||||||
|
continue;
|
||||||
|
if (!std::filesystem::is_regular_file(candidate, ec) || ec)
|
||||||
|
continue;
|
||||||
|
auto perms = std::filesystem::status(candidate, ec).permissions();
|
||||||
|
if (ec)
|
||||||
|
continue;
|
||||||
|
if ((perms & std::filesystem::perms::others_exec) != std::filesystem::perms::none)
|
||||||
|
return candidate.string();
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string subin() {
|
||||||
|
static std::string bin;
|
||||||
|
static bool once = true;
|
||||||
|
if (!once)
|
||||||
|
return bin;
|
||||||
|
|
||||||
|
for (const auto& BIN : SUPERUSER_BINARIES) {
|
||||||
|
if (!executableExistsInPath(std::string{BIN}))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
bin = BIN;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
once = false;
|
||||||
|
|
||||||
|
if (bin.empty())
|
||||||
|
Debug::die("{}", failureString("No valid superuser binary present. Supported: {}", validSubinsAsStr()));
|
||||||
|
|
||||||
|
return bin;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool verifyStringValid(const std::string& s) {
|
||||||
|
return std::ranges::none_of(s, [](const char& c) { return c == '`' || c == '$' || c == '(' || c == ')' || c == '\'' || c == '"'; });
|
||||||
|
}
|
||||||
|
|
||||||
|
int NSys::getUID() {
|
||||||
|
const auto UID = getuid();
|
||||||
|
const auto PWUID = getpwuid(UID);
|
||||||
|
return PWUID ? PWUID->pw_uid : UID;
|
||||||
|
}
|
||||||
|
|
||||||
|
int NSys::getEUID() {
|
||||||
|
const auto UID = geteuid();
|
||||||
|
const auto PWUID = getpwuid(UID);
|
||||||
|
return PWUID ? PWUID->pw_uid : UID;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NSys::isSuperuser() {
|
||||||
|
return getuid() != geteuid() || geteuid() == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NSys::root::cacheSudo() {
|
||||||
|
// "caches" the sudo so that the prompt later doesn't pop up in a weird spot
|
||||||
|
// sudo will not ask us again for a moment
|
||||||
|
CProcess proc(subin(), {"echo", "hyprland"});
|
||||||
|
proc.runSync();
|
||||||
|
}
|
||||||
|
|
||||||
|
void NSys::root::dropSudo() {
|
||||||
|
if (subin() != "sudo") {
|
||||||
|
std::println("{}", infoString("Don't know how to drop timestamp for '{}', ignoring.", subin()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CProcess proc(subin(), {"-k"});
|
||||||
|
proc.runSync();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NSys::root::createDirectory(const std::string& path, const std::string& mode) {
|
||||||
|
if (!verifyStringValid(path))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!std::ranges::all_of(mode, [](const char& c) { return c >= '0' && c <= '9'; }))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
CProcess proc(subin(), {"mkdir", "-p", "-m", mode, path});
|
||||||
|
|
||||||
|
return proc.runSync() && proc.exitCode() == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NSys::root::removeRecursive(const std::string& path) {
|
||||||
|
if (!verifyStringValid(path))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
std::error_code ec;
|
||||||
|
const std::string PATH_ABSOLUTE = std::filesystem::canonical(path, ec);
|
||||||
|
|
||||||
|
if (ec)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!PATH_ABSOLUTE.starts_with("/var/cache/hyprpm"))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
CProcess proc(subin(), {"rm", "-fr", PATH_ABSOLUTE});
|
||||||
|
|
||||||
|
return proc.runSync() && proc.exitCode() == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NSys::root::install(const std::string& what, const std::string& where, const std::string& mode) {
|
||||||
|
if (!verifyStringValid(what) || !verifyStringValid(where))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!std::ranges::all_of(mode, [](const char& c) { return c >= '0' && c <= '9'; }))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
CProcess proc(subin(), {"install", "-m" + mode, "-o", "0", "-g", "0", what, where});
|
||||||
|
|
||||||
|
return proc.runSync() && proc.exitCode() == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string NSys::root::runAsSuperuserUnsafe(const std::string& cmd) {
|
||||||
|
CProcess proc(subin(), {"/bin/sh", "-c", cmd});
|
||||||
|
|
||||||
|
if (!proc.runSync())
|
||||||
|
return "";
|
||||||
|
|
||||||
|
return proc.stdOut();
|
||||||
|
}
|
||||||
25
hyprpm/src/helpers/Sys.hpp
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
|
namespace NSys {
|
||||||
|
bool isSuperuser();
|
||||||
|
int getUID();
|
||||||
|
int getEUID();
|
||||||
|
std::optional<std::string> findInPath(const std::string& exe);
|
||||||
|
|
||||||
|
// NOLINTNEXTLINE
|
||||||
|
namespace root {
|
||||||
|
void cacheSudo();
|
||||||
|
void dropSudo();
|
||||||
|
|
||||||
|
//
|
||||||
|
[[nodiscard("Discarding could lead to vulnerabilities and bugs")]] bool createDirectory(const std::string& path, const std::string& mode);
|
||||||
|
[[nodiscard("Discarding could lead to vulnerabilities and bugs")]] bool removeRecursive(const std::string& path);
|
||||||
|
[[nodiscard("Discarding could lead to vulnerabilities and bugs")]] bool install(const std::string& what, const std::string& where, const std::string& mode);
|
||||||
|
|
||||||
|
// Do not use this unless absolutely necessary!
|
||||||
|
std::string runAsSuperuserUnsafe(const std::string& cmd);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
@ -1,107 +1,148 @@
|
||||||
#include "progress/CProgressBar.hpp"
|
|
||||||
#include "helpers/Colors.hpp"
|
#include "helpers/Colors.hpp"
|
||||||
|
#include "helpers/StringUtils.hpp"
|
||||||
#include "core/PluginManager.hpp"
|
#include "core/PluginManager.hpp"
|
||||||
#include "core/DataState.hpp"
|
#include "core/DataState.hpp"
|
||||||
|
#include "helpers/Sys.hpp"
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <chrono>
|
#include <print>
|
||||||
#include <thread>
|
|
||||||
|
|
||||||
const std::string HELP = R"#(┏ hyprpm, a Hyprland Plugin Manager
|
#include <hyprutils/utils/ScopeGuard.hpp>
|
||||||
|
using namespace Hyprutils::Utils;
|
||||||
|
|
||||||
|
constexpr std::string_view HELP = R"#(┏ hyprpm, a Hyprland Plugin Manager
|
||||||
┃
|
┃
|
||||||
┣ add [url] [git rev] → Install a new plugin repository from git. Git revision
|
┣ add <url> [git rev] → Install a new plugin repository from git. Git revision
|
||||||
┃ is optional, when set, commit locks are ignored.
|
┃ is optional, when set, commit locks are ignored.
|
||||||
┣ remove [url/name] → Remove an installed plugin repository
|
┣ remove <url|name|author/name> → Remove an installed plugin repository.
|
||||||
┣ enable [name] → Enable a plugin
|
┣ enable <name|author/name> → Enable a plugin.
|
||||||
┣ disable [name] → Disable a plugin
|
┣ disable <name|author/name> → Disable a plugin.
|
||||||
┣ update → Check and update all plugins if needed
|
┣ update → Check and update all plugins if needed.
|
||||||
┣ reload → Reload hyprpm state. Ensure all enabled plugins are loaded.
|
┣ reload → Reload hyprpm state. Ensure all enabled plugins are loaded.
|
||||||
┣ list → List all installed plugins
|
┣ list → List all installed plugins.
|
||||||
|
┣ purge-cache → Remove the entire hyprpm cache, built plugins, hyprpm settings and headers.
|
||||||
┃
|
┃
|
||||||
┣ Flags:
|
┣ Flags:
|
||||||
┃
|
┃
|
||||||
┣ --notify | -n → Send a hyprland notification for important events (e.g. load fail)
|
┣ --no-nix | → Disable `nix develop` for build commands, even if Hyprland is nix.
|
||||||
┣ --help | -h → Show this menu
|
┣ --notify | -n → Send a hyprland notification confirming successful plugin load.
|
||||||
┣ --verbose | -v → Enable too much logging
|
┃ Warnings/Errors trigger notifications regardless of this flag.
|
||||||
┣ --force | -f → Force an operation ignoring checks (e.g. update -f)
|
┣ --help | -h → Show this menu.
|
||||||
┣ --no-shallow | -s → Disable shallow cloning of Hyprland sources
|
┣ --verbose | -v → Enable too much logging.
|
||||||
|
┣ --force | -f → Force an operation ignoring checks (e.g. update -f).
|
||||||
|
┣ --no-shallow | -s → Disable shallow cloning of Hyprland sources.
|
||||||
|
┣ --hl-url | → Pass a custom hyprland source url.
|
||||||
┗
|
┗
|
||||||
)#";
|
)#";
|
||||||
|
|
||||||
int main(int argc, char** argv, char** envp) {
|
int main(int argc, char** argv, char** envp) {
|
||||||
std::vector<std::string> ARGS{argc};
|
std::vector<std::string> ARGS{argc};
|
||||||
for (int i = 0; i < argc; ++i) {
|
for (int i = 0; i < argc; ++i) {
|
||||||
ARGS[i] = std::string{argv[i]};
|
ARGS[i] = std::string{argv[i]};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ARGS.size() < 2) {
|
if (ARGS.size() < 2) {
|
||||||
std::cout << HELP;
|
std::println(stderr, "{}", HELP);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> command;
|
std::vector<std::string> command;
|
||||||
bool notify = false, verbose = false, force = false, noShallow = false;
|
bool notify = false, verbose = false, force = false, noShallow = false, noNix = false;
|
||||||
|
std::string customHlUrl;
|
||||||
|
|
||||||
for (int i = 1; i < argc; ++i) {
|
for (int i = 1; i < argc; ++i) {
|
||||||
if (ARGS[i].starts_with("-")) {
|
if (ARGS[i].starts_with("-")) {
|
||||||
if (ARGS[i] == "--help" || ARGS[i] == "-h") {
|
if (ARGS[i] == "--help" || ARGS[i] == "-h") {
|
||||||
std::cout << HELP;
|
std::println("{}", HELP);
|
||||||
return 0;
|
return 0;
|
||||||
} else if (ARGS[i] == "--notify" || ARGS[i] == "-n") {
|
} else if (ARGS[i] == "--notify" || ARGS[i] == "-n") {
|
||||||
notify = true;
|
notify = true;
|
||||||
|
} else if (ARGS[i] == "--notify-fail" || ARGS[i] == "-nn") {
|
||||||
|
// TODO: Deprecated since v.053.0. Remove in version>0.56.0
|
||||||
|
std::println(stderr, "{}", failureString("Deprececated flag."));
|
||||||
|
g_pPluginManager->notify(ICON_INFO, 0, 10000, "[hyprpm] -n flag is deprecated, see hyprpm --help.");
|
||||||
} else if (ARGS[i] == "--verbose" || ARGS[i] == "-v") {
|
} else if (ARGS[i] == "--verbose" || ARGS[i] == "-v") {
|
||||||
verbose = true;
|
verbose = true;
|
||||||
|
} else if (ARGS[i] == "--no-nix") {
|
||||||
|
noNix = true;
|
||||||
} else if (ARGS[i] == "--no-shallow" || ARGS[i] == "-s") {
|
} else if (ARGS[i] == "--no-shallow" || ARGS[i] == "-s") {
|
||||||
noShallow = true;
|
noShallow = true;
|
||||||
|
} else if (ARGS[i] == "--hl-url") {
|
||||||
|
if (i + 1 >= argc) {
|
||||||
|
std::println(stderr, "Missing argument for --hl-url");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
customHlUrl = ARGS[i + 1];
|
||||||
|
i++;
|
||||||
} else if (ARGS[i] == "--force" || ARGS[i] == "-f") {
|
} else if (ARGS[i] == "--force" || ARGS[i] == "-f") {
|
||||||
force = true;
|
force = true;
|
||||||
std::cout << Colors::RED << "!" << Colors::RESET << " Using --force, I hope you know what you are doing.\n";
|
std::println("{}", statusString("!", Colors::RED, "Using --force, I hope you know what you are doing."));
|
||||||
} else {
|
} else {
|
||||||
std::cerr << "Unrecognized option " << ARGS[i] << "\n";
|
std::println(stderr, "Unrecognized option {}", ARGS[i]);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
} else {
|
} else
|
||||||
command.push_back(ARGS[i]);
|
command.push_back(ARGS[i]);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (command.empty()) {
|
if (command.empty()) {
|
||||||
std::cout << HELP;
|
std::println(stderr, "{}", HELP);
|
||||||
return 0;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
g_pPluginManager = std::make_unique<CPluginManager>();
|
g_pPluginManager = std::make_unique<CPluginManager>();
|
||||||
g_pPluginManager->m_bVerbose = verbose;
|
g_pPluginManager->m_bVerbose = verbose;
|
||||||
g_pPluginManager->m_bNoShallow = noShallow;
|
g_pPluginManager->m_bNoShallow = noShallow;
|
||||||
|
g_pPluginManager->m_bNoNix = noNix;
|
||||||
|
g_pPluginManager->m_szCustomHlUrl = customHlUrl;
|
||||||
|
g_pPluginManager->m_szArgv0 = argv[0];
|
||||||
|
|
||||||
if (command[0] == "add") {
|
if (command[0] == "add") {
|
||||||
if (command.size() < 2) {
|
if (command.size() < 2) {
|
||||||
std::cerr << Colors::RED << "✖" << Colors::RESET << " Not enough args for add.\n";
|
std::println(stderr, "{}", failureString("Not enough args for add."));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string rev = "";
|
std::string rev = "";
|
||||||
if (command.size() >= 3) {
|
if (command.size() >= 3)
|
||||||
rev = command[2];
|
rev = command[2];
|
||||||
}
|
|
||||||
|
|
||||||
return g_pPluginManager->addNewPluginRepo(command[1], rev) ? 0 : 1;
|
const auto HLVER = g_pPluginManager->getHyprlandVersion();
|
||||||
} else if (command[0] == "remove") {
|
auto GLOBALSTATE = DataState::getGlobalState();
|
||||||
if (ARGS.size() < 2) {
|
|
||||||
std::cerr << Colors::RED << "✖" << Colors::RESET << " Not enough args for remove.\n";
|
if (GLOBALSTATE.headersAbiCompiled != HLVER.abiHash) {
|
||||||
|
std::println(stderr, "{}", failureString("Headers outdated, please run hyprpm update."));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return g_pPluginManager->removePluginRepo(command[1]) ? 0 : 1;
|
NSys::root::cacheSudo();
|
||||||
|
CScopeGuard x([] { NSys::root::dropSudo(); });
|
||||||
|
|
||||||
|
g_pPluginManager->updateHeaders(false);
|
||||||
|
|
||||||
|
return g_pPluginManager->addNewPluginRepo(command[1], rev) ? 0 : 1;
|
||||||
|
} else if (command[0] == "remove") {
|
||||||
|
if (command.size() < 2) {
|
||||||
|
std::println(stderr, "{}", failureString("Not enough args for remove."));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
NSys::root::cacheSudo();
|
||||||
|
CScopeGuard x([] { NSys::root::dropSudo(); });
|
||||||
|
|
||||||
|
return g_pPluginManager->removePluginRepo(SPluginRepoIdentifier::fromString(command[1])) ? 0 : 1;
|
||||||
} else if (command[0] == "update") {
|
} else if (command[0] == "update") {
|
||||||
bool headersValid = g_pPluginManager->headersValid() == HEADERS_OK;
|
NSys::root::cacheSudo();
|
||||||
bool headers = g_pPluginManager->updateHeaders(force);
|
CScopeGuard x([] { NSys::root::dropSudo(); });
|
||||||
|
|
||||||
|
bool headersValid = g_pPluginManager->headersValid() == HEADERS_OK;
|
||||||
|
bool headers = g_pPluginManager->updateHeaders(force);
|
||||||
|
|
||||||
if (headers) {
|
if (headers) {
|
||||||
const auto HLVER = g_pPluginManager->getHyprlandVersion();
|
const auto HLVER = g_pPluginManager->getHyprlandVersion(false);
|
||||||
auto GLOBALSTATE = DataState::getGlobalState();
|
auto GLOBALSTATE = DataState::getGlobalState();
|
||||||
const auto COMPILEDOUTDATED = HLVER.hash != GLOBALSTATE.headersHashCompiled;
|
const auto COMPILEDOUTDATED = HLVER.abiHash != GLOBALSTATE.headersAbiCompiled;
|
||||||
|
|
||||||
bool ret1 = g_pPluginManager->updatePlugins(!headersValid || force || COMPILEDOUTDATED);
|
bool ret1 = g_pPluginManager->updatePlugins(!headersValid || force || COMPILEDOUTDATED);
|
||||||
|
|
||||||
|
|
@ -110,42 +151,57 @@ int main(int argc, char** argv, char** envp) {
|
||||||
|
|
||||||
auto ret2 = g_pPluginManager->ensurePluginsLoadState();
|
auto ret2 = g_pPluginManager->ensurePluginsLoadState();
|
||||||
|
|
||||||
|
if (ret2 == LOADSTATE_HYPRLAND_UPDATED)
|
||||||
|
g_pPluginManager->notify(ICON_INFO, 0, 10000, "[hyprpm] Updated plugins, but Hyprland was updated. Please restart Hyprland.");
|
||||||
|
|
||||||
if (ret2 != LOADSTATE_OK)
|
if (ret2 != LOADSTATE_OK)
|
||||||
return 1;
|
return 1;
|
||||||
} else if (notify)
|
} else {
|
||||||
g_pPluginManager->notify(ICON_ERROR, 0, 10000, "[hyprpm] Couldn't update headers");
|
g_pPluginManager->notify(ICON_ERROR, 0, 10000, "[hyprpm] Couldn't update headers");
|
||||||
|
}
|
||||||
} else if (command[0] == "enable") {
|
} else if (command[0] == "enable") {
|
||||||
if (ARGS.size() < 2) {
|
if (command.size() < 2) {
|
||||||
std::cerr << Colors::RED << "✖" << Colors::RESET << " Not enough args for enable.\n";
|
std::println(stderr, "{}", failureString("Not enough args for enable."));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!g_pPluginManager->enablePlugin(command[1])) {
|
if (!g_pPluginManager->enablePlugin(SPluginRepoIdentifier::fromString(command[1]))) {
|
||||||
std::cerr << Colors::RED << "✖" << Colors::RESET << " Couldn't enable plugin (missing?)\n";
|
std::println(stderr, "{}", failureString("Couldn't enable plugin (missing?)"));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ret = g_pPluginManager->ensurePluginsLoadState();
|
NSys::root::cacheSudo();
|
||||||
|
CScopeGuard x([] { NSys::root::dropSudo(); });
|
||||||
|
|
||||||
|
auto ret = g_pPluginManager->ensurePluginsLoadState();
|
||||||
|
|
||||||
|
if (ret == LOADSTATE_HYPRLAND_UPDATED)
|
||||||
|
g_pPluginManager->notify(ICON_INFO, 0, 10000, "[hyprpm] Enabled plugin, but Hyprland was updated. Please restart Hyprland.");
|
||||||
|
|
||||||
if (ret != LOADSTATE_OK)
|
if (ret != LOADSTATE_OK)
|
||||||
return 1;
|
return 1;
|
||||||
} else if (command[0] == "disable") {
|
} else if (command[0] == "disable") {
|
||||||
if (command.size() < 2) {
|
if (command.size() < 2) {
|
||||||
std::cerr << Colors::RED << "✖" << Colors::RESET << " Not enough args for disable.\n";
|
std::println(stderr, "{}", failureString("Not enough args for disable."));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!g_pPluginManager->disablePlugin(command[1])) {
|
if (!g_pPluginManager->disablePlugin(SPluginRepoIdentifier::fromString(command[1]))) {
|
||||||
std::cerr << Colors::RED << "✖" << Colors::RESET << " Couldn't disable plugin (missing?)\n";
|
std::println(stderr, "{}", failureString("Couldn't disable plugin (missing?)"));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ret = g_pPluginManager->ensurePluginsLoadState();
|
NSys::root::cacheSudo();
|
||||||
|
CScopeGuard x([] { NSys::root::dropSudo(); });
|
||||||
|
|
||||||
|
auto ret = g_pPluginManager->ensurePluginsLoadState();
|
||||||
|
|
||||||
if (ret != LOADSTATE_OK)
|
if (ret != LOADSTATE_OK)
|
||||||
return 1;
|
return 1;
|
||||||
} else if (command[0] == "reload") {
|
} else if (command[0] == "reload") {
|
||||||
auto ret = g_pPluginManager->ensurePluginsLoadState();
|
auto ret = g_pPluginManager->ensurePluginsLoadState(force);
|
||||||
|
|
||||||
if (ret != LOADSTATE_OK && notify) {
|
if (ret != LOADSTATE_OK) {
|
||||||
switch (ret) {
|
switch (ret) {
|
||||||
case LOADSTATE_FAIL:
|
case LOADSTATE_FAIL:
|
||||||
case LOADSTATE_PARTIAL_FAIL: g_pPluginManager->notify(ICON_ERROR, 0, 10000, "[hyprpm] Failed to load plugins"); break;
|
case LOADSTATE_PARTIAL_FAIL: g_pPluginManager->notify(ICON_ERROR, 0, 10000, "[hyprpm] Failed to load plugins"); break;
|
||||||
|
|
@ -154,13 +210,19 @@ int main(int argc, char** argv, char** envp) {
|
||||||
break;
|
break;
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
} else if (notify) {
|
} else if (notify) {
|
||||||
g_pPluginManager->notify(ICON_OK, 0, 4000, "[hyprpm] Loaded plugins");
|
g_pPluginManager->notify(ICON_OK, 0, 4000, "[hyprpm] Loaded plugins");
|
||||||
}
|
}
|
||||||
|
} else if (command[0] == "purge-cache") {
|
||||||
|
NSys::root::cacheSudo();
|
||||||
|
CScopeGuard x([] { NSys::root::dropSudo(); });
|
||||||
|
DataState::purgeAllCache();
|
||||||
} else if (command[0] == "list") {
|
} else if (command[0] == "list") {
|
||||||
g_pPluginManager->listAllPlugins();
|
g_pPluginManager->listAllPlugins();
|
||||||
} else {
|
} else {
|
||||||
std::cout << HELP;
|
std::println(stderr, "{}", HELP);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,15 +0,0 @@
|
||||||
globber = run_command('sh', '-c', 'find . -name "*.cpp" | sort', check: true)
|
|
||||||
src = globber.stdout().strip().split('\n')
|
|
||||||
|
|
||||||
executable('hyprpm', src,
|
|
||||||
dependencies: [
|
|
||||||
dependency('hyprutils', version: '>= 0.1.1'),
|
|
||||||
dependency('threads'),
|
|
||||||
dependency('tomlplusplus')
|
|
||||||
],
|
|
||||||
install : true
|
|
||||||
)
|
|
||||||
|
|
||||||
install_data('../hyprpm.bash', install_dir: join_paths(get_option('datadir'), 'bash-completion/completions'), install_tag: 'runtime', rename: 'hyprpm')
|
|
||||||
install_data('../hyprpm.fish', install_dir: join_paths(get_option('datadir'), 'fish/vendor_completions.d'), install_tag: 'runtime')
|
|
||||||
install_data('../hyprpm.zsh', install_dir: join_paths(get_option('datadir'), 'zsh/site-functions'), install_tag: 'runtime', rename: '_hyprpm')
|
|
||||||
|
|
@ -1,80 +1,80 @@
|
||||||
#include "CProgressBar.hpp"
|
#include "CProgressBar.hpp"
|
||||||
|
|
||||||
#include <iostream>
|
#include <sys/ioctl.h>
|
||||||
#include <algorithm>
|
#include <unistd.h>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <format>
|
#include <format>
|
||||||
|
#include <print>
|
||||||
|
#include <cstdio>
|
||||||
|
|
||||||
#include <sys/ioctl.h>
|
#include <algorithm>
|
||||||
#include <stdio.h>
|
#include <sstream>
|
||||||
#include <unistd.h>
|
#include <hyprutils/memory/Casts.hpp>
|
||||||
|
|
||||||
#include "../helpers/Colors.hpp"
|
#include "../helpers/Colors.hpp"
|
||||||
|
|
||||||
void CProgressBar::printMessageAbove(const std::string& msg) {
|
using namespace Hyprutils::Memory;
|
||||||
struct winsize w;
|
|
||||||
|
static winsize getTerminalSize() {
|
||||||
|
winsize w{};
|
||||||
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
|
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
|
||||||
|
return w;
|
||||||
|
}
|
||||||
|
|
||||||
std::string spaces;
|
static void clearCurrentLine() {
|
||||||
for (size_t i = 0; i < w.ws_col; ++i) {
|
std::print("\r\33[2K"); // ansi escape sequence to clear entire line
|
||||||
spaces += ' ';
|
}
|
||||||
}
|
|
||||||
|
|
||||||
std::cout << "\r" << spaces << "\r" << msg << "\n";
|
void CProgressBar::printMessageAbove(const std::string& msg) {
|
||||||
print();
|
clearCurrentLine();
|
||||||
|
std::print("\r{}\n", msg);
|
||||||
|
|
||||||
|
print(); // reprint bar underneath
|
||||||
}
|
}
|
||||||
|
|
||||||
void CProgressBar::print() {
|
void CProgressBar::print() {
|
||||||
struct winsize w;
|
const auto w = getTerminalSize();
|
||||||
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
|
|
||||||
|
|
||||||
if (m_bFirstPrint)
|
if (m_bFirstPrint) {
|
||||||
std::cout << "\n";
|
std::print("\n");
|
||||||
m_bFirstPrint = false;
|
m_bFirstPrint = false;
|
||||||
|
|
||||||
std::string spaces;
|
|
||||||
for (size_t i = 0; i < w.ws_col; ++i) {
|
|
||||||
spaces += ' ';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << "\r" << spaces << "\r";
|
clearCurrentLine();
|
||||||
|
|
||||||
std::string message = "";
|
float percentDone = 0.0f;
|
||||||
|
if (m_fPercentage >= 0.0f)
|
||||||
float percentDone = 0;
|
|
||||||
if (m_fPercentage >= 0)
|
|
||||||
percentDone = m_fPercentage;
|
percentDone = m_fPercentage;
|
||||||
else
|
else {
|
||||||
percentDone = (float)m_iSteps / (float)m_iMaxSteps;
|
// check for divide-by-zero
|
||||||
|
percentDone = m_iMaxSteps > 0 ? sc<float>(m_iSteps) / m_iMaxSteps : 0.0f;
|
||||||
const auto BARWIDTH = std::clamp(w.ws_col - static_cast<unsigned long>(m_szCurrentMessage.length()) - 2, 0UL, 50UL);
|
|
||||||
|
|
||||||
// draw bar
|
|
||||||
message += std::string{" "} + Colors::GREEN;
|
|
||||||
size_t i = 0;
|
|
||||||
for (; i < std::floor(percentDone * BARWIDTH); ++i) {
|
|
||||||
message += "━";
|
|
||||||
}
|
}
|
||||||
|
// clamp to ensure no overflows (sanity check)
|
||||||
|
percentDone = std::clamp(percentDone, 0.0f, 1.0f);
|
||||||
|
|
||||||
|
const size_t BARWIDTH = std::clamp<size_t>(w.ws_col - m_szCurrentMessage.length() - 2, 0, 50);
|
||||||
|
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << ' ' << Colors::GREEN;
|
||||||
|
|
||||||
|
size_t filled = std::floor(percentDone * BARWIDTH);
|
||||||
|
size_t i = 0;
|
||||||
|
|
||||||
|
for (; i < filled; ++i)
|
||||||
|
oss << "━";
|
||||||
|
|
||||||
if (i < BARWIDTH) {
|
if (i < BARWIDTH) {
|
||||||
i++;
|
oss << "╍" << Colors::RESET;
|
||||||
|
++i;
|
||||||
message += std::string{"╍"} + Colors::RESET;
|
for (; i < BARWIDTH; ++i)
|
||||||
|
oss << "━";
|
||||||
for (; i < BARWIDTH; ++i) {
|
|
||||||
message += "━";
|
|
||||||
}
|
|
||||||
} else
|
} else
|
||||||
message += Colors::RESET;
|
oss << Colors::RESET;
|
||||||
|
|
||||||
// draw progress
|
if (m_fPercentage >= 0.0f)
|
||||||
if (m_fPercentage >= 0)
|
oss << " " << std::format("{}%", sc<int>(percentDone * 100.0)) << ' ';
|
||||||
message += " " + std::format("{}%", static_cast<int>(percentDone * 100.0)) + " ";
|
|
||||||
else
|
else
|
||||||
message += " " + std::format("{} / {}", m_iSteps, m_iMaxSteps) + " ";
|
oss << " " << std::format("{} / {}", m_iSteps, m_iMaxSteps) << ' ';
|
||||||
|
|
||||||
// draw message
|
|
||||||
std::cout << message + " " + m_szCurrentMessage;
|
|
||||||
|
|
||||||
|
std::print("{} {}", oss.str(), m_szCurrentMessage);
|
||||||
std::fflush(stdout);
|
std::fflush(stdout);
|
||||||
}
|
}
|
||||||
104
hyprtester/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,104 @@
|
||||||
|
cmake_minimum_required(VERSION 3.19)
|
||||||
|
|
||||||
|
project(hyprtester DESCRIPTION "Hyprland test suite")
|
||||||
|
|
||||||
|
include(GNUInstallDirs)
|
||||||
|
|
||||||
|
set(CMAKE_CXX_STANDARD 26)
|
||||||
|
set(CMAKE_EXPORT_COMPILE_COMMANDS TRUE)
|
||||||
|
|
||||||
|
find_package(PkgConfig REQUIRED)
|
||||||
|
|
||||||
|
pkg_check_modules(hyprtester_deps REQUIRED IMPORTED_TARGET hyprutils>=0.5.0)
|
||||||
|
|
||||||
|
file(GLOB_RECURSE SRCFILES CONFIGURE_DEPENDS "src/*.cpp")
|
||||||
|
|
||||||
|
add_executable(hyprtester ${SRCFILES})
|
||||||
|
add_custom_command(
|
||||||
|
TARGET hyprtester
|
||||||
|
POST_BUILD
|
||||||
|
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/plugin/build.sh
|
||||||
|
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/plugin)
|
||||||
|
|
||||||
|
target_link_libraries(hyprtester PUBLIC PkgConfig::hyprtester_deps)
|
||||||
|
|
||||||
|
install(TARGETS hyprtester)
|
||||||
|
|
||||||
|
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/test.conf
|
||||||
|
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/hypr)
|
||||||
|
|
||||||
|
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/plugin/hyprtestplugin.so
|
||||||
|
DESTINATION ${CMAKE_INSTALL_PREFIX}/lib)
|
||||||
|
|
||||||
|
file(WRITE ${CMAKE_CURRENT_SOURCE_DIR}/src/tests/clients/build.hpp
|
||||||
|
"#include <string>\n"
|
||||||
|
"static const std::string binaryDir = \"${CMAKE_CURRENT_BINARY_DIR}\";"
|
||||||
|
)
|
||||||
|
|
||||||
|
######## wayland protocols testing stuff
|
||||||
|
|
||||||
|
if(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG)
|
||||||
|
set(CMAKE_EXECUTABLE_ENABLE_EXPORTS TRUE)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
find_package(hyprwayland-scanner 0.4.0 REQUIRED)
|
||||||
|
pkg_check_modules(
|
||||||
|
protocols_deps
|
||||||
|
REQUIRED
|
||||||
|
IMPORTED_TARGET
|
||||||
|
hyprutils>=0.8.0
|
||||||
|
wayland-client
|
||||||
|
wayland-protocols
|
||||||
|
)
|
||||||
|
|
||||||
|
pkg_get_variable(WAYLAND_PROTOCOLS_DIR wayland-protocols pkgdatadir)
|
||||||
|
message(STATUS "Found wayland-protocols at ${WAYLAND_PROTOCOLS_DIR}")
|
||||||
|
pkg_get_variable(WAYLAND_SCANNER_PKGDATA_DIR wayland-scanner pkgdatadir)
|
||||||
|
message(STATUS "Found wayland-scanner pkgdatadir at ${WAYLAND_SCANNER_PKGDATA_DIR}")
|
||||||
|
|
||||||
|
# gen core wayland stuff
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/protocols/wayland.cpp
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/protocols/wayland.hpp
|
||||||
|
COMMAND hyprwayland-scanner --wayland-enums --client
|
||||||
|
${WAYLAND_SCANNER_PKGDATA_DIR}/wayland.xml ${CMAKE_CURRENT_SOURCE_DIR}/protocols/
|
||||||
|
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
|
|
||||||
|
function(protocolNew protoPath protoName external)
|
||||||
|
if(external)
|
||||||
|
set(path ${CMAKE_CURRENT_SOURCE_DIR}/${protoPath})
|
||||||
|
else()
|
||||||
|
set(path ${WAYLAND_PROTOCOLS_DIR}/${protoPath})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/protocols/${protoName}.cpp
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/protocols/${protoName}.hpp
|
||||||
|
COMMAND hyprwayland-scanner --client ${path}/${protoName}.xml
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/protocols/
|
||||||
|
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
|
endfunction()
|
||||||
|
function(clientNew sourceName)
|
||||||
|
cmake_parse_arguments(PARSE_ARGV 1 ARG "" "" "PROTOS")
|
||||||
|
|
||||||
|
add_executable(${sourceName} clients/${sourceName}.cpp)
|
||||||
|
|
||||||
|
target_include_directories(${sourceName} BEFORE PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/protocols")
|
||||||
|
target_link_libraries(${sourceName} PUBLIC PkgConfig::protocols_deps)
|
||||||
|
|
||||||
|
target_sources(${sourceName} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/protocols/wayland.cpp ${CMAKE_CURRENT_SOURCE_DIR}/protocols/wayland.hpp)
|
||||||
|
|
||||||
|
foreach(protoName IN LISTS ARG_PROTOS)
|
||||||
|
target_sources(${sourceName} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/protocols/${protoName}.cpp
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/protocols/${protoName}.hpp)
|
||||||
|
endforeach()
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
protocolnew("staging/pointer-warp" "pointer-warp-v1" false)
|
||||||
|
protocolnew("stable/xdg-shell" "xdg-shell" false)
|
||||||
|
protocolnew("unstable/keyboard-shortcuts-inhibit" "keyboard-shortcuts-inhibit-unstable-v1" false)
|
||||||
|
|
||||||
|
clientNew("pointer-warp" PROTOS "pointer-warp-v1" "xdg-shell")
|
||||||
|
clientNew("pointer-scroll" PROTOS "xdg-shell")
|
||||||
|
clientNew("child-window" PROTOS "xdg-shell")
|
||||||
|
clientNew("shortcut-inhibitor" PROTOS "xdg-shell" "keyboard-shortcuts-inhibit-unstable-v1")
|
||||||
336
hyprtester/clients/child-window.cpp
Normal file
|
|
@ -0,0 +1,336 @@
|
||||||
|
#include <print>
|
||||||
|
#include <poll.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <wayland-client.h>
|
||||||
|
#include <wayland.hpp>
|
||||||
|
#include <xdg-shell.hpp>
|
||||||
|
|
||||||
|
#include <hyprutils/memory/SharedPtr.hpp>
|
||||||
|
#include <hyprutils/math/Vector2D.hpp>
|
||||||
|
|
||||||
|
using Hyprutils::Math::Vector2D;
|
||||||
|
using namespace Hyprutils::Memory;
|
||||||
|
|
||||||
|
struct SWlState {
|
||||||
|
wl_display* display;
|
||||||
|
CSharedPointer<CCWlRegistry> registry;
|
||||||
|
|
||||||
|
// protocols
|
||||||
|
CSharedPointer<CCWlCompositor> wlCompositor;
|
||||||
|
CSharedPointer<CCWlSeat> wlSeat;
|
||||||
|
CSharedPointer<CCWlShm> wlShm;
|
||||||
|
CSharedPointer<CCXdgWmBase> xdgShell;
|
||||||
|
|
||||||
|
// shm/buffer stuff
|
||||||
|
CSharedPointer<CCWlShmPool> shmPool;
|
||||||
|
CSharedPointer<CCWlBuffer> shmBuf;
|
||||||
|
CSharedPointer<CCWlBuffer> shmBuf2;
|
||||||
|
int shmFd = 0;
|
||||||
|
size_t shmBufSize = 0;
|
||||||
|
bool xrgb8888_support = false;
|
||||||
|
|
||||||
|
// surface/toplevel stuff
|
||||||
|
CSharedPointer<CCWlSurface> surf;
|
||||||
|
CSharedPointer<CCXdgSurface> xdgSurf;
|
||||||
|
CSharedPointer<CCXdgToplevel> xdgToplevel;
|
||||||
|
Vector2D geom;
|
||||||
|
|
||||||
|
// pointer
|
||||||
|
CSharedPointer<CCWlPointer> pointer;
|
||||||
|
uint32_t enterSerial = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool debug, shouldExit, started;
|
||||||
|
|
||||||
|
template <typename... Args>
|
||||||
|
//NOLINTNEXTLINE
|
||||||
|
static void clientLog(std::format_string<Args...> fmt, Args&&... args) {
|
||||||
|
std::string text = std::vformat(fmt.get(), std::make_format_args(args...));
|
||||||
|
std::println("{}", text);
|
||||||
|
std::fflush(stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename... Args>
|
||||||
|
//NOLINTNEXTLINE
|
||||||
|
static void debugLog(std::format_string<Args...> fmt, Args&&... args) {
|
||||||
|
std::string text = std::vformat(fmt.get(), std::make_format_args(args...));
|
||||||
|
if (!debug)
|
||||||
|
return;
|
||||||
|
std::println("{}", text);
|
||||||
|
std::fflush(stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool bindRegistry(SWlState& state) {
|
||||||
|
state.registry = makeShared<CCWlRegistry>((wl_proxy*)wl_display_get_registry(state.display));
|
||||||
|
|
||||||
|
state.registry->setGlobal([&](CCWlRegistry* r, uint32_t id, const char* name, uint32_t version) {
|
||||||
|
const std::string NAME = name;
|
||||||
|
if (NAME == "wl_compositor") {
|
||||||
|
debugLog(" > binding to global: {} (version {}) with id {}", name, version, id);
|
||||||
|
state.wlCompositor = makeShared<CCWlCompositor>((wl_proxy*)wl_registry_bind((wl_registry*)state.registry->resource(), id, &wl_compositor_interface, 6));
|
||||||
|
} else if (NAME == "wl_shm") {
|
||||||
|
debugLog(" > binding to global: {} (version {}) with id {}", name, version, id);
|
||||||
|
state.wlShm = makeShared<CCWlShm>((wl_proxy*)wl_registry_bind((wl_registry*)state.registry->resource(), id, &wl_shm_interface, 1));
|
||||||
|
} else if (NAME == "wl_seat") {
|
||||||
|
debugLog(" > binding to global: {} (version {}) with id {}", name, version, id);
|
||||||
|
state.wlSeat = makeShared<CCWlSeat>((wl_proxy*)wl_registry_bind((wl_registry*)state.registry->resource(), id, &wl_seat_interface, 9));
|
||||||
|
} else if (NAME == "xdg_wm_base") {
|
||||||
|
debugLog(" > binding to global: {} (version {}) with id {}", name, version, id);
|
||||||
|
state.xdgShell = makeShared<CCXdgWmBase>((wl_proxy*)wl_registry_bind((wl_registry*)state.registry->resource(), id, &xdg_wm_base_interface, 1));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
state.registry->setGlobalRemove([](CCWlRegistry* r, uint32_t id) { debugLog("Global {} removed", id); });
|
||||||
|
|
||||||
|
wl_display_roundtrip(state.display);
|
||||||
|
|
||||||
|
if (!state.wlCompositor || !state.wlShm || !state.wlSeat || !state.xdgShell) {
|
||||||
|
clientLog("Failed to get protocols from Hyprland");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool createShm(SWlState& state, Vector2D geom) {
|
||||||
|
if (!state.xrgb8888_support)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
size_t stride = geom.x * 4;
|
||||||
|
size_t size = geom.y * stride;
|
||||||
|
if (!state.shmPool) {
|
||||||
|
const char* name = "/wl-shm-pointer-warp";
|
||||||
|
state.shmFd = shm_open(name, O_RDWR | O_CREAT | O_EXCL, 0600);
|
||||||
|
if (state.shmFd < 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (shm_unlink(name) < 0 || ftruncate(state.shmFd, size * 2) < 0) {
|
||||||
|
close(state.shmFd);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
state.shmPool = makeShared<CCWlShmPool>(state.wlShm->sendCreatePool(state.shmFd, size * 2));
|
||||||
|
if (!state.shmPool->resource()) {
|
||||||
|
close(state.shmFd);
|
||||||
|
state.shmFd = -1;
|
||||||
|
state.shmPool.reset();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
state.shmBufSize = size;
|
||||||
|
} else if (size > state.shmBufSize) {
|
||||||
|
if (ftruncate(state.shmFd, size) < 0) {
|
||||||
|
close(state.shmFd);
|
||||||
|
state.shmFd = -1;
|
||||||
|
state.shmPool.reset();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
state.shmPool->sendResize(size * 2);
|
||||||
|
state.shmBufSize = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto buf = makeShared<CCWlBuffer>(state.shmPool->sendCreateBuffer(0, geom.x, geom.y, stride, WL_SHM_FORMAT_XRGB8888));
|
||||||
|
if (!buf->resource())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (state.shmBuf) {
|
||||||
|
state.shmBuf->sendDestroy();
|
||||||
|
state.shmBuf.reset();
|
||||||
|
}
|
||||||
|
state.shmBuf = buf;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool setupToplevel(SWlState& state) {
|
||||||
|
state.wlShm->setFormat([&](CCWlShm* p, uint32_t format) {
|
||||||
|
if (format == WL_SHM_FORMAT_XRGB8888)
|
||||||
|
state.xrgb8888_support = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
state.xdgShell->setPing([&](CCXdgWmBase* p, uint32_t serial) { state.xdgShell->sendPong(serial); });
|
||||||
|
|
||||||
|
state.surf = makeShared<CCWlSurface>(state.wlCompositor->sendCreateSurface());
|
||||||
|
if (!state.surf->resource())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
state.xdgSurf = makeShared<CCXdgSurface>(state.xdgShell->sendGetXdgSurface(state.surf->resource()));
|
||||||
|
if (!state.xdgSurf->resource())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
state.xdgToplevel = makeShared<CCXdgToplevel>(state.xdgSurf->sendGetToplevel());
|
||||||
|
if (!state.xdgToplevel->resource())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
state.xdgToplevel->setClose([&](CCXdgToplevel* p) { exit(0); });
|
||||||
|
|
||||||
|
state.xdgToplevel->setConfigure([&](CCXdgToplevel* p, int32_t w, int32_t h, wl_array* arr) {
|
||||||
|
state.geom = {1280, 720};
|
||||||
|
|
||||||
|
if (!createShm(state, state.geom))
|
||||||
|
exit(-1);
|
||||||
|
});
|
||||||
|
|
||||||
|
state.xdgSurf->setConfigure([&](CCXdgSurface* p, uint32_t serial) {
|
||||||
|
if (!state.shmBuf)
|
||||||
|
debugLog("xdgSurf configure but no buf made yet?");
|
||||||
|
|
||||||
|
state.xdgSurf->sendSetWindowGeometry(0, 0, state.geom.x, state.geom.y);
|
||||||
|
state.surf->sendAttach(state.shmBuf.get(), 0, 0);
|
||||||
|
state.surf->sendCommit();
|
||||||
|
|
||||||
|
state.xdgSurf->sendAckConfigure(serial);
|
||||||
|
|
||||||
|
if (!started) {
|
||||||
|
started = true;
|
||||||
|
clientLog("started");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
state.xdgToplevel->sendSetTitle("child-test parent");
|
||||||
|
state.xdgToplevel->sendSetAppId("child-test-parent");
|
||||||
|
|
||||||
|
state.surf->sendAttach(nullptr, 0, 0);
|
||||||
|
state.surf->sendCommit();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool setupSeat(SWlState& state) {
|
||||||
|
state.pointer = makeShared<CCWlPointer>(state.wlSeat->sendGetPointer());
|
||||||
|
if (!state.pointer->resource())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
state.pointer->setEnter([&](CCWlPointer* p, uint32_t serial, wl_proxy* surf, wl_fixed_t x, wl_fixed_t y) {
|
||||||
|
debugLog("Got pointer enter event, serial {}, x {}, y {}", serial, x, y);
|
||||||
|
state.enterSerial = serial;
|
||||||
|
});
|
||||||
|
|
||||||
|
state.pointer->setLeave([&](CCWlPointer* p, uint32_t serial, wl_proxy* surf) { debugLog("Got pointer leave event, serial {}", serial); });
|
||||||
|
|
||||||
|
state.pointer->setMotion([&](CCWlPointer* p, uint32_t serial, wl_fixed_t x, wl_fixed_t y) { debugLog("Got pointer motion event, serial {}, x {}, y {}", serial, x, y); });
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct SChildWindow {
|
||||||
|
CSharedPointer<CCWlSurface> surface;
|
||||||
|
CSharedPointer<CCXdgSurface> xSurface;
|
||||||
|
CSharedPointer<CCXdgToplevel> toplevel;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void parseRequest(SWlState& state, std::string str, SChildWindow& window) {
|
||||||
|
if (str.starts_with("exit")) {
|
||||||
|
shouldExit = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t index = str.find_first_of('\n');
|
||||||
|
str = str.substr(0, index);
|
||||||
|
|
||||||
|
if (str == "toplevel") {
|
||||||
|
window.surface = makeShared<CCWlSurface>(state.wlCompositor->sendCreateSurface());
|
||||||
|
window.xSurface = makeShared<CCXdgSurface>(state.xdgShell->sendGetXdgSurface(window.surface->resource()));
|
||||||
|
|
||||||
|
window.xSurface->setConfigure([&](CCXdgSurface* p, uint32_t serial) {
|
||||||
|
if (!state.shmBuf)
|
||||||
|
debugLog("xdgSurf configure but no buf made yet?");
|
||||||
|
|
||||||
|
window.xSurface->sendSetWindowGeometry(0, 0, state.geom.x, state.geom.y);
|
||||||
|
window.surface->sendAttach(state.shmBuf2.get(), 0, 0);
|
||||||
|
window.surface->sendCommit();
|
||||||
|
|
||||||
|
window.xSurface->sendAckConfigure(serial);
|
||||||
|
});
|
||||||
|
|
||||||
|
window.toplevel = makeShared<CCXdgToplevel>(window.xSurface->sendGetToplevel());
|
||||||
|
|
||||||
|
window.toplevel->setConfigure([&](CCXdgToplevel* p, int32_t w, int32_t h, wl_array* arr) {
|
||||||
|
size_t stride = 1280 * 4;
|
||||||
|
size_t size = 720 * stride;
|
||||||
|
|
||||||
|
auto buf = makeShared<CCWlBuffer>(state.shmPool->sendCreateBuffer(size, state.geom.x, state.geom.y, stride, WL_SHM_FORMAT_XRGB8888));
|
||||||
|
if (!buf->resource())
|
||||||
|
clientLog("Failed to create child buffer");
|
||||||
|
|
||||||
|
if (state.shmBuf2) {
|
||||||
|
state.shmBuf2->sendDestroy();
|
||||||
|
state.shmBuf2.reset();
|
||||||
|
}
|
||||||
|
state.shmBuf2 = buf;
|
||||||
|
});
|
||||||
|
|
||||||
|
window.toplevel->sendSetTitle("child-test child");
|
||||||
|
window.toplevel->sendSetAppId("child-test-child");
|
||||||
|
window.toplevel->sendSetParent(state.xdgToplevel.get());
|
||||||
|
|
||||||
|
window.surface->sendAttach(nullptr, 0, 0);
|
||||||
|
window.surface->sendCommit();
|
||||||
|
clientLog("child started");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char** argv) {
|
||||||
|
if (argc != 1 && argc != 2)
|
||||||
|
clientLog("Only the \"--debug\" switch is allowed, it turns on debug logs.");
|
||||||
|
|
||||||
|
if (argc == 2 && std::string{argv[1]} == "--debug")
|
||||||
|
debug = true;
|
||||||
|
|
||||||
|
SWlState state;
|
||||||
|
SChildWindow window;
|
||||||
|
|
||||||
|
// WAYLAND_DISPLAY env should be set to the correct one
|
||||||
|
state.display = wl_display_connect(nullptr);
|
||||||
|
if (!state.display) {
|
||||||
|
clientLog("Failed to connect to wayland display");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!bindRegistry(state) || !setupSeat(state) || !setupToplevel(state))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
std::array<char, 1024> readBuf;
|
||||||
|
readBuf.fill(0);
|
||||||
|
|
||||||
|
wl_display_flush(state.display);
|
||||||
|
|
||||||
|
struct pollfd fds[2] = {{.fd = wl_display_get_fd(state.display), .events = POLLIN | POLLOUT}, {.fd = STDIN_FILENO, .events = POLLIN}};
|
||||||
|
while (!shouldExit && poll(fds, 2, 0) != -1) {
|
||||||
|
if (fds[0].revents & POLLIN) {
|
||||||
|
wl_display_flush(state.display);
|
||||||
|
|
||||||
|
if (wl_display_prepare_read(state.display) == 0) {
|
||||||
|
wl_display_read_events(state.display);
|
||||||
|
wl_display_dispatch_pending(state.display);
|
||||||
|
} else
|
||||||
|
wl_display_dispatch(state.display);
|
||||||
|
|
||||||
|
int ret = 0;
|
||||||
|
do {
|
||||||
|
ret = wl_display_dispatch_pending(state.display);
|
||||||
|
wl_display_flush(state.display);
|
||||||
|
} while (ret > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fds[1].revents & POLLIN) {
|
||||||
|
ssize_t bytesRead = read(fds[1].fd, readBuf.data(), 1023);
|
||||||
|
if (bytesRead == -1)
|
||||||
|
continue;
|
||||||
|
readBuf[bytesRead] = 0;
|
||||||
|
|
||||||
|
parseRequest(state, std::string{readBuf.data()}, window);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
wl_display* display = state.display;
|
||||||
|
state = {};
|
||||||
|
window = {};
|
||||||
|
|
||||||
|
wl_display_disconnect(display);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
319
hyprtester/clients/pointer-scroll.cpp
Normal file
|
|
@ -0,0 +1,319 @@
|
||||||
|
#include <cstring>
|
||||||
|
#include <sys/poll.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <print>
|
||||||
|
#include <format>
|
||||||
|
#include <string>
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
|
#include <wayland-client.h>
|
||||||
|
#include <wayland.hpp>
|
||||||
|
#include <xdg-shell.hpp>
|
||||||
|
#include <pointer-warp-v1.hpp>
|
||||||
|
|
||||||
|
#include <hyprutils/memory/SharedPtr.hpp>
|
||||||
|
#include <hyprutils/math/Vector2D.hpp>
|
||||||
|
#include <hyprutils/os/FileDescriptor.hpp>
|
||||||
|
|
||||||
|
using Hyprutils::Math::Vector2D;
|
||||||
|
using namespace Hyprutils::Memory;
|
||||||
|
|
||||||
|
struct SWlState {
|
||||||
|
wl_display* display;
|
||||||
|
CSharedPointer<CCWlRegistry> registry;
|
||||||
|
|
||||||
|
// protocols
|
||||||
|
CSharedPointer<CCWlCompositor> wlCompositor;
|
||||||
|
CSharedPointer<CCWlSeat> wlSeat;
|
||||||
|
CSharedPointer<CCWlShm> wlShm;
|
||||||
|
CSharedPointer<CCXdgWmBase> xdgShell;
|
||||||
|
|
||||||
|
// shm/buffer stuff
|
||||||
|
CSharedPointer<CCWlShmPool> shmPool;
|
||||||
|
CSharedPointer<CCWlBuffer> shmBuf;
|
||||||
|
int shmFd;
|
||||||
|
size_t shmBufSize;
|
||||||
|
bool xrgb8888_support = false;
|
||||||
|
|
||||||
|
// surface/toplevel stuff
|
||||||
|
CSharedPointer<CCWlSurface> surf;
|
||||||
|
CSharedPointer<CCXdgSurface> xdgSurf;
|
||||||
|
CSharedPointer<CCXdgToplevel> xdgToplevel;
|
||||||
|
Vector2D geom;
|
||||||
|
|
||||||
|
// pointer
|
||||||
|
CSharedPointer<CCWlPointer> pointer;
|
||||||
|
uint32_t enterSerial;
|
||||||
|
|
||||||
|
// last delta
|
||||||
|
float lastScrollDelta = -1.F;
|
||||||
|
bool writeDelta = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
static std::ofstream logfile;
|
||||||
|
|
||||||
|
static bool debug, started, shouldExit;
|
||||||
|
|
||||||
|
template <typename... Args>
|
||||||
|
//NOLINTNEXTLINE
|
||||||
|
static void clientLog(std::format_string<Args...> fmt, Args&&... args) {
|
||||||
|
std::string text = std::vformat(fmt.get(), std::make_format_args(args...));
|
||||||
|
std::println("{}", text);
|
||||||
|
logfile << text << std::endl;
|
||||||
|
std::fflush(stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename... Args>
|
||||||
|
//NOLINTNEXTLINE
|
||||||
|
static void debugLog(std::format_string<Args...> fmt, Args&&... args) {
|
||||||
|
std::string text = std::vformat(fmt.get(), std::make_format_args(args...));
|
||||||
|
logfile << text << std::endl;
|
||||||
|
if (!debug)
|
||||||
|
return;
|
||||||
|
std::println("{}", text);
|
||||||
|
std::fflush(stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool bindRegistry(SWlState& state) {
|
||||||
|
state.registry = makeShared<CCWlRegistry>((wl_proxy*)wl_display_get_registry(state.display));
|
||||||
|
|
||||||
|
state.registry->setGlobal([&](CCWlRegistry* r, uint32_t id, const char* name, uint32_t version) {
|
||||||
|
const std::string NAME = name;
|
||||||
|
if (NAME == "wl_compositor") {
|
||||||
|
debugLog(" > binding to global: {} (version {}) with id {}", name, version, id);
|
||||||
|
state.wlCompositor = makeShared<CCWlCompositor>((wl_proxy*)wl_registry_bind((wl_registry*)state.registry->resource(), id, &wl_compositor_interface, 6));
|
||||||
|
} else if (NAME == "wl_shm") {
|
||||||
|
debugLog(" > binding to global: {} (version {}) with id {}", name, version, id);
|
||||||
|
state.wlShm = makeShared<CCWlShm>((wl_proxy*)wl_registry_bind((wl_registry*)state.registry->resource(), id, &wl_shm_interface, 1));
|
||||||
|
} else if (NAME == "wl_seat") {
|
||||||
|
debugLog(" > binding to global: {} (version {}) with id {}", name, version, id);
|
||||||
|
state.wlSeat = makeShared<CCWlSeat>((wl_proxy*)wl_registry_bind((wl_registry*)state.registry->resource(), id, &wl_seat_interface, 9));
|
||||||
|
} else if (NAME == "xdg_wm_base") {
|
||||||
|
debugLog(" > binding to global: {} (version {}) with id {}", name, version, id);
|
||||||
|
state.xdgShell = makeShared<CCXdgWmBase>((wl_proxy*)wl_registry_bind((wl_registry*)state.registry->resource(), id, &xdg_wm_base_interface, 1));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
state.registry->setGlobalRemove([](CCWlRegistry* r, uint32_t id) { debugLog("Global {} removed", id); });
|
||||||
|
|
||||||
|
wl_display_roundtrip(state.display);
|
||||||
|
|
||||||
|
if (!state.wlCompositor || !state.wlShm || !state.wlSeat || !state.xdgShell) {
|
||||||
|
clientLog("Failed to get protocols from Hyprland");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool createShm(SWlState& state, Vector2D geom) {
|
||||||
|
if (!state.xrgb8888_support)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
size_t stride = geom.x * 4;
|
||||||
|
size_t size = geom.y * stride;
|
||||||
|
if (!state.shmPool) {
|
||||||
|
const char* name = "/wl-shm-pointer-scroll";
|
||||||
|
state.shmFd = shm_open(name, O_RDWR | O_CREAT | O_EXCL, 0600);
|
||||||
|
if (state.shmFd < 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (shm_unlink(name) < 0 || ftruncate(state.shmFd, size) < 0) {
|
||||||
|
close(state.shmFd);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
state.shmPool = makeShared<CCWlShmPool>(state.wlShm->sendCreatePool(state.shmFd, size));
|
||||||
|
if (!state.shmPool->resource()) {
|
||||||
|
close(state.shmFd);
|
||||||
|
state.shmFd = -1;
|
||||||
|
state.shmPool.reset();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
state.shmBufSize = size;
|
||||||
|
} else if (size > state.shmBufSize) {
|
||||||
|
if (ftruncate(state.shmFd, size) < 0) {
|
||||||
|
close(state.shmFd);
|
||||||
|
state.shmFd = -1;
|
||||||
|
state.shmPool.reset();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
state.shmPool->sendResize(size);
|
||||||
|
state.shmBufSize = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto buf = makeShared<CCWlBuffer>(state.shmPool->sendCreateBuffer(0, geom.x, geom.y, stride, WL_SHM_FORMAT_XRGB8888));
|
||||||
|
if (!buf->resource())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (state.shmBuf) {
|
||||||
|
state.shmBuf->sendDestroy();
|
||||||
|
state.shmBuf.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
state.shmBuf = buf;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool setupToplevel(SWlState& state) {
|
||||||
|
state.wlShm->setFormat([&](CCWlShm* p, uint32_t format) {
|
||||||
|
if (format == WL_SHM_FORMAT_XRGB8888)
|
||||||
|
state.xrgb8888_support = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
state.xdgShell->setPing([&](CCXdgWmBase* p, uint32_t serial) { state.xdgShell->sendPong(serial); });
|
||||||
|
|
||||||
|
state.surf = makeShared<CCWlSurface>(state.wlCompositor->sendCreateSurface());
|
||||||
|
if (!state.surf->resource())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
state.xdgSurf = makeShared<CCXdgSurface>(state.xdgShell->sendGetXdgSurface(state.surf->resource()));
|
||||||
|
if (!state.xdgSurf->resource())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
state.xdgToplevel = makeShared<CCXdgToplevel>(state.xdgSurf->sendGetToplevel());
|
||||||
|
if (!state.xdgToplevel->resource())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
state.xdgToplevel->setClose([&](CCXdgToplevel* p) { exit(0); });
|
||||||
|
|
||||||
|
state.xdgToplevel->setConfigure([&](CCXdgToplevel* p, int32_t w, int32_t h, wl_array* arr) {
|
||||||
|
state.geom = {1280, 720};
|
||||||
|
|
||||||
|
if (!createShm(state, state.geom))
|
||||||
|
exit(-1);
|
||||||
|
});
|
||||||
|
|
||||||
|
state.xdgSurf->setConfigure([&](CCXdgSurface* p, uint32_t serial) {
|
||||||
|
if (!state.shmBuf)
|
||||||
|
debugLog("xdgSurf configure but no buf made yet?");
|
||||||
|
|
||||||
|
state.xdgSurf->sendSetWindowGeometry(0, 0, state.geom.x, state.geom.y);
|
||||||
|
state.surf->sendAttach(state.shmBuf.get(), 0, 0);
|
||||||
|
state.surf->sendCommit();
|
||||||
|
|
||||||
|
state.xdgSurf->sendAckConfigure(serial);
|
||||||
|
|
||||||
|
if (!started) {
|
||||||
|
started = true;
|
||||||
|
clientLog("started");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
state.xdgToplevel->sendSetTitle("pointer-scroll test client");
|
||||||
|
state.xdgToplevel->sendSetAppId("pointer-scroll");
|
||||||
|
|
||||||
|
state.surf->sendAttach(nullptr, 0, 0);
|
||||||
|
state.surf->sendCommit();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool setupSeat(SWlState& state) {
|
||||||
|
state.pointer = makeShared<CCWlPointer>(state.wlSeat->sendGetPointer());
|
||||||
|
if (!state.pointer->resource())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
state.pointer->setEnter([&](CCWlPointer* p, uint32_t serial, wl_proxy* surf, wl_fixed_t x, wl_fixed_t y) {
|
||||||
|
debugLog("Got pointer enter event, serial {}, x {}, y {}", serial, x, y);
|
||||||
|
state.enterSerial = serial;
|
||||||
|
});
|
||||||
|
|
||||||
|
state.pointer->setAxis([&](CCWlPointer* p, uint32_t time, wl_pointer_axis axis, wl_fixed_t delta) {
|
||||||
|
debugLog("axis: ax {} delta {}", (int)axis, wl_fixed_to_double(delta));
|
||||||
|
|
||||||
|
if (state.writeDelta) {
|
||||||
|
clientLog("{:.2f}", wl_fixed_to_double(delta));
|
||||||
|
state.writeDelta = false;
|
||||||
|
state.lastScrollDelta = -1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
state.lastScrollDelta = wl_fixed_to_double(delta);
|
||||||
|
state.writeDelta = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
state.pointer->setLeave([&](CCWlPointer* p, uint32_t serial, wl_proxy* surf) { debugLog("Got pointer leave event, serial {}", serial); });
|
||||||
|
|
||||||
|
state.pointer->setMotion([&](CCWlPointer* p, uint32_t serial, wl_fixed_t x, wl_fixed_t y) { debugLog("Got pointer motion event, serial {}, x {}, y {}", serial, x, y); });
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// return last delta after axis
|
||||||
|
static void parseRequest(SWlState& state, std::string req) {
|
||||||
|
if (!state.writeDelta) {
|
||||||
|
state.writeDelta = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
clientLog("{:.2f}", state.lastScrollDelta);
|
||||||
|
state.writeDelta = false;
|
||||||
|
state.lastScrollDelta = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char** argv) {
|
||||||
|
logfile.open("pointer-scroll.txt", std::ios::trunc);
|
||||||
|
|
||||||
|
if (argc != 1 && argc != 2)
|
||||||
|
clientLog("Only the \"--debug\" switch is allowed, it turns on debug logs.");
|
||||||
|
|
||||||
|
if (argc == 2 && std::string{argv[1]} == "--debug")
|
||||||
|
debug = true;
|
||||||
|
|
||||||
|
SWlState state;
|
||||||
|
|
||||||
|
// WAYLAND_DISPLAY env should be set to the correct one
|
||||||
|
state.display = wl_display_connect(nullptr);
|
||||||
|
if (!state.display) {
|
||||||
|
clientLog("Failed to connect to wayland display");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!bindRegistry(state) || !setupSeat(state) || !setupToplevel(state))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
std::array<char, 1024> readBuf;
|
||||||
|
readBuf.fill(0);
|
||||||
|
|
||||||
|
wl_display_flush(state.display);
|
||||||
|
|
||||||
|
struct pollfd fds[2] = {{.fd = wl_display_get_fd(state.display), .events = POLLIN | POLLOUT}, {.fd = STDIN_FILENO, .events = POLLIN}};
|
||||||
|
while (!shouldExit && poll(fds, 2, 0) != -1) {
|
||||||
|
if (fds[0].revents & POLLIN) {
|
||||||
|
wl_display_flush(state.display);
|
||||||
|
|
||||||
|
if (wl_display_prepare_read(state.display) == 0) {
|
||||||
|
wl_display_read_events(state.display);
|
||||||
|
wl_display_dispatch_pending(state.display);
|
||||||
|
} else
|
||||||
|
wl_display_dispatch(state.display);
|
||||||
|
|
||||||
|
int ret = 0;
|
||||||
|
do {
|
||||||
|
ret = wl_display_dispatch_pending(state.display);
|
||||||
|
wl_display_flush(state.display);
|
||||||
|
} while (ret > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fds[1].revents & POLLIN) {
|
||||||
|
ssize_t bytesRead = read(fds[1].fd, readBuf.data(), 1023);
|
||||||
|
if (bytesRead == -1)
|
||||||
|
continue;
|
||||||
|
readBuf[bytesRead] = 0;
|
||||||
|
|
||||||
|
parseRequest(state, std::string{readBuf.data()});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
wl_display* display = state.display;
|
||||||
|
state = {};
|
||||||
|
|
||||||
|
wl_display_disconnect(display);
|
||||||
|
logfile.flush();
|
||||||
|
logfile.close();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
318
hyprtester/clients/pointer-warp.cpp
Normal file
|
|
@ -0,0 +1,318 @@
|
||||||
|
#include <cstring>
|
||||||
|
#include <sys/poll.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <print>
|
||||||
|
#include <format>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <wayland-client.h>
|
||||||
|
#include <wayland.hpp>
|
||||||
|
#include <xdg-shell.hpp>
|
||||||
|
#include <pointer-warp-v1.hpp>
|
||||||
|
|
||||||
|
#include <hyprutils/memory/SharedPtr.hpp>
|
||||||
|
#include <hyprutils/math/Vector2D.hpp>
|
||||||
|
#include <hyprutils/os/FileDescriptor.hpp>
|
||||||
|
|
||||||
|
using Hyprutils::Math::Vector2D;
|
||||||
|
using namespace Hyprutils::Memory;
|
||||||
|
|
||||||
|
struct SWlState {
|
||||||
|
wl_display* display;
|
||||||
|
CSharedPointer<CCWlRegistry> registry;
|
||||||
|
|
||||||
|
// protocols
|
||||||
|
CSharedPointer<CCWlCompositor> wlCompositor;
|
||||||
|
CSharedPointer<CCWlSeat> wlSeat;
|
||||||
|
CSharedPointer<CCWlShm> wlShm;
|
||||||
|
CSharedPointer<CCXdgWmBase> xdgShell;
|
||||||
|
CSharedPointer<CCWpPointerWarpV1> pointerWarp;
|
||||||
|
|
||||||
|
// shm/buffer stuff
|
||||||
|
CSharedPointer<CCWlShmPool> shmPool;
|
||||||
|
CSharedPointer<CCWlBuffer> shmBuf;
|
||||||
|
int shmFd;
|
||||||
|
size_t shmBufSize;
|
||||||
|
bool xrgb8888_support = false;
|
||||||
|
|
||||||
|
// surface/toplevel stuff
|
||||||
|
CSharedPointer<CCWlSurface> surf;
|
||||||
|
CSharedPointer<CCXdgSurface> xdgSurf;
|
||||||
|
CSharedPointer<CCXdgToplevel> xdgToplevel;
|
||||||
|
Vector2D geom;
|
||||||
|
|
||||||
|
// pointer
|
||||||
|
CSharedPointer<CCWlPointer> pointer;
|
||||||
|
uint32_t enterSerial;
|
||||||
|
};
|
||||||
|
|
||||||
|
static bool debug, started, shouldExit;
|
||||||
|
|
||||||
|
template <typename... Args>
|
||||||
|
//NOLINTNEXTLINE
|
||||||
|
static void clientLog(std::format_string<Args...> fmt, Args&&... args) {
|
||||||
|
std::println("{}", std::vformat(fmt.get(), std::make_format_args(args...)));
|
||||||
|
std::fflush(stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename... Args>
|
||||||
|
//NOLINTNEXTLINE
|
||||||
|
static void debugLog(std::format_string<Args...> fmt, Args&&... args) {
|
||||||
|
if (!debug)
|
||||||
|
return;
|
||||||
|
std::println("{}", std::vformat(fmt.get(), std::make_format_args(args...)));
|
||||||
|
std::fflush(stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool bindRegistry(SWlState& state) {
|
||||||
|
state.registry = makeShared<CCWlRegistry>((wl_proxy*)wl_display_get_registry(state.display));
|
||||||
|
|
||||||
|
state.registry->setGlobal([&](CCWlRegistry* r, uint32_t id, const char* name, uint32_t version) {
|
||||||
|
const std::string NAME = name;
|
||||||
|
if (NAME == "wl_compositor") {
|
||||||
|
debugLog(" > binding to global: {} (version {}) with id {}", name, version, id);
|
||||||
|
state.wlCompositor = makeShared<CCWlCompositor>((wl_proxy*)wl_registry_bind((wl_registry*)state.registry->resource(), id, &wl_compositor_interface, 6));
|
||||||
|
} else if (NAME == "wl_shm") {
|
||||||
|
debugLog(" > binding to global: {} (version {}) with id {}", name, version, id);
|
||||||
|
state.wlShm = makeShared<CCWlShm>((wl_proxy*)wl_registry_bind((wl_registry*)state.registry->resource(), id, &wl_shm_interface, 1));
|
||||||
|
} else if (NAME == "wl_seat") {
|
||||||
|
debugLog(" > binding to global: {} (version {}) with id {}", name, version, id);
|
||||||
|
state.wlSeat = makeShared<CCWlSeat>((wl_proxy*)wl_registry_bind((wl_registry*)state.registry->resource(), id, &wl_seat_interface, 9));
|
||||||
|
} else if (NAME == "xdg_wm_base") {
|
||||||
|
debugLog(" > binding to global: {} (version {}) with id {}", name, version, id);
|
||||||
|
state.xdgShell = makeShared<CCXdgWmBase>((wl_proxy*)wl_registry_bind((wl_registry*)state.registry->resource(), id, &xdg_wm_base_interface, 1));
|
||||||
|
} else if (NAME == "wp_pointer_warp_v1") {
|
||||||
|
debugLog(" > binding to global: {} (version {}) with id {}", name, version, id);
|
||||||
|
state.pointerWarp = makeShared<CCWpPointerWarpV1>((wl_proxy*)wl_registry_bind((wl_registry*)state.registry->resource(), id, &wp_pointer_warp_v1_interface, 1));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
state.registry->setGlobalRemove([](CCWlRegistry* r, uint32_t id) { debugLog("Global {} removed", id); });
|
||||||
|
|
||||||
|
wl_display_roundtrip(state.display);
|
||||||
|
|
||||||
|
if (!state.wlCompositor || !state.wlShm || !state.wlSeat || !state.xdgShell || !state.pointerWarp) {
|
||||||
|
clientLog("Failed to get protocols from Hyprland");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool createShm(SWlState& state, Vector2D geom) {
|
||||||
|
if (!state.xrgb8888_support)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
size_t stride = geom.x * 4;
|
||||||
|
size_t size = geom.y * stride;
|
||||||
|
if (!state.shmPool) {
|
||||||
|
const char* name = "/wl-shm-pointer-warp";
|
||||||
|
state.shmFd = shm_open(name, O_RDWR | O_CREAT | O_EXCL, 0600);
|
||||||
|
if (state.shmFd < 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (shm_unlink(name) < 0 || ftruncate(state.shmFd, size) < 0) {
|
||||||
|
close(state.shmFd);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
state.shmPool = makeShared<CCWlShmPool>(state.wlShm->sendCreatePool(state.shmFd, size));
|
||||||
|
if (!state.shmPool->resource()) {
|
||||||
|
close(state.shmFd);
|
||||||
|
state.shmFd = -1;
|
||||||
|
state.shmPool.reset();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
state.shmBufSize = size;
|
||||||
|
} else if (size > state.shmBufSize) {
|
||||||
|
if (ftruncate(state.shmFd, size) < 0) {
|
||||||
|
close(state.shmFd);
|
||||||
|
state.shmFd = -1;
|
||||||
|
state.shmPool.reset();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
state.shmPool->sendResize(size);
|
||||||
|
state.shmBufSize = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto buf = makeShared<CCWlBuffer>(state.shmPool->sendCreateBuffer(0, geom.x, geom.y, stride, WL_SHM_FORMAT_XRGB8888));
|
||||||
|
if (!buf->resource())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (state.shmBuf) {
|
||||||
|
state.shmBuf->sendDestroy();
|
||||||
|
state.shmBuf.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
state.shmBuf = buf;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool setupToplevel(SWlState& state) {
|
||||||
|
state.wlShm->setFormat([&](CCWlShm* p, uint32_t format) {
|
||||||
|
if (format == WL_SHM_FORMAT_XRGB8888)
|
||||||
|
state.xrgb8888_support = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
state.xdgShell->setPing([&](CCXdgWmBase* p, uint32_t serial) { state.xdgShell->sendPong(serial); });
|
||||||
|
|
||||||
|
state.surf = makeShared<CCWlSurface>(state.wlCompositor->sendCreateSurface());
|
||||||
|
if (!state.surf->resource())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
state.xdgSurf = makeShared<CCXdgSurface>(state.xdgShell->sendGetXdgSurface(state.surf->resource()));
|
||||||
|
if (!state.xdgSurf->resource())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
state.xdgToplevel = makeShared<CCXdgToplevel>(state.xdgSurf->sendGetToplevel());
|
||||||
|
if (!state.xdgToplevel->resource())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
state.xdgToplevel->setClose([&](CCXdgToplevel* p) { exit(0); });
|
||||||
|
|
||||||
|
state.xdgToplevel->setConfigure([&](CCXdgToplevel* p, int32_t w, int32_t h, wl_array* arr) {
|
||||||
|
state.geom = {1280, 720};
|
||||||
|
|
||||||
|
if (!createShm(state, state.geom))
|
||||||
|
exit(-1);
|
||||||
|
});
|
||||||
|
|
||||||
|
state.xdgSurf->setConfigure([&](CCXdgSurface* p, uint32_t serial) {
|
||||||
|
if (!state.shmBuf)
|
||||||
|
debugLog("xdgSurf configure but no buf made yet?");
|
||||||
|
|
||||||
|
state.xdgSurf->sendSetWindowGeometry(0, 0, state.geom.x, state.geom.y);
|
||||||
|
state.surf->sendAttach(state.shmBuf.get(), 0, 0);
|
||||||
|
state.surf->sendCommit();
|
||||||
|
|
||||||
|
state.xdgSurf->sendAckConfigure(serial);
|
||||||
|
|
||||||
|
if (!started) {
|
||||||
|
started = true;
|
||||||
|
clientLog("started");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
state.xdgToplevel->sendSetTitle("pointer-warp test client");
|
||||||
|
state.xdgToplevel->sendSetAppId("pointer-warp");
|
||||||
|
|
||||||
|
state.surf->sendAttach(nullptr, 0, 0);
|
||||||
|
state.surf->sendCommit();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool setupSeat(SWlState& state) {
|
||||||
|
state.pointer = makeShared<CCWlPointer>(state.wlSeat->sendGetPointer());
|
||||||
|
if (!state.pointer->resource())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
state.pointer->setEnter([&](CCWlPointer* p, uint32_t serial, wl_proxy* surf, wl_fixed_t x, wl_fixed_t y) {
|
||||||
|
debugLog("Got pointer enter event, serial {}, x {}, y {}", serial, x, y);
|
||||||
|
state.enterSerial = serial;
|
||||||
|
});
|
||||||
|
|
||||||
|
state.pointer->setLeave([&](CCWlPointer* p, uint32_t serial, wl_proxy* surf) { debugLog("Got pointer leave event, serial {}", serial); });
|
||||||
|
|
||||||
|
state.pointer->setMotion([&](CCWlPointer* p, uint32_t serial, wl_fixed_t x, wl_fixed_t y) { debugLog("Got pointer motion event, serial {}, x {}, y {}", serial, x, y); });
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// format is like below
|
||||||
|
// "warp 20 20\n" would ask to warp cursor to x=20,y=20 in surface local coords
|
||||||
|
static void parseRequest(SWlState& state, std::string req) {
|
||||||
|
if (req.contains("exit")) {
|
||||||
|
shouldExit = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!req.starts_with("warp "))
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto it = req.find_first_of('\n');
|
||||||
|
if (it == std::string::npos)
|
||||||
|
return;
|
||||||
|
|
||||||
|
req = req.substr(0, it);
|
||||||
|
|
||||||
|
it = req.find_first_of(' ');
|
||||||
|
if (it == std::string::npos)
|
||||||
|
return;
|
||||||
|
|
||||||
|
req = req.substr(it + 1);
|
||||||
|
|
||||||
|
it = req.find_first_of(' ');
|
||||||
|
|
||||||
|
int x = std::stoi(req.substr(0, it));
|
||||||
|
int y = std::stoi(req.substr(it + 1));
|
||||||
|
|
||||||
|
state.pointerWarp->sendWarpPointer(state.surf->resource(), state.pointer->resource(), wl_fixed_from_int(x), wl_fixed_from_int(y), state.enterSerial);
|
||||||
|
|
||||||
|
// sync the request then reply
|
||||||
|
wl_display_roundtrip(state.display);
|
||||||
|
|
||||||
|
clientLog("parsed request to move to x:{}, y:{}", x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char** argv) {
|
||||||
|
if (argc != 1 && argc != 2)
|
||||||
|
clientLog("Only the \"--debug\" switch is allowed, it turns on debug logs.");
|
||||||
|
|
||||||
|
if (argc == 2 && std::string{argv[1]} == "--debug")
|
||||||
|
debug = true;
|
||||||
|
|
||||||
|
SWlState state;
|
||||||
|
|
||||||
|
// WAYLAND_DISPLAY env should be set to the correct one
|
||||||
|
state.display = wl_display_connect(nullptr);
|
||||||
|
if (!state.display) {
|
||||||
|
clientLog("Failed to connect to wayland display");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!bindRegistry(state) || !setupSeat(state) || !setupToplevel(state))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
std::array<char, 1024> readBuf;
|
||||||
|
readBuf.fill(0);
|
||||||
|
|
||||||
|
wl_display_flush(state.display);
|
||||||
|
|
||||||
|
struct pollfd fds[2] = {{.fd = wl_display_get_fd(state.display), .events = POLLIN | POLLOUT}, {.fd = STDIN_FILENO, .events = POLLIN}};
|
||||||
|
while (!shouldExit && poll(fds, 2, 0) != -1) {
|
||||||
|
if (fds[0].revents & POLLIN) {
|
||||||
|
wl_display_flush(state.display);
|
||||||
|
|
||||||
|
if (wl_display_prepare_read(state.display) == 0) {
|
||||||
|
wl_display_read_events(state.display);
|
||||||
|
wl_display_dispatch_pending(state.display);
|
||||||
|
} else
|
||||||
|
wl_display_dispatch(state.display);
|
||||||
|
|
||||||
|
int ret = 0;
|
||||||
|
do {
|
||||||
|
ret = wl_display_dispatch_pending(state.display);
|
||||||
|
wl_display_flush(state.display);
|
||||||
|
} while (ret > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fds[1].revents & POLLIN) {
|
||||||
|
ssize_t bytesRead = read(fds[1].fd, readBuf.data(), 1023);
|
||||||
|
if (bytesRead == -1)
|
||||||
|
continue;
|
||||||
|
readBuf[bytesRead] = 0;
|
||||||
|
|
||||||
|
parseRequest(state, std::string{readBuf.data()});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
wl_display* display = state.display;
|
||||||
|
state = {};
|
||||||
|
|
||||||
|
wl_display_disconnect(display);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
297
hyprtester/clients/shortcut-inhibitor.cpp
Normal file
|
|
@ -0,0 +1,297 @@
|
||||||
|
#include <sys/poll.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <print>
|
||||||
|
|
||||||
|
#include <wayland-client.h>
|
||||||
|
#include <wayland.hpp>
|
||||||
|
#include <xdg-shell.hpp>
|
||||||
|
#include <keyboard-shortcuts-inhibit-unstable-v1.hpp>
|
||||||
|
|
||||||
|
#include <hyprutils/memory/SharedPtr.hpp>
|
||||||
|
#include <hyprutils/math/Vector2D.hpp>
|
||||||
|
|
||||||
|
using Hyprutils::Math::Vector2D;
|
||||||
|
using namespace Hyprutils::Memory;
|
||||||
|
|
||||||
|
struct SWlState {
|
||||||
|
wl_display* display;
|
||||||
|
CSharedPointer<CCWlRegistry> registry;
|
||||||
|
|
||||||
|
// protocols
|
||||||
|
CSharedPointer<CCWlCompositor> wlCompositor;
|
||||||
|
CSharedPointer<CCWlSeat> wlSeat;
|
||||||
|
CSharedPointer<CCWlShm> wlShm;
|
||||||
|
CSharedPointer<CCXdgWmBase> xdgShell;
|
||||||
|
CSharedPointer<CCZwpKeyboardShortcutsInhibitManagerV1> inhibitManager;
|
||||||
|
|
||||||
|
// shm/buffer stuff
|
||||||
|
CSharedPointer<CCWlShmPool> shmPool;
|
||||||
|
CSharedPointer<CCWlBuffer> shmBuf;
|
||||||
|
int shmFd;
|
||||||
|
size_t shmBufSize;
|
||||||
|
bool xrgb8888_support = false;
|
||||||
|
|
||||||
|
// surface/toplevel stuff
|
||||||
|
CSharedPointer<CCWlSurface> surf;
|
||||||
|
CSharedPointer<CCXdgSurface> xdgSurf;
|
||||||
|
CSharedPointer<CCXdgToplevel> xdgToplevel;
|
||||||
|
Vector2D geom;
|
||||||
|
|
||||||
|
// pointer
|
||||||
|
CSharedPointer<CCWlPointer> pointer;
|
||||||
|
uint32_t enterSerial;
|
||||||
|
|
||||||
|
// shortcut inhibiting
|
||||||
|
CSharedPointer<CCZwpKeyboardShortcutsInhibitorV1> inhibitor;
|
||||||
|
};
|
||||||
|
|
||||||
|
static bool debug, started, shouldExit;
|
||||||
|
|
||||||
|
template <typename... Args>
|
||||||
|
//NOLINTNEXTLINE
|
||||||
|
static void clientLog(std::format_string<Args...> fmt, Args&&... args) {
|
||||||
|
std::string text = std::vformat(fmt.get(), std::make_format_args(args...));
|
||||||
|
std::println("{}", text);
|
||||||
|
std::fflush(stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename... Args>
|
||||||
|
//NOLINTNEXTLINE
|
||||||
|
static void debugLog(std::format_string<Args...> fmt, Args&&... args) {
|
||||||
|
std::string text = std::vformat(fmt.get(), std::make_format_args(args...));
|
||||||
|
if (!debug)
|
||||||
|
return;
|
||||||
|
std::println("{}", text);
|
||||||
|
std::fflush(stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool bindRegistry(SWlState& state) {
|
||||||
|
state.registry = makeShared<CCWlRegistry>((wl_proxy*)wl_display_get_registry(state.display));
|
||||||
|
|
||||||
|
state.registry->setGlobal([&](CCWlRegistry* r, uint32_t id, const char* name, uint32_t version) {
|
||||||
|
const std::string NAME = name;
|
||||||
|
if (NAME == "wl_compositor") {
|
||||||
|
debugLog(" > binding to global: {} (version {}) with id {}", name, version, id);
|
||||||
|
state.wlCompositor = makeShared<CCWlCompositor>((wl_proxy*)wl_registry_bind((wl_registry*)state.registry->resource(), id, &wl_compositor_interface, 6));
|
||||||
|
} else if (NAME == "wl_shm") {
|
||||||
|
debugLog(" > binding to global: {} (version {}) with id {}", name, version, id);
|
||||||
|
state.wlShm = makeShared<CCWlShm>((wl_proxy*)wl_registry_bind((wl_registry*)state.registry->resource(), id, &wl_shm_interface, 1));
|
||||||
|
} else if (NAME == "wl_seat") {
|
||||||
|
debugLog(" > binding to global: {} (version {}) with id {}", name, version, id);
|
||||||
|
state.wlSeat = makeShared<CCWlSeat>((wl_proxy*)wl_registry_bind((wl_registry*)state.registry->resource(), id, &wl_seat_interface, 9));
|
||||||
|
} else if (NAME == "xdg_wm_base") {
|
||||||
|
debugLog(" > binding to global: {} (version {}) with id {}", name, version, id);
|
||||||
|
state.xdgShell = makeShared<CCXdgWmBase>((wl_proxy*)wl_registry_bind((wl_registry*)state.registry->resource(), id, &xdg_wm_base_interface, 1));
|
||||||
|
} else if (NAME == "zwp_keyboard_shortcuts_inhibit_manager_v1") {
|
||||||
|
debugLog(" > binding to global: {} (version {}) with id {}", name, version, id);
|
||||||
|
state.inhibitManager = makeShared<CCZwpKeyboardShortcutsInhibitManagerV1>(
|
||||||
|
(wl_proxy*)wl_registry_bind((wl_registry*)state.registry->resource(), id, &zwp_keyboard_shortcuts_inhibit_manager_v1_interface, 1));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
state.registry->setGlobalRemove([](CCWlRegistry* r, uint32_t id) { debugLog("Global {} removed", id); });
|
||||||
|
|
||||||
|
wl_display_roundtrip(state.display);
|
||||||
|
|
||||||
|
if (!state.wlCompositor || !state.wlShm || !state.wlSeat || !state.xdgShell || !state.inhibitManager) {
|
||||||
|
clientLog("Failed to get protocols from Hyprland");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool createShm(SWlState& state, Vector2D geom) {
|
||||||
|
if (!state.xrgb8888_support)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
size_t stride = geom.x * 4;
|
||||||
|
size_t size = geom.y * stride;
|
||||||
|
if (!state.shmPool) {
|
||||||
|
const char* name = "/wl-shm-shortcut-inhibitor";
|
||||||
|
state.shmFd = shm_open(name, O_RDWR | O_CREAT | O_EXCL, 0600);
|
||||||
|
if (state.shmFd < 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (shm_unlink(name) < 0 || ftruncate(state.shmFd, size) < 0) {
|
||||||
|
close(state.shmFd);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
state.shmPool = makeShared<CCWlShmPool>(state.wlShm->sendCreatePool(state.shmFd, size));
|
||||||
|
if (!state.shmPool->resource()) {
|
||||||
|
close(state.shmFd);
|
||||||
|
state.shmFd = -1;
|
||||||
|
state.shmPool.reset();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
state.shmBufSize = size;
|
||||||
|
} else if (size > state.shmBufSize) {
|
||||||
|
if (ftruncate(state.shmFd, size) < 0) {
|
||||||
|
close(state.shmFd);
|
||||||
|
state.shmFd = -1;
|
||||||
|
state.shmPool.reset();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
state.shmPool->sendResize(size);
|
||||||
|
state.shmBufSize = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto buf = makeShared<CCWlBuffer>(state.shmPool->sendCreateBuffer(0, geom.x, geom.y, stride, WL_SHM_FORMAT_XRGB8888));
|
||||||
|
if (!buf->resource())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (state.shmBuf) {
|
||||||
|
state.shmBuf->sendDestroy();
|
||||||
|
state.shmBuf.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
state.shmBuf = buf;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool setupToplevel(SWlState& state) {
|
||||||
|
state.wlShm->setFormat([&](CCWlShm* p, uint32_t format) {
|
||||||
|
if (format == WL_SHM_FORMAT_XRGB8888)
|
||||||
|
state.xrgb8888_support = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
state.xdgShell->setPing([&](CCXdgWmBase* p, uint32_t serial) { state.xdgShell->sendPong(serial); });
|
||||||
|
|
||||||
|
state.surf = makeShared<CCWlSurface>(state.wlCompositor->sendCreateSurface());
|
||||||
|
if (!state.surf->resource())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
state.xdgSurf = makeShared<CCXdgSurface>(state.xdgShell->sendGetXdgSurface(state.surf->resource()));
|
||||||
|
if (!state.xdgSurf->resource())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
state.xdgToplevel = makeShared<CCXdgToplevel>(state.xdgSurf->sendGetToplevel());
|
||||||
|
if (!state.xdgToplevel->resource())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
state.xdgToplevel->setClose([&](CCXdgToplevel* p) { exit(0); });
|
||||||
|
|
||||||
|
state.xdgToplevel->setConfigure([&](CCXdgToplevel* p, int32_t w, int32_t h, wl_array* arr) {
|
||||||
|
state.geom = {1280, 720};
|
||||||
|
|
||||||
|
if (!createShm(state, state.geom))
|
||||||
|
exit(-1);
|
||||||
|
});
|
||||||
|
|
||||||
|
state.xdgSurf->setConfigure([&](CCXdgSurface* p, uint32_t serial) {
|
||||||
|
if (!state.shmBuf)
|
||||||
|
debugLog("xdgSurf configure but no buf made yet?");
|
||||||
|
|
||||||
|
state.xdgSurf->sendSetWindowGeometry(0, 0, state.geom.x, state.geom.y);
|
||||||
|
state.surf->sendAttach(state.shmBuf.get(), 0, 0);
|
||||||
|
state.surf->sendCommit();
|
||||||
|
|
||||||
|
state.xdgSurf->sendAckConfigure(serial);
|
||||||
|
|
||||||
|
if (!started) {
|
||||||
|
started = true;
|
||||||
|
clientLog("started");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
state.xdgToplevel->sendSetTitle("shortcut-inhibitor test client");
|
||||||
|
state.xdgToplevel->sendSetAppId("shortcut-inhibitor");
|
||||||
|
|
||||||
|
state.surf->sendAttach(nullptr, 0, 0);
|
||||||
|
state.surf->sendCommit();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool setupSeat(SWlState& state) {
|
||||||
|
state.pointer = makeShared<CCWlPointer>(state.wlSeat->sendGetPointer());
|
||||||
|
if (!state.pointer->resource())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
state.pointer->setEnter([&](CCWlPointer* p, uint32_t serial, wl_proxy* surf, wl_fixed_t x, wl_fixed_t y) {
|
||||||
|
debugLog("Got pointer enter event, serial {}, x {}, y {}", serial, x, y);
|
||||||
|
state.enterSerial = serial;
|
||||||
|
});
|
||||||
|
|
||||||
|
state.pointer->setLeave([&](CCWlPointer* p, uint32_t serial, wl_proxy* surf) { debugLog("Got pointer leave event, serial {}", serial); });
|
||||||
|
|
||||||
|
state.pointer->setMotion([&](CCWlPointer* p, uint32_t serial, wl_fixed_t x, wl_fixed_t y) { debugLog("Got pointer motion event, serial {}, x {}, y {}", serial, x, y); });
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void parseRequest(SWlState& state, std::string req) {
|
||||||
|
if (req.starts_with("on")) {
|
||||||
|
state.inhibitor = makeShared<CCZwpKeyboardShortcutsInhibitorV1>(state.inhibitManager->sendInhibitShortcuts(state.surf->resource(), state.wlSeat->resource()));
|
||||||
|
|
||||||
|
state.inhibitor->setActive([&](CCZwpKeyboardShortcutsInhibitorV1* inhibitorV1) { clientLog("inhibiting"); });
|
||||||
|
state.inhibitor->setInactive([&](CCZwpKeyboardShortcutsInhibitorV1* inhibitorV1) { clientLog("inhibit disabled by compositor"); });
|
||||||
|
} else if (req.starts_with("off")) {
|
||||||
|
state.inhibitor->sendDestroy();
|
||||||
|
state.inhibitor.reset();
|
||||||
|
shouldExit = true;
|
||||||
|
clientLog("inhibit disabled by request");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char** argv) {
|
||||||
|
if (argc != 1 && argc != 2)
|
||||||
|
clientLog("Only the \"--debug\" switch is allowed, it turns on debug logs.");
|
||||||
|
|
||||||
|
if (argc == 2 && std::string{argv[1]} == "--debug")
|
||||||
|
debug = true;
|
||||||
|
|
||||||
|
SWlState state;
|
||||||
|
|
||||||
|
// WAYLAND_DISPLAY env should be set to the correct one
|
||||||
|
state.display = wl_display_connect(nullptr);
|
||||||
|
if (!state.display) {
|
||||||
|
clientLog("Failed to connect to wayland display");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!bindRegistry(state) || !setupSeat(state) || !setupToplevel(state))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
std::array<char, 1024> readBuf;
|
||||||
|
readBuf.fill(0);
|
||||||
|
|
||||||
|
wl_display_flush(state.display);
|
||||||
|
|
||||||
|
struct pollfd fds[2] = {{.fd = wl_display_get_fd(state.display), .events = POLLIN | POLLOUT}, {.fd = STDIN_FILENO, .events = POLLIN}};
|
||||||
|
while (!shouldExit && poll(fds, 2, 0) != -1) {
|
||||||
|
if (fds[0].revents & POLLIN) {
|
||||||
|
wl_display_flush(state.display);
|
||||||
|
|
||||||
|
if (wl_display_prepare_read(state.display) == 0) {
|
||||||
|
wl_display_read_events(state.display);
|
||||||
|
wl_display_dispatch_pending(state.display);
|
||||||
|
} else
|
||||||
|
wl_display_dispatch(state.display);
|
||||||
|
|
||||||
|
int ret = 0;
|
||||||
|
do {
|
||||||
|
ret = wl_display_dispatch_pending(state.display);
|
||||||
|
wl_display_flush(state.display);
|
||||||
|
} while (ret > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fds[1].revents & POLLIN) {
|
||||||
|
ssize_t bytesRead = read(fds[1].fd, readBuf.data(), 1023);
|
||||||
|
if (bytesRead == -1)
|
||||||
|
continue;
|
||||||
|
readBuf[bytesRead] = 0;
|
||||||
|
|
||||||
|
parseRequest(state, std::string{readBuf.data()});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
wl_display* display = state.display;
|
||||||
|
state = {};
|
||||||
|
|
||||||
|
wl_display_disconnect(display);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
16
hyprtester/plugin/Makefile
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
CXXFLAGS = -shared -fPIC -g -std=c++2b -Wno-c++11-narrowing
|
||||||
|
INCLUDES = `pkg-config --cflags pixman-1 libdrm pangocairo libinput libudev wayland-server xkbcommon`
|
||||||
|
LIBS = `pkg-config --libs pangocairo`
|
||||||
|
|
||||||
|
SRC = src/main.cpp
|
||||||
|
TARGET = hyprtestplugin.so
|
||||||
|
|
||||||
|
all: $(TARGET)
|
||||||
|
|
||||||
|
$(TARGET): $(SRC)
|
||||||
|
$(CXX) $(CXXFLAGS) -I../.. -I../../protocols $(INCLUDES) $^ $> -o $@ $(LIBS) -O2
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f ./$(TARGET)
|
||||||
|
|
||||||
|
.PHONY: all clean
|
||||||
4
hyprtester/plugin/build.sh
Executable file
|
|
@ -0,0 +1,4 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
make clean
|
||||||
|
make all
|
||||||
5
hyprtester/plugin/src/globals.hpp
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <src/plugins/PluginAPI.hpp>
|
||||||
|
|
||||||
|
inline HANDLE PHANDLE = nullptr;
|
||||||
387
hyprtester/plugin/src/main.cpp
Normal file
|
|
@ -0,0 +1,387 @@
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <src/includes.hpp>
|
||||||
|
#include <sstream>
|
||||||
|
#include <any>
|
||||||
|
|
||||||
|
#define private public
|
||||||
|
#include <src/config/ConfigManager.hpp>
|
||||||
|
#include <src/config/ConfigDescriptions.hpp>
|
||||||
|
#include <src/managers/input/InputManager.hpp>
|
||||||
|
#include <src/managers/PointerManager.hpp>
|
||||||
|
#include <src/managers/input/trackpad/TrackpadGestures.hpp>
|
||||||
|
#include <src/desktop/rule/windowRule/WindowRuleEffectContainer.hpp>
|
||||||
|
#include <src/desktop/rule/layerRule/LayerRuleEffectContainer.hpp>
|
||||||
|
#include <src/desktop/rule/windowRule/WindowRuleApplicator.hpp>
|
||||||
|
#include <src/desktop/view/LayerSurface.hpp>
|
||||||
|
#include <src/Compositor.hpp>
|
||||||
|
#include <src/desktop/state/FocusState.hpp>
|
||||||
|
#include <src/layout/LayoutManager.hpp>
|
||||||
|
#undef private
|
||||||
|
|
||||||
|
#include <hyprutils/utils/ScopeGuard.hpp>
|
||||||
|
#include <hyprutils/string/VarList.hpp>
|
||||||
|
using namespace Hyprutils::Utils;
|
||||||
|
using namespace Hyprutils::String;
|
||||||
|
|
||||||
|
#include "globals.hpp"
|
||||||
|
|
||||||
|
// Do NOT change this function.
|
||||||
|
APICALL EXPORT std::string PLUGIN_API_VERSION() {
|
||||||
|
return HYPRLAND_API_VERSION;
|
||||||
|
}
|
||||||
|
|
||||||
|
static SDispatchResult test(std::string in) {
|
||||||
|
bool success = true;
|
||||||
|
std::string errors = "";
|
||||||
|
|
||||||
|
if (g_pConfigManager->m_configValueNumber != CONFIG_OPTIONS.size() + 1 /* autogenerated is special */) {
|
||||||
|
errors += "config value number mismatches descriptions size\n";
|
||||||
|
success = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SDispatchResult{
|
||||||
|
.success = success,
|
||||||
|
.error = errors,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trigger a snap move event for the active window
|
||||||
|
static SDispatchResult snapMove(std::string in) {
|
||||||
|
const auto PLASTWINDOW = Desktop::focusState()->window();
|
||||||
|
if (!PLASTWINDOW->m_isFloating)
|
||||||
|
return {.success = false, .error = "Window must be floating"};
|
||||||
|
|
||||||
|
Vector2D pos = PLASTWINDOW->m_realPosition->goal();
|
||||||
|
Vector2D size = PLASTWINDOW->m_realSize->goal();
|
||||||
|
|
||||||
|
g_layoutManager->performSnap(pos, size, PLASTWINDOW->layoutTarget(), MBIND_MOVE, -1, size);
|
||||||
|
|
||||||
|
PLASTWINDOW->layoutTarget()->setPositionGlobal(CBox{pos, size});
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
class CTestKeyboard : public IKeyboard {
|
||||||
|
public:
|
||||||
|
static SP<CTestKeyboard> create(bool isVirtual) {
|
||||||
|
auto keeb = SP<CTestKeyboard>(new CTestKeyboard());
|
||||||
|
keeb->m_self = keeb;
|
||||||
|
keeb->m_isVirtual = isVirtual;
|
||||||
|
keeb->m_shareStates = !isVirtual;
|
||||||
|
return keeb;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool isVirtual() {
|
||||||
|
return m_isVirtual;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual SP<Aquamarine::IKeyboard> aq() {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sendKey(uint32_t key, bool pressed) {
|
||||||
|
auto event = IKeyboard::SKeyEvent{
|
||||||
|
.timeMs = sc<uint32_t>(Time::millis(Time::steadyNow())),
|
||||||
|
.keycode = key,
|
||||||
|
.state = pressed ? WL_KEYBOARD_KEY_STATE_PRESSED : WL_KEYBOARD_KEY_STATE_RELEASED,
|
||||||
|
};
|
||||||
|
updatePressed(event.keycode, pressed);
|
||||||
|
m_keyboardEvents.key.emit(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroy() {
|
||||||
|
m_events.destroy.emit();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool m_isVirtual = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CTestMouse : public IPointer {
|
||||||
|
public:
|
||||||
|
static SP<CTestMouse> create(bool isVirtual) {
|
||||||
|
auto maus = SP<CTestMouse>(new CTestMouse());
|
||||||
|
maus->m_self = maus;
|
||||||
|
maus->m_isVirtual = isVirtual;
|
||||||
|
maus->m_deviceName = "test-mouse";
|
||||||
|
maus->m_hlName = "test-mouse";
|
||||||
|
return maus;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool isVirtual() {
|
||||||
|
return m_isVirtual;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual SP<Aquamarine::IPointer> aq() {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroy() {
|
||||||
|
m_events.destroy.emit();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool m_isVirtual = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
SP<CTestMouse> g_mouse;
|
||||||
|
SP<CTestKeyboard> g_keyboard;
|
||||||
|
|
||||||
|
static SDispatchResult pressAlt(std::string in) {
|
||||||
|
g_pInputManager->m_lastMods = in == "1" ? HL_MODIFIER_ALT : 0;
|
||||||
|
|
||||||
|
return {.success = true};
|
||||||
|
}
|
||||||
|
|
||||||
|
static SDispatchResult simulateGesture(std::string in) {
|
||||||
|
CVarList data(in);
|
||||||
|
|
||||||
|
uint32_t fingers = 3;
|
||||||
|
try {
|
||||||
|
fingers = std::stoul(data[1]);
|
||||||
|
} catch (...) { return {.success = false}; }
|
||||||
|
|
||||||
|
if (data[0] == "down") {
|
||||||
|
g_pTrackpadGestures->gestureBegin(IPointer::SSwipeBeginEvent{});
|
||||||
|
g_pTrackpadGestures->gestureUpdate(IPointer::SSwipeUpdateEvent{.fingers = fingers, .delta = {0, 300}});
|
||||||
|
g_pTrackpadGestures->gestureEnd(IPointer::SSwipeEndEvent{});
|
||||||
|
} else if (data[0] == "up") {
|
||||||
|
g_pTrackpadGestures->gestureBegin(IPointer::SSwipeBeginEvent{});
|
||||||
|
g_pTrackpadGestures->gestureUpdate(IPointer::SSwipeUpdateEvent{.fingers = fingers, .delta = {0, -300}});
|
||||||
|
g_pTrackpadGestures->gestureEnd(IPointer::SSwipeEndEvent{});
|
||||||
|
} else if (data[0] == "left") {
|
||||||
|
g_pTrackpadGestures->gestureBegin(IPointer::SSwipeBeginEvent{});
|
||||||
|
g_pTrackpadGestures->gestureUpdate(IPointer::SSwipeUpdateEvent{.fingers = fingers, .delta = {-300, 0}});
|
||||||
|
g_pTrackpadGestures->gestureEnd(IPointer::SSwipeEndEvent{});
|
||||||
|
} else {
|
||||||
|
g_pTrackpadGestures->gestureBegin(IPointer::SSwipeBeginEvent{});
|
||||||
|
g_pTrackpadGestures->gestureUpdate(IPointer::SSwipeUpdateEvent{.fingers = fingers, .delta = {300, 0}});
|
||||||
|
g_pTrackpadGestures->gestureEnd(IPointer::SSwipeEndEvent{});
|
||||||
|
}
|
||||||
|
|
||||||
|
return {.success = true};
|
||||||
|
}
|
||||||
|
|
||||||
|
static SDispatchResult vkb(std::string in) {
|
||||||
|
auto tkb0 = CTestKeyboard::create(false);
|
||||||
|
auto tkb1 = CTestKeyboard::create(false);
|
||||||
|
auto vkb0 = CTestKeyboard::create(true);
|
||||||
|
|
||||||
|
g_pInputManager->newKeyboard(tkb0);
|
||||||
|
g_pInputManager->newKeyboard(tkb1);
|
||||||
|
g_pInputManager->newKeyboard(vkb0);
|
||||||
|
|
||||||
|
CScopeGuard x([&] {
|
||||||
|
tkb0->destroy();
|
||||||
|
tkb1->destroy();
|
||||||
|
vkb0->destroy();
|
||||||
|
});
|
||||||
|
|
||||||
|
const auto& PRESSED = g_pInputManager->getKeysFromAllKBs();
|
||||||
|
const uint32_t TESTKEY = 1;
|
||||||
|
|
||||||
|
tkb0->sendKey(TESTKEY, true);
|
||||||
|
if (!std::ranges::contains(PRESSED, TESTKEY)) {
|
||||||
|
return {
|
||||||
|
.success = false,
|
||||||
|
.error = "Expected pressed key not found",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
tkb1->sendKey(TESTKEY, true);
|
||||||
|
tkb0->sendKey(TESTKEY, false);
|
||||||
|
if (!std::ranges::contains(PRESSED, TESTKEY)) {
|
||||||
|
return {
|
||||||
|
.success = false,
|
||||||
|
.error = "Expected pressed key not found (kb share state)",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
vkb0->sendKey(TESTKEY, true);
|
||||||
|
tkb1->sendKey(TESTKEY, false);
|
||||||
|
if (std::ranges::contains(PRESSED, TESTKEY)) {
|
||||||
|
return {
|
||||||
|
.success = false,
|
||||||
|
.error = "Expected released key found in pressed (vkb no share state)",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
static SDispatchResult scroll(std::string in) {
|
||||||
|
double by;
|
||||||
|
try {
|
||||||
|
by = std::stod(in);
|
||||||
|
} catch (...) { return SDispatchResult{.success = false, .error = "invalid input"}; }
|
||||||
|
|
||||||
|
Log::logger->log(Log::DEBUG, "tester: scrolling by {}", by);
|
||||||
|
|
||||||
|
g_mouse->m_pointerEvents.axis.emit(IPointer::SAxisEvent{
|
||||||
|
.delta = by,
|
||||||
|
.deltaDiscrete = 120,
|
||||||
|
.mouse = true,
|
||||||
|
});
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
static SDispatchResult click(std::string in) {
|
||||||
|
CVarList2 data(std::move(in));
|
||||||
|
|
||||||
|
uint32_t button;
|
||||||
|
bool pressed;
|
||||||
|
try {
|
||||||
|
button = std::stoul(std::string{data[0]});
|
||||||
|
pressed = std::stoul(std::string{data[1]}) == 1;
|
||||||
|
} catch (...) { return {.success = false, .error = "invalid input"}; }
|
||||||
|
|
||||||
|
Log::logger->log(Log::DEBUG, "tester: mouse button {} state {}", button, pressed);
|
||||||
|
|
||||||
|
g_mouse->m_pointerEvents.button.emit(IPointer::SButtonEvent{
|
||||||
|
.timeMs = sc<uint32_t>(Time::millis(Time::steadyNow())),
|
||||||
|
.button = button,
|
||||||
|
.state = pressed ? WL_POINTER_BUTTON_STATE_PRESSED : WL_POINTER_BUTTON_STATE_RELEASED,
|
||||||
|
.mouse = true,
|
||||||
|
});
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
static SDispatchResult keybind(std::string in) {
|
||||||
|
CVarList2 data(std::move(in));
|
||||||
|
// 0 = release, 1 = press
|
||||||
|
bool press;
|
||||||
|
// See src/devices/IKeyboard.hpp : eKeyboardModifiers for modifier bitmasks
|
||||||
|
// 0 = none, eKeyboardModifiers is shifted to start at 1
|
||||||
|
uint32_t modifier;
|
||||||
|
// keycode
|
||||||
|
uint32_t key;
|
||||||
|
try {
|
||||||
|
press = std::stoul(std::string{data[0]}) == 1;
|
||||||
|
modifier = std::stoul(std::string{data[1]});
|
||||||
|
key = std::stoul(std::string{data[2]}) - 8; // xkb offset
|
||||||
|
} catch (...) { return {.success = false, .error = "invalid input"}; }
|
||||||
|
|
||||||
|
uint32_t modifierMask = 0;
|
||||||
|
if (modifier > 0)
|
||||||
|
modifierMask = 1 << (modifier - 1);
|
||||||
|
g_pInputManager->m_lastMods = modifierMask;
|
||||||
|
g_keyboard->sendKey(key, press);
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
static Desktop::Rule::CWindowRuleEffectContainer::storageType windowRuleIDX = 0;
|
||||||
|
|
||||||
|
//
|
||||||
|
static SDispatchResult addWindowRule(std::string in) {
|
||||||
|
windowRuleIDX = Desktop::Rule::windowEffects()->registerEffect("plugin_rule");
|
||||||
|
|
||||||
|
if (Desktop::Rule::windowEffects()->registerEffect("plugin_rule") != windowRuleIDX)
|
||||||
|
return {.success = false, .error = "re-registering returned a different id?"};
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
static SDispatchResult checkWindowRule(std::string in) {
|
||||||
|
const auto PLASTWINDOW = Desktop::focusState()->window();
|
||||||
|
|
||||||
|
if (!PLASTWINDOW)
|
||||||
|
return {.success = false, .error = "No window"};
|
||||||
|
|
||||||
|
if (!PLASTWINDOW->m_ruleApplicator->m_otherProps.props.contains(windowRuleIDX))
|
||||||
|
return {.success = false, .error = "No rule"};
|
||||||
|
|
||||||
|
if (PLASTWINDOW->m_ruleApplicator->m_otherProps.props[windowRuleIDX]->effect != "effect")
|
||||||
|
return {.success = false, .error = "Effect isn't \"effect\""};
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
static Desktop::Rule::CLayerRuleEffectContainer::storageType layerRuleIDX = 0;
|
||||||
|
|
||||||
|
static SDispatchResult addLayerRule(std::string in) {
|
||||||
|
layerRuleIDX = Desktop::Rule::layerEffects()->registerEffect("plugin_rule");
|
||||||
|
|
||||||
|
if (Desktop::Rule::layerEffects()->registerEffect("plugin_rule") != layerRuleIDX)
|
||||||
|
return {.success = false, .error = "re-registering returned a different id?"};
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
static SDispatchResult checkLayerRule(std::string in) {
|
||||||
|
if (g_pCompositor->m_layers.size() != 3)
|
||||||
|
return {.success = false, .error = "Layers under test not here"};
|
||||||
|
|
||||||
|
for (const auto& layer : g_pCompositor->m_layers) {
|
||||||
|
if (layer->m_namespace == "rule-layer") {
|
||||||
|
|
||||||
|
if (!layer->m_ruleApplicator->m_otherProps.props.contains(layerRuleIDX))
|
||||||
|
return {.success = false, .error = "No rule"};
|
||||||
|
|
||||||
|
if (layer->m_ruleApplicator->m_otherProps.props[layerRuleIDX]->effect != "effect")
|
||||||
|
return {.success = false, .error = "Effect isn't \"effect\""};
|
||||||
|
|
||||||
|
} else if (layer->m_namespace == "norule-layer") {
|
||||||
|
|
||||||
|
if (layer->m_ruleApplicator->m_otherProps.props.contains(layerRuleIDX))
|
||||||
|
return {.success = false, .error = "Rule even though it shouldn't"};
|
||||||
|
|
||||||
|
} else
|
||||||
|
return {.success = false, .error = "Unrecognized layer"};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
static SDispatchResult floatingFocusOnFullscreen(std::string in) {
|
||||||
|
const auto PLASTWINDOW = Desktop::focusState()->window();
|
||||||
|
|
||||||
|
if (!PLASTWINDOW)
|
||||||
|
return {.success = false, .error = "No window"};
|
||||||
|
|
||||||
|
if (!PLASTWINDOW->m_isFloating)
|
||||||
|
return {.success = false, .error = "Window must be floating"};
|
||||||
|
|
||||||
|
if (PLASTWINDOW->m_alpha != 1.f)
|
||||||
|
return {.success = false, .error = "floating window doesnt restore it opacity when focused on fullscreen workspace"};
|
||||||
|
|
||||||
|
if (!PLASTWINDOW->m_createdOverFullscreen)
|
||||||
|
return {.success = false, .error = "floating window doesnt get flagged as createdOverFullscreen"};
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) {
|
||||||
|
PHANDLE = handle;
|
||||||
|
|
||||||
|
HyprlandAPI::addDispatcherV2(PHANDLE, "plugin:test:test", ::test);
|
||||||
|
HyprlandAPI::addDispatcherV2(PHANDLE, "plugin:test:snapmove", ::snapMove);
|
||||||
|
HyprlandAPI::addDispatcherV2(PHANDLE, "plugin:test:vkb", ::vkb);
|
||||||
|
HyprlandAPI::addDispatcherV2(PHANDLE, "plugin:test:alt", ::pressAlt);
|
||||||
|
HyprlandAPI::addDispatcherV2(PHANDLE, "plugin:test:gesture", ::simulateGesture);
|
||||||
|
HyprlandAPI::addDispatcherV2(PHANDLE, "plugin:test:scroll", ::scroll);
|
||||||
|
HyprlandAPI::addDispatcherV2(PHANDLE, "plugin:test:click", ::click);
|
||||||
|
HyprlandAPI::addDispatcherV2(PHANDLE, "plugin:test:keybind", ::keybind);
|
||||||
|
HyprlandAPI::addDispatcherV2(PHANDLE, "plugin:test:add_window_rule", ::addWindowRule);
|
||||||
|
HyprlandAPI::addDispatcherV2(PHANDLE, "plugin:test:check_window_rule", ::checkWindowRule);
|
||||||
|
HyprlandAPI::addDispatcherV2(PHANDLE, "plugin:test:add_layer_rule", ::addLayerRule);
|
||||||
|
HyprlandAPI::addDispatcherV2(PHANDLE, "plugin:test:check_layer_rule", ::checkLayerRule);
|
||||||
|
HyprlandAPI::addDispatcherV2(PHANDLE, "plugin:test:floating_focus_on_fullscreen", ::floatingFocusOnFullscreen);
|
||||||
|
|
||||||
|
// init mouse
|
||||||
|
g_mouse = CTestMouse::create(false);
|
||||||
|
g_pInputManager->newMouse(g_mouse);
|
||||||
|
|
||||||
|
// init keyboard
|
||||||
|
g_keyboard = CTestKeyboard::create(false);
|
||||||
|
g_pInputManager->newKeyboard(g_keyboard);
|
||||||
|
|
||||||
|
return {"hyprtestplugin", "hyprtestplugin", "Vaxry", "1.0"};
|
||||||
|
}
|
||||||
|
|
||||||
|
APICALL EXPORT void PLUGIN_EXIT() {
|
||||||
|
g_mouse->destroy();
|
||||||
|
g_mouse.reset();
|
||||||
|
g_keyboard->destroy();
|
||||||
|
g_keyboard.reset();
|
||||||
|
}
|
||||||
2
hyprtester/protocols/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
*
|
||||||
|
!.gitignore
|
||||||
17
hyprtester/src/Log.hpp
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
#pragma once
|
||||||
|
#include <string>
|
||||||
|
#include <format>
|
||||||
|
#include <print>
|
||||||
|
|
||||||
|
namespace NLog {
|
||||||
|
template <typename... Args>
|
||||||
|
//NOLINTNEXTLINE
|
||||||
|
void log(std::format_string<Args...> fmt, Args&&... args) {
|
||||||
|
std::string logMsg = "";
|
||||||
|
|
||||||
|
logMsg += std::vformat(fmt.get(), std::make_format_args(args...));
|
||||||
|
|
||||||
|
std::println("{}", logMsg);
|
||||||
|
std::fflush(stdout);
|
||||||
|
}
|
||||||
|
}
|
||||||
138
hyprtester/src/hyprctlCompat.cpp
Normal file
|
|
@ -0,0 +1,138 @@
|
||||||
|
#include "hyprctlCompat.hpp"
|
||||||
|
#include "shared.hpp"
|
||||||
|
|
||||||
|
#include <pwd.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/un.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
#include <fstream>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <csignal>
|
||||||
|
#include <cerrno>
|
||||||
|
#include <print>
|
||||||
|
#include <hyprutils/memory/Casts.hpp>
|
||||||
|
using namespace Hyprutils::Memory;
|
||||||
|
|
||||||
|
static int getUID() {
|
||||||
|
const auto UID = getuid();
|
||||||
|
const auto PWUID = getpwuid(UID);
|
||||||
|
return PWUID ? PWUID->pw_uid : UID;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string getRuntimeDir() {
|
||||||
|
const auto XDG = getenv("XDG_RUNTIME_DIR");
|
||||||
|
|
||||||
|
if (!XDG) {
|
||||||
|
const std::string USERID = std::to_string(getUID());
|
||||||
|
return "/run/user/" + USERID + "/hypr";
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::string{XDG} + "/hypr";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<SInstanceData> instances() {
|
||||||
|
std::vector<SInstanceData> result;
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (!std::filesystem::exists(getRuntimeDir()))
|
||||||
|
return {};
|
||||||
|
} catch (std::exception& e) { return {}; }
|
||||||
|
|
||||||
|
for (const auto& el : std::filesystem::directory_iterator(getRuntimeDir())) {
|
||||||
|
if (!el.is_directory() || !std::filesystem::exists(el.path().string() + "/hyprland.lock"))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// read lock
|
||||||
|
SInstanceData* data = &result.emplace_back();
|
||||||
|
data->id = el.path().filename().string();
|
||||||
|
|
||||||
|
try {
|
||||||
|
data->time = std::stoull(data->id.substr(data->id.find_first_of('_') + 1, data->id.find_last_of('_') - (data->id.find_first_of('_') + 1)));
|
||||||
|
} catch (std::exception& e) { continue; }
|
||||||
|
|
||||||
|
// read file
|
||||||
|
std::ifstream ifs(el.path().string() + "/hyprland.lock");
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
for (std::string line; std::getline(ifs, line); ++i) {
|
||||||
|
if (i == 0) {
|
||||||
|
try {
|
||||||
|
data->pid = std::stoull(line);
|
||||||
|
} catch (std::exception& e) { continue; }
|
||||||
|
} else if (i == 1) {
|
||||||
|
data->wlSocket = line;
|
||||||
|
} else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ifs.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::erase_if(result, [&](const auto& el) { return kill(el.pid, 0) != 0 && errno == ESRCH; });
|
||||||
|
|
||||||
|
std::sort(result.begin(), result.end(), [&](const auto& a, const auto& b) { return a.time < b.time; });
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string getFromSocket(const std::string& cmd) {
|
||||||
|
const auto SERVERSOCKET = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||||
|
|
||||||
|
auto t = timeval{.tv_sec = 5, .tv_usec = 0};
|
||||||
|
setsockopt(SERVERSOCKET, SOL_SOCKET, SO_RCVTIMEO, &t, sizeof(struct timeval));
|
||||||
|
|
||||||
|
if (SERVERSOCKET < 0) {
|
||||||
|
std::println("socket: Couldn't open a socket (1)");
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
sockaddr_un serverAddress = {0};
|
||||||
|
serverAddress.sun_family = AF_UNIX;
|
||||||
|
|
||||||
|
std::string socketPath = getRuntimeDir() + "/" + HIS + "/.socket.sock";
|
||||||
|
|
||||||
|
strncpy(serverAddress.sun_path, socketPath.c_str(), sizeof(serverAddress.sun_path) - 1);
|
||||||
|
|
||||||
|
if (connect(SERVERSOCKET, rc<sockaddr*>(&serverAddress), SUN_LEN(&serverAddress)) < 0) {
|
||||||
|
std::println("Couldn't connect to {}. (3)", socketPath);
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
auto sizeWritten = write(SERVERSOCKET, cmd.c_str(), cmd.length());
|
||||||
|
|
||||||
|
if (sizeWritten < 0) {
|
||||||
|
std::println("Couldn't write (4)");
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string reply = "";
|
||||||
|
char buffer[8192] = {0};
|
||||||
|
|
||||||
|
sizeWritten = read(SERVERSOCKET, buffer, 8192);
|
||||||
|
|
||||||
|
if (sizeWritten < 0) {
|
||||||
|
if (errno == EWOULDBLOCK)
|
||||||
|
std::println("Hyprland IPC didn't respond in time");
|
||||||
|
std::println("Couldn't read (5)");
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
reply += std::string(buffer, sizeWritten);
|
||||||
|
|
||||||
|
while (sizeWritten == 8192) {
|
||||||
|
sizeWritten = read(SERVERSOCKET, buffer, 8192);
|
||||||
|
if (sizeWritten < 0) {
|
||||||
|
std::println("Couldn't read (5)");
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
reply += std::string(buffer, sizeWritten);
|
||||||
|
}
|
||||||
|
|
||||||
|
close(SERVERSOCKET);
|
||||||
|
|
||||||
|
return reply;
|
||||||
|
}
|
||||||
16
hyprtester/src/hyprctlCompat.hpp
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
struct SInstanceData {
|
||||||
|
std::string id;
|
||||||
|
uint64_t time;
|
||||||
|
uint64_t pid;
|
||||||
|
std::string wlSocket;
|
||||||
|
bool valid = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<SInstanceData> instances();
|
||||||
|
std::string getFromSocket(const std::string& cmd);
|
||||||
261
hyprtester/src/main.cpp
Normal file
|
|
@ -0,0 +1,261 @@
|
||||||
|
|
||||||
|
// This is a tester for Hyprland. It will launch the built binary in ./build/Hyprland
|
||||||
|
// in headless mode and test various things.
|
||||||
|
// for now it's quite basic and limited, but will be expanded in the future.
|
||||||
|
|
||||||
|
// NOTE: This tester has to be ran from its directory!!
|
||||||
|
|
||||||
|
// Some TODO:
|
||||||
|
// - Add a plugin built alongside so that we can do more detailed tests (e.g. simulating keystrokes)
|
||||||
|
// - test coverage
|
||||||
|
// - maybe figure out a way to do some visual tests too?
|
||||||
|
|
||||||
|
// Required runtime deps for checks:
|
||||||
|
// - kitty
|
||||||
|
// - xeyes
|
||||||
|
|
||||||
|
#include "shared.hpp"
|
||||||
|
#include "hyprctlCompat.hpp"
|
||||||
|
#include "tests/main/tests.hpp"
|
||||||
|
#include "tests/clients/tests.hpp"
|
||||||
|
#include "tests/plugin/plugin.hpp"
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
#include <hyprutils/os/Process.hpp>
|
||||||
|
#include <hyprutils/memory/WeakPtr.hpp>
|
||||||
|
#include <hyprutils/memory/Casts.hpp>
|
||||||
|
using namespace Hyprutils::Memory;
|
||||||
|
|
||||||
|
#include <csignal>
|
||||||
|
#include <cerrno>
|
||||||
|
#include <chrono>
|
||||||
|
#include <thread>
|
||||||
|
#include <print>
|
||||||
|
#include <string_view>
|
||||||
|
#include <span>
|
||||||
|
|
||||||
|
#include "Log.hpp"
|
||||||
|
|
||||||
|
using namespace Hyprutils::OS;
|
||||||
|
using namespace Hyprutils::Memory;
|
||||||
|
|
||||||
|
#define SP CSharedPointer
|
||||||
|
|
||||||
|
static int ret = 0;
|
||||||
|
static SP<CProcess> hyprlandProc;
|
||||||
|
static const std::string cwd = std::filesystem::current_path().string();
|
||||||
|
|
||||||
|
//
|
||||||
|
static bool launchHyprland(std::string configPath, std::string binaryPath) {
|
||||||
|
if (binaryPath == "") {
|
||||||
|
std::error_code ec;
|
||||||
|
if (!std::filesystem::exists(cwd + "/../build/Hyprland", ec) || ec) {
|
||||||
|
NLog::log("{}No Hyprland binary", Colors::RED);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
binaryPath = cwd + "/../build/Hyprland";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (configPath == "") {
|
||||||
|
std::error_code ec;
|
||||||
|
if (!std::filesystem::exists(cwd + "/test.conf", ec) || ec) {
|
||||||
|
NLog::log("{}No test config", Colors::RED);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
configPath = cwd + "/test.conf";
|
||||||
|
}
|
||||||
|
|
||||||
|
NLog::log("{}Launching Hyprland", Colors::YELLOW);
|
||||||
|
hyprlandProc = makeShared<CProcess>(binaryPath, std::vector<std::string>{"--config", configPath});
|
||||||
|
hyprlandProc->addEnv("HYPRLAND_HEADLESS_ONLY", "1");
|
||||||
|
|
||||||
|
NLog::log("{}Launched async process", Colors::YELLOW);
|
||||||
|
|
||||||
|
return hyprlandProc->runAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool hyprlandAlive() {
|
||||||
|
NLog::log("{}hyprlandAlive", Colors::YELLOW);
|
||||||
|
kill(hyprlandProc->pid(), 0);
|
||||||
|
return errno != ESRCH;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void help() {
|
||||||
|
NLog::log("usage: hyprtester [arg [...]].\n");
|
||||||
|
NLog::log(R"(Arguments:
|
||||||
|
--help -h - Show this message again
|
||||||
|
--config FILE -c FILE - Specify config file to use
|
||||||
|
--binary FILE -b FILE - Specify Hyprland binary to use
|
||||||
|
--plugin FILE -p FILE - Specify the location of the test plugin)");
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char** argv, char** envp) {
|
||||||
|
|
||||||
|
std::string configPath = "";
|
||||||
|
std::string binaryPath = "";
|
||||||
|
std::string pluginPath = std::filesystem::current_path().string();
|
||||||
|
|
||||||
|
if (argc > 1) {
|
||||||
|
std::span<char*> args{argv + 1, sc<std::size_t>(argc - 1)};
|
||||||
|
|
||||||
|
for (auto it = args.begin(); it != args.end(); it++) {
|
||||||
|
std::string_view value = *it;
|
||||||
|
|
||||||
|
if (value == "--config" || value == "-c") {
|
||||||
|
if (std::next(it) == args.end()) {
|
||||||
|
help();
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
configPath = *std::next(it);
|
||||||
|
|
||||||
|
try {
|
||||||
|
configPath = std::filesystem::canonical(configPath);
|
||||||
|
|
||||||
|
if (!std::filesystem::is_regular_file(configPath)) {
|
||||||
|
throw std::exception();
|
||||||
|
}
|
||||||
|
} catch (...) {
|
||||||
|
std::println(stderr, "[ ERROR ] Config file '{}' doesn't exist!", configPath);
|
||||||
|
help();
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
it++;
|
||||||
|
|
||||||
|
continue;
|
||||||
|
} else if (value == "--binary" || value == "-b") {
|
||||||
|
if (std::next(it) == args.end()) {
|
||||||
|
help();
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
binaryPath = *std::next(it);
|
||||||
|
|
||||||
|
try {
|
||||||
|
binaryPath = std::filesystem::canonical(binaryPath);
|
||||||
|
|
||||||
|
if (!std::filesystem::is_regular_file(binaryPath)) {
|
||||||
|
throw std::exception();
|
||||||
|
}
|
||||||
|
} catch (...) {
|
||||||
|
std::println(stderr, "[ ERROR ] Binary '{}' doesn't exist!", binaryPath);
|
||||||
|
help();
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
it++;
|
||||||
|
|
||||||
|
continue;
|
||||||
|
} else if (value == "--plugin" || value == "-p") {
|
||||||
|
if (std::next(it) == args.end()) {
|
||||||
|
help();
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
pluginPath = *std::next(it);
|
||||||
|
|
||||||
|
try {
|
||||||
|
pluginPath = std::filesystem::canonical(pluginPath);
|
||||||
|
|
||||||
|
if (!std::filesystem::is_regular_file(pluginPath)) {
|
||||||
|
throw std::exception();
|
||||||
|
}
|
||||||
|
} catch (...) {
|
||||||
|
std::println(stderr, "[ ERROR ] plugin '{}' doesn't exist!", pluginPath);
|
||||||
|
help();
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
it++;
|
||||||
|
|
||||||
|
continue;
|
||||||
|
} else if (value == "--help" || value == "-h") {
|
||||||
|
help();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
std::println(stderr, "[ ERROR ] Unknown option '{}' !", *it);
|
||||||
|
help();
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NLog::log("{}launching hl", Colors::YELLOW);
|
||||||
|
if (!launchHyprland(configPath, binaryPath)) {
|
||||||
|
NLog::log("{}well it failed", Colors::RED);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// hyprland has launched, let's check if it's alive after 10s
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(10000));
|
||||||
|
NLog::log("{}slept for 10s", Colors::YELLOW);
|
||||||
|
if (!hyprlandAlive()) {
|
||||||
|
NLog::log("{}Hyprland failed to launch", Colors::RED);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// wonderful, we are in. Let's get the instance signature.
|
||||||
|
NLog::log("{}trying to get INSTANCES", Colors::YELLOW);
|
||||||
|
const auto INSTANCES = instances();
|
||||||
|
if (INSTANCES.empty()) {
|
||||||
|
NLog::log("{}Hyprland failed to launch (2)", Colors::RED);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
HIS = INSTANCES.back().id;
|
||||||
|
WLDISPLAY = INSTANCES.back().wlSocket;
|
||||||
|
|
||||||
|
NLog::log("{}trying to get create headless output", Colors::YELLOW);
|
||||||
|
getFromSocket("/output create headless");
|
||||||
|
|
||||||
|
NLog::log("{}trying to load plugin", Colors::YELLOW);
|
||||||
|
if (const auto R = getFromSocket(std::format("/plugin load {}", pluginPath)); R != "ok") {
|
||||||
|
NLog::log("{}Failed to load the test plugin: {}", Colors::RED, R);
|
||||||
|
getFromSocket("/dispatch exit 1");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
NLog::log("{}Loaded plugin", Colors::YELLOW);
|
||||||
|
|
||||||
|
NLog::log("{}Running main tests", Colors::YELLOW);
|
||||||
|
|
||||||
|
for (const auto& fn : testFns) {
|
||||||
|
EXPECT(fn(), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
NLog::log("{}Running protocol client tests", Colors::YELLOW);
|
||||||
|
|
||||||
|
for (const auto& fn : clientTestFns) {
|
||||||
|
EXPECT(fn(), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
NLog::log("{}running plugin test", Colors::YELLOW);
|
||||||
|
EXPECT(testPlugin(), true);
|
||||||
|
|
||||||
|
NLog::log("{}running vkb test from plugin", Colors::YELLOW);
|
||||||
|
EXPECT(testVkb(), true);
|
||||||
|
|
||||||
|
// kill hyprland
|
||||||
|
NLog::log("{}dispatching exit", Colors::YELLOW);
|
||||||
|
getFromSocket("/dispatch exit");
|
||||||
|
|
||||||
|
NLog::log("\n{}Summary:\n\tPASSED: {}{}{}/{}\n\tFAILED: {}{}{}/{}\n{}", Colors::RESET, Colors::GREEN, TESTS_PASSED, Colors::RESET, TESTS_PASSED + TESTS_FAILED, Colors::RED,
|
||||||
|
TESTS_FAILED, Colors::RESET, TESTS_PASSED + TESTS_FAILED, (TESTS_FAILED > 0 ? std::string{Colors::RED} + "\nSome tests failed.\n" : ""));
|
||||||
|
|
||||||
|
kill(hyprlandProc->pid(), SIGKILL);
|
||||||
|
|
||||||
|
hyprlandProc.reset();
|
||||||
|
|
||||||
|
return ret || TESTS_FAILED;
|
||||||
|
}
|
||||||
111
hyprtester/src/shared.hpp
Normal file
|
|
@ -0,0 +1,111 @@
|
||||||
|
// Stolen from hyprutils
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
inline std::string HIS = "";
|
||||||
|
inline std::string WLDISPLAY = "";
|
||||||
|
inline int TESTS_PASSED = 0;
|
||||||
|
inline int TESTS_FAILED = 0;
|
||||||
|
|
||||||
|
namespace Colors {
|
||||||
|
constexpr const char* RED = "\x1b[31m";
|
||||||
|
constexpr const char* GREEN = "\x1b[32m";
|
||||||
|
constexpr const char* YELLOW = "\x1b[33m";
|
||||||
|
constexpr const char* BLUE = "\x1b[34m";
|
||||||
|
constexpr const char* MAGENTA = "\x1b[35m";
|
||||||
|
constexpr const char* CYAN = "\x1b[36m";
|
||||||
|
constexpr const char* RESET = "\x1b[0m";
|
||||||
|
};
|
||||||
|
|
||||||
|
#define EXPECT_MAX_DELTA(expr, desired, delta) \
|
||||||
|
if (const auto RESULT = expr; std::abs(RESULT - (desired)) > delta) { \
|
||||||
|
NLog::log("{}Failed: {}{}, expected max delta of {}, got delta {} ({} - {}). Source: {}@{}.", Colors::RED, Colors::RESET, #expr, delta, (RESULT - (desired)), RESULT, \
|
||||||
|
desired, __FILE__, __LINE__); \
|
||||||
|
ret = 1; \
|
||||||
|
TESTS_FAILED++; \
|
||||||
|
} else { \
|
||||||
|
NLog::log("{}Passed: {}{}. Got {}", Colors::GREEN, Colors::RESET, #expr, (RESULT - (desired))); \
|
||||||
|
TESTS_PASSED++; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define EXPECT(expr, val) \
|
||||||
|
if (const auto RESULT = expr; RESULT != (val)) { \
|
||||||
|
NLog::log("{}Failed: {}{}, expected {}, got {}. Source: {}@{}.", Colors::RED, Colors::RESET, #expr, val, RESULT, __FILE__, __LINE__); \
|
||||||
|
ret = 1; \
|
||||||
|
TESTS_FAILED++; \
|
||||||
|
} else { \
|
||||||
|
NLog::log("{}Passed: {}{}. Got {}", Colors::GREEN, Colors::RESET, #expr, val); \
|
||||||
|
TESTS_PASSED++; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define EXPECT_NOT(expr, val) \
|
||||||
|
if (const auto RESULT = expr; RESULT == (val)) { \
|
||||||
|
NLog::log("{}Failed: {}{}, expected not {}, got {}. Source: {}@{}.", Colors::RED, Colors::RESET, #expr, val, RESULT, __FILE__, __LINE__); \
|
||||||
|
ret = 1; \
|
||||||
|
TESTS_FAILED++; \
|
||||||
|
} else { \
|
||||||
|
NLog::log("{}Passed: {}{}. Got {}", Colors::GREEN, Colors::RESET, #expr, val); \
|
||||||
|
TESTS_PASSED++; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define EXPECT_VECTOR2D(expr, val) \
|
||||||
|
do { \
|
||||||
|
const auto& RESULT = expr; \
|
||||||
|
const auto& EXPECTED = val; \
|
||||||
|
if (!(std::abs(RESULT.x - EXPECTED.x) < 1e-6 && std::abs(RESULT.y - EXPECTED.y) < 1e-6)) { \
|
||||||
|
NLog::log("{}Failed: {}{}, expected [{}, {}], got [{}, {}]. Source: {}@{}.", Colors::RED, Colors::RESET, #expr, EXPECTED.x, EXPECTED.y, RESULT.x, RESULT.y, __FILE__, \
|
||||||
|
__LINE__); \
|
||||||
|
ret = 1; \
|
||||||
|
TESTS_FAILED++; \
|
||||||
|
} else { \
|
||||||
|
NLog::log("{}Passed: {}{}. Got [{}, {}].", Colors::GREEN, Colors::RESET, #expr, RESULT.x, RESULT.y); \
|
||||||
|
TESTS_PASSED++; \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define EXPECT_CONTAINS(haystack, needle) \
|
||||||
|
if (const auto EXPECTED = needle; !std::string{haystack}.contains(EXPECTED)) { \
|
||||||
|
NLog::log("{}Failed: {}{} should contain {} but doesn't. Source: {}@{}. Haystack is:\n{}", Colors::RED, Colors::RESET, #haystack, #needle, __FILE__, __LINE__, \
|
||||||
|
std::string{haystack}); \
|
||||||
|
ret = 1; \
|
||||||
|
TESTS_FAILED++; \
|
||||||
|
} else { \
|
||||||
|
NLog::log("{}Passed: {}{} contains {}.", Colors::GREEN, Colors::RESET, #haystack, EXPECTED); \
|
||||||
|
TESTS_PASSED++; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define EXPECT_NOT_CONTAINS(haystack, needle) \
|
||||||
|
if (std::string{haystack}.contains(needle)) { \
|
||||||
|
NLog::log("{}Failed: {}{} shouldn't contain {} but does. Source: {}@{}. Haystack is:\n{}", Colors::RED, Colors::RESET, #haystack, #needle, __FILE__, __LINE__, \
|
||||||
|
std::string{haystack}); \
|
||||||
|
ret = 1; \
|
||||||
|
TESTS_FAILED++; \
|
||||||
|
} else { \
|
||||||
|
NLog::log("{}Passed: {}{} doesn't contain {}.", Colors::GREEN, Colors::RESET, #haystack, #needle); \
|
||||||
|
TESTS_PASSED++; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define EXPECT_STARTS_WITH(str, what) \
|
||||||
|
if (!std::string{str}.starts_with(what)) { \
|
||||||
|
NLog::log("{}Failed: {}{} should start with {} but doesn't. Source: {}@{}. String is:\n{}", Colors::RED, Colors::RESET, #str, #what, __FILE__, __LINE__, \
|
||||||
|
std::string{str}); \
|
||||||
|
ret = 1; \
|
||||||
|
TESTS_FAILED++; \
|
||||||
|
} else { \
|
||||||
|
NLog::log("{}Passed: {}{} starts with {}.", Colors::GREEN, Colors::RESET, #str, #what); \
|
||||||
|
TESTS_PASSED++; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define EXPECT_COUNT_STRING(str, what, no) \
|
||||||
|
if (Tests::countOccurrences(str, what) != no) { \
|
||||||
|
NLog::log("{}Failed: {}{} should contain {} {} times, but doesn't. Source: {}@{}. String is:\n{}", Colors::RED, Colors::RESET, #str, #what, no, __FILE__, __LINE__, \
|
||||||
|
std::string{str}); \
|
||||||
|
ret = 1; \
|
||||||
|
TESTS_FAILED++; \
|
||||||
|
} else { \
|
||||||
|
NLog::log("{}Passed: {}{} contains {} {} times.", Colors::GREEN, Colors::RESET, #str, #what, no); \
|
||||||
|
TESTS_PASSED++; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define OK(x) EXPECT(x, "ok")
|
||||||
1
hyprtester/src/tests/clients/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
build.hpp
|
||||||