mirror of
https://github.com/hyprwm/Hyprland.git
synced 2025-08-19 14:03:47 -07:00
Compare commits
1810 Commits
v0.17.0bet
...
v0.33.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d74607e414 | ||
|
|
c4bd91ec8a | ||
|
|
03c6f4506a | ||
|
|
13b4c6de86 | ||
|
|
8bd86cf37e | ||
|
|
cfd94c5b30 | ||
|
|
ab66fa430e | ||
|
|
37d7a8c64d | ||
|
|
da863459c4 | ||
|
|
83248b6936 | ||
|
|
3bb9c7c5cf | ||
|
|
2d04cb1cc6 | ||
|
|
c6804ccaab | ||
|
|
aa46aaed04 | ||
|
|
68783d904d | ||
|
|
5d100bdcbb | ||
|
|
45d3fbb8d8 | ||
|
|
9a9528d093 | ||
|
|
e496b0f250 | ||
|
|
dc2082b00a | ||
|
|
59cb0e20de | ||
|
|
80b9b21f9f | ||
|
|
758cf90ea1 | ||
|
|
6e8b9ef7d8 | ||
|
|
9c09f2a847 | ||
|
|
8440a30231 | ||
|
|
ab40f240c3 | ||
|
|
b394c1695c | ||
|
|
0a4c4da5f0 | ||
|
|
b2f3623131 | ||
|
|
5513eed64d | ||
|
|
29970228c5 | ||
|
|
12ec549a18 | ||
|
|
9f2027be4b | ||
|
|
b9937484f4 | ||
|
|
776f944619 | ||
|
|
1fc1e4e9cb | ||
|
|
e1258707ad | ||
|
|
d2c3b23ace | ||
|
|
b80c72c7dd | ||
|
|
3caaa483d4 | ||
|
|
e2f18f8c7f | ||
|
|
99ca26d4eb | ||
|
|
e416ab740d | ||
|
|
7a0a5666d5 | ||
|
|
1778fb77e2 | ||
|
|
adeb20ea11 | ||
|
|
68e57b7ee3 | ||
|
|
408d96668d | ||
|
|
75e5799310 | ||
|
|
9e2b939024 | ||
|
|
cd96ceecc5 | ||
|
|
ad3f688648 | ||
|
|
98c7ba4782 | ||
|
|
a5f64b48ca | ||
|
|
b281d8647a | ||
|
|
15b282ee0c | ||
|
|
6f733292bf | ||
|
|
3fe6162af1 | ||
|
|
2ce4b94a22 | ||
|
|
de95e956a0 | ||
|
|
929c44e361 | ||
|
|
512a59731b | ||
|
|
a6eba91935 | ||
|
|
745b998587 | ||
|
|
1a2a2da6aa | ||
|
|
822775aa8c | ||
|
|
d79cf0afe2 | ||
|
|
334d0ae31b | ||
|
|
be3d635265 | ||
|
|
f9ba5a0551 | ||
|
|
258c83f3bb | ||
|
|
aedcade68d | ||
|
|
802ab58f8a | ||
|
|
af5d06593f | ||
|
|
2ebfd0c745 | ||
|
|
e40e486f61 | ||
|
|
e55c5a916a | ||
|
|
45ebe0df8f | ||
|
|
812a3f6d78 | ||
|
|
44accacff9 | ||
|
|
d417370bb7 | ||
|
|
4729265284 | ||
|
|
572fd554b8 | ||
|
|
7d1c8d827a | ||
|
|
6d26199e1c | ||
|
|
646f4bc638 | ||
|
|
7e0c90b92c | ||
|
|
add23a9ba2 | ||
|
|
3d89654254 | ||
|
|
6ad5f26cfe | ||
|
|
89f6457a99 | ||
|
|
8b57a1973e | ||
|
|
483302a2cd | ||
|
|
a903dba858 | ||
|
|
395985f815 | ||
|
|
51282f964f | ||
|
|
db8f13291a | ||
|
|
30ad71ff36 | ||
|
|
84bc0a73f6 | ||
|
|
1d9bfa60a1 | ||
|
|
a34e192433 | ||
|
|
4868d4dfd3 | ||
|
|
859841f4d1 | ||
|
|
28ef18a921 | ||
|
|
91d6be1f09 | ||
|
|
9e3dccca76 | ||
|
|
81598b3dbd | ||
|
|
e195e51c1b | ||
|
|
e8469f8b1b | ||
|
|
49597688e9 | ||
|
|
5edb4e4a30 | ||
|
|
4d6fa6ed0c | ||
|
|
016a7a9c9b | ||
|
|
2e26542e3b | ||
|
|
68935ba9dc | ||
|
|
ba5bc5871f | ||
|
|
824ccd957b | ||
|
|
45e86d4fdf | ||
|
|
0ba2e68704 | ||
|
|
e974d1fe98 | ||
|
|
47d46aa56c | ||
|
|
65efde32c9 | ||
|
|
69e314207d | ||
|
|
1bfd4a2bff | ||
|
|
91cbe93cf8 | ||
|
|
9afdd61ade | ||
|
|
f39a6ca17c | ||
|
|
eab2799842 | ||
|
|
6eb2abcb20 | ||
|
|
ae46fbafe5 | ||
|
|
52cf122a0a | ||
|
|
844da8db56 | ||
|
|
db82fc5b09 | ||
|
|
8180ca65a5 | ||
|
|
bea828ea45 | ||
|
|
c5d1faf72d | ||
|
|
cc04b52ce1 | ||
|
|
9b5e2e71e0 | ||
|
|
9be6fbf5ea | ||
|
|
7345b1a1ea | ||
|
|
e44d6de555 | ||
|
|
427153e86a | ||
|
|
1e6e9b66a5 | ||
|
|
92cb44ddb2 | ||
|
|
b8a615ffb8 | ||
|
|
8dd02eb5f3 | ||
|
|
14195835ef | ||
|
|
11432f69b9 | ||
|
|
da6fa9cbd2 | ||
|
|
c619e6976f | ||
|
|
751d2851cc | ||
|
|
a0fcda301d | ||
|
|
47654a84c2 | ||
|
|
29e0a7112e | ||
|
|
a1b7a5a53d | ||
|
|
ecf98069f6 | ||
|
|
0476e1b498 | ||
|
|
a122271f09 | ||
|
|
600a128f83 | ||
|
|
55825c301e | ||
|
|
d8b7ded18c | ||
|
|
c4e1a9b13b | ||
|
|
9404972732 | ||
|
|
3b786419d8 | ||
|
|
92e535025e | ||
|
|
d3e5796ee1 | ||
|
|
56dec1c6a2 | ||
|
|
931927de29 | ||
|
|
74cf2281dd | ||
|
|
2b07d54bc7 | ||
|
|
66a3719b86 | ||
|
|
64a084477e | ||
|
|
7a09d24065 | ||
|
|
a3e20d2d5f | ||
|
|
32b3d2b456 | ||
|
|
447c173cad | ||
|
|
55b4f84fea | ||
|
|
73e78f05ad | ||
|
|
54e51b7acf | ||
|
|
200cccdd3b | ||
|
|
15b25d5850 | ||
|
|
21ba8b363e | ||
|
|
9d2a5fb417 | ||
|
|
ed3d5053b2 | ||
|
|
93a2ac9de4 | ||
|
|
49fdffacea | ||
|
|
0f6e530798 | ||
|
|
88b47dfa83 | ||
|
|
ba9e7814b0 | ||
|
|
f10996b575 | ||
|
|
ef90d1eaaf | ||
|
|
062f749450 | ||
|
|
a4db48b46b | ||
|
|
c44e255194 | ||
|
|
21e9313c10 | ||
|
|
7b32b4214d | ||
|
|
6914103289 | ||
|
|
ab5497a0c9 | ||
|
|
f48b3774a2 | ||
|
|
1c9d6b94d1 | ||
|
|
4b592d0819 | ||
|
|
a1924ae435 | ||
|
|
cb6cfde6e8 | ||
|
|
8e91c038db | ||
|
|
86318ce04f | ||
|
|
59d6a12a7e | ||
|
|
935c90915a | ||
|
|
b95c0c318e | ||
|
|
9abfa9efc6 | ||
|
|
7a5234a0cc | ||
|
|
af9440152e | ||
|
|
7f4b0aaadc | ||
|
|
4a4e13f8ac | ||
|
|
1d47e2c408 | ||
|
|
47256a6ed8 | ||
|
|
732b058489 | ||
|
|
92cf1c2337 | ||
|
|
07714dd5bd | ||
|
|
5cc33b4e8c | ||
|
|
b0b88a63b6 | ||
|
|
5b0dc779ed | ||
|
|
8991be671f | ||
|
|
6650e4ba85 | ||
|
|
a1b138a625 | ||
|
|
df00727310 | ||
|
|
03771d3aa9 | ||
|
|
50a80efad5 | ||
|
|
14a3c939ce | ||
|
|
aeb8c8fc70 | ||
|
|
616ff343b7 | ||
|
|
2f6729f557 | ||
|
|
015664eb4c | ||
|
|
98059b52d7 | ||
|
|
b135bd6cd4 | ||
|
|
59f27e7f57 | ||
|
|
edb26e0306 | ||
|
|
d0367d8560 | ||
|
|
95db9108e5 | ||
|
|
a61eb7694d | ||
|
|
c6233a790f | ||
|
|
92311d260a | ||
|
|
af72404259 | ||
|
|
4a79718fe8 | ||
|
|
7f35f33b4c | ||
|
|
bab2f6a664 | ||
|
|
bb9d0aed5b | ||
|
|
386708563c | ||
|
|
ba5f1d8783 | ||
|
|
d994e6aea6 | ||
|
|
6e15590e98 | ||
|
|
d70cc88dab | ||
|
|
a0b675ec9e | ||
|
|
784f8a88fb | ||
|
|
20e7ccd480 | ||
|
|
210be10c92 | ||
|
|
421f5fb221 | ||
|
|
93676f91a0 | ||
|
|
54e1c2ccbd | ||
|
|
5b8cfdf2ef | ||
|
|
8af3e7beeb | ||
|
|
1f582457cf | ||
|
|
442209942f | ||
|
|
43b39e0bc6 | ||
|
|
261c594458 | ||
|
|
962a0de01a | ||
|
|
21b5cf402a | ||
|
|
d4e4931008 | ||
|
|
d5a572bd39 | ||
|
|
424c9a7e70 | ||
|
|
3a61350286 | ||
|
|
e4bcd2e2da | ||
|
|
06cc42441c | ||
|
|
5dc7161b1d | ||
|
|
0cf3d5b39a | ||
|
|
34455844e9 | ||
|
|
d83357f497 | ||
|
|
a0038fa161 | ||
|
|
914851b91a | ||
|
|
3219c84433 | ||
|
|
1a0909aa20 | ||
|
|
bf94df7b00 | ||
|
|
d537815d43 | ||
|
|
ac1bd47653 | ||
|
|
8abb6e1cee | ||
|
|
df0c8e0f7a | ||
|
|
7f8e0a1318 | ||
|
|
499df49f7b | ||
|
|
728a8bb48e | ||
|
|
7d7565e7ec | ||
|
|
38e242953d | ||
|
|
61d3d4dee7 | ||
|
|
1afb00a01b | ||
|
|
cb7dd1ac6e | ||
|
|
4b3efc73c5 | ||
|
|
24c04a8b7c | ||
|
|
3d1a167960 | ||
|
|
1b99a69dc1 | ||
|
|
8e0eafc502 | ||
|
|
e689b1ba11 | ||
|
|
322c5cc4b9 | ||
|
|
230356012b | ||
|
|
4531717f3e | ||
|
|
f8c18ff797 | ||
|
|
f803be3d31 | ||
|
|
2901bb0d2f | ||
|
|
d61e4f9ad7 | ||
|
|
b784931e67 | ||
|
|
fcab2a4358 | ||
|
|
b814ba98a7 | ||
|
|
50fecf084d | ||
|
|
5ffb1032e1 | ||
|
|
fc1d7acd9a | ||
|
|
778bdf730f | ||
|
|
763bb2d3bc | ||
|
|
9ec656a37d | ||
|
|
161fee1d82 | ||
|
|
a2a29a60e5 | ||
|
|
e2b72b2975 | ||
|
|
772c7d1d3c | ||
|
|
6a4643842d | ||
|
|
a05076a7ee | ||
|
|
b8f8912db2 | ||
|
|
86e8ed038f | ||
|
|
c298439433 | ||
|
|
495d4f2d11 | ||
|
|
7b002d609b | ||
|
|
4daa515700 | ||
|
|
e07e64458e | ||
|
|
a44ab7748f | ||
|
|
ab11bd2085 | ||
|
|
27cd7ef0c9 | ||
|
|
9cc614d096 | ||
|
|
3f09b14381 | ||
|
|
453128ee0e | ||
|
|
88b63a00b6 | ||
|
|
1e513e25d5 | ||
|
|
d48c11cc3f | ||
|
|
08595f839b | ||
|
|
eab5967ef4 | ||
|
|
280f385cf8 | ||
|
|
1f4eab176e | ||
|
|
6d7dc70f66 | ||
|
|
ffacd2efd1 | ||
|
|
3b657257ec | ||
|
|
6bdc45e9ce | ||
|
|
46d66f4bcc | ||
|
|
352ceb1117 | ||
|
|
2c4a06eb54 | ||
|
|
3b445ec849 | ||
|
|
8252957392 | ||
|
|
8637bfb1b7 | ||
|
|
de95089552 | ||
|
|
9c00381dfc | ||
|
|
fb80cbe415 | ||
|
|
1b48642fd1 | ||
|
|
3b1e09e5a1 | ||
|
|
9f68aa33ea | ||
|
|
ea45bfb63c | ||
|
|
ea5d9584da | ||
|
|
1357b66091 | ||
|
|
2e1842b5ff | ||
|
|
b662215fad | ||
|
|
e4ddfcfa0c | ||
|
|
d41a91e050 | ||
|
|
47f38dbc8f | ||
|
|
1925e64c21 | ||
|
|
62efc045d7 | ||
|
|
ef94375882 | ||
|
|
0dbd997003 | ||
|
|
3785defaf1 | ||
|
|
6594b50e57 | ||
|
|
d8d0cd75c2 | ||
|
|
c50072b108 | ||
|
|
60f10e6037 | ||
|
|
e4d6695375 | ||
|
|
b0a82c04df | ||
|
|
af15b15b4b | ||
|
|
f72e04d63b | ||
|
|
c8cc811e85 | ||
|
|
c0082519ae | ||
|
|
2f01a18989 | ||
|
|
a53ec98b82 | ||
|
|
d126d2c092 | ||
|
|
cc630c90b5 | ||
|
|
b9b38424b0 | ||
|
|
56adec7c1a | ||
|
|
824290c791 | ||
|
|
d3cbec2d1a | ||
|
|
f8008e4b3b | ||
|
|
2536630049 | ||
|
|
e6651334f2 | ||
|
|
0e64dd2ea5 | ||
|
|
db2b72adee | ||
|
|
0dc8289b02 | ||
|
|
f6473aa3ad | ||
|
|
84f8f4d77d | ||
|
|
2ad429dfe0 | ||
|
|
4f88897fc0 | ||
|
|
41e5f401c5 | ||
|
|
b884544ee6 | ||
|
|
6b1ac659e0 | ||
|
|
b0d5e4008b | ||
|
|
be19773aaa | ||
|
|
2e34548aea | ||
|
|
5cc53c14d9 | ||
|
|
9192b20b96 | ||
|
|
b6191cbc76 | ||
|
|
ed51fe7bac | ||
|
|
bc41d7ec85 | ||
|
|
df51c45d7f | ||
|
|
5a6d0e9963 | ||
|
|
99fac59938 | ||
|
|
e96e0dc02d | ||
|
|
3859607b6c | ||
|
|
ac2f1a9c30 | ||
|
|
81661b49aa | ||
|
|
79862c957c | ||
|
|
19bbdeed47 | ||
|
|
0d53401217 | ||
|
|
1e60802968 | ||
|
|
d28725c678 | ||
|
|
dcb909df04 | ||
|
|
807fc20525 | ||
|
|
6c855dd6e4 | ||
|
|
d490f198a4 | ||
|
|
a781c152ff | ||
|
|
f7f70c9e72 | ||
|
|
f4e99a36a9 | ||
|
|
1a6f961de2 | ||
|
|
c061946a94 | ||
|
|
6648274735 | ||
|
|
398e861b55 | ||
|
|
0be6b03ee9 | ||
|
|
cc5852faa2 | ||
|
|
b2516010b7 | ||
|
|
0d5a6f3168 | ||
|
|
1581666171 | ||
|
|
8c83852704 | ||
|
|
60c01dab01 | ||
|
|
a15e3e1f38 | ||
|
|
a1cc99a986 | ||
|
|
f90a009e93 | ||
|
|
8b9cc9a8db | ||
|
|
37e2311a3e | ||
|
|
61a71c65ac | ||
|
|
c3a83daa1e | ||
|
|
fa3de9b70e | ||
|
|
2d100bf57e | ||
|
|
28f1f035b1 | ||
|
|
db48f973fd | ||
|
|
4ddcda93f5 | ||
|
|
8e9f010ee0 | ||
|
|
4eecb8bffc | ||
|
|
d9937fcdba | ||
|
|
e3c83ab2e0 | ||
|
|
b4c832a1f2 | ||
|
|
9f3a64481e | ||
|
|
69439871e6 | ||
|
|
6a0e2bbff3 | ||
|
|
32f75ebb70 | ||
|
|
35df4693ea | ||
|
|
8fefb180b1 | ||
|
|
5126bfab72 | ||
|
|
96d555e8e7 | ||
|
|
c6c820d16d | ||
|
|
e6ca4b6eee | ||
|
|
5e0cf7d6a5 | ||
|
|
01c6c5ae22 | ||
|
|
423b129b24 | ||
|
|
00bee91bbc | ||
|
|
d4ec54d048 | ||
|
|
69ce11a063 | ||
|
|
204a580544 | ||
|
|
1ecfb5e852 | ||
|
|
f69c5469d7 | ||
|
|
2985e20e6a | ||
|
|
d2a785dfe3 | ||
|
|
563fe83db2 | ||
|
|
f242f9447b | ||
|
|
d9292800a2 | ||
|
|
774a5bedf8 | ||
|
|
8314341ffe | ||
|
|
b48f810a12 | ||
|
|
bb0933437f | ||
|
|
5035f5fc68 | ||
|
|
1a13d44d5d | ||
|
|
fc0c1896e0 | ||
|
|
9c4f776757 | ||
|
|
b10cae3010 | ||
|
|
c98a00678c | ||
|
|
b4f123d1f2 | ||
|
|
28a90d6055 | ||
|
|
32f4059b37 | ||
|
|
84c4a14dad | ||
|
|
c5084f36c6 | ||
|
|
0a78f6031c | ||
|
|
981386d2ae | ||
|
|
b8f38dcbd3 | ||
|
|
df691859fb | ||
|
|
aed1f66bec | ||
|
|
4a41d013a2 | ||
|
|
299d201e56 | ||
|
|
d63a42e93f | ||
|
|
ae69b9a2fa | ||
|
|
116b9a8056 | ||
|
|
9dae8ece71 | ||
|
|
870471dd96 | ||
|
|
23e17700a7 | ||
|
|
f0da0b0be4 | ||
|
|
3a1f30519b | ||
|
|
6a5a5ed11e | ||
|
|
ad085666c1 | ||
|
|
90c03e5bd2 | ||
|
|
17ea7db23a | ||
|
|
4d14edd8a5 | ||
|
|
3576ee61f1 | ||
|
|
6692fb12ab | ||
|
|
9d094f655e | ||
|
|
5e7183daf5 | ||
|
|
ba31518ed8 | ||
|
|
41d9b6f0d7 | ||
|
|
9ad4a96d18 | ||
|
|
cb59763d32 | ||
|
|
9977a8bfd4 | ||
|
|
37128bfd43 | ||
|
|
17d8e4750b | ||
|
|
63b2189ce8 | ||
|
|
025c023e4b | ||
|
|
09cc96c0d5 | ||
|
|
b79dfcceb4 | ||
|
|
7713daa86a | ||
|
|
fff118fa76 | ||
|
|
ebc5fed9b2 | ||
|
|
942ee943f5 | ||
|
|
14f20a7372 | ||
|
|
3d9545d2e0 | ||
|
|
37a211a2ae | ||
|
|
7155b4c266 | ||
|
|
7e8a212027 | ||
|
|
19f3e927d9 | ||
|
|
78fa8adadc | ||
|
|
19c4855afc | ||
|
|
63b266cf65 | ||
|
|
4986d74ef2 | ||
|
|
91e28bbe9d | ||
|
|
2b4537606f | ||
|
|
347a1eb662 | ||
|
|
7c4daee29a | ||
|
|
b9a783229b | ||
|
|
2110dc1f03 | ||
|
|
e5fb9b1b02 | ||
|
|
13886a264f | ||
|
|
a0cf890292 | ||
|
|
9ba6eab8db | ||
|
|
9180fb08e2 | ||
|
|
314f88de53 | ||
|
|
aff4a1e237 | ||
|
|
2650224c1f | ||
|
|
e510c6a7fc | ||
|
|
c1bcbdb3dd | ||
|
|
0314a727eb | ||
|
|
3fc4ac07e0 | ||
|
|
38814e8a95 | ||
|
|
0220e4c1ea | ||
|
|
4b568ae5f6 | ||
|
|
739598717b | ||
|
|
d20837bef8 | ||
|
|
3f7f4207a6 | ||
|
|
8a7ce59ad4 | ||
|
|
60b548296d | ||
|
|
901236a535 | ||
|
|
e4e8ae8f88 | ||
|
|
c4c3b590e5 | ||
|
|
126792584f | ||
|
|
cbb899740c | ||
|
|
fe9453c643 | ||
|
|
d7209b90bb | ||
|
|
47430411d6 | ||
|
|
ec269622fc | ||
|
|
12cb109137 | ||
|
|
8e04a80e60 | ||
|
|
6295cbe9cb | ||
|
|
b68292340c | ||
|
|
ab73183cb2 | ||
|
|
36052abd33 | ||
|
|
b3393c429f | ||
|
|
c748f36939 | ||
|
|
ad3b8dddf9 | ||
|
|
cebab759d5 | ||
|
|
deeeb33c5f | ||
|
|
261c3307f7 | ||
|
|
6e53c47e68 | ||
|
|
6c10c38481 | ||
|
|
a077b7a92e | ||
|
|
b925f1b497 | ||
|
|
46cf4eb837 | ||
|
|
79ce387cb8 | ||
|
|
ef0d97153a | ||
|
|
2e6693fbb6 | ||
|
|
7d98181ade | ||
|
|
7a2027d1fd | ||
|
|
9654749244 | ||
|
|
da46e01b97 | ||
|
|
d96f8ff0fe | ||
|
|
5c50fac907 | ||
|
|
51cda87fe4 | ||
|
|
da0c74cdf0 | ||
|
|
08651736ad | ||
|
|
bf0d8ab4a3 | ||
|
|
a805905a49 | ||
|
|
f61a714320 | ||
|
|
77818e3457 | ||
|
|
2ea7d10d04 | ||
|
|
ef26f711c9 | ||
|
|
c36c30c17b | ||
|
|
a9b8e2159c | ||
|
|
4173d2ccf6 | ||
|
|
427321c5ab | ||
|
|
f5913135c6 | ||
|
|
76d4a50af3 | ||
|
|
603de16f9a | ||
|
|
f6b340cc19 | ||
|
|
76c6e09e39 | ||
|
|
9bad2a8180 | ||
|
|
6db3c4ef5e | ||
|
|
2bbe3aa122 | ||
|
|
9fc5f4c48b | ||
|
|
50e6f368ff | ||
|
|
975c4175b2 | ||
|
|
af395a8f55 | ||
|
|
90f69782ee | ||
|
|
5a64c73e05 | ||
|
|
9845f99b60 | ||
|
|
d3bba2489d | ||
|
|
b21644b611 | ||
|
|
b70553cf46 | ||
|
|
1a7fb1572a | ||
|
|
375e8385ee | ||
|
|
27dd07f1b8 | ||
|
|
263b9c6e39 | ||
|
|
d7e9eb65e2 | ||
|
|
0af97636fa | ||
|
|
1ec0b7b59a | ||
|
|
f864b15427 | ||
|
|
61dc0909ae | ||
|
|
ca54ceff6f | ||
|
|
6c1f4faff2 | ||
|
|
7940f779e9 | ||
|
|
a3f6a72a51 | ||
|
|
d2a8b8c2de | ||
|
|
833d73df09 | ||
|
|
23eda1411b | ||
|
|
ff598b0827 | ||
|
|
e5dd133808 | ||
|
|
a3e1e5e8ba | ||
|
|
a921c5b89e | ||
|
|
948855a984 | ||
|
|
547305c7ed | ||
|
|
b65adf8d4a | ||
|
|
3a1496b4eb | ||
|
|
a58b70ca07 | ||
|
|
91e3c654d3 | ||
|
|
7091d4e597 | ||
|
|
80cd2ef3d7 | ||
|
|
2c2314faa0 | ||
|
|
88c2a02773 | ||
|
|
89b87158db | ||
|
|
ce9896204a | ||
|
|
f4f0f35c5b | ||
|
|
b08b72358a | ||
|
|
aac75ddcbf | ||
|
|
5cd5631fb2 | ||
|
|
b8a7b09092 | ||
|
|
81f4a4f471 | ||
|
|
2623364dbd | ||
|
|
3b03597784 | ||
|
|
ce9c5fd722 | ||
|
|
f2999e84b9 | ||
|
|
2fed1badbf | ||
|
|
7c1dacea09 | ||
|
|
08310b4af9 | ||
|
|
16fd9084ea | ||
|
|
0ba28a46fd | ||
|
|
8370a7fcc4 | ||
|
|
629e61c7a5 | ||
|
|
2e323a5671 | ||
|
|
8c9e2e1ff1 | ||
|
|
5c8a20be77 | ||
|
|
d2eb4fee76 | ||
|
|
4537860079 | ||
|
|
7f47655f60 | ||
|
|
2c7b2ad6ca | ||
|
|
ddb8c89776 | ||
|
|
cacdb424a9 | ||
|
|
b156a9654f | ||
|
|
3229862dd4 | ||
|
|
06563d7034 | ||
|
|
459afcc47f | ||
|
|
06f5910365 | ||
|
|
b159634ef9 | ||
|
|
db2367bf33 | ||
|
|
f8def68e7e | ||
|
|
9f7382bca4 | ||
|
|
d3a644d81c | ||
|
|
70dae78c1b | ||
|
|
5e577acf51 | ||
|
|
21f64b6660 | ||
|
|
7a7e3ee6d9 | ||
|
|
9c9f56743e | ||
|
|
64e7d5345d | ||
|
|
29d017f54b | ||
|
|
26579fa962 | ||
|
|
0c61a1530f | ||
|
|
da7ea2b33d | ||
|
|
382af06406 | ||
|
|
515a363ecd | ||
|
|
fe54dcb4eb | ||
|
|
42f46aeac5 | ||
|
|
4cc0e6de90 | ||
|
|
d9f7f039e1 | ||
|
|
b99ac063ea | ||
|
|
b33d82734f | ||
|
|
f49af187bc | ||
|
|
e632bf176b | ||
|
|
41358c6fb5 | ||
|
|
bbedb065e1 | ||
|
|
bc34713b29 | ||
|
|
0c974b7236 | ||
|
|
8407a9af0a | ||
|
|
c4f288582b | ||
|
|
981c71e60a | ||
|
|
86e487e003 | ||
|
|
34d845da13 | ||
|
|
07d7962c7f | ||
|
|
18f9fb5e0f | ||
|
|
6f91997f06 | ||
|
|
283a8e77aa | ||
|
|
50755d26d4 | ||
|
|
05047f60f4 | ||
|
|
738ec900f4 | ||
|
|
86ca283352 | ||
|
|
6c28388420 | ||
|
|
e96fcb31f0 | ||
|
|
64fc19cc81 | ||
|
|
1012e2735a | ||
|
|
990ad854bd | ||
|
|
d83296c7a9 | ||
|
|
62c75883d1 | ||
|
|
7ed66abe57 | ||
|
|
4294456cdc | ||
|
|
a82559f185 | ||
|
|
01f85a09a9 | ||
|
|
69fae18e63 | ||
|
|
c241da5ea5 | ||
|
|
0283c498d6 | ||
|
|
fc59cef1ee | ||
|
|
2f875aec79 | ||
|
|
cfa4086b0b | ||
|
|
cbe9bf0e69 | ||
|
|
83ad6b9af8 | ||
|
|
cabdf38ce4 | ||
|
|
2295bbdd80 | ||
|
|
74ca81cc79 | ||
|
|
5ac625d7bd | ||
|
|
1d902a4621 | ||
|
|
302ec1372c | ||
|
|
d768226de9 | ||
|
|
c55c28ec7f | ||
|
|
c4dec4f796 | ||
|
|
0f1911a8d4 | ||
|
|
e43f7fc98d | ||
|
|
fbabb105c3 | ||
|
|
f0e4f6622e | ||
|
|
9a88c19f1a | ||
|
|
7762ac0173 | ||
|
|
e8c6d0f51e | ||
|
|
807b52b019 | ||
|
|
0e31eaa157 | ||
|
|
24ed9b061f | ||
|
|
528cfc2889 | ||
|
|
91fbee24da | ||
|
|
6beb79f27b | ||
|
|
64ce06a353 | ||
|
|
e1edfde539 | ||
|
|
10fd75c833 | ||
|
|
7932e42507 | ||
|
|
003993337a | ||
|
|
bca3068db2 | ||
|
|
cf37922d42 | ||
|
|
d123835ef5 | ||
|
|
7f753cab9a | ||
|
|
4afeedbd56 | ||
|
|
10db5a4fdb | ||
|
|
1a4e6e6a4b | ||
|
|
e4e6ddb075 | ||
|
|
4ef684f615 | ||
|
|
2629cfeeab | ||
|
|
d83e5b8409 | ||
|
|
df98db5092 | ||
|
|
d87010f300 | ||
|
|
c5a7202cd9 | ||
|
|
70e4162dcc | ||
|
|
147e962370 | ||
|
|
d7db7040d4 | ||
|
|
67be8d89b5 | ||
|
|
18956144d5 | ||
|
|
871ab24c6e | ||
|
|
ce0f248d20 | ||
|
|
dd0bf87c01 | ||
|
|
6ba8310c13 | ||
|
|
ca3791fed8 | ||
|
|
9cf72a30fc | ||
|
|
e76bd43f53 | ||
|
|
baf81cdc5d | ||
|
|
9f72d508ae | ||
|
|
1844e8adad | ||
|
|
b540d28849 | ||
|
|
fd73a7f795 | ||
|
|
51a930f802 | ||
|
|
a7cfbdb854 | ||
|
|
1e3571eb5b | ||
|
|
5484411232 | ||
|
|
f1ad270ff8 | ||
|
|
b3a86952cf | ||
|
|
409ff027f8 | ||
|
|
438d063ec6 | ||
|
|
078ba6daa8 | ||
|
|
74b49de883 | ||
|
|
8afc2f45c7 | ||
|
|
5f4659afef | ||
|
|
0887e2ee6e | ||
|
|
62e3953f5b | ||
|
|
9c9b74179c | ||
|
|
a2bb95fc60 | ||
|
|
12227d7b6a | ||
|
|
a4c120d608 | ||
|
|
53285a75ad | ||
|
|
f877d68f4f | ||
|
|
5bfd5a9240 | ||
|
|
eb1f832fce | ||
|
|
799add8659 | ||
|
|
90cb5fb672 | ||
|
|
d1ec314a03 | ||
|
|
7bcc01efb7 | ||
|
|
206ac000b9 | ||
|
|
1eb6cfd45c | ||
|
|
088b4a68e6 | ||
|
|
086f724951 | ||
|
|
ad244190e0 | ||
|
|
9f8c5cb63c | ||
|
|
5627b70981 | ||
|
|
79b8576df9 | ||
|
|
ba714b3b71 | ||
|
|
d7935356da | ||
|
|
9ef7225532 | ||
|
|
642030f959 | ||
|
|
78826c6d18 | ||
|
|
b5b9af508a | ||
|
|
d68f8ea668 | ||
|
|
5b84b0fb44 | ||
|
|
621eac32d3 | ||
|
|
824813fc6a | ||
|
|
7c207243e4 | ||
|
|
b748b0734f | ||
|
|
896a78aaa0 | ||
|
|
cc01550aff | ||
|
|
413a36a914 | ||
|
|
86ef85efae | ||
|
|
a483376591 | ||
|
|
f2725a374a | ||
|
|
7fde80f38e | ||
|
|
cc4ccfdbfd | ||
|
|
2f87e4c2f3 | ||
|
|
e7c2ea9724 | ||
|
|
826dc61e5c | ||
|
|
a31dceb2c6 | ||
|
|
1ba7a09bf6 | ||
|
|
afe8d8dfec | ||
|
|
7e5ba5e824 | ||
|
|
83cd5e2ebd | ||
|
|
7f0738bcb3 | ||
|
|
583b8842e7 | ||
|
|
a8541d5f64 | ||
|
|
4ad03af544 | ||
|
|
0859944c9a | ||
|
|
c0be1e2fd8 | ||
|
|
7b73a332ea | ||
|
|
a5d63a0324 | ||
|
|
8435d6fc12 | ||
|
|
d1d4683c91 | ||
|
|
bf04c83e3d | ||
|
|
0432804b18 | ||
|
|
da093a8aec | ||
|
|
f27873a6f0 | ||
|
|
c3b9326ba1 | ||
|
|
fd3e6a3bfd | ||
|
|
0155b85950 | ||
|
|
a663823af2 | ||
|
|
5a3c144919 | ||
|
|
4fe5827598 | ||
|
|
2e28e88dfd | ||
|
|
72b118cd8f | ||
|
|
80b2ac1cc5 | ||
|
|
79791c9ed4 | ||
|
|
ac3edec14b | ||
|
|
cde7f79af0 | ||
|
|
609c7ab6b5 | ||
|
|
c949173bc9 | ||
|
|
250d5cf78c | ||
|
|
45b1e6dc5e | ||
|
|
d6b069458d | ||
|
|
3a631e40db | ||
|
|
dc469dc4c1 | ||
|
|
11b7ce14f8 | ||
|
|
ddfeebad3d | ||
|
|
11e87986a2 | ||
|
|
dbf0b92de7 | ||
|
|
02312cac59 | ||
|
|
6501bceb42 | ||
|
|
3580f845e6 | ||
|
|
b7e69be51e | ||
|
|
fdb772832f | ||
|
|
5c3684d0cc | ||
|
|
5a3e3deb33 | ||
|
|
2946221195 | ||
|
|
ce6c13f86b | ||
|
|
fbb938fcf2 | ||
|
|
093755d53f | ||
|
|
dbb6d9d174 | ||
|
|
f23455e592 | ||
|
|
5ce76cd0b0 | ||
|
|
49f9ca06c7 | ||
|
|
1a1656ddbf | ||
|
|
550700bed0 | ||
|
|
72d2f33b34 | ||
|
|
38bdbdb0f5 | ||
|
|
622132290f | ||
|
|
77223e1cad | ||
|
|
4a1fb3e903 | ||
|
|
28ca434fb5 | ||
|
|
1e526411b6 | ||
|
|
849d657595 | ||
|
|
bf27066fd7 | ||
|
|
1f80154823 | ||
|
|
f40272d509 | ||
|
|
e195a51cd4 | ||
|
|
247ff4e60d | ||
|
|
eb570c88e6 | ||
|
|
1a91c6ee60 | ||
|
|
67c73ec100 | ||
|
|
f7579fc923 | ||
|
|
fbcbe947da | ||
|
|
97b0368765 | ||
|
|
c0f4e9f52e | ||
|
|
4a92deec54 | ||
|
|
5bf1c32bc0 | ||
|
|
49fb4cd94d | ||
|
|
99079f7094 | ||
|
|
1911e4262b | ||
|
|
d366fc48b8 | ||
|
|
7b5b4a1049 | ||
|
|
458ea56b86 | ||
|
|
d03dcc3d99 | ||
|
|
2df0d034bc | ||
|
|
510db64860 | ||
|
|
b15803510c | ||
|
|
f914a5a06d | ||
|
|
6225591dbd | ||
|
|
e446db02f6 | ||
|
|
a4330fe378 | ||
|
|
716d713b04 | ||
|
|
1c50a11688 | ||
|
|
385fe4e301 | ||
|
|
412d46ff65 | ||
|
|
ae82c3a639 | ||
|
|
b4f75525d9 | ||
|
|
8b3d8dc792 | ||
|
|
5cb5b628b8 | ||
|
|
b0d86a7159 | ||
|
|
a6cfe70428 | ||
|
|
b6a7be7663 | ||
|
|
25f14294a8 | ||
|
|
7c36a3e167 | ||
|
|
785fc8d669 | ||
|
|
c62ab1bee7 | ||
|
|
f80f4f3194 | ||
|
|
6e58428336 | ||
|
|
b05ff89c76 | ||
|
|
28dfe21584 | ||
|
|
c86f06caa0 | ||
|
|
afc887d941 | ||
|
|
edad24c257 | ||
|
|
12604b7676 | ||
|
|
63841c8aac | ||
|
|
8944db49be | ||
|
|
4c4fcc128b | ||
|
|
d6c4ae71d0 | ||
|
|
a6d94eafba | ||
|
|
29fc410a8f | ||
|
|
83f1616a65 | ||
|
|
7ec23254fd | ||
|
|
c2b5dd1be6 | ||
|
|
727160f0a4 | ||
|
|
3f2a18a435 | ||
|
|
e329bc2c7b | ||
|
|
8dd0c4fe74 | ||
|
|
cf7c5e4dff | ||
|
|
287e6c4ede | ||
|
|
011600ac6e | ||
|
|
70eb74c356 | ||
|
|
260ef788f5 | ||
|
|
6131e0bef7 | ||
|
|
41c7d896e3 | ||
|
|
33d06fb0e5 | ||
|
|
4bc3f9adbe | ||
|
|
a22e1174ee | ||
|
|
985764c8db | ||
|
|
5f000306f5 | ||
|
|
efee6a1cda | ||
|
|
a68feb5aa0 | ||
|
|
293df75b97 | ||
|
|
f00e11d457 | ||
|
|
0fd09579a1 | ||
|
|
3ae33b951f | ||
|
|
92fecb8ad4 | ||
|
|
ac2cd0f0dc | ||
|
|
c2f29be9ba | ||
|
|
16a034a34a | ||
|
|
ea77622e04 | ||
|
|
a38b0e736d | ||
|
|
7b43f9f056 | ||
|
|
fa4aef4531 | ||
|
|
56a307d734 | ||
|
|
6a4bda60f2 | ||
|
|
16d05a5c8b | ||
|
|
7faead75bd | ||
|
|
a1b1480c21 | ||
|
|
f3909cf2bf | ||
|
|
4ae784dc53 | ||
|
|
dd2372d2e6 | ||
|
|
c03db1a1cd | ||
|
|
3ade6c4a96 | ||
|
|
046ad79d11 | ||
|
|
e4e653ada6 | ||
|
|
b32af6ebfb | ||
|
|
86852cdc78 | ||
|
|
31963f823b | ||
|
|
3ce19e67fe | ||
|
|
10b9e9bbe5 | ||
|
|
07e4ba9d80 | ||
|
|
5e2d4d644a | ||
|
|
50876f1b15 | ||
|
|
c2a85c9d36 | ||
|
|
41d1fdedf2 | ||
|
|
cd1b982b2a | ||
|
|
a35ea4d242 | ||
|
|
d8645cd148 | ||
|
|
c9f7afbf78 | ||
|
|
dfb78e0593 | ||
|
|
24ace03780 | ||
|
|
569eaff04c | ||
|
|
801a17194c | ||
|
|
1a5d5bf620 | ||
|
|
366ebc123b | ||
|
|
bc4a51dbbb | ||
|
|
80650b6722 | ||
|
|
a740e3e517 | ||
|
|
19809532df | ||
|
|
110f3fd658 | ||
|
|
a80ba54bbc | ||
|
|
00d199b477 | ||
|
|
eea99abc49 | ||
|
|
903d298381 | ||
|
|
49f0f53f51 | ||
|
|
2dc02bbb39 | ||
|
|
e7185b338f | ||
|
|
6519c0308c | ||
|
|
d154a8da20 | ||
|
|
7d9977d028 | ||
|
|
882be7765b | ||
|
|
99314fbe71 | ||
|
|
bab949599f | ||
|
|
f81b3eef4f | ||
|
|
c50df4c0c3 | ||
|
|
ee85dd6b61 | ||
|
|
bae19cb10e | ||
|
|
2f7fb2f553 | ||
|
|
23001f6144 | ||
|
|
55d585ce17 | ||
|
|
d3b0c90356 | ||
|
|
a43b18ae26 | ||
|
|
0a099ca2ab | ||
|
|
e6211eef00 | ||
|
|
b1426cad28 | ||
|
|
0fc145c52c | ||
|
|
c2b25f4701 | ||
|
|
88a96110b7 | ||
|
|
2b4d96e0ef | ||
|
|
16bc5997bb | ||
|
|
7680cd549c | ||
|
|
1df8b1957e | ||
|
|
430778293e | ||
|
|
de3b00b5ee | ||
|
|
24ef5d888c | ||
|
|
5688e24b8a | ||
|
|
3d9bf17f11 | ||
|
|
614ea53ad7 | ||
|
|
b88de63abb | ||
|
|
60527ab180 | ||
|
|
d6241a3086 | ||
|
|
df54ab40ce | ||
|
|
6fec5bfbeb | ||
|
|
e994b0c8b8 | ||
|
|
3343aac6bf | ||
|
|
41f7736c85 | ||
|
|
c418007c68 | ||
|
|
cc2c270dde | ||
|
|
70e3cb8151 | ||
|
|
a80f8f257f | ||
|
|
b3a70b565e | ||
|
|
e73c6fd3b0 | ||
|
|
a5a0434fff | ||
|
|
463690a27a | ||
|
|
471ac474a1 | ||
|
|
a3fda12ba1 | ||
|
|
0268bb9888 | ||
|
|
3a3a3f7bdb | ||
|
|
cf51a31807 | ||
|
|
5be42965ff | ||
|
|
a8b3be2c9c | ||
|
|
5ce91bb0fd | ||
|
|
adf5d8a114 | ||
|
|
cb229f6436 | ||
|
|
e80e93fcda | ||
|
|
37ced6aca4 | ||
|
|
5ffe5dd594 | ||
|
|
dc78c58c77 | ||
|
|
22721a37d5 | ||
|
|
dd4270eadf | ||
|
|
e2923a9385 | ||
|
|
316674fecf | ||
|
|
34da16b7e6 | ||
|
|
71a95a581f | ||
|
|
788a8f7c13 | ||
|
|
d23bbd1687 | ||
|
|
7a514f41a3 | ||
|
|
928de33447 | ||
|
|
0624455591 | ||
|
|
2ba5238b8e | ||
|
|
00c2ca4697 | ||
|
|
d544c30551 | ||
|
|
ef80a69399 | ||
|
|
6e6971606d | ||
|
|
e5ad53ac42 | ||
|
|
e98ee49aee | ||
|
|
d797d9905d | ||
|
|
e5870d47c7 | ||
|
|
91a565c7b0 | ||
|
|
5b924aaf60 | ||
|
|
606cb2832a | ||
|
|
4b52c1e68f | ||
|
|
e77ebec629 | ||
|
|
162f235972 | ||
|
|
e8adae65fe | ||
|
|
96718d8b09 | ||
|
|
5d44ea802a | ||
|
|
d9d57ce39a | ||
|
|
3e261b1fa7 | ||
|
|
cee7f11d8b | ||
|
|
1c67849bf1 | ||
|
|
595f2052c4 | ||
|
|
f5669a7d6b | ||
|
|
25d3d73dbf | ||
|
|
569ae86c90 | ||
|
|
8531d1d7a6 | ||
|
|
e4b6af41e5 | ||
|
|
d63e8c8f45 | ||
|
|
7e5a3eb045 | ||
|
|
f960f72785 | ||
|
|
0807b8b95f | ||
|
|
5dc1a5fec6 | ||
|
|
e749af7b60 | ||
|
|
17deeb07ad | ||
|
|
bcd8fe9573 | ||
|
|
146d231ec5 | ||
|
|
71ef1bde7e | ||
|
|
253286669a | ||
|
|
0ad2d9f0b5 | ||
|
|
c9167d9646 | ||
|
|
ca1c1438e3 | ||
|
|
878fe20409 | ||
|
|
5a5c41301d | ||
|
|
92d2331170 | ||
|
|
a85a6fa6c8 | ||
|
|
b11e2eaa3b | ||
|
|
0aeb61a95a | ||
|
|
4f647a8e8b | ||
|
|
7739b776cd | ||
|
|
0c8d1ba4a8 | ||
|
|
7ce92f93ad | ||
|
|
b03c8970e6 | ||
|
|
de5f1b2a83 | ||
|
|
dc7d783d14 | ||
|
|
8e5ee31f30 | ||
|
|
90c5715bc6 | ||
|
|
d5093f7af0 | ||
|
|
4abc608bc0 | ||
|
|
7bae0823c8 | ||
|
|
5184b542b1 | ||
|
|
fea2031bfe | ||
|
|
be22172a35 | ||
|
|
b69f40815f | ||
|
|
f678789dfd | ||
|
|
c386c52cf9 | ||
|
|
c444099325 | ||
|
|
31cd104286 | ||
|
|
1ead6c46f4 | ||
|
|
fb45f8f2f9 | ||
|
|
c1217066d1 | ||
|
|
3b41169395 | ||
|
|
8bfb2ad2b7 | ||
|
|
b602ac0970 | ||
|
|
a34b747661 | ||
|
|
fe007fd36a | ||
|
|
141365cbc1 | ||
|
|
51ce3ddd67 | ||
|
|
64f35c0e31 | ||
|
|
9c0e2bba54 | ||
|
|
62e0c9226e | ||
|
|
c5aa20f226 | ||
|
|
66b8629964 | ||
|
|
9e028d56c0 | ||
|
|
489ef7c51c | ||
|
|
34685a836a | ||
|
|
dea71875e4 | ||
|
|
76fc12869d | ||
|
|
556c7dd51f | ||
|
|
52878161e4 | ||
|
|
6c250df77e | ||
|
|
7c5c7ced91 | ||
|
|
3cef005fec | ||
|
|
71496a0a3c | ||
|
|
86acdcf8b6 | ||
|
|
ea717731a4 | ||
|
|
72f528cb52 | ||
|
|
0905515c40 | ||
|
|
50a4a74b4e | ||
|
|
7cbbf9a850 | ||
|
|
0e252d2c77 | ||
|
|
5c93f6947a | ||
|
|
07b98952bc | ||
|
|
cd2399715d | ||
|
|
2187c6cf43 | ||
|
|
984c2fdc68 | ||
|
|
a224d366ca | ||
|
|
5e48e6b075 | ||
|
|
72fc309fb1 | ||
|
|
7187ea443e | ||
|
|
91fd854e3b | ||
|
|
4b20d4f1ad | ||
|
|
7beb9fd606 | ||
|
|
4d3f2ca96b | ||
|
|
99b7d53817 | ||
|
|
7e523e4d5e | ||
|
|
89e7d812c8 | ||
|
|
ac251d7a66 | ||
|
|
49f423aa8f | ||
|
|
18229043fa | ||
|
|
03d7651916 | ||
|
|
c5d741fb39 | ||
|
|
3bceabe29b | ||
|
|
5da96132b9 | ||
|
|
15d108fbc1 | ||
|
|
8b81f41e52 | ||
|
|
74a10f26a4 | ||
|
|
492f36f7df | ||
|
|
2e21ad875b | ||
|
|
18ed73f091 | ||
|
|
55b412e0f4 | ||
|
|
3bfaeacf7d | ||
|
|
e302724847 | ||
|
|
edd0a141de | ||
|
|
cf566b59ce | ||
|
|
1089e858b4 | ||
|
|
60e37d727d | ||
|
|
14a2de0d0e | ||
|
|
2bf7f9e413 | ||
|
|
513bbb8047 | ||
|
|
f1c9077139 | ||
|
|
66e3679ba3 | ||
|
|
708bb014e9 | ||
|
|
ca3c8cdfae | ||
|
|
a66ef50469 | ||
|
|
431c74f111 | ||
|
|
f023126a73 | ||
|
|
474ada9267 | ||
|
|
784cdd7638 | ||
|
|
fc49a055c6 | ||
|
|
be8cf8ea1e | ||
|
|
0eee57aab9 | ||
|
|
ecd0156265 | ||
|
|
cd6640e890 | ||
|
|
40622a9e60 | ||
|
|
df2956b411 | ||
|
|
e5a4c0c986 | ||
|
|
2363cc2572 | ||
|
|
1b56cc4e99 | ||
|
|
6e16627cbc | ||
|
|
67e13fbb64 | ||
|
|
ad28321a8d | ||
|
|
0e5df91e3a | ||
|
|
38c25bb50d | ||
|
|
6548439f6c | ||
|
|
c92e0c05e4 | ||
|
|
b944386ca5 | ||
|
|
be2e4d9dd1 | ||
|
|
dbfa6eea7b | ||
|
|
f3d1ab55a2 | ||
|
|
ff95721ad9 | ||
|
|
d710e7347a | ||
|
|
3fbef25ffc | ||
|
|
ab6a092dbc | ||
|
|
1992f27a26 | ||
|
|
f37866eb7e | ||
|
|
87a4cc7654 | ||
|
|
fdc847706a | ||
|
|
61c817319f | ||
|
|
127e80692f | ||
|
|
98c95aa34d | ||
|
|
6b7e409f05 | ||
|
|
79ad93d536 | ||
|
|
7d914cd427 | ||
|
|
287f31329e | ||
|
|
97e0f02621 | ||
|
|
bda8208aaa | ||
|
|
42f4664022 | ||
|
|
d1a7f1dd36 | ||
|
|
1dde751da4 | ||
|
|
7b05133af0 | ||
|
|
68f56130ba | ||
|
|
4ea4efb871 | ||
|
|
48c86ad863 | ||
|
|
859d6b9b8a | ||
|
|
cb6c47098d | ||
|
|
5eb98c0072 | ||
|
|
863812a097 | ||
|
|
4a5c3c4861 | ||
|
|
15544c7544 | ||
|
|
53945cff31 | ||
|
|
760b37f71d | ||
|
|
a431c1b01c | ||
|
|
bd2245d642 | ||
|
|
be6325dd4b | ||
|
|
fcf1bafb09 | ||
|
|
6688421240 | ||
|
|
3e6601fa29 | ||
|
|
a0bc0e4998 | ||
|
|
d81f45e54a | ||
|
|
fd3a1cd086 | ||
|
|
494103b521 | ||
|
|
8e6950e200 | ||
|
|
9e40e47a2e | ||
|
|
a46abd8b1a | ||
|
|
129e99a6f6 | ||
|
|
32d56fec97 | ||
|
|
1a41f729a3 | ||
|
|
445f8c71c5 | ||
|
|
85c07c2fe0 | ||
|
|
eaf0fb14c9 | ||
|
|
11234529db | ||
|
|
f90ff8303b | ||
|
|
d4e2a0fd16 | ||
|
|
32381fe6c4 | ||
|
|
5d35c0432b | ||
|
|
4c4d3b3aa5 | ||
|
|
b2314aa33a | ||
|
|
ef12120270 | ||
|
|
3d83a0bc5f | ||
|
|
38011c50ab | ||
|
|
c3adc9ec56 | ||
|
|
ff9bcb19fa | ||
|
|
ce632b7a05 | ||
|
|
328e034472 | ||
|
|
1c1e688564 | ||
|
|
86f4772bd6 | ||
|
|
61c9e50bcd | ||
|
|
af37a3895f | ||
|
|
666c805101 | ||
|
|
94b7b6b584 | ||
|
|
06b17db227 | ||
|
|
fc89e70a1f | ||
|
|
8ae1fd0173 | ||
|
|
9813ba2f56 | ||
|
|
12e293e309 | ||
|
|
da23ec847e | ||
|
|
84954f376f | ||
|
|
5de659cc7a | ||
|
|
e273717a27 | ||
|
|
a2ae37396f | ||
|
|
eb9fa8460f | ||
|
|
e3d1743722 | ||
|
|
63babcba36 | ||
|
|
1cc7587789 | ||
|
|
70b5c1b119 | ||
|
|
7574b3db64 | ||
|
|
cb6e36d804 | ||
|
|
2a5ae435e1 | ||
|
|
c074f260a1 | ||
|
|
cb98242ea7 | ||
|
|
147be3e10b | ||
|
|
b963a6624e | ||
|
|
ef90a7ad13 | ||
|
|
eb7927d278 | ||
|
|
8f57db28f7 | ||
|
|
7d754b7c22 | ||
|
|
fcbfd19393 | ||
|
|
e811394603 | ||
|
|
434719611d | ||
|
|
5814d9b2a0 | ||
|
|
18330dec4e | ||
|
|
60b880d931 | ||
|
|
cee7bc6e74 | ||
|
|
d345804cd5 | ||
|
|
fb2679d5ef | ||
|
|
6f3548b184 | ||
|
|
d5913a23ac | ||
|
|
3436486575 | ||
|
|
5112056fdb | ||
|
|
d8ee624e35 | ||
|
|
428063ff23 | ||
|
|
32c11bb212 | ||
|
|
31ab2349f9 | ||
|
|
c31c627cf8 | ||
|
|
f14e808847 | ||
|
|
5c83976977 | ||
|
|
2ec7e241cd | ||
|
|
6a56d1e4d0 | ||
|
|
589046ecf7 | ||
|
|
040e99fd17 | ||
|
|
b5b436e01d | ||
|
|
668d90c700 | ||
|
|
b3012d97ab | ||
|
|
0b5a751e52 | ||
|
|
7729fa9ac9 | ||
|
|
9c77415cda | ||
|
|
cbd31ba481 | ||
|
|
8440aa3e9b | ||
|
|
11afb66010 | ||
|
|
c4e422644b | ||
|
|
df30f0519a | ||
|
|
8ba4f34a7c | ||
|
|
7afb7c85a7 | ||
|
|
b24f066c47 | ||
|
|
4ec034ad49 | ||
|
|
20a1a47e66 | ||
|
|
989ee6473f | ||
|
|
a572321f61 | ||
|
|
ff11883482 | ||
|
|
c0c7c12bb9 | ||
|
|
e5dcbf73d8 | ||
|
|
50e106f2e6 | ||
|
|
3173fbdc4a | ||
|
|
b1104b1ca7 | ||
|
|
809b7181a8 | ||
|
|
af4b9700b7 | ||
|
|
2858e08ce0 | ||
|
|
2b248b25c8 | ||
|
|
0d2e1e1270 | ||
|
|
464dd79246 | ||
|
|
85a71d15b6 | ||
|
|
f3551021e0 | ||
|
|
a54247125f | ||
|
|
98ce867104 | ||
|
|
461fab0f27 | ||
|
|
e9a6c3b498 | ||
|
|
c02ac5e08a | ||
|
|
c56b2b99f5 | ||
|
|
0d14fd9136 | ||
|
|
96198dae55 | ||
|
|
0e3547e0f6 | ||
|
|
3d1b255199 | ||
|
|
0b26b1eed6 | ||
|
|
a33ecec61e | ||
|
|
9ba93f4b0a | ||
|
|
85d1b06a79 | ||
|
|
cb4f748226 | ||
|
|
7525818097 | ||
|
|
ddcae74e09 | ||
|
|
228e630f40 | ||
|
|
7f595ed0ca | ||
|
|
a91d0a374a | ||
|
|
0baef17a02 | ||
|
|
5d095bb9e1 | ||
|
|
759490689c | ||
|
|
3e2200ed90 | ||
|
|
a55db95a3b | ||
|
|
b4ebc18367 | ||
|
|
a6699ef30c | ||
|
|
b5f5c26be3 | ||
|
|
d64fc7d336 | ||
|
|
659a5195d4 | ||
|
|
545e63d1dd | ||
|
|
fa79703b04 | ||
|
|
d39ed9254a | ||
|
|
17b4a2786d | ||
|
|
cd08fa22fd | ||
|
|
d87d2dac0b | ||
|
|
f7ce3c27ea | ||
|
|
5fe437da7e | ||
|
|
e6cbb6072b | ||
|
|
fbc7a9391a | ||
|
|
2b888d5106 | ||
|
|
4b8d417fca | ||
|
|
21cc6d7ae5 | ||
|
|
6749c8abd7 | ||
|
|
8c094b0eec | ||
|
|
eb9d063229 | ||
|
|
a1143521d3 | ||
|
|
8a23b66c39 | ||
|
|
de5e784e07 | ||
|
|
96cb47fc64 | ||
|
|
e9bd2ee996 | ||
|
|
41cdfb7420 | ||
|
|
fc37ce4a72 | ||
|
|
edcf4cd61d | ||
|
|
261fbb5b62 | ||
|
|
4fd90144d1 | ||
|
|
3e2785b970 | ||
|
|
ab7f2e847e | ||
|
|
781f0adad4 | ||
|
|
668cc93962 | ||
|
|
2f6b37e103 | ||
|
|
e2ee8b9f20 | ||
|
|
6424a1e398 | ||
|
|
a163ca9237 | ||
|
|
27b8561d25 | ||
|
|
974739457f | ||
|
|
563835404f | ||
|
|
2daabfa0e9 | ||
|
|
0f3214714f | ||
|
|
e7940569dd | ||
|
|
f59c9a805e | ||
|
|
85f50a4a13 | ||
|
|
a3b37b0191 | ||
|
|
11ba6afdd3 | ||
|
|
99ca1ad353 | ||
|
|
2076905d6e | ||
|
|
deb8d3d82e | ||
|
|
f72c237d85 | ||
|
|
98a4fa2b0d | ||
|
|
7c33c7fc64 | ||
|
|
20899b597e | ||
|
|
198b7cae12 | ||
|
|
121ea1fac2 | ||
|
|
3bd9ee0d32 | ||
|
|
95a042691a | ||
|
|
702c0a0fbf | ||
|
|
e405490593 | ||
|
|
ac07e447b8 | ||
|
|
9702b8ce75 | ||
|
|
efc686423a | ||
|
|
b89a07596e | ||
|
|
5a138bed6b | ||
|
|
a2ecca936e | ||
|
|
374571da96 | ||
|
|
f8188ed7f8 | ||
|
|
516949380d | ||
|
|
5d66122689 | ||
|
|
de9396d2a1 | ||
|
|
f8a6799d4e | ||
|
|
111d209bff | ||
|
|
b45a213413 | ||
|
|
1a9ee959dd | ||
|
|
46891b12cf | ||
|
|
0c1bec023f | ||
|
|
80f58bc93f | ||
|
|
06e6c6021e | ||
|
|
e8b99ae13a | ||
|
|
bb99f151da | ||
|
|
f97289a3c0 | ||
|
|
6381b6474f | ||
|
|
c3f1dc3f52 | ||
|
|
62f4503f07 | ||
|
|
bf78dcecf0 | ||
|
|
d5352a5d12 | ||
|
|
fd43d2bea7 | ||
|
|
b9812f8bc0 | ||
|
|
fba03540d5 | ||
|
|
11a1a6c271 | ||
|
|
ff12a41c40 | ||
|
|
629cca4816 | ||
|
|
9fc143cf3d | ||
|
|
726732244a | ||
|
|
be6e1a33b1 | ||
|
|
6e3bd440ba | ||
|
|
cba10ba5b7 | ||
|
|
050693be2e | ||
|
|
0803febac5 | ||
|
|
6259202c01 | ||
|
|
e1d7a13333 | ||
|
|
bf5844d607 | ||
|
|
5b7fec481b | ||
|
|
73b3bbe49b | ||
|
|
d8dcf670da | ||
|
|
87b9313034 | ||
|
|
993c382e74 | ||
|
|
3c9a7811b8 | ||
|
|
6c8d993477 | ||
|
|
dfa9277867 | ||
|
|
50e37419e9 | ||
|
|
22978aa31e | ||
|
|
7ed401e5e0 | ||
|
|
da76a1ed9e | ||
|
|
9c67e08dbd | ||
|
|
6cf716f182 | ||
|
|
9fb24ac1e9 | ||
|
|
66fb083003 | ||
|
|
20b91f58f8 | ||
|
|
ac0e675f3b | ||
|
|
f71f04db9e | ||
|
|
9e4e98acfb | ||
|
|
826e35f7a4 | ||
|
|
ffc580dda9 | ||
|
|
4557d13a32 | ||
|
|
215c7bd3cb | ||
|
|
ea2ef63de5 | ||
|
|
d9998f2ca5 | ||
|
|
686d6fc6d1 | ||
|
|
9e8df888eb | ||
|
|
409ac12f23 | ||
|
|
6aa26582f6 | ||
|
|
056a45d035 | ||
|
|
fbc839e8d9 | ||
|
|
cb85eea261 | ||
|
|
439b827a08 | ||
|
|
d39d6cc1e3 | ||
|
|
d6b3bfc48e | ||
|
|
70d4fadc39 | ||
|
|
a2a12018d9 | ||
|
|
10d34ef818 | ||
|
|
bf52545a91 | ||
|
|
c012e3d66b | ||
|
|
39a4f82460 | ||
|
|
7b020ffa84 | ||
|
|
b8ccf3dc3a | ||
|
|
869f0a0238 | ||
|
|
ff4ea1a13a | ||
|
|
51aebb2845 | ||
|
|
212f599412 | ||
|
|
55776df685 | ||
|
|
3dd06b674a | ||
|
|
12df799572 | ||
|
|
c341792092 | ||
|
|
afe12dc90b | ||
|
|
45d2d1e97d | ||
|
|
0a302901d2 | ||
|
|
49063f949d | ||
|
|
7699d657d9 | ||
|
|
b2cb3b8bf2 | ||
|
|
6cbaad896c | ||
|
|
9247f88d0c | ||
|
|
92f2e342a3 | ||
|
|
e2f3f5fe63 | ||
|
|
0db75852f3 | ||
|
|
afe688e6ab | ||
|
|
493fc00953 | ||
|
|
c709dc5e8e | ||
|
|
684c59e5bc | ||
|
|
0948b078e1 | ||
|
|
52c0356900 | ||
|
|
1c9a0be8c4 | ||
|
|
f45ec24977 | ||
|
|
75b7e661e7 | ||
|
|
381d7a4300 | ||
|
|
0e6e8461eb | ||
|
|
141456dd89 | ||
|
|
9616dc7bd8 | ||
|
|
379597e78f | ||
|
|
f6067816fb | ||
|
|
750eb76df3 | ||
|
|
79a9bc9076 | ||
|
|
dcb6a0425c | ||
|
|
e15a9f3d7d | ||
|
|
b0f95c63c9 | ||
|
|
5327565b33 | ||
|
|
95047fb083 | ||
|
|
f00b2fd509 | ||
|
|
eb86e7967f | ||
|
|
88874fcfe2 | ||
|
|
d504c1e5ab | ||
|
|
c78db1212b | ||
|
|
be03a6186c | ||
|
|
41a8975bd1 | ||
|
|
254c3d166f | ||
|
|
137cf9e582 | ||
|
|
11e841580f | ||
|
|
f8b9138383 | ||
|
|
c03e4c36b0 | ||
|
|
5530cf6e79 | ||
|
|
1f72237291 | ||
|
|
e427d9f622 | ||
|
|
f88feec02b | ||
|
|
df132e5ff3 | ||
|
|
0ffaa8d667 | ||
|
|
e887149f25 | ||
|
|
250d61e0b3 | ||
|
|
ba05c43ae3 | ||
|
|
82fe530045 | ||
|
|
f91f3d1c81 | ||
|
|
5d39223239 | ||
|
|
d2a7e22efd | ||
|
|
724e411ffc | ||
|
|
c02bfc3897 | ||
|
|
878a20741b | ||
|
|
d5eafe1926 | ||
|
|
e2da4ff257 | ||
|
|
dbb6732743 | ||
|
|
4034aa2c60 | ||
|
|
fcb5037a1d | ||
|
|
0634abf168 | ||
|
|
478fa7cafe | ||
|
|
549fdf63f6 | ||
|
|
1a14841a75 | ||
|
|
a7ed3a5e47 | ||
|
|
884fc4f89c | ||
|
|
1e5cab1ee7 | ||
|
|
5a00f0c657 | ||
|
|
2cbb10d850 | ||
|
|
23cd1b8c66 | ||
|
|
be6f5ce831 | ||
|
|
78a545112a | ||
|
|
2cdabf581e | ||
|
|
34a7f17956 | ||
|
|
dd11434e90 | ||
|
|
61995e3b4e | ||
|
|
13befbd266 | ||
|
|
a5ffd44caf | ||
|
|
0208dff574 | ||
|
|
3157bebed7 | ||
|
|
c0bb4db15c | ||
|
|
27cada2a02 | ||
|
|
153c99217d | ||
|
|
851df11eb5 | ||
|
|
5f2c741f49 | ||
|
|
9a9ecc25db | ||
|
|
34b145ee65 | ||
|
|
f41fe59cb6 | ||
|
|
7ff1fd9d69 | ||
|
|
d0b3cdc835 | ||
|
|
1cf829c889 | ||
|
|
17992b633d | ||
|
|
c545ab4993 | ||
|
|
1d2e4243dc | ||
|
|
aefc34b405 | ||
|
|
2a20cf5379 | ||
|
|
e3a3837164 | ||
|
|
c86ab4694c | ||
|
|
5d5066570c | ||
|
|
1a55fb4170 | ||
|
|
efbc3f8194 | ||
|
|
f755351511 | ||
|
|
57817f7252 | ||
|
|
b4c45aa2e3 | ||
|
|
5295244026 | ||
|
|
082f439db2 | ||
|
|
12697d2b72 | ||
|
|
976b44443a | ||
|
|
6553fb5a40 | ||
|
|
bee06f3507 | ||
|
|
5a750b485a | ||
|
|
a71f44baa5 | ||
|
|
65db3a7bd3 | ||
|
|
22384869a6 | ||
|
|
ff76fbe763 | ||
|
|
cfbab453e8 | ||
|
|
6a59b57ef8 | ||
|
|
f50c786640 | ||
|
|
70aece8522 | ||
|
|
c9eb0f3aab | ||
|
|
206360177f | ||
|
|
34ad837fd9 | ||
|
|
e796157672 | ||
|
|
b51222c004 | ||
|
|
9aad352789 | ||
|
|
ce8c20c1ed | ||
|
|
349afa0e7a | ||
|
|
748a6965ca | ||
|
|
97af7c416e | ||
|
|
47512dd6db | ||
|
|
653b9ed0e4 | ||
|
|
d0e47d9fe0 | ||
|
|
f978368a4e | ||
|
|
c47581fc5a | ||
|
|
31aa357c17 | ||
|
|
6ddfae0a07 | ||
|
|
0d7176792b | ||
|
|
c1542da18a | ||
|
|
5b548f5bc3 | ||
|
|
5ac2005318 | ||
|
|
a2b8e3b34e | ||
|
|
d78b53968f | ||
|
|
61b950d942 | ||
|
|
a16073a87b | ||
|
|
603a90886f | ||
|
|
95bbac8791 | ||
|
|
a69fd21a1a | ||
|
|
b6e33830af | ||
|
|
2c67c1c4f8 | ||
|
|
989deafd5e |
65
.clang-format
Normal file
65
.clang-format
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
---
|
||||||
|
Language: Cpp
|
||||||
|
BasedOnStyle: LLVM
|
||||||
|
|
||||||
|
AccessModifierOffset: -2
|
||||||
|
AlignAfterOpenBracket: Align
|
||||||
|
AlignConsecutiveMacros: true
|
||||||
|
AlignConsecutiveAssignments: true
|
||||||
|
AlignEscapedNewlines: Right
|
||||||
|
AlignOperands: false
|
||||||
|
AlignTrailingComments: true
|
||||||
|
AllowAllArgumentsOnNextLine: true
|
||||||
|
AllowAllConstructorInitializersOnNextLine: true
|
||||||
|
AllowAllParametersOfDeclarationOnNextLine: true
|
||||||
|
AllowShortBlocksOnASingleLine: true
|
||||||
|
AllowShortCaseLabelsOnASingleLine: true
|
||||||
|
AllowShortFunctionsOnASingleLine: Empty
|
||||||
|
AllowShortIfStatementsOnASingleLine: Never
|
||||||
|
AllowShortLambdasOnASingleLine: All
|
||||||
|
AllowShortLoopsOnASingleLine: false
|
||||||
|
AlwaysBreakAfterDefinitionReturnType: None
|
||||||
|
AlwaysBreakAfterReturnType: None
|
||||||
|
AlwaysBreakBeforeMultilineStrings: false
|
||||||
|
AlwaysBreakTemplateDeclarations: Yes
|
||||||
|
BreakBeforeBraces: Attach
|
||||||
|
BreakBeforeTernaryOperators: false
|
||||||
|
BreakConstructorInitializers: AfterColon
|
||||||
|
ColumnLimit: 180
|
||||||
|
CompactNamespaces: false
|
||||||
|
ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
||||||
|
ExperimentalAutoDetectBinPacking: false
|
||||||
|
FixNamespaceComments: false
|
||||||
|
IncludeBlocks: Preserve
|
||||||
|
IndentCaseLabels: true
|
||||||
|
IndentWidth: 4
|
||||||
|
PointerAlignment: Left
|
||||||
|
ReflowComments: false
|
||||||
|
SortIncludes: false
|
||||||
|
SortUsingDeclarations: false
|
||||||
|
SpaceAfterCStyleCast: false
|
||||||
|
SpaceAfterLogicalNot: false
|
||||||
|
SpaceAfterTemplateKeyword: true
|
||||||
|
SpaceBeforeCtorInitializerColon: true
|
||||||
|
SpaceBeforeInheritanceColon: true
|
||||||
|
SpaceBeforeParens: ControlStatements
|
||||||
|
SpaceBeforeRangeBasedForLoopColon: true
|
||||||
|
SpaceInEmptyParentheses: false
|
||||||
|
SpacesBeforeTrailingComments: 1
|
||||||
|
SpacesInAngles: false
|
||||||
|
SpacesInCStyleCastParentheses: false
|
||||||
|
SpacesInContainerLiterals: false
|
||||||
|
SpacesInParentheses: false
|
||||||
|
SpacesInSquareBrackets: false
|
||||||
|
Standard: Auto
|
||||||
|
TabWidth: 4
|
||||||
|
UseTab: Never
|
||||||
|
|
||||||
|
AllowShortEnumsOnASingleLine: false
|
||||||
|
|
||||||
|
BraceWrapping:
|
||||||
|
AfterEnum: false
|
||||||
|
|
||||||
|
AlignConsecutiveDeclarations: AcrossEmptyLines
|
||||||
|
|
||||||
|
NamespaceIndentation: All
|
||||||
56
.github/ISSUE_TEMPLATE/bug.yml
vendored
Normal file
56
.github/ISSUE_TEMPLATE/bug.yml
vendored
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
name: Bug Report
|
||||||
|
description: Something is not working right
|
||||||
|
labels: ["bug"]
|
||||||
|
body:
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: |
|
||||||
|
Before opening a new issue, take a moment to search through the current open ones.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
- type: input
|
||||||
|
id: ver
|
||||||
|
attributes:
|
||||||
|
label: Hyprland Version
|
||||||
|
description: "Paste here the output of `hyprctl version`."
|
||||||
|
placeholder: Hyprland, built from branch main at commit...
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: dropdown
|
||||||
|
id: type
|
||||||
|
attributes:
|
||||||
|
label: Bug or Regression?
|
||||||
|
description: Is this a bug or a regression?
|
||||||
|
options:
|
||||||
|
- Bug
|
||||||
|
- Regression
|
||||||
|
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 /tmp/hypr
|
||||||
|
Crash reports are stored in ~/.hyprland or $XDG_CACHE_HOME/hyprland
|
||||||
|
|
||||||
12
.github/ISSUE_TEMPLATE/bug_report.md
vendored
12
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -1,12 +0,0 @@
|
|||||||
---
|
|
||||||
name: Bug report
|
|
||||||
about: Found a bug? Report it here!
|
|
||||||
title: ''
|
|
||||||
labels: bug
|
|
||||||
assignees: ''
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
Please consult the issue guidelines at
|
|
||||||
https://github.com/vaxerski/Hyprland/blob/main/docs/ISSUE_GUIDELINES.md
|
|
||||||
BEFORE submitting.
|
|
||||||
19
.github/ISSUE_TEMPLATE/feature.yml
vendored
Normal file
19
.github/ISSUE_TEMPLATE/feature.yml
vendored
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
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
|
||||||
|
|
||||||
12
.github/ISSUE_TEMPLATE/feature_request.md
vendored
12
.github/ISSUE_TEMPLATE/feature_request.md
vendored
@@ -1,12 +0,0 @@
|
|||||||
---
|
|
||||||
name: Feature request
|
|
||||||
about: Suggest a feature/change/idea
|
|
||||||
title: ''
|
|
||||||
labels: enhancement
|
|
||||||
assignees: ''
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
Please consult the issue guidelines at
|
|
||||||
https://github.com/vaxerski/Hyprland/blob/main/docs/ISSUE_GUIDELINES.md
|
|
||||||
BEFORE submitting.
|
|
||||||
31
.github/workflows/ci.yaml
vendored
31
.github/workflows/ci.yaml
vendored
@@ -12,15 +12,14 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
sed -i 's/SigLevel = Required DatabaseOptional/SigLevel = Optional TrustAll/' /etc/pacman.conf
|
sed -i 's/SigLevel = Required DatabaseOptional/SigLevel = Optional TrustAll/' /etc/pacman.conf
|
||||||
pacman --noconfirm --noprogressbar -Syyu
|
pacman --noconfirm --noprogressbar -Syyu
|
||||||
pacman --noconfirm --noprogressbar -Sy glslang libepoxy libfontenc libxcvt libxfont2 libxkbfile vulkan-headers vulkan-validation-layers xcb-util-errors xcb-util-renderutil xcb-util-wm xorg-fonts-encodings xorg-server-common xorg-setxkbmap xorg-xkbcomp xorg-xwayland git cmake go clang lld libc++ pkgconf meson ninja wayland wayland-protocols libinput libxkbcommon pixman glm libdrm libglvnd cairo pango systemd scdoc base-devel seatd
|
pacman --noconfirm --noprogressbar -Sy glslang libepoxy libfontenc libxcvt libxfont2 libxkbfile vulkan-headers vulkan-validation-layers xcb-util-errors xcb-util-renderutil xcb-util-wm xorg-fonts-encodings xorg-server-common xorg-setxkbmap xorg-xkbcomp xorg-xwayland git cmake go clang lld libc++ pkgconf meson ninja wayland wayland-protocols libinput libxkbcommon pixman glm libdrm libglvnd cairo pango systemd scdoc base-devel seatd python libliftoff
|
||||||
- name: Set up user
|
- name: Set up user
|
||||||
run: |
|
run: |
|
||||||
useradd -m githubuser
|
useradd -m githubuser
|
||||||
echo -e "root ALL=(ALL:ALL) ALL\ngithubuser ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers
|
echo -e "root ALL=(ALL:ALL) ALL\ngithubuser ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers
|
||||||
- name: Build wlroots
|
- name: Install libdisplay-info from the AUR
|
||||||
run: |
|
run: |
|
||||||
su githubuser -c "cd ~ && git clone https://gitlab.freedesktop.org/wlroots/wlroots"
|
su githubuser -c "cd ~ && git clone https://aur.archlinux.org/libdisplay-info.git && cd ./libdisplay-info && makepkg -si --skippgpcheck --noconfirm --noprogressbar"
|
||||||
su githubuser -c "cd ~/wlroots && meson build/ --prefix=/usr && ninja -C build/ && sudo ninja -C build/ install && cd .."
|
|
||||||
- name: Fix permissions for git
|
- name: Fix permissions for git
|
||||||
run: |
|
run: |
|
||||||
git config --global --add safe.directory /__w/Hyprland/Hyprland
|
git config --global --add safe.directory /__w/Hyprland/Hyprland
|
||||||
@@ -40,8 +39,8 @@ jobs:
|
|||||||
mkdir hyprland/assets
|
mkdir hyprland/assets
|
||||||
cp ./LICENSE hyprland/
|
cp ./LICENSE hyprland/
|
||||||
cp build/Hyprland hyprland/
|
cp build/Hyprland hyprland/
|
||||||
cp hyprctl/hyprctl hyprland/
|
cp build/hyprctl/hyprctl hyprland/
|
||||||
cp subprojects/wlroots/build/libwlroots.so.11032 hyprland/
|
cp subprojects/wlroots/build/libwlroots.so.13032 hyprland/
|
||||||
cp build/Hyprland hyprland/
|
cp build/Hyprland hyprland/
|
||||||
cp -r example/ hyprland/
|
cp -r example/ hyprland/
|
||||||
cp -r assets/ hyprland/
|
cp -r assets/ hyprland/
|
||||||
@@ -62,7 +61,14 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
sed -i 's/SigLevel = Required DatabaseOptional/SigLevel = Optional TrustAll/' /etc/pacman.conf
|
sed -i 's/SigLevel = Required DatabaseOptional/SigLevel = Optional TrustAll/' /etc/pacman.conf
|
||||||
pacman --noconfirm --noprogressbar -Syyu
|
pacman --noconfirm --noprogressbar -Syyu
|
||||||
pacman --noconfirm --noprogressbar -Sy glslang libepoxy libfontenc libxcvt libxfont2 libxkbfile vulkan-headers vulkan-validation-layers git go clang lld libc++ pkgconf meson ninja wayland wayland-protocols libinput libxkbcommon pixman glm libdrm libglvnd cairo pango systemd scdoc base-devel seatd cmake
|
pacman --noconfirm --noprogressbar -Sy glslang libepoxy libfontenc libxcvt libxfont2 libxkbfile vulkan-headers vulkan-validation-layers git go clang lld libc++ pkgconf meson ninja wayland wayland-protocols libinput libxkbcommon pixman glm libdrm libglvnd cairo pango systemd scdoc base-devel seatd cmake jq python libliftoff
|
||||||
|
- name: Set up user
|
||||||
|
run: |
|
||||||
|
useradd -m githubuser
|
||||||
|
echo -e "root ALL=(ALL:ALL) ALL\ngithubuser ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers
|
||||||
|
- name: Install libdisplay-info from the AUR
|
||||||
|
run: |
|
||||||
|
su githubuser -c "cd ~ && git clone https://aur.archlinux.org/libdisplay-info.git && cd ./libdisplay-info && makepkg -si --skippgpcheck --noconfirm --noprogressbar"
|
||||||
- name: Checkout Hyprland
|
- name: Checkout Hyprland
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
@@ -84,7 +90,14 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
sed -i 's/SigLevel = Required DatabaseOptional/SigLevel = Optional TrustAll/' /etc/pacman.conf
|
sed -i 's/SigLevel = Required DatabaseOptional/SigLevel = Optional TrustAll/' /etc/pacman.conf
|
||||||
pacman --noconfirm --noprogressbar -Syyu
|
pacman --noconfirm --noprogressbar -Syyu
|
||||||
pacman --noconfirm --noprogressbar -Sy glslang libepoxy libfontenc libxcvt libxfont2 libxkbfile vulkan-headers vulkan-validation-layers git cmake go clang lld libc++ pkgconf meson ninja wayland wayland-protocols libinput libxkbcommon pixman glm libdrm libglvnd cairo pango systemd scdoc base-devel seatd
|
pacman --noconfirm --noprogressbar -Sy glslang libepoxy libfontenc libxcvt libxfont2 libxkbfile vulkan-headers vulkan-validation-layers git cmake go clang lld libc++ pkgconf meson ninja wayland wayland-protocols libinput libxkbcommon pixman glm libdrm libglvnd cairo pango systemd scdoc base-devel seatd libliftoff
|
||||||
|
- name: Set up user
|
||||||
|
run: |
|
||||||
|
useradd -m githubuser
|
||||||
|
echo -e "root ALL=(ALL:ALL) ALL\ngithubuser ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers
|
||||||
|
- name: Install libdisplay-info from the AUR
|
||||||
|
run: |
|
||||||
|
su githubuser -c "cd ~ && git clone https://aur.archlinux.org/libdisplay-info.git && cd ./libdisplay-info && makepkg -si --skippgpcheck --noconfirm --noprogressbar"
|
||||||
- name: Checkout Hyprland
|
- name: Checkout Hyprland
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
@@ -92,4 +105,4 @@ jobs:
|
|||||||
- name: Configure
|
- 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
|
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
|
- name: Compile
|
||||||
run: make config && make release
|
run: make release
|
||||||
|
|||||||
30
.github/workflows/flawfinder.yml
vendored
30
.github/workflows/flawfinder.yml
vendored
@@ -1,30 +0,0 @@
|
|||||||
name: Flawfinder
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: [ main ]
|
|
||||||
pull_request:
|
|
||||||
branches: [ main ]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
flawfinder:
|
|
||||||
name: Flawfinder Checks
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
permissions:
|
|
||||||
actions: read
|
|
||||||
contents: read
|
|
||||||
security-events: write
|
|
||||||
steps:
|
|
||||||
- name: Checkout code
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
|
|
||||||
- name: Scan with Flawfinder
|
|
||||||
uses: david-a-wheeler/flawfinder@8e4a779ad59dbfaee5da586aa9210853b701959c
|
|
||||||
with:
|
|
||||||
arguments: '--sarif ./'
|
|
||||||
output: 'flawfinder_results.sarif'
|
|
||||||
|
|
||||||
- name: Upload analysis results to GitHub Security tab
|
|
||||||
uses: github/codeql-action/upload-sarif@v2
|
|
||||||
with:
|
|
||||||
sarif_file: ${{github.workspace}}/flawfinder_results.sarif
|
|
||||||
8
.github/workflows/man-update.yaml
vendored
8
.github/workflows/man-update.yaml
vendored
@@ -15,13 +15,15 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Install deps
|
- name: Install deps
|
||||||
run: sudo apt install pandoc
|
run: sudo apt install pandoc
|
||||||
|
|
||||||
- name: Clone repository
|
- name: Clone repository
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
# Not needed
|
with:
|
||||||
# with:
|
token: ${{ secrets.PAT }}
|
||||||
# submodules: recursive
|
|
||||||
- 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@v4
|
||||||
name: Commit
|
name: Commit
|
||||||
with:
|
with:
|
||||||
|
|||||||
30
.github/workflows/nix-build.yaml
vendored
30
.github/workflows/nix-build.yaml
vendored
@@ -1,30 +0,0 @@
|
|||||||
name: Build Hyprland (Nix)
|
|
||||||
|
|
||||||
on: [push, pull_request, workflow_dispatch]
|
|
||||||
jobs:
|
|
||||||
nix:
|
|
||||||
name: "Build Hyprland (Nix)"
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
package:
|
|
||||||
- default
|
|
||||||
- hyprland-no-hidpi
|
|
||||||
steps:
|
|
||||||
- name: Clone repository
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
with:
|
|
||||||
submodules: recursive
|
|
||||||
- name: Install nix
|
|
||||||
uses: cachix/install-nix-action@v17
|
|
||||||
with:
|
|
||||||
install_url: https://releases.nixos.org/nix/nix-2.10.3/install
|
|
||||||
extra_nix_config: |
|
|
||||||
auto-optimise-store = true
|
|
||||||
experimental-features = nix-command flakes
|
|
||||||
- uses: cachix/cachix-action@v10
|
|
||||||
with:
|
|
||||||
name: hyprland
|
|
||||||
authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'
|
|
||||||
- name: Build Hyprland with default settings
|
|
||||||
run: nix build .#${{ matrix.package }} --print-build-logs
|
|
||||||
29
.github/workflows/nix-build.yml
vendored
Normal file
29
.github/workflows/nix-build.yml
vendored
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
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@v3
|
||||||
|
with:
|
||||||
|
ref: ${{ github.ref }}
|
||||||
|
|
||||||
|
- uses: DeterminateSystems/nix-installer-action@main
|
||||||
|
- uses: DeterminateSystems/magic-nix-cache-action@main
|
||||||
|
- uses: cachix/cachix-action@v12
|
||||||
|
with:
|
||||||
|
name: hyprland
|
||||||
|
authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'
|
||||||
|
|
||||||
|
- run: nix build -L ${{ matrix.command }}
|
||||||
15
.github/workflows/nix-ci.yml
vendored
Normal file
15
.github/workflows/nix-ci.yml
vendored
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
name: Nix
|
||||||
|
|
||||||
|
on: [push, pull_request, workflow_dispatch]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
wlroots:
|
||||||
|
if: github.event_name != 'pull_request'
|
||||||
|
uses: ./.github/workflows/nix-update-wlroots.yml
|
||||||
|
secrets: inherit
|
||||||
|
|
||||||
|
build:
|
||||||
|
if: always() && !cancelled() && !contains(needs.*.result, 'failure')
|
||||||
|
needs: wlroots
|
||||||
|
uses: ./.github/workflows/nix-build.yml
|
||||||
|
secrets: inherit
|
||||||
26
.github/workflows/nix-meson-ver-update.yaml
vendored
26
.github/workflows/nix-meson-ver-update.yaml
vendored
@@ -1,26 +0,0 @@
|
|||||||
name: "Nix & Meson: update version"
|
|
||||||
|
|
||||||
on: [workflow_dispatch]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
update:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Clone repository
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
- name: Update flake and meson version
|
|
||||||
run: |
|
|
||||||
REGEX="([0-9]+(\.[0-9a-zA-Z]+)+)"
|
|
||||||
|
|
||||||
CRT_REV=$(git show-ref --tags --head --abbrev | head -n 1 | head -c 7)
|
|
||||||
TAG_REV=$(git show-ref --tags --abbrev | tail -n 1 | head -c 7)
|
|
||||||
CRT_VER=$(sed -nEe "/$REGEX/{p;q;}" meson.build | awk -F\' '{print $2}')
|
|
||||||
VERSION=$(git show-ref --tags --abbrev | tail -n 1 | tail -c +20)
|
|
||||||
|
|
||||||
if [[ $TAG_REV = $CRT_REV ]] || [[ $CRT_VER != $VERSION ]]; then
|
|
||||||
sed -Ei "s/$REGEX/$VERSION/g" meson.build
|
|
||||||
sed -Ei "s/$REGEX/$VERSION/g" flake.nix
|
|
||||||
fi
|
|
||||||
- uses: stefanzweifel/git-auto-commit-action@v4
|
|
||||||
with:
|
|
||||||
commit_message: "[gha] bump flake and meson version"
|
|
||||||
29
.github/workflows/nix-update-inputs.yml
vendored
Normal file
29
.github/workflows/nix-update-inputs.yml
vendored
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
name: Nix
|
||||||
|
|
||||||
|
on:
|
||||||
|
schedule:
|
||||||
|
- cron: '0 0 * * *' # check daily
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
update:
|
||||||
|
name: inputs
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Clone repository
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.PAT }}
|
||||||
|
|
||||||
|
- uses: DeterminateSystems/nix-installer-action@main
|
||||||
|
- name: Update inputs
|
||||||
|
run: nix/update-inputs.sh
|
||||||
|
|
||||||
|
- name: Commit
|
||||||
|
uses: stefanzweifel/git-auto-commit-action@v4
|
||||||
|
with:
|
||||||
|
commit_message: "[gha] Nix: update inputs"
|
||||||
|
|
||||||
|
update-build:
|
||||||
|
needs: update
|
||||||
|
uses: ./.github/workflows/nix-build.yml
|
||||||
|
secrets: inherit
|
||||||
26
.github/workflows/nix-update-wlroots.yml
vendored
Normal file
26
.github/workflows/nix-update-wlroots.yml
vendored
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
name: Nix
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_call:
|
||||||
|
secrets:
|
||||||
|
PAT:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
update:
|
||||||
|
name: wlroots
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Clone repository
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.PAT }}
|
||||||
|
|
||||||
|
- uses: DeterminateSystems/nix-installer-action@main
|
||||||
|
- name: Update lockfile
|
||||||
|
run: nix/update-wlroots.sh
|
||||||
|
|
||||||
|
- name: Commit
|
||||||
|
uses: stefanzweifel/git-auto-commit-action@v4
|
||||||
|
with:
|
||||||
|
commit_message: "[gha] Nix: update wlroots"
|
||||||
22
.github/workflows/nix-update.yaml
vendored
22
.github/workflows/nix-update.yaml
vendored
@@ -1,22 +0,0 @@
|
|||||||
name: "Nix: update lockfile"
|
|
||||||
|
|
||||||
on: [push, workflow_dispatch]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
update:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Clone repository
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
- name: Install nix
|
|
||||||
uses: cachix/install-nix-action@v17
|
|
||||||
with:
|
|
||||||
install_url: https://releases.nixos.org/nix/nix-2.8.0/install
|
|
||||||
extra_nix_config: |
|
|
||||||
auto-optimise-store = true
|
|
||||||
experimental-features = nix-command flakes
|
|
||||||
- name: Update lockfile
|
|
||||||
run: nix/update-inputs.sh
|
|
||||||
- uses: stefanzweifel/git-auto-commit-action@v4
|
|
||||||
with:
|
|
||||||
commit_message: "[gha] bump flake inputs"
|
|
||||||
9
.github/workflows/release.yaml
vendored
9
.github/workflows/release.yaml
vendored
@@ -15,9 +15,16 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
submodules: recursive
|
submodules: recursive
|
||||||
|
|
||||||
|
- name: Generate version
|
||||||
|
id: genversion
|
||||||
|
run: |
|
||||||
|
bash -c scripts/generateVersion.sh
|
||||||
|
mv scripts/generateVersion.sh scripts/generateVersion.sh.bak
|
||||||
|
|
||||||
- name: Create tarball with submodules
|
- name: Create tarball with submodules
|
||||||
id: tar
|
id: tar
|
||||||
run: tar -czv --owner=0 --group=0 --no-same-owner --no-same-permissions -f source.tar.gz *
|
run: |
|
||||||
|
mkdir hyprland-source; mv ./* ./hyprland-source || tar -czv --owner=0 --group=0 --no-same-owner --no-same-permissions -f source.tar.gz *
|
||||||
|
|
||||||
- id: whatrelease
|
- id: whatrelease
|
||||||
name: Get latest release
|
name: Get latest release
|
||||||
|
|||||||
76
.github/workflows/security-checks.yml
vendored
Normal file
76
.github/workflows/security-checks.yml
vendored
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
name: Security Checks
|
||||||
|
|
||||||
|
on: [push, pull_request]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
flawfinder:
|
||||||
|
name: Flawfinder Checks
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
actions: read
|
||||||
|
contents: read
|
||||||
|
security-events: write
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Scan with Flawfinder
|
||||||
|
uses: david-a-wheeler/flawfinder@8e4a779ad59dbfaee5da586aa9210853b701959c
|
||||||
|
with:
|
||||||
|
arguments: '--sarif ./'
|
||||||
|
output: 'flawfinder_results.sarif'
|
||||||
|
|
||||||
|
- name: Upload analysis results to GitHub Security tab
|
||||||
|
uses: github/codeql-action/upload-sarif@v2
|
||||||
|
with:
|
||||||
|
sarif_file: ${{github.workspace}}/flawfinder_results.sarif
|
||||||
|
|
||||||
|
codeql:
|
||||||
|
name: CodeQL
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container:
|
||||||
|
image: archlinux
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
actions: read
|
||||||
|
contents: read
|
||||||
|
security-events: write
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
language: [ 'cpp' ]
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Initialize CodeQL
|
||||||
|
uses: github/codeql-action/init@v2
|
||||||
|
with:
|
||||||
|
languages: ${{ matrix.language }}
|
||||||
|
|
||||||
|
- name: Init Hyprland build
|
||||||
|
run: |
|
||||||
|
sed -i 's/SigLevel = Required DatabaseOptional/SigLevel = Optional TrustAll/' /etc/pacman.conf
|
||||||
|
pacman --noconfirm --noprogressbar -Syyu
|
||||||
|
pacman --noconfirm --noprogressbar -Sy glslang libepoxy libfontenc libxcvt libxfont2 libxkbfile vulkan-headers vulkan-validation-layers xcb-util-errors xcb-util-renderutil xcb-util-wm xorg-fonts-encodings xorg-server-common xorg-setxkbmap xorg-xkbcomp xorg-xwayland git cmake go clang lld libc++ pkgconf meson ninja wayland wayland-protocols libinput libxkbcommon pixman glm libdrm libglvnd cairo pango systemd scdoc base-devel seatd python libliftoff
|
||||||
|
useradd -m githubuser
|
||||||
|
echo -e "root ALL=(ALL:ALL) ALL\ngithubuser ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers
|
||||||
|
su githubuser -c "cd ~ && git clone https://aur.archlinux.org/libdisplay-info.git && cd ./libdisplay-info && makepkg -si --skippgpcheck --noconfirm --noprogressbar"
|
||||||
|
git config --global --add safe.directory /__w/Hyprland/Hyprland
|
||||||
|
|
||||||
|
- name: Checkout Hyprland
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
|
||||||
|
- name: Build Hyprland
|
||||||
|
run: |
|
||||||
|
git submodule sync --recursive && git submodule update --init --force --recursive
|
||||||
|
make all
|
||||||
|
|
||||||
|
- name: Perform CodeQL Analysis
|
||||||
|
uses: github/codeql-action/analyze@v2
|
||||||
|
with:
|
||||||
|
category: "/language:${{matrix.language}}"
|
||||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -12,6 +12,7 @@ _deps
|
|||||||
build/
|
build/
|
||||||
result*
|
result*
|
||||||
/.vscode/
|
/.vscode/
|
||||||
|
/.idea/
|
||||||
.envrc
|
.envrc
|
||||||
.cache
|
.cache
|
||||||
|
|
||||||
@@ -19,6 +20,7 @@ result*
|
|||||||
*-protocol.c
|
*-protocol.c
|
||||||
*-protocol.h
|
*-protocol.h
|
||||||
.ccls-cache
|
.ccls-cache
|
||||||
|
*.so
|
||||||
|
|
||||||
hyprctl/hyprctl
|
hyprctl/hyprctl
|
||||||
|
|
||||||
@@ -27,3 +29,5 @@ gmon.out
|
|||||||
*.tar.gz
|
*.tar.gz
|
||||||
|
|
||||||
PKGBUILD
|
PKGBUILD
|
||||||
|
|
||||||
|
src/version.h
|
||||||
|
|||||||
9
.gitmodules
vendored
9
.gitmodules
vendored
@@ -1,3 +1,12 @@
|
|||||||
[submodule "wlroots"]
|
[submodule "wlroots"]
|
||||||
path = subprojects/wlroots
|
path = subprojects/wlroots
|
||||||
url = https://gitlab.freedesktop.org/wlroots/wlroots.git
|
url = https://gitlab.freedesktop.org/wlroots/wlroots.git
|
||||||
|
[submodule "subprojects/hyprland-protocols"]
|
||||||
|
path = subprojects/hyprland-protocols
|
||||||
|
url = https://github.com/hyprwm/hyprland-protocols
|
||||||
|
[submodule "subprojects/udis86"]
|
||||||
|
path = subprojects/udis86
|
||||||
|
url = https://github.com/canihavesomecoffee/udis86
|
||||||
|
[submodule "subprojects/tracy"]
|
||||||
|
path = subprojects/tracy
|
||||||
|
url = https://github.com/wolfpld/tracy
|
||||||
|
|||||||
274
CMakeLists.txt
Normal file → Executable file
274
CMakeLists.txt
Normal file → Executable file
@@ -1,8 +1,19 @@
|
|||||||
cmake_minimum_required(VERSION 3.4)
|
cmake_minimum_required(VERSION 3.19)
|
||||||
project(Hyprland
|
include(CheckIncludeFile)
|
||||||
|
|
||||||
|
# Get version
|
||||||
|
file(READ ${CMAKE_CURRENT_SOURCE_DIR}/props.json PROPS)
|
||||||
|
string(JSON VER GET ${PROPS} version)
|
||||||
|
|
||||||
|
project(Hyprland
|
||||||
DESCRIPTION "A Modern C++ Wayland Compositor"
|
DESCRIPTION "A Modern C++ Wayland Compositor"
|
||||||
|
VERSION ${VER}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
set(HYPRLAND_VERSION ${VER})
|
||||||
|
set(PREFIX ${CMAKE_INSTALL_PREFIX})
|
||||||
|
configure_file(hyprland.pc.in hyprland.pc @ONLY)
|
||||||
|
|
||||||
set(CMAKE_MESSAGE_LOG_LEVEL "STATUS")
|
set(CMAKE_MESSAGE_LOG_LEVEL "STATUS")
|
||||||
|
|
||||||
message(STATUS "Gathering git info")
|
message(STATUS "Gathering git info")
|
||||||
@@ -10,98 +21,229 @@ message(STATUS "Gathering git info")
|
|||||||
# Get git info
|
# Get git info
|
||||||
# hash and branch
|
# hash and branch
|
||||||
execute_process(
|
execute_process(
|
||||||
COMMAND git rev-parse --abbrev-ref HEAD
|
COMMAND ./scripts/generateVersion.sh
|
||||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
|
||||||
OUTPUT_VARIABLE GIT_BRANCH
|
|
||||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
|
||||||
|
|
||||||
execute_process(
|
|
||||||
COMMAND git rev-parse HEAD
|
|
||||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
|
||||||
OUTPUT_VARIABLE GIT_COMMIT_HASH
|
|
||||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
|
||||||
|
|
||||||
execute_process(
|
|
||||||
COMMAND sh -c "git show ${GIT_COMMIT_HASH} | head -n 5 | tail -n 1"
|
|
||||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
|
||||||
OUTPUT_VARIABLE GIT_COMMIT_MESSAGE
|
|
||||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
|
||||||
|
|
||||||
execute_process(
|
|
||||||
COMMAND sh -c "git diff-index --quiet HEAD -- || echo \"dirty\""
|
|
||||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
|
||||||
OUTPUT_VARIABLE GIT_DIRTY
|
|
||||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
|
||||||
IF(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG)
|
# udis
|
||||||
|
add_subdirectory("subprojects/udis86")
|
||||||
|
|
||||||
|
# wlroots
|
||||||
|
message(STATUS "Setting up wlroots")
|
||||||
|
|
||||||
|
include(ExternalProject)
|
||||||
|
|
||||||
|
if(CMAKE_BUILD_TYPE)
|
||||||
|
string(TOLOWER ${CMAKE_BUILD_TYPE} BUILDTYPE_LOWER)
|
||||||
|
if(BUILDTYPE_LOWER STREQUAL "release")
|
||||||
|
# Pass.
|
||||||
|
elseif(BUILDTYPE_LOWER STREQUAL "debug")
|
||||||
|
# Pass.
|
||||||
|
elseif(BUILDTYPE_LOWER STREQUAL "relwithdebinfo")
|
||||||
|
set(BUILDTYPE_LOWER "debugoptimized")
|
||||||
|
elseif(BUILDTYPE_LOWER STREQUAL "minsizerel")
|
||||||
|
set(BUILDTYPE_LOWER "minsize")
|
||||||
|
elseif(BUILDTYPE_LOWER STREQUAL "none")
|
||||||
|
set(BUILDTYPE_LOWER "plain")
|
||||||
|
else()
|
||||||
|
set(BUILDTYPE_LOWER "release")
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
set(BUILDTYPE_LOWER "release")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
ExternalProject_Add(
|
||||||
|
wlroots
|
||||||
|
PREFIX ${CMAKE_SOURCE_DIR}/subprojects/wlroots
|
||||||
|
SOURCE_DIR ${CMAKE_SOURCE_DIR}/subprojects/wlroots
|
||||||
|
PATCH_COMMAND sed -E -i -e "s/(soversion = 13)([^032]|$$)/soversion = 13032/g" meson.build
|
||||||
|
CONFIGURE_COMMAND meson setup build --buildtype=${BUILDTYPE_LOWER} -Dwerror=false -Dexamples=false -Drenderers=gles2 $<IF:$<BOOL:${WITH_ASAN}>,-Db_sanitize=address,-Db_sanitize=none> && meson setup build --buildtype=${BUILDTYPE_LOWER} -Dwerror=false -Dexamples=false -Drenderers=gles2 $<IF:$<BOOL:${WITH_ASAN}>,-Db_sanitize=address,-Db_sanitize=none> --reconfigure
|
||||||
|
BUILD_COMMAND ninja -C build
|
||||||
|
BUILD_ALWAYS true
|
||||||
|
BUILD_IN_SOURCE true
|
||||||
|
BUILD_BYPRODUCTS ${CMAKE_SOURCE_DIR}/subprojects/wlroots/build/libwlroots.so.13032
|
||||||
|
INSTALL_COMMAND echo "wlroots: install not needed"
|
||||||
|
)
|
||||||
|
|
||||||
|
find_program(WaylandScanner NAMES wayland-scanner)
|
||||||
|
message(STATUS "Found WaylandScanner at ${WaylandScanner}")
|
||||||
|
execute_process(
|
||||||
|
COMMAND pkg-config --variable=pkgdatadir wayland-protocols
|
||||||
|
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||||
|
OUTPUT_VARIABLE WAYLAND_PROTOCOLS_DIR
|
||||||
|
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||||
|
message(STATUS "Found wayland-protocols at ${WAYLAND_PROTOCOLS_DIR}")
|
||||||
|
|
||||||
|
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_definitions( -DHYPRLAND_DEBUG )
|
add_compile_definitions(HYPRLAND_DEBUG)
|
||||||
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")
|
||||||
ENDIF(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG)
|
endif()
|
||||||
|
|
||||||
include_directories(. PRIVATE "subprojects/wlroots/include/")
|
include_directories(
|
||||||
include_directories(. PRIVATE "subprojects/wlroots/build/include/")
|
.
|
||||||
add_compile_options(-std=c++23 -DWLR_USE_UNSTABLE )
|
"src/"
|
||||||
add_compile_options(-Wall -Wextra -Wno-unused-parameter -Wno-unused-value -Wno-missing-field-initializers -Wno-narrowing)
|
"subprojects/wlroots/include/"
|
||||||
|
"subprojects/wlroots/build/include/"
|
||||||
|
"subprojects/udis86/"
|
||||||
|
"protocols/")
|
||||||
|
set(CMAKE_CXX_STANDARD 23)
|
||||||
|
add_compile_definitions(WLR_USE_UNSTABLE)
|
||||||
|
add_compile_options(-Wall -Wextra -Wno-unused-parameter -Wno-unused-value -Wno-missing-field-initializers -Wno-narrowing -Wno-pointer-arith)
|
||||||
|
add_link_options(-rdynamic)
|
||||||
|
set(CMAKE_ENABLE_EXPORTS TRUE)
|
||||||
|
|
||||||
message(STATUS "Checking deps...")
|
message(STATUS "Checking deps...")
|
||||||
|
|
||||||
find_package(Threads REQUIRED)
|
find_package(Threads REQUIRED)
|
||||||
|
|
||||||
find_package(PkgConfig REQUIRED)
|
find_package(PkgConfig REQUIRED)
|
||||||
pkg_check_modules(deps REQUIRED IMPORTED_TARGET wayland-server wayland-client wayland-cursor wayland-protocols cairo pango pangocairo libdrm egl xkbcommon libinput) # we do not check for wlroots, as we provide it ourselves
|
find_package(OpenGL REQUIRED)
|
||||||
|
pkg_check_modules(deps REQUIRED IMPORTED_TARGET wayland-server wayland-client wayland-cursor wayland-protocols cairo libdrm xkbcommon libinput pango pangocairo pixman-1) # we do not check for wlroots, as we provide it ourselves
|
||||||
|
|
||||||
file(GLOB_RECURSE SRCFILES "src/*.cpp")
|
file(GLOB_RECURSE SRCFILES CONFIGURE_DEPENDS "src/*.cpp")
|
||||||
|
|
||||||
add_executable(Hyprland ${SRCFILES})
|
set(TRACY_CPP_FILES "")
|
||||||
|
if(USE_TRACY)
|
||||||
|
set(TRACY_CPP_FILES "subprojects/tracy/public/TracyClient.cpp")
|
||||||
|
message(STATUS "Tracy enabled, TRACY_CPP_FILES: " ${TRACY_CPP_FILES})
|
||||||
|
endif()
|
||||||
|
|
||||||
IF(LEGACY_RENDERER MATCHES true)
|
add_executable(Hyprland ${SRCFILES} ${TRACY_CPP_FILES})
|
||||||
|
add_dependencies(Hyprland wlroots)
|
||||||
|
|
||||||
|
if(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG)
|
||||||
|
message(STATUS "Setting debug flags")
|
||||||
|
|
||||||
|
if (WITH_ASAN)
|
||||||
|
message(STATUS "Enabling ASan")
|
||||||
|
|
||||||
|
target_link_libraries(Hyprland asan)
|
||||||
|
target_compile_options(Hyprland 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()
|
||||||
|
|
||||||
|
add_compile_options(-pg -no-pie -fno-builtin)
|
||||||
|
add_link_options(-pg -no-pie -fno-builtin)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
check_include_file("execinfo.h" EXECINFOH)
|
||||||
|
if(EXECINFOH)
|
||||||
|
message(STATUS "Configuration supports execinfo")
|
||||||
|
add_compile_definitions(HAS_EXECINFO)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
include(CheckLibraryExists)
|
||||||
|
check_library_exists(execinfo backtrace "" HAVE_LIBEXECINFO)
|
||||||
|
if(HAVE_LIBEXECINFO)
|
||||||
|
target_link_libraries(Hyprland execinfo)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(LEGACY_RENDERER)
|
||||||
message(STATUS "Using the legacy GLES2 renderer!")
|
message(STATUS "Using the legacy GLES2 renderer!")
|
||||||
add_definitions( -DLEGACY_RENDERER )
|
add_compile_definitions(LEGACY_RENDERER)
|
||||||
ENDIF(LEGACY_RENDERER MATCHES true)
|
endif()
|
||||||
|
|
||||||
IF(NO_XWAYLAND MATCHES true)
|
if(NO_XWAYLAND)
|
||||||
message(STATUS "Using the NO_XWAYLAND flag, disabling XWayland!")
|
message(STATUS "Using the NO_XWAYLAND flag, disabling XWayland!")
|
||||||
add_definitions( -DNO_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(xcbdep REQUIRED xcb)
|
pkg_check_modules(xcbdep REQUIRED IMPORTED_TARGET xcb)
|
||||||
target_link_libraries(Hyprland xcb)
|
target_link_libraries(Hyprland PkgConfig::xcbdep)
|
||||||
ENDIF(NO_XWAYLAND MATCHES true)
|
endif()
|
||||||
|
|
||||||
target_compile_definitions(Hyprland PRIVATE "-DGIT_COMMIT_HASH=\"${GIT_COMMIT_HASH}\"")
|
if(NO_SYSTEMD)
|
||||||
target_compile_definitions(Hyprland PRIVATE "-DGIT_BRANCH=\"${GIT_BRANCH}\"")
|
message(STATUS "SYSTEMD support is disabled...")
|
||||||
target_compile_definitions(Hyprland PRIVATE "-DGIT_COMMIT_MESSAGE=\"${GIT_COMMIT_MESSAGE}\"")
|
else()
|
||||||
target_compile_definitions(Hyprland PRIVATE "-DGIT_DIRTY=\"${GIT_DIRTY}\"")
|
message(STATUS "SYSTEMD support is requested (NO_SYSTEMD not defined) checking deps...")
|
||||||
|
check_include_file("systemd/sd-daemon.h" SYSTEMDH)
|
||||||
target_link_libraries(Hyprland rt)
|
if(SYSTEMDH)
|
||||||
|
pkg_check_modules(LIBSYSTEMD libsystemd)
|
||||||
|
if (LIBSYSTEMD_FOUND)
|
||||||
|
add_compile_definitions(USES_SYSTEMD)
|
||||||
|
target_link_libraries(Hyprland "${LIBSYSTEMD_LIBRARIES}")
|
||||||
|
message(STATUS "Systemd found")
|
||||||
|
else()
|
||||||
|
message(WARNING "Systemd support requested but systemd libraries were not found")
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
message(WARNING "Systemd support requested but systemd headers were not found")
|
||||||
|
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")
|
||||||
|
|
||||||
|
target_precompile_headers(Hyprland PRIVATE $<$<COMPILE_LANGUAGE:CXX>:src/pch/pch.hpp>)
|
||||||
|
|
||||||
message(STATUS "Setting link libraries")
|
message(STATUS "Setting link libraries")
|
||||||
|
|
||||||
target_link_libraries(Hyprland PkgConfig::deps)
|
target_link_libraries(Hyprland rt PkgConfig::deps)
|
||||||
|
|
||||||
|
function(protocol protoPath protoName external)
|
||||||
|
if (external)
|
||||||
|
execute_process(
|
||||||
|
COMMAND ${WaylandScanner} server-header ${protoPath} protocols/${protoName}-protocol.h
|
||||||
|
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
|
||||||
|
execute_process(
|
||||||
|
COMMAND ${WaylandScanner} private-code ${protoPath} protocols/${protoName}-protocol.c
|
||||||
|
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
|
||||||
|
target_sources(Hyprland PRIVATE protocols/${protoName}-protocol.c)
|
||||||
|
else()
|
||||||
|
execute_process(
|
||||||
|
COMMAND ${WaylandScanner} server-header ${WAYLAND_PROTOCOLS_DIR}/${protoPath} protocols/${protoName}-protocol.h
|
||||||
|
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
|
||||||
|
execute_process(
|
||||||
|
COMMAND ${WaylandScanner} private-code ${WAYLAND_PROTOCOLS_DIR}/${protoPath} protocols/${protoName}-protocol.c
|
||||||
|
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
|
||||||
|
target_sources(Hyprland PRIVATE protocols/${protoName}-protocol.c)
|
||||||
|
endif()
|
||||||
|
endfunction()
|
||||||
|
|
||||||
target_link_libraries(Hyprland
|
target_link_libraries(Hyprland
|
||||||
${CMAKE_SOURCE_DIR}/subprojects/wlroots/build/libwlroots.so.11032 # wlroots is provided by us
|
${CMAKE_SOURCE_DIR}/subprojects/wlroots/build/libwlroots.so.13032 # wlroots is provided by us
|
||||||
pixman-1
|
OpenGL::EGL
|
||||||
OpenGL
|
OpenGL::GL
|
||||||
GLESv2
|
Threads::Threads
|
||||||
pthread
|
libudis86
|
||||||
${CMAKE_THREAD_LIBS_INIT}
|
|
||||||
${CMAKE_SOURCE_DIR}/ext-workspace-unstable-v1-protocol.o
|
|
||||||
)
|
)
|
||||||
|
|
||||||
IF(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG)
|
protocol("protocols/idle.xml" "idle" true)
|
||||||
message(STATUS "Setting debug flags")
|
protocol("protocols/pointer-constraints-unstable-v1.xml" "pointer-constraints-unstable-v1" true)
|
||||||
|
protocol("protocols/tablet-unstable-v2.xml" "tablet-unstable-v2" true)
|
||||||
|
protocol("protocols/wlr-foreign-toplevel-management-unstable-v1.xml" "wlr-foreign-toplevel-management-unstable-v1" true)
|
||||||
|
protocol("protocols/wlr-layer-shell-unstable-v1.xml" "wlr-layer-shell-unstable-v1" true)
|
||||||
|
protocol("protocols/wlr-output-power-management-unstable-v1.xml" "wlr-output-power-management-unstable-v1" true)
|
||||||
|
protocol("protocols/wlr-screencopy-unstable-v1.xml" "wlr-screencopy-unstable-v1" true)
|
||||||
|
protocol("subprojects/hyprland-protocols/protocols/hyprland-global-shortcuts-v1.xml" "hyprland-global-shortcuts-v1" true)
|
||||||
|
protocol("subprojects/hyprland-protocols/protocols/hyprland-toplevel-export-v1.xml" "hyprland-toplevel-export-v1" true)
|
||||||
|
protocol("stable/xdg-shell/xdg-shell.xml" "xdg-shell" false)
|
||||||
|
protocol("unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml" "linux-dmabuf-unstable-v1" false)
|
||||||
|
protocol("unstable/xdg-output/xdg-output-unstable-v1.xml" "xdg-output-unstable-v1" false)
|
||||||
|
protocol("staging/fractional-scale/fractional-scale-v1.xml" "fractional-scale-v1" false)
|
||||||
|
protocol("staging/tearing-control/tearing-control-v1.xml" "tearing-control-v1" false)
|
||||||
|
protocol("unstable/text-input/text-input-unstable-v1.xml" "text-input-unstable-v1" false)
|
||||||
|
protocol("staging/cursor-shape/cursor-shape-v1.xml" "cursor-shape-v1" false)
|
||||||
|
|
||||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pg -no-pie -fno-builtin")
|
# hyprctl
|
||||||
SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pg -no-pie -fno-builtin")
|
add_subdirectory(hyprctl)
|
||||||
SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -pg -no-pie -fno-builtin")
|
|
||||||
ENDIF(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG)
|
|
||||||
|
|||||||
96
CODE_OF_CONDUCT.md
Normal file
96
CODE_OF_CONDUCT.md
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
## Goal
|
||||||
|
|
||||||
|
Our goal is to provide a space where it is safe for everyone to contribute to,
|
||||||
|
and get support for, open-source software in a respectful and cooperative
|
||||||
|
manner.
|
||||||
|
|
||||||
|
We value all contributions and want to make this organization and its
|
||||||
|
surrounding community a place for everyone.
|
||||||
|
|
||||||
|
As members, contributors, and everyone else who may participate in the
|
||||||
|
development, we strive to keep the entire experience civil.
|
||||||
|
|
||||||
|
## Standards
|
||||||
|
|
||||||
|
Our community standards exist in order to make sure everyone feels comfortable
|
||||||
|
contributing to the project(s) together.
|
||||||
|
|
||||||
|
Our standards are:
|
||||||
|
- Do not harass, attack, or in any other way discriminate against anyone, including
|
||||||
|
for their protected traits, including, but not limited to, sex, religion, race,
|
||||||
|
appearance, gender, identity, nationality, sexuality, etc.
|
||||||
|
- Do not go off-topic, do not post spam.
|
||||||
|
- Treat everyone with respect.
|
||||||
|
|
||||||
|
Examples of breaking each rule respectively include:
|
||||||
|
- Harassment, bullying or inappropriate jokes about another person.
|
||||||
|
- Posting distasteful imagery, trolling, or posting things unrelated to the topic at hand.
|
||||||
|
- Treating someone as worse because of their lack of understanding of an issue.
|
||||||
|
|
||||||
|
## Enforcement
|
||||||
|
|
||||||
|
Enforcement of this CoC is done by the members of the hyprwm organization.
|
||||||
|
|
||||||
|
We, as the organization, will strive our best to keep this community civil and
|
||||||
|
following the standards outlined above.
|
||||||
|
|
||||||
|
### Reporting incidents
|
||||||
|
|
||||||
|
If you believe an incident of breaking our standards has occurred, but nobody has
|
||||||
|
taken appropriate action, you can privately contact the people responsible for dealing
|
||||||
|
with such incidents in multiple ways:
|
||||||
|
|
||||||
|
***E-Mail***
|
||||||
|
- `vaxry[at]vaxry.net`
|
||||||
|
- `mihai[at]fufexan.net`
|
||||||
|
|
||||||
|
***Discord***
|
||||||
|
- `@vaxry`
|
||||||
|
- `@fufexan`
|
||||||
|
|
||||||
|
***Matrix***
|
||||||
|
- `@vaxry:matrix.vaxry.net`
|
||||||
|
- `@fufexan:matrix.org`
|
||||||
|
|
||||||
|
We, as members, guarantee your privacy and will not share those reports with anyone.
|
||||||
|
|
||||||
|
## Enforcement Strategy
|
||||||
|
|
||||||
|
Depending on the severity of the infraction, any action from the list below may be applied.
|
||||||
|
Please keep in mind cases are reviewed on a per-case basis and members are the ultimate
|
||||||
|
deciding factor in the type of punishment.
|
||||||
|
|
||||||
|
If the matter would benefit from an outside opinion, a member might reach for more opinions
|
||||||
|
from people unrelated to the organization, however, the final decision regarding the action
|
||||||
|
to be taken is still up to the member.
|
||||||
|
|
||||||
|
For example, if the matter at hand regards a representative of a marginalized group or minority,
|
||||||
|
the member might ask for a first-hand opinion from another representative of such group.
|
||||||
|
|
||||||
|
### Correction/Edit
|
||||||
|
|
||||||
|
If your message is found to be misleading or poorly worded, a member might
|
||||||
|
edit your message.
|
||||||
|
|
||||||
|
### Warning/Deletion
|
||||||
|
|
||||||
|
If your message is found inappropriate, a member might give you a public or private warning,
|
||||||
|
and/or delete your message.
|
||||||
|
|
||||||
|
### Mute
|
||||||
|
|
||||||
|
If your message is disruptive, or you have been repeatedly violating the standards,
|
||||||
|
a member might mute (or temporarily ban) you.
|
||||||
|
|
||||||
|
### Ban
|
||||||
|
|
||||||
|
If your message is hateful, very disruptive, or other, less serious infractions are repeated
|
||||||
|
ignoring previous punishments, a member might ban you permanently.
|
||||||
|
|
||||||
|
## Scope
|
||||||
|
|
||||||
|
This CoC shall apply to all projects ran under the `hyprwm` organization and all _official_ communities
|
||||||
|
outside of GitHub.
|
||||||
|
|
||||||
|
However, it is worth noting that official communities outside of GitHub might have their own,
|
||||||
|
additional sets of rules.
|
||||||
2
LICENSE
2
LICENSE
@@ -1,6 +1,6 @@
|
|||||||
BSD 3-Clause License
|
BSD 3-Clause License
|
||||||
|
|
||||||
Copyright (c) 2022, vaxerski
|
Copyright (c) 2022-2023, 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
|
||||||
|
|||||||
204
Makefile
204
Makefile
@@ -1,187 +1,89 @@
|
|||||||
include config.mk
|
PREFIX = /usr/local
|
||||||
|
|
||||||
CFLAGS += -I. -DWLR_USE_UNSTABLE -std=c99
|
|
||||||
|
|
||||||
WAYLAND_PROTOCOLS=$(shell pkg-config --variable=pkgdatadir wayland-protocols)
|
|
||||||
WAYLAND_SCANNER=$(shell pkg-config --variable=wayland_scanner wayland-scanner)
|
|
||||||
|
|
||||||
PKGS = wlroots wayland-server xcb xkbcommon libinput
|
|
||||||
CFLAGS += $(foreach p,$(PKGS),$(shell pkg-config --cflags $(p)))
|
|
||||||
LDLIBS += $(foreach p,$(PKGS),$(shell pkg-config --libs $(p)))
|
|
||||||
|
|
||||||
DATE=$(shell date "+%d %b %Y")
|
|
||||||
|
|
||||||
xdg-shell-protocol.h:
|
|
||||||
$(WAYLAND_SCANNER) server-header \
|
|
||||||
$(WAYLAND_PROTOCOLS)/stable/xdg-shell/xdg-shell.xml $@
|
|
||||||
|
|
||||||
xdg-shell-protocol.c:
|
|
||||||
$(WAYLAND_SCANNER) private-code \
|
|
||||||
$(WAYLAND_PROTOCOLS)/stable/xdg-shell/xdg-shell.xml $@
|
|
||||||
|
|
||||||
xdg-shell-protocol.o: xdg-shell-protocol.h
|
|
||||||
|
|
||||||
wlr-layer-shell-unstable-v1-protocol.h:
|
|
||||||
$(WAYLAND_SCANNER) server-header \
|
|
||||||
protocols/wlr-layer-shell-unstable-v1.xml $@
|
|
||||||
|
|
||||||
wlr-layer-shell-unstable-v1-protocol.c:
|
|
||||||
$(WAYLAND_SCANNER) private-code \
|
|
||||||
protocols/wlr-layer-shell-unstable-v1.xml $@
|
|
||||||
|
|
||||||
wlr-layer-shell-unstable-v1-protocol.o: wlr-layer-shell-unstable-v1-protocol.h
|
|
||||||
|
|
||||||
wlr-screencopy-unstable-v1-protocol.h:
|
|
||||||
$(WAYLAND_SCANNER) server-header \
|
|
||||||
protocols/wlr-screencopy-unstable-v1.xml $@
|
|
||||||
|
|
||||||
wlr-screencopy-unstable-v1-protocol.c:
|
|
||||||
$(WAYLAND_SCANNER) private-code \
|
|
||||||
protocols/wlr-screencopy-unstable-v1.xml $@
|
|
||||||
|
|
||||||
wlr-screencopy-unstable-v1-protocol.o: wlr-screencopy-unstable-v1-protocol.h
|
|
||||||
|
|
||||||
ext-workspace-unstable-v1-protocol.h:
|
|
||||||
$(WAYLAND_SCANNER) server-header \
|
|
||||||
protocols/ext-workspace-unstable-v1.xml $@
|
|
||||||
|
|
||||||
ext-workspace-unstable-v1-protocol.c:
|
|
||||||
$(WAYLAND_SCANNER) private-code \
|
|
||||||
protocols/ext-workspace-unstable-v1.xml $@
|
|
||||||
|
|
||||||
ext-workspace-unstable-v1-protocol.o: ext-workspace-unstable-v1-protocol.h
|
|
||||||
|
|
||||||
pointer-constraints-unstable-v1-protocol.h:
|
|
||||||
$(WAYLAND_SCANNER) server-header \
|
|
||||||
protocols/pointer-constraints-unstable-v1.xml $@
|
|
||||||
|
|
||||||
pointer-constraints-unstable-v1-protocol.c:
|
|
||||||
$(WAYLAND_SCANNER) private-code \
|
|
||||||
protocols/pointer-constraints-unstable-v1.xml $@
|
|
||||||
|
|
||||||
pointer-constraints-unstable-v1-protocol.o: pointer-constraints-unstable-v1-protocol.h
|
|
||||||
|
|
||||||
tablet-unstable-v2-protocol.h:
|
|
||||||
$(WAYLAND_SCANNER) server-header \
|
|
||||||
protocols/tablet-unstable-v2.xml $@
|
|
||||||
|
|
||||||
tablet-unstable-v2-protocol.c:
|
|
||||||
$(WAYLAND_SCANNER) private-code \
|
|
||||||
protocols/tablet-unstable-v2.xml $@
|
|
||||||
|
|
||||||
tablet-unstable-v2-protocol.o: tablet-unstable-v2-protocol.h
|
|
||||||
|
|
||||||
idle-protocol.h:
|
|
||||||
$(WAYLAND_SCANNER) server-header \
|
|
||||||
protocols/idle.xml $@
|
|
||||||
|
|
||||||
idle-protocol.c:
|
|
||||||
$(WAYLAND_SCANNER) private-code \
|
|
||||||
protocols/idle.xml $@
|
|
||||||
|
|
||||||
idle-protocol.o: idle-protocol.h
|
|
||||||
|
|
||||||
wlr-output-power-management-unstable-v1-protocol.h:
|
|
||||||
$(WAYLAND_SCANNER) server-header \
|
|
||||||
protocols/wlr-output-power-management-unstable-v1.xml $@
|
|
||||||
|
|
||||||
wlr-output-power-management-unstable-v1-protocol.c:
|
|
||||||
$(WAYLAND_SCANNER) private-code \
|
|
||||||
protocols/wlr-output-power-management-unstable-v1.xml $@
|
|
||||||
|
|
||||||
wlr-output-power-management-unstable-v1-protocol.o: wlr-output-power-management-unstable-v1-protocol.h
|
|
||||||
|
|
||||||
legacyrenderer:
|
legacyrenderer:
|
||||||
mkdir -p build && cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DLEGACY_RENDERER:STRING=true -H./ -B./build -G Ninja
|
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DLEGACY_RENDERER:BOOL=true -S . -B ./build -G Ninja
|
||||||
cmake --build ./build --config Release --target all -j$(shell nproc)
|
cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
|
||||||
|
chmod -R 777 ./build
|
||||||
|
|
||||||
legacyrendererdebug:
|
legacyrendererdebug:
|
||||||
mkdir -p build && cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Debug -DLEGACY_RENDERER:STRING=true -H./ -B./build -G Ninja
|
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Debug -DLEGACY_RENDERER:BOOL=true -S . -B ./build -G Ninja
|
||||||
cmake --build ./build --config Release --target all -j$(shell nproc)
|
cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
|
||||||
|
chmod -R 777 ./build
|
||||||
|
|
||||||
release:
|
release:
|
||||||
mkdir -p build && cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -H./ -B./build -G Ninja
|
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -S . -B ./build -G Ninja
|
||||||
cmake --build ./build --config Release --target all -j$(shell nproc)
|
cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
|
||||||
|
chmod -R 777 ./build
|
||||||
|
|
||||||
debug:
|
debug:
|
||||||
mkdir -p build && cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Debug -H./ -B./build -G Ninja
|
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Debug -S . -B ./build -G Ninja
|
||||||
cmake --build ./build --config Debug --target all -j$(shell nproc)
|
cmake --build ./build --config Debug --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
|
||||||
|
chmod -R 777 ./build
|
||||||
|
|
||||||
clear:
|
clear:
|
||||||
rm -rf build
|
rm -rf build
|
||||||
rm -f *.o *-protocol.h *-protocol.c
|
rm -f ./protocols/*-protocol.h ./protocols/*-protocol.c
|
||||||
rm -f ./hyprctl/hyprctl
|
|
||||||
rm -rf ./subprojects/wlroots/build
|
rm -rf ./subprojects/wlroots/build
|
||||||
|
|
||||||
all:
|
all:
|
||||||
make config
|
@if [[ "$EUID" = 0 ]]; then echo -en "Avoid running $(MAKE) all as sudo.\n"; fi
|
||||||
make release
|
$(MAKE) clear
|
||||||
cd ./hyprctl && make all && cd ..
|
$(MAKE) release
|
||||||
|
|
||||||
install:
|
install:
|
||||||
make clear
|
@if [ ! -f ./build/Hyprland ]; then echo -en "You need to run $(MAKE) all first.\n" && exit 1; fi
|
||||||
make fixwlr
|
@echo -en "!NOTE: Please note make install does not compile Hyprland and only installs the already built files."
|
||||||
cd ./subprojects/wlroots && meson build/ --buildtype=release && ninja -C build/ && cp ./build/libwlroots.so.11032 /usr/lib/ && cd ../..
|
|
||||||
make protocols
|
|
||||||
make release
|
|
||||||
cd hyprctl && make all && cd ..
|
|
||||||
|
|
||||||
mkdir -p /usr/share/wayland-sessions
|
mkdir -p ${PREFIX}/share/wayland-sessions
|
||||||
cp ./example/hyprland.desktop /usr/share/wayland-sessions/
|
|
||||||
mkdir -p ${PREFIX}/bin
|
mkdir -p ${PREFIX}/bin
|
||||||
cp ./build/Hyprland ${PREFIX}/bin
|
cp -f ./build/Hyprland ${PREFIX}/bin
|
||||||
cp ./hyprctl/hyprctl ${PREFIX}/bin
|
cp -f ./build/hyprctl/hyprctl ${PREFIX}/bin
|
||||||
|
chmod 755 ${PREFIX}/bin/Hyprland
|
||||||
|
chmod 755 ${PREFIX}/bin/hyprctl
|
||||||
|
if [ ! -f ${PREFIX}/share/wayland-sessions/hyprland.desktop ]; then cp ./example/hyprland.desktop ${PREFIX}/share/wayland-sessions; fi
|
||||||
mkdir -p ${PREFIX}/share/hyprland
|
mkdir -p ${PREFIX}/share/hyprland
|
||||||
cp ./assets/wall_2K.png ${PREFIX}/share/hyprland
|
cp ./assets/wall_* ${PREFIX}/share/hyprland
|
||||||
cp ./assets/wall_4K.png ${PREFIX}/share/hyprland
|
mkdir -p ${PREFIX}/share/xdg-desktop-portal
|
||||||
cp ./assets/wall_8K.png ${PREFIX}/share/hyprland
|
cp ./assets/hyprland-portals.conf ${PREFIX}/share/xdg-desktop-portal
|
||||||
|
|
||||||
install -Dm644 -t ${PREFIX}/share/man/man1 ./docs/*.1
|
mkdir -p ${PREFIX}/share/man/man1
|
||||||
|
install -m644 ./docs/*.1 ${PREFIX}/share/man/man1
|
||||||
|
|
||||||
cleaninstall:
|
mkdir -p ${PREFIX}/lib/
|
||||||
make clear
|
cp ./subprojects/wlroots/build/libwlroots.so.13032 ${PREFIX}/lib/
|
||||||
make fixwlr
|
|
||||||
cd ./subprojects/wlroots && meson build/ --buildtype=release && ninja -C build/ && cp ./build/libwlroots.so.11032 /usr/lib/ && cd ../..
|
|
||||||
make protocols
|
|
||||||
make release
|
|
||||||
cd hyprctl && make all && cd ..
|
|
||||||
|
|
||||||
mkdir -p /usr/share/wayland-sessions
|
$(MAKE) installheaders
|
||||||
mkdir -p ${PREFIX}/bin
|
|
||||||
cp ./build/Hyprland ${PREFIX}/bin
|
|
||||||
cp ./hyprctl/hyprctl ${PREFIX}/bin
|
|
||||||
mkdir -p ${PREFIX}/share/hyprland
|
|
||||||
cp ./assets/wall_2K.png ${PREFIX}/share/hyprland
|
|
||||||
cp ./assets/wall_4K.png ${PREFIX}/share/hyprland
|
|
||||||
cp ./assets/wall_8K.png ${PREFIX}/share/hyprland
|
|
||||||
|
|
||||||
install -Dm644 -t ${PREFIX}/share/man/man1 ./docs/*.1
|
|
||||||
|
|
||||||
uninstall:
|
uninstall:
|
||||||
rm -f ${PREFIX}/share/wayland-sessions/hyprland.desktop
|
rm -f ${PREFIX}/share/wayland-sessions/hyprland.desktop
|
||||||
rm -f ${PREFIX}/bin/Hyprland
|
rm -f ${PREFIX}/bin/Hyprland
|
||||||
rm -f ${PREFIX}/bin/hyprctl
|
rm -f ${PREFIX}/bin/hyprctl
|
||||||
rm -f /usr/lib/libwlroots.so.11032
|
rm -f ${PREFIX}/lib/libwlroots.so.13032
|
||||||
rm -rf ${PREFIX}/share/hyprland
|
rm -rf ${PREFIX}/share/hyprland
|
||||||
rm -f ${PREFIX}/share/man/man1/Hyprland.1
|
rm -f ${PREFIX}/share/man/man1/Hyprland.1
|
||||||
rm -f ${PREFIX}/share/man/man1/hyprctl.1
|
rm -f ${PREFIX}/share/man/man1/hyprctl.1
|
||||||
|
|
||||||
protocols: xdg-shell-protocol.o wlr-layer-shell-unstable-v1-protocol.o wlr-screencopy-unstable-v1-protocol.o idle-protocol.o ext-workspace-unstable-v1-protocol.o pointer-constraints-unstable-v1-protocol.o tablet-unstable-v2-protocol.o wlr-output-power-management-unstable-v1-protocol.o
|
pluginenv:
|
||||||
|
@echo -en "$(MAKE) pluginenv has been deprecated.\nPlease run $(MAKE) all && sudo $(MAKE) installheaders\n"
|
||||||
|
@exit 1
|
||||||
|
|
||||||
|
installheaders:
|
||||||
|
@if [ ! -f ./src/version.h ]; then echo -en "You need to run $(MAKE) all first.\n" && exit 1; fi
|
||||||
|
|
||||||
fixwlr:
|
mkdir -p ${PREFIX}/include/hyprland
|
||||||
sed -i -E 's/(soversion = 11)([^032]|$$)/soversion = 11032/g' subprojects/wlroots/meson.build
|
mkdir -p ${PREFIX}/include/hyprland/protocols
|
||||||
|
mkdir -p ${PREFIX}/include/hyprland/wlroots
|
||||||
|
mkdir -p ${PREFIX}/share/pkgconfig
|
||||||
|
|
||||||
|
find src -name '*.h*' -print0 | cpio --quiet -0dump ${PREFIX}/include/hyprland
|
||||||
|
cd subprojects/wlroots/include && find . -name '*.h*' -print0 | cpio --quiet -0dump ${PREFIX}/include/hyprland/wlroots && cd ../../..
|
||||||
|
cd subprojects/wlroots/build/include && find . -name '*.h*' -print0 | cpio --quiet -0dump ${PREFIX}/include/hyprland/wlroots && cd ../../../..
|
||||||
|
cp ./protocols/*-protocol.h ${PREFIX}/include/hyprland/protocols
|
||||||
|
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
|
||||||
|
|
||||||
rm -rf ./subprojects/wlroots/build
|
chmod -R 755 ${PREFIX}/include/hyprland
|
||||||
|
chmod 755 ${PREFIX}/share/pkgconfig
|
||||||
config:
|
|
||||||
make protocols
|
|
||||||
|
|
||||||
make fixwlr
|
|
||||||
|
|
||||||
cd subprojects/wlroots && meson ./build --prefix=/usr --buildtype=release
|
|
||||||
cd subprojects/wlroots && ninja -C build/
|
|
||||||
|
|
||||||
cd subprojects/wlroots && ninja -C build/ install
|
|
||||||
|
|
||||||
man:
|
man:
|
||||||
pandoc ./docs/Hyprland.1.rst \
|
pandoc ./docs/Hyprland.1.rst \
|
||||||
|
|||||||
60
README.md
60
README.md
@@ -6,7 +6,6 @@
|
|||||||
|
|
||||||
![Badge Workflow]
|
![Badge Workflow]
|
||||||
[![Badge License]][License]
|
[![Badge License]][License]
|
||||||
![Badge Lines]
|
|
||||||
![Badge Language]
|
![Badge Language]
|
||||||
[![Badge Pull Requests]][Pull Requests]
|
[![Badge Pull Requests]][Pull Requests]
|
||||||
[![Badge Issues]][Issues]
|
[![Badge Issues]][Issues]
|
||||||
@@ -17,7 +16,8 @@
|
|||||||
|
|
||||||
Hyprland is a dynamic tiling Wayland compositor based on wlroots that doesn't sacrifice on its looks.
|
Hyprland is a dynamic tiling Wayland compositor based on wlroots that doesn't sacrifice on its looks.
|
||||||
|
|
||||||
It supports multiple layouts, fancy effects, has a very flexible IPC model allowing for a lot of customization, and more.
|
It provides the latest Wayland features, is highly customizable, has all the eyecandy, the most powerful plugins,
|
||||||
|
easy IPC, much more QoL stuff than other wlr-based compositors and more...
|
||||||
<br>
|
<br>
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
@@ -33,42 +33,29 @@ It supports multiple layouts, fancy effects, has a very flexible IPC model allow
|
|||||||
<br>
|
<br>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
# Notice
|
|
||||||
|
|
||||||
Hyprland is still in pretty early development compared to some other Wayland compositors.
|
|
||||||
|
|
||||||
Although Hyprland is pretty stable, it may have some bugs.
|
|
||||||
|
|
||||||
### Help Wanted
|
|
||||||
|
|
||||||
Hyprland needs testers! <br/>
|
|
||||||
Try it out and report bugs / suggestions!
|
|
||||||
|
|
||||||
# Features
|
# Features
|
||||||
|
|
||||||
|
- All of the eyecandy: gradient borders, blur, animations, shadows and much more
|
||||||
|
- A lot of customization
|
||||||
|
- Much more QoL stuff than other wlr-based compositors
|
||||||
|
- Custom bezier curves for the best animations
|
||||||
|
- Powerful plugin support
|
||||||
|
- Tearing support for better gaming performance
|
||||||
- Easily expandable and readable codebase
|
- Easily expandable and readable codebase
|
||||||
|
- Fast and active development
|
||||||
|
- Not scared to provide bleeding-edge features
|
||||||
- Config reloaded instantly upon saving
|
- Config reloaded instantly upon saving
|
||||||
- Custom bezier curve based animations
|
|
||||||
- `wlr_ext` workspaces protocol support
|
|
||||||
- Dual Kawase blur
|
|
||||||
- Drop shadows
|
|
||||||
- Fully dynamic workspaces
|
- Fully dynamic workspaces
|
||||||
|
- Two built-in layouts and more available as plugins
|
||||||
- Closely follows `wlroots-git`
|
- Closely follows `wlroots-git`
|
||||||
- Global keybinds passed to your apps of choice
|
- Global keybinds passed to your apps of choice
|
||||||
- Bundled wlroots
|
|
||||||
- Window/layer fade in/out
|
|
||||||
- Tiling/pseudotiling/floating/fullscreen windows
|
- Tiling/pseudotiling/floating/fullscreen windows
|
||||||
- Switching workspaces between window modes on the fly
|
- Special workspaces (scratchpads)
|
||||||
- Special workspace (scratchpad)
|
- Window groups (tabbed mode)
|
||||||
- Window/monitor rules
|
- Powerful window/monitor/layer rules
|
||||||
- Socket-based IPC
|
- Socket-based IPC
|
||||||
- Event system for bash scripts
|
- Native IME and Input Panels Support
|
||||||
- Rounded corners
|
|
||||||
- Full damage tracking
|
|
||||||
- Docks support
|
|
||||||
- Drawing tablet support
|
|
||||||
- Native IME + Input panels support
|
|
||||||
- and much more...
|
- and much more...
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
@@ -93,15 +80,6 @@ Try it out and report bugs / suggestions!
|
|||||||
<br>
|
<br>
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
# Stars Over Time
|
|
||||||
|
|
||||||
<br>
|
|
||||||
|
|
||||||
[![Stars Preview]][Stars]
|
|
||||||
|
|
||||||
<br>
|
|
||||||
<br>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
# Special Thanks
|
# Special Thanks
|
||||||
@@ -134,7 +112,7 @@ Try it out and report bugs / suggestions!
|
|||||||
|
|
||||||
[Contribute]: https://wiki.hyprland.org/Contributing-and-Debugging/
|
[Contribute]: https://wiki.hyprland.org/Contributing-and-Debugging/
|
||||||
[Install]: https://wiki.hyprland.org/Getting-Started/Installation/
|
[Install]: https://wiki.hyprland.org/Getting-Started/Installation/
|
||||||
[Quick Start]: https://wiki.hyprland.org/Getting-Started/Quick-start/
|
[Quick Start]: https://wiki.hyprland.org/Getting-Started/Master-Tutorial/
|
||||||
[License]: LICENSE
|
[License]: LICENSE
|
||||||
|
|
||||||
|
|
||||||
@@ -150,9 +128,9 @@ Try it out and report bugs / suggestions!
|
|||||||
<!----------------------------------{ Images }--------------------------------->
|
<!----------------------------------{ Images }--------------------------------->
|
||||||
|
|
||||||
[Stars Preview]: https://starchart.cc/vaxerski/Hyprland.svg
|
[Stars Preview]: https://starchart.cc/vaxerski/Hyprland.svg
|
||||||
[Preview A]: https://i.imgur.com/pC6YF1Y.png
|
[Preview A]: https://i.ibb.co/C1yTb0r/falf.png
|
||||||
[Preview B]: https://i.imgur.com/NbrTnZH.png
|
[Preview B]: https://cdn.discordapp.com/attachments/1091569872535814185/1107675866101723277/screenshot-summer.png
|
||||||
[Preview C]: https://i.imgur.com/sCafdKQ.png
|
[Preview C]: https://i.ibb.co/B3GJg28/20221126-20h53m26s-grim.png
|
||||||
|
|
||||||
|
|
||||||
<!----------------------------------{ Badges }--------------------------------->
|
<!----------------------------------{ Badges }--------------------------------->
|
||||||
|
|||||||
2
assets/hyprland-portals.conf
Normal file
2
assets/hyprland-portals.conf
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
[preferred]
|
||||||
|
default=hyprland;gtk
|
||||||
@@ -1,5 +1,9 @@
|
|||||||
wallpapers = ['wall_2K.png', 'wall_4K.png', 'wall_8K.png']
|
wallpaper_types = ['', 'anime_', 'anime2_']
|
||||||
|
|
||||||
foreach wallpaper : wallpapers
|
foreach type : wallpaper_types
|
||||||
install_data(wallpapers, install_dir: join_paths(get_option('datadir'), 'hyprland'), install_tag: 'runtime')
|
foreach size : [2, 4, 8]
|
||||||
|
install_data(f'wall_@type@@size@K.png', install_dir: join_paths(get_option('datadir'), 'hyprland'), install_tag: 'runtime')
|
||||||
|
endforeach
|
||||||
endforeach
|
endforeach
|
||||||
|
|
||||||
|
install_data('hyprland-portals.conf', install_dir: join_paths(get_option('datadir'), 'xdg-desktop-portal'), install_tag: 'runtime')
|
||||||
|
|||||||
BIN
assets/wall_anime2_2K.png
Normal file
BIN
assets/wall_anime2_2K.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 511 KiB |
BIN
assets/wall_anime2_4K.png
Normal file
BIN
assets/wall_anime2_4K.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.3 MiB |
BIN
assets/wall_anime2_8K.png
Normal file
BIN
assets/wall_anime2_8K.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.3 MiB |
BIN
assets/wall_anime_2K.png
Normal file
BIN
assets/wall_anime_2K.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 502 KiB |
BIN
assets/wall_anime_4K.png
Normal file
BIN
assets/wall_anime_4K.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.4 MiB |
BIN
assets/wall_anime_8K.png
Normal file
BIN
assets/wall_anime_8K.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.6 MiB |
@@ -1,4 +0,0 @@
|
|||||||
PREFIX = /usr/local
|
|
||||||
CFLAGS ?= -g -Wall -Wextra -Werror -Wno-unused-parameter -Wno-sign-compare -Wno-unused-function -Wno-unused-variable -Wno-unused-result -Wdeclaration-after-statement
|
|
||||||
CFLAGS += -DXWAYLAND
|
|
||||||
|
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
.\" Automatically generated by Pandoc 2.5
|
.\" Automatically generated by Pandoc 2.9.2.1
|
||||||
.\"
|
.\"
|
||||||
.TH "Hyprland" "1" "11 Oct 2022" "" "Hyprland User Manual"
|
.TH "Hyprland" "1" "" "" "Hyprland User Manual"
|
||||||
.hy
|
.hy
|
||||||
.SH NAME
|
.SH NAME
|
||||||
.PP
|
.PP
|
||||||
Hyprland \- Dynamic tiling Wayland compositor
|
Hyprland - Dynamic tiling Wayland compositor
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
.PP
|
.PP
|
||||||
\f[B]Hyprland\f[R] [\f[I]arg [...]\f[R]].
|
\f[B]Hyprland\f[R] [\f[I]arg [...]\f[R]].
|
||||||
@@ -27,14 +27,14 @@ For configuration information please see
|
|||||||
<\f[I]https://github.com/hyprwm/Hyprland/wiki\f[R]>.
|
<\f[I]https://github.com/hyprwm/Hyprland/wiki\f[R]>.
|
||||||
.SH OPTIONS
|
.SH OPTIONS
|
||||||
.TP
|
.TP
|
||||||
.B \f[B]\-h\f[R], \f[B]\-\-help\f[R]
|
\f[B]-h\f[R], \f[B]--help\f[R]
|
||||||
Show command usage.
|
Show command usage.
|
||||||
.TP
|
.TP
|
||||||
.B \f[B]\-c\f[R], \f[B]\-\-config\f[R]
|
\f[B]-c\f[R], \f[B]--config\f[R]
|
||||||
Specify config file to use.
|
Specify config file to use.
|
||||||
.SH BUGS
|
.SH BUGS
|
||||||
.TP
|
.TP
|
||||||
.B Submit bug reports and request features online at:
|
Submit bug reports and request features online at:
|
||||||
<\f[I]https://github.com/hyprwm/Hyprland/issues\f[R]>
|
<\f[I]https://github.com/hyprwm/Hyprland/issues\f[R]>
|
||||||
.SH SEE ALSO
|
.SH SEE ALSO
|
||||||
.PP
|
.PP
|
||||||
|
|||||||
@@ -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://github.com/vaxerski/Hyprland/wiki/FAQ)
|
- Read the [FAQ](https://wiki.hyprland.org/FAQ/)
|
||||||
- Read the [Configuring Page](https://github.com/vaxerski/Hyprland/wiki/Configuring-Hyprland)
|
- Read the [Configuring Page](https://wiki.hyprland.org/Configuring/Configuring-Hyprland)
|
||||||
|
|
||||||
<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://github.com/vaxerski/Hyprland/wiki/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.hyprland.org/IPC). Please do not suggest features that can be implemented as such.
|
||||||
|
|
||||||
<br/>
|
<br/>
|
||||||
|
|
||||||
@@ -25,8 +25,9 @@ If your bug is one that doesn't crash Hyprland, but feels like invalid behavior,
|
|||||||
|
|
||||||
If your bug crashes Hyprland, append additionally:
|
If your bug crashes Hyprland, append additionally:
|
||||||
- The Hyprland log
|
- The Hyprland log
|
||||||
- Coredump / Coredump analysis (with a stacktrace)
|
|
||||||
- Your config
|
- Your config
|
||||||
|
- (v0.22.0beta and up) The Hyprland Crash Report
|
||||||
|
- (v0.21.0beta and below) Coredump / Coredump analysis (with a stacktrace)
|
||||||
|
|
||||||
**Important**: Please do NOT use any package for reporting bugs! Clone and compile from source.
|
**Important**: Please do NOT use any package for reporting bugs! Clone and compile from source.
|
||||||
|
|
||||||
@@ -44,7 +45,14 @@ cat /tmp/hypr/$(ls -t /tmp/hypr/ | head -n 2 | tail -n 1)/hyprland.log
|
|||||||
|
|
||||||
basically, directories in /tmp/hypr are your sessions.
|
basically, directories in /tmp/hypr are your sessions.
|
||||||
|
|
||||||
## Obtaining the Hyprland coredump
|
## Obtaining the Hyprland Crash Report (v0.22.0beta and up)
|
||||||
|
|
||||||
|
If you have `$XDG_CACHE_HOME` set, the crash report directory is `$XDG_CACHE_HOME/hyprland`. If not, it's `~/.hyprland`
|
||||||
|
|
||||||
|
Go to the crash report directory and you should find a file named `hyprlandCrashReport[XXXX].txt` where `[XXXX]` is the PID of the process that crashed.
|
||||||
|
|
||||||
|
Attach that file to your issue.
|
||||||
|
## Obtaining the Hyprland coredump (v0.21.0beta and below)
|
||||||
If you are on systemd, you can simply use
|
If you are on systemd, you can simply use
|
||||||
```
|
```
|
||||||
coredumpctl
|
coredumpctl
|
||||||
@@ -58,14 +66,15 @@ coredumpctl info [PID]
|
|||||||
where `[PID]` is the PID you remembered.
|
where `[PID]` is the PID you remembered.
|
||||||
|
|
||||||
## Obtaining the debug Hyprland coredump
|
## Obtaining the debug Hyprland coredump
|
||||||
In very rare cases, the normal coredump would not be enough.
|
A debug coredump provides more information for debugging and may speed up the process of fixing the bug.
|
||||||
If that's the case, you could try obtaining the debug coredump.
|
|
||||||
|
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.hyprland.org/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. Reproduce the crash in debug mode.
|
2. `cd ~`
|
||||||
3. `env DEBUGINFOD_URLS="https://debuginfod.archlinux.org/" coredumpctl debug [PID]`(see section above)
|
3. For your own convenience, launch Hyprland from a tty with the envvar `ASAN_OPTIONS="log_path=asan.log" ~/path/to/Hyprland`
|
||||||
4. Wait until the `(gdb)` appears
|
4. Reproduce the crash. Hyprland should instantly close.
|
||||||
5. If gdb asks you `press y to continue without paging?` Type `y`
|
5. Check out your `~` and find a file called `asan.log.XXXXX` where `XXXXX` will be a number corresponding to the PID of the Hyprland instance that crashed.
|
||||||
6. `bt -full`
|
6. That is your coredump. Attach it to your issue.
|
||||||
7. copy the output of the command and provide that.
|
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
.\" Automatically generated by Pandoc 2.5
|
.\" Automatically generated by Pandoc 2.9.2.1
|
||||||
.\"
|
.\"
|
||||||
.TH "hyprctl" "1" "11 Oct 2022" "" "hyprctl User Manual"
|
.TH "hyprctl" "1" "" "" "hyprctl User Manual"
|
||||||
.hy
|
.hy
|
||||||
.SH NAME
|
.SH NAME
|
||||||
.PP
|
.PP
|
||||||
hyprctl \- Utility for controlling parts of Hyprland from a CLI or a
|
hyprctl - Utility for controlling parts of Hyprland from a CLI or a
|
||||||
script
|
script
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
.PP
|
.PP
|
||||||
@@ -26,7 +26,7 @@ For dispatchers without parameters it can be anything.
|
|||||||
.PP
|
.PP
|
||||||
Returns: \f[I]ok\f[R] on success, and an error message on failure.
|
Returns: \f[I]ok\f[R] on success, and an error message on failure.
|
||||||
.TP
|
.TP
|
||||||
.B Examples:
|
Examples:
|
||||||
\f[B]hyprctl\f[R] \f[I]dispatch exec kitty\f[R]
|
\f[B]hyprctl\f[R] \f[I]dispatch exec kitty\f[R]
|
||||||
.RS
|
.RS
|
||||||
.PP
|
.PP
|
||||||
@@ -41,7 +41,7 @@ Set a config keyword dynamically.
|
|||||||
.PP
|
.PP
|
||||||
Returns: \f[I]ok\f[R] on success, and an error message on failure.
|
Returns: \f[I]ok\f[R] on success, and an error message on failure.
|
||||||
.TP
|
.TP
|
||||||
.B Examples:
|
Examples:
|
||||||
\f[B]hyprctl\f[R] \f[I]keyword bind SUPER,0,pseudo\f[R]
|
\f[B]hyprctl\f[R] \f[I]keyword bind SUPER,0,pseudo\f[R]
|
||||||
.RS
|
.RS
|
||||||
.PP
|
.PP
|
||||||
@@ -112,13 +112,13 @@ Returns the current random splash.
|
|||||||
.RE
|
.RE
|
||||||
.SH OPTIONS
|
.SH OPTIONS
|
||||||
.PP
|
.PP
|
||||||
\f[B]\-\-batch\f[R]
|
\f[B]--batch\f[R]
|
||||||
.RS
|
.RS
|
||||||
.PP
|
.PP
|
||||||
Specify a batch of commands to execute.
|
Specify a batch of commands to execute.
|
||||||
.TP
|
.TP
|
||||||
.B Example:
|
Example:
|
||||||
\f[B]hyprctl\f[R] \f[I]\-\-batch \[dq]keyword general:border_size 2 ;
|
\f[B]hyprctl\f[R] \f[I]--batch \[dq]keyword general:border_size 2 ;
|
||||||
keyword general:gaps_out 20\[dq]\f[R]
|
keyword general:gaps_out 20\[dq]\f[R]
|
||||||
.RS
|
.RS
|
||||||
.PP
|
.PP
|
||||||
@@ -126,14 +126,14 @@ keyword general:gaps_out 20\[dq]\f[R]
|
|||||||
.RE
|
.RE
|
||||||
.RE
|
.RE
|
||||||
.PP
|
.PP
|
||||||
\f[B]\-j\f[R]
|
\f[B]-j\f[R]
|
||||||
.RS
|
.RS
|
||||||
.PP
|
.PP
|
||||||
Outputs information in JSON.
|
Outputs information in JSON.
|
||||||
.RE
|
.RE
|
||||||
.SH BUGS
|
.SH BUGS
|
||||||
.TP
|
.TP
|
||||||
.B Submit bug reports and request features online at:
|
Submit bug reports and request features online at:
|
||||||
<\f[I]https://github.com/hyprwm/Hyprland/issues\f[R]>
|
<\f[I]https://github.com/hyprwm/Hyprland/issues\f[R]>
|
||||||
.SH SEE ALSO
|
.SH SEE ALSO
|
||||||
.PP
|
.PP
|
||||||
|
|||||||
8
example/examplePlugin/Makefile
Normal file
8
example/examplePlugin/Makefile
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
# compile with HYPRLAND_HEADERS=<path_to_hl> make all
|
||||||
|
# make sure that the path above is to the root hl repo directory, NOT src/
|
||||||
|
# and that you have ran `make protocols` in the hl dir.
|
||||||
|
|
||||||
|
all:
|
||||||
|
$(CXX) -shared -fPIC --no-gnu-unique main.cpp customLayout.cpp customDecoration.cpp -o examplePlugin.so -g `pkg-config --cflags pixman-1 libdrm hyprland` -std=c++2b
|
||||||
|
clean:
|
||||||
|
rm ./examplePlugin.so
|
||||||
74
example/examplePlugin/customDecoration.cpp
Normal file
74
example/examplePlugin/customDecoration.cpp
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
#include "customDecoration.hpp"
|
||||||
|
#include <hyprland/src/Window.hpp>
|
||||||
|
#include <hyprland/src/Compositor.hpp>
|
||||||
|
#include "globals.hpp"
|
||||||
|
|
||||||
|
CCustomDecoration::CCustomDecoration(CWindow* pWindow) {
|
||||||
|
m_pWindow = pWindow;
|
||||||
|
m_vLastWindowPos = pWindow->m_vRealPosition.vec();
|
||||||
|
m_vLastWindowSize = pWindow->m_vRealSize.vec();
|
||||||
|
}
|
||||||
|
|
||||||
|
CCustomDecoration::~CCustomDecoration() {
|
||||||
|
damageEntire();
|
||||||
|
}
|
||||||
|
|
||||||
|
SWindowDecorationExtents CCustomDecoration::getWindowDecorationExtents() {
|
||||||
|
return m_seExtents;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CCustomDecoration::draw(CMonitor* pMonitor, float a, const Vector2D& offset) {
|
||||||
|
if (!g_pCompositor->windowValidMapped(m_pWindow))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!m_pWindow->m_sSpecialRenderData.decorate)
|
||||||
|
return;
|
||||||
|
|
||||||
|
static auto* const PCOLOR = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:example:border_color")->intValue;
|
||||||
|
static auto* const PROUNDING = &HyprlandAPI::getConfigValue(PHANDLE, "decoration:rounding")->intValue;
|
||||||
|
static auto* const PBORDERSIZE = &HyprlandAPI::getConfigValue(PHANDLE, "general:border_size")->intValue;
|
||||||
|
|
||||||
|
const auto ROUNDING = !m_pWindow->m_sSpecialRenderData.rounding ?
|
||||||
|
0 :
|
||||||
|
(m_pWindow->m_sAdditionalConfigData.rounding.toUnderlying() == -1 ? *PROUNDING : m_pWindow->m_sAdditionalConfigData.rounding.toUnderlying());
|
||||||
|
|
||||||
|
// draw the border
|
||||||
|
CBox fullBox = {(int)(m_vLastWindowPos.x - *PBORDERSIZE), (int)(m_vLastWindowPos.y - *PBORDERSIZE), (int)(m_vLastWindowSize.x + 2.0 * *PBORDERSIZE),
|
||||||
|
(int)(m_vLastWindowSize.y + 2.0 * *PBORDERSIZE)};
|
||||||
|
|
||||||
|
fullBox.x -= pMonitor->vecPosition.x;
|
||||||
|
fullBox.y -= pMonitor->vecPosition.y;
|
||||||
|
|
||||||
|
m_seExtents = {{m_vLastWindowPos.x - fullBox.x - pMonitor->vecPosition.x + 2, m_vLastWindowPos.y - fullBox.y - pMonitor->vecPosition.y + 2},
|
||||||
|
{fullBox.x + fullBox.width + pMonitor->vecPosition.x - m_vLastWindowPos.x - m_vLastWindowSize.x + 2,
|
||||||
|
fullBox.y + fullBox.height + pMonitor->vecPosition.y - m_vLastWindowPos.y - m_vLastWindowSize.y + 2}};
|
||||||
|
|
||||||
|
fullBox.x += offset.x;
|
||||||
|
fullBox.y += offset.y;
|
||||||
|
|
||||||
|
if (fullBox.width < 1 || fullBox.height < 1)
|
||||||
|
return; // don't draw invisible shadows
|
||||||
|
|
||||||
|
g_pHyprOpenGL->scissor((CBox*)nullptr);
|
||||||
|
|
||||||
|
fullBox.scale(pMonitor->scale);
|
||||||
|
g_pHyprOpenGL->renderBorder(&fullBox, CColor(*PCOLOR), *PROUNDING * pMonitor->scale + *PBORDERSIZE * 2, a);
|
||||||
|
}
|
||||||
|
|
||||||
|
eDecorationType CCustomDecoration::getDecorationType() {
|
||||||
|
return DECORATION_CUSTOM;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CCustomDecoration::updateWindow(CWindow* pWindow) {
|
||||||
|
|
||||||
|
m_vLastWindowPos = pWindow->m_vRealPosition.vec();
|
||||||
|
m_vLastWindowSize = pWindow->m_vRealSize.vec();
|
||||||
|
|
||||||
|
damageEntire();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CCustomDecoration::damageEntire() {
|
||||||
|
CBox dm = {(int)(m_vLastWindowPos.x - m_seExtents.topLeft.x), (int)(m_vLastWindowPos.y - m_seExtents.topLeft.y),
|
||||||
|
(int)(m_vLastWindowSize.x + m_seExtents.topLeft.x + m_seExtents.bottomRight.x), (int)m_seExtents.topLeft.y};
|
||||||
|
g_pHyprRenderer->damageBox(&dm);
|
||||||
|
}
|
||||||
29
example/examplePlugin/customDecoration.hpp
Normal file
29
example/examplePlugin/customDecoration.hpp
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define WLR_USE_UNSTABLE
|
||||||
|
|
||||||
|
#include <hyprland/src/render/decorations/IHyprWindowDecoration.hpp>
|
||||||
|
|
||||||
|
class CCustomDecoration : public IHyprWindowDecoration {
|
||||||
|
public:
|
||||||
|
CCustomDecoration(CWindow*);
|
||||||
|
virtual ~CCustomDecoration();
|
||||||
|
|
||||||
|
virtual SWindowDecorationExtents getWindowDecorationExtents();
|
||||||
|
|
||||||
|
virtual void draw(CMonitor*, float a, const Vector2D& offset);
|
||||||
|
|
||||||
|
virtual eDecorationType getDecorationType();
|
||||||
|
|
||||||
|
virtual void updateWindow(CWindow*);
|
||||||
|
|
||||||
|
virtual void damageEntire();
|
||||||
|
|
||||||
|
private:
|
||||||
|
SWindowDecorationExtents m_seExtents;
|
||||||
|
|
||||||
|
CWindow* m_pWindow = nullptr;
|
||||||
|
|
||||||
|
Vector2D m_vLastWindowPos;
|
||||||
|
Vector2D m_vLastWindowSize;
|
||||||
|
};
|
||||||
80
example/examplePlugin/customLayout.cpp
Normal file
80
example/examplePlugin/customLayout.cpp
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
#include "customLayout.hpp"
|
||||||
|
#include <hyprland/src/Compositor.hpp>
|
||||||
|
#include "globals.hpp"
|
||||||
|
|
||||||
|
void CHyprCustomLayout::onWindowCreatedTiling(CWindow* pWindow) {
|
||||||
|
const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID);
|
||||||
|
const auto SIZE = PMONITOR->vecSize;
|
||||||
|
|
||||||
|
// these are used for focus and move calculations, and are *required* to touch for moving focus to work properly.
|
||||||
|
pWindow->m_vPosition = Vector2D{(SIZE.x / 2.0) * (m_vWindowData.size() % 2), (SIZE.y / 2.0) * (int)(m_vWindowData.size() > 1)};
|
||||||
|
pWindow->m_vSize = SIZE / 2.0;
|
||||||
|
|
||||||
|
// this is the actual pos and size of the window (where it's rendered)
|
||||||
|
pWindow->m_vRealPosition = pWindow->m_vPosition + Vector2D{10, 10};
|
||||||
|
pWindow->m_vRealSize = pWindow->m_vSize - Vector2D{20, 20};
|
||||||
|
|
||||||
|
const auto PDATA = &m_vWindowData.emplace_back();
|
||||||
|
PDATA->pWindow = pWindow;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CHyprCustomLayout::onWindowRemovedTiling(CWindow* pWindow) {
|
||||||
|
std::erase_if(m_vWindowData, [&](const auto& other) { return other.pWindow == pWindow; });
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CHyprCustomLayout::isWindowTiled(CWindow* pWindow) {
|
||||||
|
return std::find_if(m_vWindowData.begin(), m_vWindowData.end(), [&](const auto& other) { return other.pWindow == pWindow; }) != m_vWindowData.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CHyprCustomLayout::recalculateMonitor(const int& eIdleInhibitMode) {
|
||||||
|
; // empty
|
||||||
|
}
|
||||||
|
|
||||||
|
void CHyprCustomLayout::recalculateWindow(CWindow* pWindow) {
|
||||||
|
; // empty
|
||||||
|
}
|
||||||
|
|
||||||
|
void CHyprCustomLayout::resizeActiveWindow(const Vector2D& delta, CWindow* pWindow) {
|
||||||
|
; // empty
|
||||||
|
}
|
||||||
|
|
||||||
|
void CHyprCustomLayout::fullscreenRequestForWindow(CWindow* pWindow, eFullscreenMode mode, bool on) {
|
||||||
|
; // empty
|
||||||
|
}
|
||||||
|
|
||||||
|
std::any CHyprCustomLayout::layoutMessage(SLayoutMessageHeader header, std::string content) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
SWindowRenderLayoutHints CHyprCustomLayout::requestRenderHints(CWindow* pWindow) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
void CHyprCustomLayout::switchWindows(CWindow* pWindowA, CWindow* pWindowB) {
|
||||||
|
; // empty
|
||||||
|
}
|
||||||
|
|
||||||
|
void CHyprCustomLayout::alterSplitRatio(CWindow* pWindow, float delta, bool exact) {
|
||||||
|
; // empty
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string CHyprCustomLayout::getLayoutName() {
|
||||||
|
return "custom";
|
||||||
|
}
|
||||||
|
|
||||||
|
void CHyprCustomLayout::replaceWindowDataWith(CWindow* from, CWindow* to) {
|
||||||
|
; // empty
|
||||||
|
}
|
||||||
|
|
||||||
|
void CHyprCustomLayout::onEnable() {
|
||||||
|
for (auto& w : g_pCompositor->m_vWindows) {
|
||||||
|
if (w->isHidden() || !w->m_bIsMapped || w->m_bFadingOut || w->m_bIsFloating)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
onWindowCreatedTiling(w.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CHyprCustomLayout::onDisable() {
|
||||||
|
m_vWindowData.clear();
|
||||||
|
}
|
||||||
32
example/examplePlugin/customLayout.hpp
Normal file
32
example/examplePlugin/customLayout.hpp
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define WLR_USE_UNSTABLE
|
||||||
|
|
||||||
|
#include <hyprland/src/layout/IHyprLayout.hpp>
|
||||||
|
|
||||||
|
struct SWindowData {
|
||||||
|
CWindow* pWindow = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CHyprCustomLayout : public IHyprLayout {
|
||||||
|
public:
|
||||||
|
virtual void onWindowCreatedTiling(CWindow*);
|
||||||
|
virtual void onWindowRemovedTiling(CWindow*);
|
||||||
|
virtual bool isWindowTiled(CWindow*);
|
||||||
|
virtual void recalculateMonitor(const int&);
|
||||||
|
virtual void recalculateWindow(CWindow*);
|
||||||
|
virtual void resizeActiveWindow(const Vector2D&, CWindow* pWindow = nullptr);
|
||||||
|
virtual void fullscreenRequestForWindow(CWindow*, eFullscreenMode, bool);
|
||||||
|
virtual std::any layoutMessage(SLayoutMessageHeader, std::string);
|
||||||
|
virtual SWindowRenderLayoutHints requestRenderHints(CWindow*);
|
||||||
|
virtual void switchWindows(CWindow*, CWindow*);
|
||||||
|
virtual void alterSplitRatio(CWindow*, float, bool);
|
||||||
|
virtual std::string getLayoutName();
|
||||||
|
virtual void replaceWindowDataWith(CWindow* from, CWindow* to);
|
||||||
|
|
||||||
|
virtual void onEnable();
|
||||||
|
virtual void onDisable();
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<SWindowData> m_vWindowData;
|
||||||
|
};
|
||||||
5
example/examplePlugin/globals.hpp
Normal file
5
example/examplePlugin/globals.hpp
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <hyprland/src/plugins/PluginAPI.hpp>
|
||||||
|
|
||||||
|
inline HANDLE PHANDLE = nullptr;
|
||||||
99
example/examplePlugin/main.cpp
Normal file
99
example/examplePlugin/main.cpp
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
#define WLR_USE_UNSTABLE
|
||||||
|
|
||||||
|
#include "globals.hpp"
|
||||||
|
|
||||||
|
#include <hyprland/src/Window.hpp>
|
||||||
|
#include <hyprland/src/Compositor.hpp>
|
||||||
|
#include "customLayout.hpp"
|
||||||
|
#include "customDecoration.hpp"
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
// Methods
|
||||||
|
inline std::unique_ptr<CHyprCustomLayout> g_pCustomLayout;
|
||||||
|
inline CFunctionHook* g_pFocusHook = nullptr;
|
||||||
|
inline CFunctionHook* g_pMotionHook = nullptr;
|
||||||
|
inline CFunctionHook* g_pMouseDownHook = nullptr;
|
||||||
|
typedef void (*origFocusWindow)(void*, CWindow*, wlr_surface*);
|
||||||
|
typedef void (*origMotion)(wlr_seat*, uint32_t, double, double);
|
||||||
|
typedef void (*origMouseDownNormal)(void*, wlr_pointer_button_event*);
|
||||||
|
|
||||||
|
// Do NOT change this function.
|
||||||
|
APICALL EXPORT std::string PLUGIN_API_VERSION() {
|
||||||
|
return HYPRLAND_API_VERSION;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void onActiveWindowChange(void* self, std::any data) {
|
||||||
|
try {
|
||||||
|
auto* const PWINDOW = std::any_cast<CWindow*>(data);
|
||||||
|
|
||||||
|
HyprlandAPI::addNotification(PHANDLE, "[ExamplePlugin] Active window: " + (PWINDOW ? PWINDOW->m_szTitle : "None"), CColor{0.f, 0.5f, 1.f, 1.f}, 5000);
|
||||||
|
} catch (std::bad_any_cast& e) { HyprlandAPI::addNotification(PHANDLE, "[ExamplePlugin] Active window: None", CColor{0.f, 0.5f, 1.f, 1.f}, 5000); }
|
||||||
|
}
|
||||||
|
|
||||||
|
static void onNewWindow(void* self, std::any data) {
|
||||||
|
auto* const PWINDOW = std::any_cast<CWindow*>(data);
|
||||||
|
|
||||||
|
HyprlandAPI::addWindowDecoration(PHANDLE, PWINDOW, new CCustomDecoration(PWINDOW));
|
||||||
|
}
|
||||||
|
|
||||||
|
void hkFocusWindow(void* thisptr, CWindow* pWindow, wlr_surface* pSurface) {
|
||||||
|
// HyprlandAPI::addNotification(PHANDLE, getFormat("FocusWindow with %lx %lx", pWindow, pSurface), CColor{0.f, 1.f, 1.f, 1.f}, 5000);
|
||||||
|
(*(origFocusWindow)g_pFocusHook->m_pOriginal)(thisptr, pWindow, pSurface);
|
||||||
|
}
|
||||||
|
|
||||||
|
void hkNotifyMotion(wlr_seat* wlr_seat, uint32_t time_msec, double sx, double sy) {
|
||||||
|
// HyprlandAPI::addNotification(PHANDLE, getFormat("NotifyMotion with %lf %lf", sx, sy), CColor{0.f, 1.f, 1.f, 1.f}, 5000);
|
||||||
|
(*(origMotion)g_pMotionHook->m_pOriginal)(wlr_seat, time_msec, sx, sy);
|
||||||
|
}
|
||||||
|
|
||||||
|
void hkProcessMouseDownNormal(void* thisptr, wlr_pointer_button_event* e) {
|
||||||
|
// HyprlandAPI::addNotification(PHANDLE, "Mouse down normal!", CColor{0.8f, 0.2f, 0.5f, 1.0f}, 5000);
|
||||||
|
(*(origMouseDownNormal)g_pMouseDownHook->m_pOriginal)(thisptr, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) {
|
||||||
|
PHANDLE = handle;
|
||||||
|
|
||||||
|
HyprlandAPI::addNotification(PHANDLE, "Hello World from an example plugin!", CColor{0.f, 1.f, 1.f, 1.f}, 5000);
|
||||||
|
|
||||||
|
HyprlandAPI::registerCallbackDynamic(PHANDLE, "activeWindow", [&](void* self, SCallbackInfo& info, std::any data) { onActiveWindowChange(self, data); });
|
||||||
|
HyprlandAPI::registerCallbackDynamic(PHANDLE, "openWindow", [&](void* self, SCallbackInfo& info, std::any data) { onNewWindow(self, data); });
|
||||||
|
|
||||||
|
g_pCustomLayout = std::make_unique<CHyprCustomLayout>();
|
||||||
|
|
||||||
|
HyprlandAPI::addLayout(PHANDLE, "custom", g_pCustomLayout.get());
|
||||||
|
|
||||||
|
HyprlandAPI::addConfigValue(PHANDLE, "plugin:example:border_color", SConfigValue{.intValue = configStringToInt("rgb(44ee44)")});
|
||||||
|
|
||||||
|
HyprlandAPI::addDispatcher(PHANDLE, "example", [](std::string arg) { HyprlandAPI::addNotification(PHANDLE, "Arg passed: " + arg, CColor{0.5f, 0.5f, 0.7f, 1.0f}, 5000); });
|
||||||
|
|
||||||
|
// Hook a public member
|
||||||
|
g_pFocusHook = HyprlandAPI::createFunctionHook(PHANDLE, (void*)&CCompositor::focusWindow, (void*)&hkFocusWindow);
|
||||||
|
// Hook a public non-member
|
||||||
|
g_pMotionHook = HyprlandAPI::createFunctionHook(PHANDLE, (void*)&wlr_seat_pointer_notify_motion, (void*)&hkNotifyMotion);
|
||||||
|
// Hook a private member
|
||||||
|
static const auto METHODS = HyprlandAPI::findFunctionsByName(PHANDLE, "processMouseDownNormal");
|
||||||
|
g_pMouseDownHook = HyprlandAPI::createFunctionHook(PHANDLE, METHODS[0].address, (void*)&hkProcessMouseDownNormal);
|
||||||
|
|
||||||
|
static auto* const PBORDERCOLOR = HyprlandAPI::getConfigValue(PHANDLE, "plugin:example:border_color");
|
||||||
|
|
||||||
|
// fancy notifications
|
||||||
|
HyprlandAPI::addNotificationV2(
|
||||||
|
PHANDLE,
|
||||||
|
{{"text", "Example hint, color " + std::to_string(PBORDERCOLOR->intValue)}, {"time", (uint64_t)10000}, {"color", CColor{PBORDERCOLOR->intValue}}, {"icon", ICON_HINT}});
|
||||||
|
|
||||||
|
// Enable our hooks
|
||||||
|
g_pFocusHook->hook();
|
||||||
|
g_pMotionHook->hook();
|
||||||
|
g_pMouseDownHook->hook();
|
||||||
|
|
||||||
|
HyprlandAPI::reloadConfig();
|
||||||
|
|
||||||
|
return {"ExamplePlugin", "An example plugin", "Vaxry", "1.0"};
|
||||||
|
}
|
||||||
|
|
||||||
|
APICALL EXPORT void PLUGIN_EXIT() {
|
||||||
|
HyprlandAPI::invokeHyprctlCommand("seterror", "disable");
|
||||||
|
}
|
||||||
@@ -8,7 +8,7 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
# See https://wiki.hyprland.org/Configuring/Monitors/
|
# See https://wiki.hyprland.org/Configuring/Monitors/
|
||||||
monitor=,preferred,auto,1
|
monitor=,preferred,auto,auto
|
||||||
|
|
||||||
|
|
||||||
# See https://wiki.hyprland.org/Configuring/Keywords/ for more
|
# See https://wiki.hyprland.org/Configuring/Keywords/ for more
|
||||||
@@ -19,6 +19,13 @@ monitor=,preferred,auto,1
|
|||||||
# Source a file (multi-file configs)
|
# Source a file (multi-file configs)
|
||||||
# source = ~/.config/hypr/myColors.conf
|
# source = ~/.config/hypr/myColors.conf
|
||||||
|
|
||||||
|
# Set programs that you use
|
||||||
|
$terminal = kitty
|
||||||
|
$fileManager = dolphin
|
||||||
|
$menu = wofi --show drun
|
||||||
|
# Some default env vars.
|
||||||
|
env = XCURSOR_SIZE,24
|
||||||
|
|
||||||
# For all categories, see https://wiki.hyprland.org/Configuring/Variables/
|
# For all categories, see https://wiki.hyprland.org/Configuring/Variables/
|
||||||
input {
|
input {
|
||||||
kb_layout = us
|
kb_layout = us
|
||||||
@@ -30,7 +37,7 @@ input {
|
|||||||
follow_mouse = 1
|
follow_mouse = 1
|
||||||
|
|
||||||
touchpad {
|
touchpad {
|
||||||
natural_scroll = no
|
natural_scroll = false
|
||||||
}
|
}
|
||||||
|
|
||||||
sensitivity = 0 # -1.0 - 1.0, 0 means no modification.
|
sensitivity = 0 # -1.0 - 1.0, 0 means no modification.
|
||||||
@@ -42,29 +49,36 @@ general {
|
|||||||
gaps_in = 5
|
gaps_in = 5
|
||||||
gaps_out = 20
|
gaps_out = 20
|
||||||
border_size = 2
|
border_size = 2
|
||||||
col.active_border = rgba(1affffee)
|
col.active_border = rgba(33ccffee) rgba(00ff99ee) 45deg
|
||||||
col.inactive_border = rgba(595959aa)
|
col.inactive_border = rgba(595959aa)
|
||||||
|
|
||||||
layout = dwindle
|
layout = dwindle
|
||||||
|
|
||||||
|
# Please see https://wiki.hyprland.org/Configuring/Tearing/ before you turn this on
|
||||||
|
allow_tearing = false
|
||||||
}
|
}
|
||||||
|
|
||||||
decoration {
|
decoration {
|
||||||
# See https://wiki.hyprland.org/Configuring/Variables/ for more
|
# See https://wiki.hyprland.org/Configuring/Variables/ for more
|
||||||
|
|
||||||
rounding = 10
|
rounding = 10
|
||||||
blur = yes
|
|
||||||
blur_size = 3
|
|
||||||
blur_passes = 1
|
|
||||||
blur_new_optimizations = on
|
|
||||||
|
|
||||||
drop_shadow = yes
|
blur {
|
||||||
|
enabled = true
|
||||||
|
size = 3
|
||||||
|
passes = 1
|
||||||
|
|
||||||
|
vibrancy = 0.1696
|
||||||
|
}
|
||||||
|
|
||||||
|
drop_shadow = true
|
||||||
shadow_range = 4
|
shadow_range = 4
|
||||||
shadow_render_power = 3
|
shadow_render_power = 3
|
||||||
col.shadow = rgba(1a1a1aee)
|
col.shadow = rgba(1a1a1aee)
|
||||||
}
|
}
|
||||||
|
|
||||||
animations {
|
animations {
|
||||||
enabled = yes
|
enabled = true
|
||||||
|
|
||||||
# Some default animations, see https://wiki.hyprland.org/Configuring/Animations/ for more
|
# Some default animations, see https://wiki.hyprland.org/Configuring/Animations/ for more
|
||||||
|
|
||||||
@@ -73,14 +87,15 @@ animations {
|
|||||||
animation = windows, 1, 7, myBezier
|
animation = windows, 1, 7, myBezier
|
||||||
animation = windowsOut, 1, 7, default, popin 80%
|
animation = windowsOut, 1, 7, default, popin 80%
|
||||||
animation = border, 1, 10, default
|
animation = border, 1, 10, default
|
||||||
|
animation = borderangle, 1, 8, default
|
||||||
animation = fade, 1, 7, default
|
animation = fade, 1, 7, default
|
||||||
animation = workspaces, 1, 6, default
|
animation = workspaces, 1, 6, default
|
||||||
}
|
}
|
||||||
|
|
||||||
dwindle {
|
dwindle {
|
||||||
# See https://wiki.hyprland.org/Configuring/Dwindle-Layout/ for more
|
# See https://wiki.hyprland.org/Configuring/Dwindle-Layout/ for more
|
||||||
pseudotile = yes # 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 = yes # you probably want this
|
preserve_split = true # you probably want this
|
||||||
}
|
}
|
||||||
|
|
||||||
master {
|
master {
|
||||||
@@ -90,12 +105,17 @@ master {
|
|||||||
|
|
||||||
gestures {
|
gestures {
|
||||||
# See https://wiki.hyprland.org/Configuring/Variables/ for more
|
# See https://wiki.hyprland.org/Configuring/Variables/ for more
|
||||||
workspace_swipe = off
|
workspace_swipe = false
|
||||||
|
}
|
||||||
|
|
||||||
|
misc {
|
||||||
|
# See https://wiki.hyprland.org/Configuring/Variables/ for more
|
||||||
|
force_default_wallpaper = -1 # Set to 0 to disable the anime mascot wallpapers
|
||||||
}
|
}
|
||||||
|
|
||||||
# Example per-device config
|
# Example per-device config
|
||||||
# See https://wiki.hyprland.org/Configuring/Keywords/#executing for more
|
# See https://wiki.hyprland.org/Configuring/Keywords/#per-device-input-configs for more
|
||||||
device:epic mouse V1 {
|
device:epic-mouse-v1 {
|
||||||
sensitivity = -0.5
|
sensitivity = -0.5
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -104,18 +124,19 @@ device:epic mouse V1 {
|
|||||||
# Example windowrule v2
|
# Example windowrule v2
|
||||||
# windowrulev2 = float,class:^(kitty)$,title:^(kitty)$
|
# windowrulev2 = float,class:^(kitty)$,title:^(kitty)$
|
||||||
# See https://wiki.hyprland.org/Configuring/Window-Rules/ for more
|
# See https://wiki.hyprland.org/Configuring/Window-Rules/ for more
|
||||||
|
windowrulev2 = nomaximizerequest, class:.* # You'll probably like this.
|
||||||
|
|
||||||
|
|
||||||
# See https://wiki.hyprland.org/Configuring/Keywords/ for more
|
# See https://wiki.hyprland.org/Configuring/Keywords/ for more
|
||||||
$mainMod = SUPER
|
$mainMod = SUPER
|
||||||
|
|
||||||
# Example binds, see https://wiki.hyprland.org/Configuring/Binds/ for more
|
# Example binds, see https://wiki.hyprland.org/Configuring/Binds/ for more
|
||||||
bind = $mainMod, Q, exec, kitty
|
bind = $mainMod, Q, exec, $terminal
|
||||||
bind = $mainMod, C, killactive,
|
bind = $mainMod, C, killactive,
|
||||||
bind = $mainMod, M, exit,
|
bind = $mainMod, M, exit,
|
||||||
bind = $mainMod, E, exec, dolphin
|
bind = $mainMod, E, exec, $fileManager
|
||||||
bind = $mainMod, V, togglefloating,
|
bind = $mainMod, V, togglefloating,
|
||||||
bind = $mainMod, R, exec, wofi --show drun
|
bind = $mainMod, R, exec, $menu
|
||||||
bind = $mainMod, P, pseudo, # dwindle
|
bind = $mainMod, P, pseudo, # dwindle
|
||||||
bind = $mainMod, J, togglesplit, # dwindle
|
bind = $mainMod, J, togglesplit, # dwindle
|
||||||
|
|
||||||
@@ -149,6 +170,10 @@ bind = $mainMod SHIFT, 8, movetoworkspace, 8
|
|||||||
bind = $mainMod SHIFT, 9, movetoworkspace, 9
|
bind = $mainMod SHIFT, 9, movetoworkspace, 9
|
||||||
bind = $mainMod SHIFT, 0, movetoworkspace, 10
|
bind = $mainMod SHIFT, 0, movetoworkspace, 10
|
||||||
|
|
||||||
|
# Example special workspace (scratchpad)
|
||||||
|
bind = $mainMod, S, togglespecialworkspace, magic
|
||||||
|
bind = $mainMod SHIFT, S, movetoworkspace, special:magic
|
||||||
|
|
||||||
# Scroll through existing workspaces with mainMod + scroll
|
# Scroll through existing workspaces with mainMod + scroll
|
||||||
bind = $mainMod, mouse_down, workspace, e+1
|
bind = $mainMod, mouse_down, workspace, e+1
|
||||||
bind = $mainMod, mouse_up, workspace, e-1
|
bind = $mainMod, mouse_up, workspace, e-1
|
||||||
|
|||||||
12
example/hyprland.service
Normal file
12
example/hyprland.service
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
; a primitive systemd --user example
|
||||||
|
[Unit]
|
||||||
|
Description = %p
|
||||||
|
BindsTo = graphical-session.target
|
||||||
|
Upholds = swaybg@333333.service
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type = notify
|
||||||
|
ExecStart = /usr/bin/Hyprland
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy = default.target
|
||||||
16
example/screenShader.frag
Normal file
16
example/screenShader.frag
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
//
|
||||||
|
// Example blue light filter shader.
|
||||||
|
//
|
||||||
|
|
||||||
|
precision mediump float;
|
||||||
|
varying vec2 v_texcoord;
|
||||||
|
uniform sampler2D tex;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
|
||||||
|
vec4 pixColor = texture2D(tex, v_texcoord);
|
||||||
|
|
||||||
|
pixColor[2] *= 0.8;
|
||||||
|
|
||||||
|
gl_FragColor = pixColor;
|
||||||
|
}
|
||||||
13
example/swaybg@.service
Normal file
13
example/swaybg@.service
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
; a primitive systemd --user example
|
||||||
|
; see example/hyprland.service for more details
|
||||||
|
[Unit]
|
||||||
|
Description = %p
|
||||||
|
BindsTo = hyprland.service
|
||||||
|
Wants = hyprland.service
|
||||||
|
After = hyprland.service
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
ExecStart = /usr/bin/swaybg --color #%i
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy = default.target
|
||||||
82
flake.lock
generated
82
flake.lock
generated
@@ -1,12 +1,35 @@
|
|||||||
{
|
{
|
||||||
"nodes": {
|
"nodes": {
|
||||||
|
"hyprland-protocols": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": [
|
||||||
|
"nixpkgs"
|
||||||
|
],
|
||||||
|
"systems": [
|
||||||
|
"systems"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1691753796,
|
||||||
|
"narHash": "sha256-zOEwiWoXk3j3+EoF3ySUJmberFewWlagvewDRuWYAso=",
|
||||||
|
"owner": "hyprwm",
|
||||||
|
"repo": "hyprland-protocols",
|
||||||
|
"rev": "0c2ce70625cb30aef199cb388f99e19a61a6ce03",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "hyprwm",
|
||||||
|
"repo": "hyprland-protocols",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1666377499,
|
"lastModified": 1700612854,
|
||||||
"narHash": "sha256-dZZCGvWcxc7oGnUgFVf0UeNHsJ4VhkTM0v5JRe8EwR8=",
|
"narHash": "sha256-yrQ8osMD+vDLGFX7pcwsY/Qr5PUd6OmDMYJZzZi0+zc=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "301aada7a64812853f2e2634a530ef5d34505048",
|
"rev": "19cbff58383a4ae384dea4d1d0c823d72b49d614",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -18,27 +41,72 @@
|
|||||||
},
|
},
|
||||||
"root": {
|
"root": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
|
"hyprland-protocols": "hyprland-protocols",
|
||||||
"nixpkgs": "nixpkgs",
|
"nixpkgs": "nixpkgs",
|
||||||
"wlroots": "wlroots"
|
"systems": "systems",
|
||||||
|
"wlroots": "wlroots",
|
||||||
|
"xdph": "xdph"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"systems": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1689347949,
|
||||||
|
"narHash": "sha256-12tWmuL2zgBgZkdoB6qXZsgJEH9LR3oUgpaQq2RbI80=",
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default-linux",
|
||||||
|
"rev": "31732fcf5e8fea42e59c2488ad31a0e651500f68",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default-linux",
|
||||||
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"wlroots": {
|
"wlroots": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"host": "gitlab.freedesktop.org",
|
"host": "gitlab.freedesktop.org",
|
||||||
"lastModified": 1666466001,
|
"lastModified": 1701368958,
|
||||||
"narHash": "sha256-ZjxAnqtcGmHQHKL1Z9sIraDnzIqrJleWcJXfPtzAm74=",
|
"narHash": "sha256-7kvyoA91etzVEl9mkA/EJfB6z/PltxX7Xc4gcr7/xlo=",
|
||||||
"owner": "wlroots",
|
"owner": "wlroots",
|
||||||
"repo": "wlroots",
|
"repo": "wlroots",
|
||||||
"rev": "c2d2773df57750081b16d56da13b5015d752cbd7",
|
"rev": "5d639394f3e83b01596dcd166a44a9a1a2583350",
|
||||||
"type": "gitlab"
|
"type": "gitlab"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"host": "gitlab.freedesktop.org",
|
"host": "gitlab.freedesktop.org",
|
||||||
"owner": "wlroots",
|
"owner": "wlroots",
|
||||||
"repo": "wlroots",
|
"repo": "wlroots",
|
||||||
|
"rev": "5d639394f3e83b01596dcd166a44a9a1a2583350",
|
||||||
"type": "gitlab"
|
"type": "gitlab"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"xdph": {
|
||||||
|
"inputs": {
|
||||||
|
"hyprland-protocols": [
|
||||||
|
"hyprland-protocols"
|
||||||
|
],
|
||||||
|
"nixpkgs": [
|
||||||
|
"nixpkgs"
|
||||||
|
],
|
||||||
|
"systems": [
|
||||||
|
"systems"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1700508250,
|
||||||
|
"narHash": "sha256-X4o/mifI7Nhu0UKYlxx53wIC+gYDo3pVM9L2u3PE2bE=",
|
||||||
|
"owner": "hyprwm",
|
||||||
|
"repo": "xdg-desktop-portal-hyprland",
|
||||||
|
"rev": "eb120ff25265ecacd0fc13d7dab12131b60d0f47",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "hyprwm",
|
||||||
|
"repo": "xdg-desktop-portal-hyprland",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"root": "root",
|
"root": "root",
|
||||||
|
|||||||
116
flake.nix
116
flake.nix
@@ -3,70 +3,84 @@
|
|||||||
|
|
||||||
inputs = {
|
inputs = {
|
||||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||||
|
|
||||||
|
# <https://github.com/nix-systems/nix-systems>
|
||||||
|
systems.url = "github:nix-systems/default-linux";
|
||||||
|
|
||||||
wlroots = {
|
wlroots = {
|
||||||
url = "gitlab:wlroots/wlroots?host=gitlab.freedesktop.org";
|
type = "gitlab";
|
||||||
|
host = "gitlab.freedesktop.org";
|
||||||
|
owner = "wlroots";
|
||||||
|
repo = "wlroots";
|
||||||
|
rev = "5d639394f3e83b01596dcd166a44a9a1a2583350";
|
||||||
flake = false;
|
flake = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
hyprland-protocols = {
|
||||||
|
url = "github:hyprwm/hyprland-protocols";
|
||||||
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
|
inputs.systems.follows = "systems";
|
||||||
|
};
|
||||||
|
|
||||||
|
xdph = {
|
||||||
|
url = "github:hyprwm/xdg-desktop-portal-hyprland";
|
||||||
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
|
inputs.systems.follows = "systems";
|
||||||
|
inputs.hyprland-protocols.follows = "hyprland-protocols";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
outputs = inputs @ {
|
outputs = inputs @ {
|
||||||
self,
|
self,
|
||||||
nixpkgs,
|
nixpkgs,
|
||||||
|
systems,
|
||||||
...
|
...
|
||||||
}: let
|
}: let
|
||||||
inherit (nixpkgs) lib;
|
inherit (nixpkgs) lib;
|
||||||
genSystems = lib.genAttrs [
|
eachSystem = lib.genAttrs (import systems);
|
||||||
# Add more systems if they are supported
|
pkgsFor = eachSystem (system:
|
||||||
"aarch64-linux"
|
import nixpkgs {
|
||||||
"x86_64-linux"
|
localSystem = system;
|
||||||
];
|
overlays = with self.overlays; [
|
||||||
|
hyprland-packages
|
||||||
|
hyprland-extras
|
||||||
|
];
|
||||||
|
});
|
||||||
|
in {
|
||||||
|
overlays = import ./nix/overlays.nix {inherit self lib inputs;};
|
||||||
|
|
||||||
pkgsFor = genSystems (system: import nixpkgs {
|
checks = eachSystem (system:
|
||||||
inherit system;
|
(lib.filterAttrs
|
||||||
overlays = [(_: prev: {
|
(n: _: (lib.hasPrefix "hyprland" n) && !(lib.hasSuffix "debug" n))
|
||||||
wayland-protocols = prev.wayland-protocols.overrideAttrs (old: rec {
|
self.packages.${system})
|
||||||
version = "1.27";
|
// {
|
||||||
src = prev.fetchurl {
|
inherit (self.packages.${system}) xdg-desktop-portal-hyprland;
|
||||||
url = "https://gitlab.freedesktop.org/wayland/${old.pname}/-/releases/${version}/downloads/${old.pname}-${version}.tar.xz";
|
});
|
||||||
hash = "sha256-kEbxCkJdTioAlloDrPtrP7V1pWUDrHLCuGghxpZTN1w=";
|
|
||||||
};
|
packages = eachSystem (system: {
|
||||||
});
|
default = self.packages.${system}.hyprland;
|
||||||
})];
|
inherit
|
||||||
|
(pkgsFor.${system})
|
||||||
|
# hyprland-packages
|
||||||
|
hyprland
|
||||||
|
hyprland-unwrapped
|
||||||
|
hyprland-debug
|
||||||
|
# hyprland-extras
|
||||||
|
xdg-desktop-portal-hyprland
|
||||||
|
# dependencies
|
||||||
|
hyprland-protocols
|
||||||
|
wlroots-hyprland
|
||||||
|
udis86
|
||||||
|
;
|
||||||
});
|
});
|
||||||
|
|
||||||
mkDate = longDate: (lib.concatStringsSep "-" [
|
devShells = eachSystem (system: {
|
||||||
(builtins.substring 0 4 longDate)
|
default = pkgsFor.${system}.mkShell.override {
|
||||||
(builtins.substring 4 2 longDate)
|
stdenv = pkgsFor.${system}.gcc13Stdenv;
|
||||||
(builtins.substring 6 2 longDate)
|
} {
|
||||||
]);
|
|
||||||
in {
|
|
||||||
overlays.default = _: prev: rec {
|
|
||||||
wlroots-hyprland = prev.callPackage ./nix/wlroots.nix {
|
|
||||||
version = mkDate (inputs.wlroots.lastModifiedDate or "19700101") + "_" + (inputs.wlroots.shortRev or "dirty");
|
|
||||||
src = inputs.wlroots;
|
|
||||||
};
|
|
||||||
hyprland = prev.callPackage ./nix/default.nix {
|
|
||||||
stdenv = prev.gcc12Stdenv;
|
|
||||||
version = "0.16.0beta" + "+date=" + (mkDate (self.lastModifiedDate or "19700101")) + "_" + (self.shortRev or "dirty");
|
|
||||||
wlroots = wlroots-hyprland;
|
|
||||||
};
|
|
||||||
hyprland-debug = hyprland.override {debug = true;};
|
|
||||||
hyprland-no-hidpi = hyprland.override {hidpiXWayland = false;};
|
|
||||||
|
|
||||||
waybar-hyprland = prev.waybar.overrideAttrs (oldAttrs: {
|
|
||||||
mesonFlags = oldAttrs.mesonFlags ++ ["-Dexperimental=true"];
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
packages = genSystems (system:
|
|
||||||
(self.overlays.default null pkgsFor.${system})
|
|
||||||
// {
|
|
||||||
default = self.packages.${system}.hyprland;
|
|
||||||
});
|
|
||||||
|
|
||||||
devShells = genSystems (system: {
|
|
||||||
default = pkgsFor.${system}.mkShell.override {stdenv = pkgsFor.${system}.gcc12Stdenv;} {
|
|
||||||
name = "hyprland-shell";
|
name = "hyprland-shell";
|
||||||
|
nativeBuildInputs = with pkgsFor.${system}; [cmake python3];
|
||||||
|
buildInputs = [self.packages.${system}.wlroots-hyprland];
|
||||||
inputsFrom = [
|
inputsFrom = [
|
||||||
self.packages.${system}.wlroots-hyprland
|
self.packages.${system}.wlroots-hyprland
|
||||||
self.packages.${system}.hyprland
|
self.packages.${system}.hyprland
|
||||||
@@ -74,9 +88,9 @@
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
formatter = genSystems (system: pkgsFor.${system}.alejandra);
|
formatter = eachSystem (system: nixpkgs.legacyPackages.${system}.alejandra);
|
||||||
|
|
||||||
nixosModules.default = import ./nix/module.nix self;
|
nixosModules.default = import ./nix/module.nix inputs;
|
||||||
homeManagerModules.default = import ./nix/hm-module.nix self;
|
homeManagerModules.default = import ./nix/hm-module.nix self;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
8
hyprctl/CMakeLists.txt
Normal file
8
hyprctl/CMakeLists.txt
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.19)
|
||||||
|
|
||||||
|
project(
|
||||||
|
hyprctl
|
||||||
|
DESCRIPTION "Control utility for Hyprland"
|
||||||
|
)
|
||||||
|
|
||||||
|
add_executable(hyprctl "main.cpp")
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
all:
|
all:
|
||||||
g++ -std=c++23 ./main.cpp -o ./hyprctl
|
$(CXX) $(CXXFLAGS) -std=c++2b ./main.cpp -o ./hyprctl
|
||||||
clean:
|
clean:
|
||||||
rm ./hyprctl
|
rm ./hyprctl
|
||||||
|
|||||||
362
hyprctl/main.cpp
362
hyprctl/main.cpp
@@ -11,63 +11,130 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <ranges>
|
#include <ranges>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <format>
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
#include <deque>
|
#include <deque>
|
||||||
|
#include <filesystem>
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
const std::string USAGE = R"#(usage: hyprctl [(opt)flags] [command] [(opt)args]
|
const std::string USAGE = R"#(usage: hyprctl [(opt)flags] [command] [(opt)args]
|
||||||
|
|
||||||
commands:
|
commands:
|
||||||
monitors
|
|
||||||
workspaces
|
|
||||||
clients
|
|
||||||
activewindow
|
activewindow
|
||||||
layers
|
activeworkspace
|
||||||
|
binds
|
||||||
|
clients
|
||||||
|
cursorpos
|
||||||
devices
|
devices
|
||||||
dispatch
|
dispatch
|
||||||
keyword
|
getoption
|
||||||
version
|
globalshortcuts
|
||||||
kill
|
|
||||||
splash
|
|
||||||
hyprpaper
|
hyprpaper
|
||||||
|
instances
|
||||||
|
keyword
|
||||||
|
kill
|
||||||
|
layers
|
||||||
|
layouts
|
||||||
|
monitors
|
||||||
|
notify
|
||||||
|
plugin
|
||||||
reload
|
reload
|
||||||
setcursor
|
setcursor
|
||||||
getoption
|
seterror
|
||||||
cursorpos
|
setprop
|
||||||
|
splash
|
||||||
|
switchxkblayout
|
||||||
|
version
|
||||||
|
workspacerules
|
||||||
|
workspaces
|
||||||
|
|
||||||
flags:
|
flags:
|
||||||
-j -> output in JSON
|
-j -> output in JSON
|
||||||
--batch -> execute a batch of commands, separated by ';'
|
--batch -> execute a batch of commands, separated by ';'
|
||||||
|
--instance (-i) -> use a specific instance. Can be either signature or index in hyprctl instances (0, 1, etc)
|
||||||
)#";
|
)#";
|
||||||
|
|
||||||
void request(std::string arg) {
|
#define PAD
|
||||||
|
|
||||||
|
std::string instanceSignature;
|
||||||
|
|
||||||
|
struct SInstanceData {
|
||||||
|
std::string id;
|
||||||
|
uint64_t time;
|
||||||
|
uint64_t pid;
|
||||||
|
std::string wlSocket;
|
||||||
|
bool valid = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<SInstanceData> instances() {
|
||||||
|
std::vector<SInstanceData> result;
|
||||||
|
|
||||||
|
for (const auto& el : std::filesystem::directory_iterator("/tmp/hypr")) {
|
||||||
|
if (el.is_directory())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// read lock
|
||||||
|
SInstanceData* data = &result.emplace_back();
|
||||||
|
data->id = el.path().string();
|
||||||
|
data->id = data->id.substr(data->id.find_last_of('/') + 1, data->id.find(".lock") - data->id.find_last_of('/') - 1);
|
||||||
|
|
||||||
|
data->time = std::stoull(data->id.substr(data->id.find_first_of('_') + 1));
|
||||||
|
|
||||||
|
// read file
|
||||||
|
std::ifstream ifs(el.path().string());
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
for (std::string line; std::getline(ifs, line); ++i) {
|
||||||
|
if (i == 0) {
|
||||||
|
data->pid = std::stoull(line);
|
||||||
|
} 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
void request(std::string arg, int minArgs = 0) {
|
||||||
const auto SERVERSOCKET = socket(AF_UNIX, SOCK_STREAM, 0);
|
const auto SERVERSOCKET = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||||
|
|
||||||
|
const auto ARGS = std::count(arg.begin(), arg.end(), ' ');
|
||||||
|
|
||||||
|
if (ARGS < minArgs) {
|
||||||
|
std::cout << "Not enough arguments, expected at least " << minArgs;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (SERVERSOCKET < 0) {
|
if (SERVERSOCKET < 0) {
|
||||||
std::cout << "Couldn't open a socket (1)";
|
std::cout << "Couldn't open a socket (1)";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (instanceSignature.empty()) {
|
||||||
// get the instance signature
|
|
||||||
auto instanceSig = getenv("HYPRLAND_INSTANCE_SIGNATURE");
|
|
||||||
|
|
||||||
if (!instanceSig) {
|
|
||||||
std::cout << "HYPRLAND_INSTANCE_SIGNATURE was not set! (Is Hyprland running?)";
|
std::cout << "HYPRLAND_INSTANCE_SIGNATURE was not set! (Is Hyprland running?)";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string instanceSigStr = std::string(instanceSig);
|
|
||||||
|
|
||||||
sockaddr_un serverAddress = {0};
|
sockaddr_un serverAddress = {0};
|
||||||
serverAddress.sun_family = AF_UNIX;
|
serverAddress.sun_family = AF_UNIX;
|
||||||
|
|
||||||
std::string socketPath = "/tmp/hypr/" + instanceSigStr + "/.socket.sock";
|
std::string socketPath = "/tmp/hypr/" + instanceSignature + "/.socket.sock";
|
||||||
|
|
||||||
strcpy(serverAddress.sun_path, socketPath.c_str());
|
strncpy(serverAddress.sun_path, socketPath.c_str(), sizeof(serverAddress.sun_path) - 1);
|
||||||
|
|
||||||
if (connect(SERVERSOCKET, (sockaddr*)&serverAddress, SUN_LEN(&serverAddress)) < 0) {
|
if (connect(SERVERSOCKET, (sockaddr*)&serverAddress, SUN_LEN(&serverAddress)) < 0) {
|
||||||
std::cout << "Couldn't connect to " << socketPath << ". (3)";
|
std::cout << "Couldn't connect to " << socketPath << ". (3)";
|
||||||
@@ -81,8 +148,8 @@ void request(std::string arg) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string reply = "";
|
std::string reply = "";
|
||||||
char buffer[8192] = {0};
|
char buffer[8192] = {0};
|
||||||
|
|
||||||
sizeWritten = read(SERVERSOCKET, buffer, 8192);
|
sizeWritten = read(SERVERSOCKET, buffer, 8192);
|
||||||
|
|
||||||
@@ -115,28 +182,26 @@ void requestHyprpaper(std::string arg) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the instance signature
|
if (instanceSignature.empty()) {
|
||||||
auto instanceSig = getenv("HYPRLAND_INSTANCE_SIGNATURE");
|
|
||||||
|
|
||||||
if (!instanceSig) {
|
|
||||||
std::cout << "HYPRLAND_INSTANCE_SIGNATURE was not set! (Is Hyprland running?)";
|
std::cout << "HYPRLAND_INSTANCE_SIGNATURE was not set! (Is Hyprland running?)";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string instanceSigStr = std::string(instanceSig);
|
|
||||||
|
|
||||||
sockaddr_un serverAddress = {0};
|
sockaddr_un serverAddress = {0};
|
||||||
serverAddress.sun_family = AF_UNIX;
|
serverAddress.sun_family = AF_UNIX;
|
||||||
|
|
||||||
std::string socketPath = "/tmp/hypr/" + instanceSigStr + "/.hyprpaper.sock";
|
std::string socketPath = "/tmp/hypr/" + instanceSignature + "/.hyprpaper.sock";
|
||||||
|
|
||||||
strcpy(serverAddress.sun_path, socketPath.c_str());
|
strncpy(serverAddress.sun_path, socketPath.c_str(), sizeof(serverAddress.sun_path) - 1);
|
||||||
|
|
||||||
if (connect(SERVERSOCKET, (sockaddr*)&serverAddress, SUN_LEN(&serverAddress)) < 0) {
|
if (connect(SERVERSOCKET, (sockaddr*)&serverAddress, SUN_LEN(&serverAddress)) < 0) {
|
||||||
std::cout << "Couldn't connect to " << socketPath << ". (3)";
|
std::cout << "Couldn't connect to " << socketPath << ". (3)";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
arg = arg.substr(arg.find_first_of('/') + 1); // strip flags
|
||||||
|
arg = arg.substr(arg.find_first_of(' ') + 1); // strip "hyprpaper"
|
||||||
|
|
||||||
auto sizeWritten = write(SERVERSOCKET, arg.c_str(), arg.length());
|
auto sizeWritten = write(SERVERSOCKET, arg.c_str(), arg.length());
|
||||||
|
|
||||||
if (sizeWritten < 0) {
|
if (sizeWritten < 0) {
|
||||||
@@ -158,71 +223,42 @@ void requestHyprpaper(std::string arg) {
|
|||||||
std::cout << std::string(buffer);
|
std::cout << std::string(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
int dispatchRequest(int argc, char** argv) {
|
|
||||||
|
|
||||||
if (argc < 4) {
|
|
||||||
std::cout << "Usage: hyprctl dispatch <dispatcher> <arg>\n\
|
|
||||||
Execute a hyprland keybind dispatcher with the given argument";
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string rq = "/dispatch";
|
|
||||||
|
|
||||||
for(int i = 2; i < argc; i++)
|
|
||||||
rq += " " + std::string(argv[i]);
|
|
||||||
|
|
||||||
request(rq);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int keywordRequest(int argc, char** argv) {
|
|
||||||
if (argc < 4) {
|
|
||||||
std::cout << "Usage: hyprctl keyword <keyword> <arg>\n\
|
|
||||||
Execute a hyprland keyword with the given argument";
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string rq = "/keyword";
|
|
||||||
|
|
||||||
for(int i = 2; i < argc; i++)
|
|
||||||
rq += " " + std::string(argv[i]);
|
|
||||||
|
|
||||||
request(rq);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int hyprpaperRequest(int argc, char** argv) {
|
|
||||||
if (argc < 4) {
|
|
||||||
std::cout << "Usage: hyprctl hyprpaper <command> <arg>\n\
|
|
||||||
Execute a hyprpaper command with the given argument";
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string rq = std::string(argv[2]) + " " + std::string(argv[3]);
|
|
||||||
|
|
||||||
requestHyprpaper(rq);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int setcursorRequest(int argc, char** argv) {
|
|
||||||
if (argc < 4) {
|
|
||||||
std::cout << "Usage: hyprctl setcursor <theme> <size>\n\
|
|
||||||
Sets the cursor theme for everything except GTK and reloads the cursor";
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string rq = "setcursor " + std::string(argv[2]) + " " + std::string(argv[3]);
|
|
||||||
|
|
||||||
request(rq);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void batchRequest(std::string arg) {
|
void batchRequest(std::string arg) {
|
||||||
std::string rq = "[[BATCH]]" + arg.substr(arg.find_first_of(" ") + 1);
|
std::string rq = "[[BATCH]]" + arg.substr(arg.find_first_of(" ") + 1);
|
||||||
|
|
||||||
request(rq);
|
request(rq);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void instancesRequest(bool json) {
|
||||||
|
std::string result = "";
|
||||||
|
|
||||||
|
// gather instance data
|
||||||
|
std::vector<SInstanceData> inst = instances();
|
||||||
|
|
||||||
|
if (!json) {
|
||||||
|
for (auto& el : inst) {
|
||||||
|
result += std::format("instance {}:\n\ttime: {}\n\tpid: {}\n\twl socket: {}\n\n", el.id, el.time, el.pid, el.wlSocket);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result += '[';
|
||||||
|
for (auto& el : inst) {
|
||||||
|
result += std::format(R"#(
|
||||||
|
{{
|
||||||
|
"instance": "{}",
|
||||||
|
"time": {},
|
||||||
|
"pid": {},
|
||||||
|
"wl_socket": "{}"
|
||||||
|
}},)#",
|
||||||
|
el.id, el.time, el.pid, el.wlSocket);
|
||||||
|
}
|
||||||
|
|
||||||
|
result.pop_back();
|
||||||
|
result += "\n]";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << result << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
std::deque<std::string> splitArgs(int argc, char** argv) {
|
std::deque<std::string> splitArgs(int argc, char** argv) {
|
||||||
std::deque<std::string> result;
|
std::deque<std::string> result;
|
||||||
|
|
||||||
@@ -233,28 +269,47 @@ std::deque<std::string> splitArgs(int argc, char** argv) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool isNumber(const std::string& str, bool allowfloat) {
|
bool isNumber(const std::string& str, bool allowfloat) {
|
||||||
|
if (str.empty())
|
||||||
|
return false;
|
||||||
return std::ranges::all_of(str.begin(), str.end(), [&](char c) { return isdigit(c) != 0 || c == '-' || (allowfloat && c == '.'); });
|
return std::ranges::all_of(str.begin(), str.end(), [&](char c) { return isdigit(c) != 0 || c == '-' || (allowfloat && c == '.'); });
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
int main(int argc, char** argv) {
|
||||||
int bflag = 0, sflag = 0, index, c;
|
bool parseArgs = true;
|
||||||
|
|
||||||
if (argc < 2) {
|
if (argc < 2) {
|
||||||
printf("%s\n", USAGE.c_str());
|
printf("%s\n", USAGE.c_str());
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string fullRequest = "";
|
std::string fullRequest = "";
|
||||||
std::string fullArgs = "";
|
std::string fullArgs = "";
|
||||||
const auto ARGS = splitArgs(argc, argv);
|
const auto ARGS = splitArgs(argc, argv);
|
||||||
|
bool json = false;
|
||||||
|
std::string overrideInstance = "";
|
||||||
|
|
||||||
for (auto i = 0; i < ARGS.size(); ++i) {
|
for (std::size_t i = 0; i < ARGS.size(); ++i) {
|
||||||
if (ARGS[i][0] == '-' && !isNumber(ARGS[i], true) /* For stuff like -2 */) {
|
if (ARGS[i] == "--") {
|
||||||
|
// Stop parsing arguments after --
|
||||||
|
parseArgs = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (parseArgs && (ARGS[i][0] == '-') && !isNumber(ARGS[i], true) /* For stuff like -2 */) {
|
||||||
// parse
|
// parse
|
||||||
if (ARGS[i] == "-j" && !fullArgs.contains("j")) {
|
if (ARGS[i] == "-j" && !fullArgs.contains("j")) {
|
||||||
fullArgs += "j";
|
fullArgs += "j";
|
||||||
|
json = true;
|
||||||
} else if (ARGS[i] == "--batch") {
|
} else if (ARGS[i] == "--batch") {
|
||||||
fullRequest = "--batch ";
|
fullRequest = "--batch ";
|
||||||
|
} else if (ARGS[i] == "--instance" || ARGS[i] == "-i") {
|
||||||
|
++i;
|
||||||
|
|
||||||
|
if (i >= ARGS.size()) {
|
||||||
|
printf("%s\n", USAGE.c_str());
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
overrideInstance = ARGS[i];
|
||||||
} else {
|
} else {
|
||||||
printf("%s\n", USAGE.c_str());
|
printf("%s\n", USAGE.c_str());
|
||||||
return 1;
|
return 1;
|
||||||
@@ -274,27 +329,102 @@ int main(int argc, char** argv) {
|
|||||||
fullRequest.pop_back(); // remove trailing space
|
fullRequest.pop_back(); // remove trailing space
|
||||||
|
|
||||||
fullRequest = fullArgs + "/" + fullRequest;
|
fullRequest = fullArgs + "/" + fullRequest;
|
||||||
|
|
||||||
|
if (overrideInstance.contains("_"))
|
||||||
|
instanceSignature = overrideInstance;
|
||||||
|
else if (!overrideInstance.empty()) {
|
||||||
|
if (!isNumber(overrideInstance, false)) {
|
||||||
|
std::cout << "instance invalid\n";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto INSTANCENO = std::stoi(overrideInstance);
|
||||||
|
|
||||||
|
const auto INSTANCES = instances();
|
||||||
|
|
||||||
|
if (INSTANCENO < 0 || static_cast<std::size_t>(INSTANCENO) >= INSTANCES.size()) {
|
||||||
|
std::cout << "no such instance\n";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
instanceSignature = INSTANCES[INSTANCENO].id;
|
||||||
|
} else {
|
||||||
|
const auto ISIG = getenv("HYPRLAND_INSTANCE_SIGNATURE");
|
||||||
|
|
||||||
|
if (!ISIG) {
|
||||||
|
std::cout << "HYPRLAND_INSTANCE_SIGNATURE not set! (is hyprland running?)";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
instanceSignature = ISIG;
|
||||||
|
}
|
||||||
|
|
||||||
int exitStatus = 0;
|
int exitStatus = 0;
|
||||||
|
|
||||||
if (fullRequest.contains("/--batch")) batchRequest(fullRequest);
|
if (fullRequest.contains("/--batch"))
|
||||||
else if (fullRequest.contains("/monitors")) request(fullRequest);
|
batchRequest(fullRequest);
|
||||||
else if (fullRequest.contains("/clients")) request(fullRequest);
|
else if (fullRequest.contains("/monitors"))
|
||||||
else if (fullRequest.contains("/workspaces")) request(fullRequest);
|
request(fullRequest);
|
||||||
else if (fullRequest.contains("/activewindow")) request(fullRequest);
|
else if (fullRequest.contains("/clients"))
|
||||||
else if (fullRequest.contains("/layers")) request(fullRequest);
|
request(fullRequest);
|
||||||
else if (fullRequest.contains("/version")) request(fullRequest);
|
else if (fullRequest.contains("/workspaces"))
|
||||||
else if (fullRequest.contains("/kill")) request(fullRequest);
|
request(fullRequest);
|
||||||
else if (fullRequest.contains("/splash")) request(fullRequest);
|
else if (fullRequest.contains("/activeworkspace"))
|
||||||
else if (fullRequest.contains("/devices")) request(fullRequest);
|
request(fullRequest);
|
||||||
else if (fullRequest.contains("/reload")) request(fullRequest);
|
else if (fullRequest.contains("/workspacerules"))
|
||||||
else if (fullRequest.contains("/getoption")) request(fullRequest);
|
request(fullRequest);
|
||||||
else if (fullRequest.contains("/cursorpos")) request(fullRequest);
|
else if (fullRequest.contains("/activewindow"))
|
||||||
else if (fullRequest.contains("/setcursor")) exitStatus = setcursorRequest(argc, argv);
|
request(fullRequest);
|
||||||
else if (fullRequest.contains("/dispatch")) exitStatus = dispatchRequest(argc, argv);
|
else if (fullRequest.contains("/layers"))
|
||||||
else if (fullRequest.contains("/keyword")) exitStatus = keywordRequest(argc, argv);
|
request(fullRequest);
|
||||||
else if (fullRequest.contains("/hyprpaper")) exitStatus = hyprpaperRequest(argc, argv);
|
else if (fullRequest.contains("/version"))
|
||||||
else if (fullRequest.contains("/--help")) printf("%s", USAGE.c_str());
|
request(fullRequest);
|
||||||
|
else if (fullRequest.contains("/kill"))
|
||||||
|
request(fullRequest);
|
||||||
|
else if (fullRequest.contains("/splash"))
|
||||||
|
request(fullRequest);
|
||||||
|
else if (fullRequest.contains("/devices"))
|
||||||
|
request(fullRequest);
|
||||||
|
else if (fullRequest.contains("/reload"))
|
||||||
|
request(fullRequest);
|
||||||
|
else if (fullRequest.contains("/getoption"))
|
||||||
|
request(fullRequest);
|
||||||
|
else if (fullRequest.contains("/binds"))
|
||||||
|
request(fullRequest);
|
||||||
|
else if (fullRequest.contains("/cursorpos"))
|
||||||
|
request(fullRequest);
|
||||||
|
else if (fullRequest.contains("/animations"))
|
||||||
|
request(fullRequest);
|
||||||
|
else if (fullRequest.contains("/globalshortcuts"))
|
||||||
|
request(fullRequest);
|
||||||
|
else if (fullRequest.contains("/rollinglog"))
|
||||||
|
request(fullRequest);
|
||||||
|
else if (fullRequest.contains("/instances"))
|
||||||
|
instancesRequest(json);
|
||||||
|
else if (fullRequest.contains("/switchxkblayout"))
|
||||||
|
request(fullRequest, 2);
|
||||||
|
else if (fullRequest.contains("/seterror"))
|
||||||
|
request(fullRequest, 1);
|
||||||
|
else if (fullRequest.contains("/setprop"))
|
||||||
|
request(fullRequest, 3);
|
||||||
|
else if (fullRequest.contains("/plugin"))
|
||||||
|
request(fullRequest, 1);
|
||||||
|
else if (fullRequest.contains("/notify"))
|
||||||
|
request(fullRequest, 2);
|
||||||
|
else if (fullRequest.contains("/output"))
|
||||||
|
request(fullRequest, 2);
|
||||||
|
else if (fullRequest.contains("/setcursor"))
|
||||||
|
request(fullRequest, 1);
|
||||||
|
else if (fullRequest.contains("/dispatch"))
|
||||||
|
request(fullRequest, 1);
|
||||||
|
else if (fullRequest.contains("/keyword"))
|
||||||
|
request(fullRequest, 2);
|
||||||
|
else if (fullRequest.contains("/hyprpaper"))
|
||||||
|
requestHyprpaper(fullRequest);
|
||||||
|
else if (fullRequest.contains("/layouts"))
|
||||||
|
request(fullRequest);
|
||||||
|
else if (fullRequest.contains("/--help"))
|
||||||
|
printf("%s", USAGE.c_str());
|
||||||
else {
|
else {
|
||||||
printf("%s\n", USAGE.c_str());
|
printf("%s\n", USAGE.c_str());
|
||||||
return 1;
|
return 1;
|
||||||
|
|||||||
8
hyprland.pc.in
Normal file
8
hyprland.pc.in
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
prefix="@PREFIX@"
|
||||||
|
includedir="${prefix}/include"
|
||||||
|
|
||||||
|
Name: Hyprland
|
||||||
|
URL: https://github.com/hyprwm/Hyprland
|
||||||
|
Description: Hyprland header files
|
||||||
|
Version: @HYPRLAND_VERSION@
|
||||||
|
Cflags: -I"${includedir}/hyprland/protocols" -I"${includedir}/hyprland/wlroots" -I"${includedir}"
|
||||||
60
meson.build
60
meson.build
@@ -1,9 +1,11 @@
|
|||||||
project('Hyprland', 'cpp', 'c',
|
project('Hyprland', 'cpp', 'c',
|
||||||
version : '0.16.0beta',
|
version : run_command('jq', '-r', '.version', join_paths(meson.source_root(), 'props.json'), check: true).stdout().strip(),
|
||||||
default_options : [
|
default_options : [
|
||||||
'warning_level=2',
|
'warning_level=2',
|
||||||
'default_library=static',
|
'default_library=static',
|
||||||
'optimization=3',
|
'optimization=3',
|
||||||
|
'buildtype=release',
|
||||||
|
'debug=false'
|
||||||
# 'cpp_std=c++23' # not yet supported by meson, as of version 0.63.0
|
# 'cpp_std=c++23' # not yet supported by meson, as of version 0.63.0
|
||||||
])
|
])
|
||||||
|
|
||||||
@@ -18,45 +20,77 @@ else
|
|||||||
error('Could not configure current C++ compiler (' + cpp_compiler.get_id() + ' ' + cpp_compiler.version() + ') with required C++ standard (C++23)')
|
error('Could not configure current C++ compiler (' + cpp_compiler.get_id() + ' ' + cpp_compiler.version() + ') with required C++ standard (C++23)')
|
||||||
endif
|
endif
|
||||||
|
|
||||||
GIT_BRANCH = run_command('git', 'rev-parse', '--abbrev-ref', 'HEAD', check: false).stdout().strip()
|
|
||||||
GIT_COMMIT_HASH = run_command('git', 'rev-parse', 'HEAD', check: false).stdout().strip()
|
|
||||||
GIT_COMMIT_MESSAGE = run_command('sh', '-c', 'git show | head -n 5 | tail -n 1', check: false).stdout().strip()
|
|
||||||
GIT_DIRTY = run_command('sh', '-c', 'git diff-index --quiet HEAD -- || echo "dirty"', check: false).stdout().strip()
|
|
||||||
|
|
||||||
add_project_arguments(
|
add_project_arguments(
|
||||||
[
|
[
|
||||||
'-Wno-unused-parameter',
|
'-Wno-unused-parameter',
|
||||||
'-Wno-unused-value',
|
'-Wno-unused-value',
|
||||||
'-Wno-missing-field-initializers',
|
'-Wno-missing-field-initializers',
|
||||||
'-Wno-narrowing',
|
'-Wno-narrowing',
|
||||||
|
|
||||||
f'-DGIT_BRANCH="@GIT_BRANCH@"',
|
|
||||||
f'-DGIT_COMMIT_HASH="@GIT_COMMIT_HASH@"',
|
|
||||||
f'-DGIT_COMMIT_MESSAGE="@GIT_COMMIT_MESSAGE@"',
|
|
||||||
f'-DGIT_DIRTY="@GIT_DIRTY@"',
|
|
||||||
],
|
],
|
||||||
language: 'cpp')
|
language: 'cpp')
|
||||||
|
|
||||||
wlroots = subproject('wlroots', default_options: ['examples=false'])
|
if cpp_compiler.check_header('execinfo.h')
|
||||||
|
add_project_arguments('-DHAS_EXECINFO', language: 'cpp')
|
||||||
|
endif
|
||||||
|
|
||||||
|
wlroots = subproject('wlroots', default_options: ['examples=false', 'renderers=gles2'])
|
||||||
have_xwlr = wlroots.get_variable('features').get('xwayland')
|
have_xwlr = wlroots.get_variable('features').get('xwayland')
|
||||||
xcb_dep = dependency('xcb', required: get_option('xwayland'))
|
xcb_dep = dependency('xcb', required: get_option('xwayland'))
|
||||||
|
|
||||||
|
cmake = import('cmake')
|
||||||
|
udis = cmake.subproject('udis86')
|
||||||
|
udis86 = udis.dependency('libudis86')
|
||||||
|
|
||||||
if get_option('xwayland').enabled() and not have_xwlr
|
if get_option('xwayland').enabled() and not have_xwlr
|
||||||
error('Cannot enable Xwayland in Hyprland: wlroots has been built without Xwayland support')
|
error('Cannot enable Xwayland in Hyprland: wlroots has been built without Xwayland support')
|
||||||
endif
|
endif
|
||||||
have_xwayland = xcb_dep.found() and have_xwlr
|
have_xwayland = xcb_dep.found() and have_xwlr
|
||||||
|
|
||||||
if not have_xwayland
|
if not have_xwayland
|
||||||
add_project_arguments('-DNO_XWAYLAND', language: 'cpp')
|
add_project_arguments('-DNO_XWAYLAND', language: 'cpp')
|
||||||
|
endif
|
||||||
|
|
||||||
|
backtrace_dep = cpp_compiler.find_library('execinfo', required: false)
|
||||||
|
systemd_dep = dependency('libsystemd', required: get_option('systemd'))
|
||||||
|
|
||||||
|
if get_option('systemd').enabled()
|
||||||
|
if systemd_dep.found()
|
||||||
|
add_project_arguments('-DUSES_SYSTEMD', language: 'cpp')
|
||||||
|
else
|
||||||
|
error('Cannot enable systemd in Hyprland: libsystemd was not found')
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
if get_option('legacy_renderer').enabled()
|
||||||
|
add_project_arguments('-DLEGACY_RENDERER', language: 'cpp')
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if get_option('buildtype') == 'debug'
|
if get_option('buildtype') == 'debug'
|
||||||
add_project_arguments('-DHYPRLAND_DEBUG', language: 'cpp')
|
add_project_arguments('-DHYPRLAND_DEBUG', language: 'cpp')
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
version_h = run_command('sh', '-c', 'scripts/generateVersion.sh')
|
||||||
|
|
||||||
|
globber = run_command('find', 'src', '-name', '*.h*', check: true)
|
||||||
|
headers = globber.stdout().strip().split('\n')
|
||||||
|
foreach file : headers
|
||||||
|
install_headers(file, subdir: 'hyprland', preserve_path: true)
|
||||||
|
endforeach
|
||||||
|
|
||||||
subdir('protocols')
|
subdir('protocols')
|
||||||
subdir('src')
|
subdir('src')
|
||||||
subdir('hyprctl')
|
subdir('hyprctl')
|
||||||
subdir('assets')
|
subdir('assets')
|
||||||
subdir('example')
|
subdir('example')
|
||||||
subdir('docs')
|
subdir('docs')
|
||||||
|
|
||||||
|
pkg_install_dir = join_paths(get_option('datadir'), 'pkgconfig')
|
||||||
|
|
||||||
|
import('pkgconfig').generate(
|
||||||
|
name: 'Hyprland',
|
||||||
|
filebase: 'hyprland',
|
||||||
|
url: 'https://github.com/hyprwm/Hyprland',
|
||||||
|
description: 'Hyprland header files',
|
||||||
|
install_dir: pkg_install_dir,
|
||||||
|
subdirs: ['', 'hyprland/protocols', 'hyprland/wlroots'],
|
||||||
|
)
|
||||||
|
|||||||
@@ -1 +1,3 @@
|
|||||||
option('xwayland', type: 'feature', value: 'auto', description: 'Enable support for X11 applications')
|
option('xwayland', type: 'feature', value: 'auto', description: 'Enable support for X11 applications')
|
||||||
|
option('systemd', type: 'feature', value: 'auto', description: 'Enable systemd integration')
|
||||||
|
option('legacy_renderer', type: 'feature', value: 'disabled', description: 'Enable legacy renderer')
|
||||||
|
|||||||
191
nix/default.nix
191
nix/default.nix
@@ -1,19 +1,26 @@
|
|||||||
{
|
{
|
||||||
lib,
|
lib,
|
||||||
|
fetchurl,
|
||||||
stdenv,
|
stdenv,
|
||||||
fetchFromGitHub,
|
|
||||||
fetchpatch,
|
|
||||||
pkg-config,
|
pkg-config,
|
||||||
|
makeWrapper,
|
||||||
meson,
|
meson,
|
||||||
ninja,
|
ninja,
|
||||||
|
binutils,
|
||||||
|
cairo,
|
||||||
git,
|
git,
|
||||||
|
hyprland-protocols,
|
||||||
|
jq,
|
||||||
|
libGL,
|
||||||
libdrm,
|
libdrm,
|
||||||
libinput,
|
libinput,
|
||||||
libxcb,
|
libxcb,
|
||||||
libxkbcommon,
|
libxkbcommon,
|
||||||
mesa,
|
mesa,
|
||||||
mount,
|
|
||||||
pango,
|
pango,
|
||||||
|
pciutils,
|
||||||
|
systemd,
|
||||||
|
udis86,
|
||||||
wayland,
|
wayland,
|
||||||
wayland-protocols,
|
wayland-protocols,
|
||||||
wayland-scanner,
|
wayland-scanner,
|
||||||
@@ -22,85 +29,127 @@
|
|||||||
xwayland,
|
xwayland,
|
||||||
debug ? false,
|
debug ? false,
|
||||||
enableXWayland ? true,
|
enableXWayland ? true,
|
||||||
hidpiXWayland ? true,
|
|
||||||
legacyRenderer ? false,
|
legacyRenderer ? false,
|
||||||
nvidiaPatches ? false,
|
withSystemd ? lib.meta.availableOn stdenv.hostPlatform systemd,
|
||||||
|
wrapRuntimeDeps ? true,
|
||||||
version ? "git",
|
version ? "git",
|
||||||
}: let
|
commit,
|
||||||
assertXWayland = lib.assertMsg (hidpiXWayland -> enableXWayland) ''
|
# deprecated flags
|
||||||
Hyprland: cannot have hidpiXWayland when enableXWayland is false.
|
enableNvidiaPatches ? false,
|
||||||
'';
|
nvidiaPatches ? false,
|
||||||
|
hidpiXWayland ? false,
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
# NOTE: remove after https://github.com/NixOS/nixpkgs/pull/271096 reaches nixos-unstable
|
||||||
|
libdrm_2_4_118 = libdrm.overrideAttrs(attrs: rec {
|
||||||
|
version = "2.4.118";
|
||||||
|
src = fetchurl {
|
||||||
|
url = "https://dri.freedesktop.org/${attrs.pname}/${attrs.pname}-${version}.tar.xz";
|
||||||
|
hash = "sha256-p3e9hfK1/JxX+IbIIFgwBXgxfK/bx30Kdp1+mpVnq4g=";
|
||||||
|
};
|
||||||
|
});
|
||||||
in
|
in
|
||||||
assert assertXWayland;
|
assert lib.assertMsg (!nvidiaPatches) "The option `nvidiaPatches` has been removed.";
|
||||||
stdenv.mkDerivation {
|
assert lib.assertMsg (!enableNvidiaPatches) "The option `enableNvidiaPatches` has been removed.";
|
||||||
pname = "hyprland" + lib.optionalString debug "-debug";
|
assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been removed. Please refer https://wiki.hyprland.org/Configuring/XWayland";
|
||||||
inherit version;
|
stdenv.mkDerivation {
|
||||||
|
pname = "hyprland${lib.optionalString debug "-debug"}";
|
||||||
|
inherit version;
|
||||||
|
|
||||||
src = lib.cleanSourceWith {
|
src = lib.cleanSourceWith {
|
||||||
filter = name: type: let
|
filter = name: type: let
|
||||||
baseName = baseNameOf (toString name);
|
baseName = baseNameOf (toString name);
|
||||||
in
|
in
|
||||||
! (
|
! (lib.hasSuffix ".nix" baseName);
|
||||||
lib.hasSuffix ".nix" baseName
|
src = lib.cleanSource ../.;
|
||||||
);
|
};
|
||||||
src = lib.cleanSource ../.;
|
|
||||||
};
|
|
||||||
|
|
||||||
nativeBuildInputs = [
|
nativeBuildInputs = [
|
||||||
meson
|
jq
|
||||||
ninja
|
meson
|
||||||
pkg-config
|
ninja
|
||||||
];
|
pkg-config
|
||||||
|
makeWrapper
|
||||||
|
wayland-scanner
|
||||||
|
];
|
||||||
|
|
||||||
outputs = [
|
outputs = [
|
||||||
"out"
|
"out"
|
||||||
"man"
|
"man"
|
||||||
];
|
"dev"
|
||||||
|
];
|
||||||
|
|
||||||
buildInputs =
|
buildInputs =
|
||||||
[
|
[
|
||||||
git
|
git
|
||||||
libdrm
|
cairo
|
||||||
libinput
|
hyprland-protocols
|
||||||
libxcb
|
libGL
|
||||||
libxkbcommon
|
libdrm_2_4_118
|
||||||
mesa
|
libinput
|
||||||
pango
|
libxkbcommon
|
||||||
wayland
|
mesa
|
||||||
wayland-protocols
|
pango
|
||||||
wayland-scanner
|
udis86
|
||||||
(wlroots.override {inherit enableXWayland hidpiXWayland nvidiaPatches;})
|
wayland
|
||||||
xcbutilwm
|
wayland-protocols
|
||||||
]
|
pciutils
|
||||||
++ lib.optional enableXWayland xwayland;
|
wlroots
|
||||||
|
]
|
||||||
|
++ lib.optionals enableXWayland [libxcb xcbutilwm xwayland]
|
||||||
|
++ lib.optionals withSystemd [systemd];
|
||||||
|
|
||||||
mesonBuildType =
|
mesonBuildType =
|
||||||
if debug
|
if debug
|
||||||
then "debug"
|
then "debug"
|
||||||
else "release";
|
else "release";
|
||||||
|
|
||||||
mesonFlags = builtins.concatLists [
|
mesonAutoFeatures = "disabled";
|
||||||
(lib.optional (!enableXWayland) "-Dxwayland=disabled")
|
|
||||||
(lib.optional legacyRenderer "-DLEGACY_RENDERER:STRING=true")
|
|
||||||
];
|
|
||||||
|
|
||||||
patches = [
|
mesonFlags = builtins.concatLists [
|
||||||
# make meson use the provided wlroots instead of the git submodule
|
(lib.optional enableXWayland "-Dxwayland=enabled")
|
||||||
./meson-build.patch
|
(lib.optional legacyRenderer "-Dlegacy_renderer=enabled")
|
||||||
];
|
(lib.optional withSystemd "-Dsystemd=enabled")
|
||||||
|
];
|
||||||
|
|
||||||
|
patches = [
|
||||||
|
# make meson use the provided wlroots instead of the git submodule
|
||||||
|
./patches/meson-build.patch
|
||||||
|
];
|
||||||
|
|
||||||
|
postPatch = ''
|
||||||
# Fix hardcoded paths to /usr installation
|
# Fix hardcoded paths to /usr installation
|
||||||
postPatch = ''
|
sed -i "s#/usr#$out#" src/render/OpenGL.cpp
|
||||||
sed -i "s#/usr#$out#" src/render/OpenGL.cpp
|
|
||||||
'';
|
|
||||||
|
|
||||||
passthru.providedSessions = ["hyprland"];
|
# Generate version.h
|
||||||
|
cp src/version.h.in src/version.h
|
||||||
|
substituteInPlace src/version.h \
|
||||||
|
--replace "@HASH@" '${commit}' \
|
||||||
|
--replace "@BRANCH@" "" \
|
||||||
|
--replace "@MESSAGE@" "" \
|
||||||
|
--replace "@TAG@" "" \
|
||||||
|
--replace "@DIRTY@" '${
|
||||||
|
if commit == ""
|
||||||
|
then "dirty"
|
||||||
|
else ""
|
||||||
|
}'
|
||||||
|
'';
|
||||||
|
|
||||||
meta = with lib; {
|
postInstall = ''
|
||||||
homepage = "https://github.com/vaxerski/Hyprland";
|
ln -s ${wlroots}/include/wlr $dev/include/hyprland/wlroots
|
||||||
description = "A dynamic tiling Wayland compositor that doesn't sacrifice on its looks";
|
${lib.optionalString wrapRuntimeDeps ''
|
||||||
license = licenses.bsd3;
|
wrapProgram $out/bin/Hyprland \
|
||||||
platforms = platforms.linux;
|
--suffix PATH : ${lib.makeBinPath [binutils pciutils]}
|
||||||
mainProgram = "Hyprland";
|
''}
|
||||||
};
|
'';
|
||||||
}
|
|
||||||
|
passthru.providedSessions = ["hyprland"];
|
||||||
|
|
||||||
|
meta = with lib; {
|
||||||
|
homepage = "https://github.com/vaxerski/Hyprland";
|
||||||
|
description = "A dynamic tiling Wayland compositor that doesn't sacrifice on its looks";
|
||||||
|
license = licenses.bsd3;
|
||||||
|
platforms = platforms.linux;
|
||||||
|
mainProgram = "Hyprland";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|||||||
@@ -5,131 +5,170 @@ self: {
|
|||||||
...
|
...
|
||||||
}: let
|
}: let
|
||||||
cfg = config.wayland.windowManager.hyprland;
|
cfg = config.wayland.windowManager.hyprland;
|
||||||
defaultHyprlandPackage = self.packages.${pkgs.system}.default.override {
|
defaultHyprlandPackage = self.packages.${pkgs.stdenv.hostPlatform.system}.default.override {
|
||||||
enableXWayland = cfg.xwayland.enable;
|
enableXWayland = cfg.xwayland.enable;
|
||||||
hidpiXWayland = cfg.xwayland.hidpi;
|
|
||||||
};
|
};
|
||||||
in {
|
in {
|
||||||
|
disabledModules = ["services/window-managers/hyprland.nix"];
|
||||||
|
|
||||||
|
meta.maintainers = [lib.maintainers.fufexan];
|
||||||
|
|
||||||
options.wayland.windowManager.hyprland = {
|
options.wayland.windowManager.hyprland = {
|
||||||
enable = lib.mkEnableOption "hyprland wayland compositor";
|
enable =
|
||||||
|
lib.mkEnableOption null
|
||||||
|
// {
|
||||||
|
description = lib.mdDoc ''
|
||||||
|
Whether to enable Hyprland, the dynamic tiling Wayland compositor
|
||||||
|
that doesn't sacrifice on its looks.
|
||||||
|
|
||||||
|
You can manually launch Hyprland by executing {command}`Hyprland` on
|
||||||
|
a TTY.
|
||||||
|
|
||||||
|
See <https://wiki.hyprland.org> for more information.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
package = lib.mkOption {
|
package = lib.mkOption {
|
||||||
type = with lib.types; nullOr package;
|
type = with lib.types; nullOr package;
|
||||||
default = defaultHyprlandPackage;
|
default = defaultHyprlandPackage;
|
||||||
description = ''
|
defaultText = lib.literalExpression ''
|
||||||
|
hyprland.packages.''${pkgs.stdenv.hostPlatform.system}.default.override {
|
||||||
|
enableXWayland = config.wayland.windowManager.hyprland.xwayland.enable;
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
description = lib.mdDoc ''
|
||||||
Hyprland package to use. Will override the 'xwayland' option.
|
Hyprland package to use. Will override the 'xwayland' option.
|
||||||
|
|
||||||
Defaults to the one provided by the flake. Set it to
|
Defaults to the one provided by the flake. Set it to
|
||||||
<literal>pkgs.hyprland</literal> to use the one provided by nixpkgs or
|
{package}`pkgs.hyprland` to use the one provided by nixpkgs or
|
||||||
if you have an overlay.
|
if you have an overlay.
|
||||||
|
|
||||||
Set to null to not add any Hyprland package to your path. This should
|
Set to null to not add any Hyprland package to your path. This should
|
||||||
be done if you want to use the NixOS module to install Hyprland.
|
be done if you want to use the NixOS module to install Hyprland.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
plugins = lib.mkOption {
|
||||||
|
type = with lib.types; listOf (either package path);
|
||||||
|
default = [];
|
||||||
|
description = lib.mdDoc ''
|
||||||
|
List of Hyprland plugins to use. Can either be packages or
|
||||||
|
absolute plugin paths.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
systemdIntegration = lib.mkOption {
|
systemdIntegration = lib.mkOption {
|
||||||
type = lib.types.bool;
|
type = lib.types.bool;
|
||||||
default = pkgs.stdenv.isLinux;
|
default = pkgs.stdenv.isLinux;
|
||||||
description = ''
|
description = lib.mdDoc ''
|
||||||
Whether to enable <filename>hyprland-session.target</filename> on
|
Whether to enable {file}`hyprland-session.target` on
|
||||||
hyprland startup. This links to <filename>graphical-session.target</filename>.
|
Hyprland startup. This links to {file}`graphical-session.target`.
|
||||||
Some important environment variables will be imported to systemd
|
Some important environment variables will be imported to systemd
|
||||||
and dbus user environment before reaching the target, including
|
and dbus user environment before reaching the target, including
|
||||||
<itemizedlist>
|
- {env}`DISPLAY`
|
||||||
<listitem><para><literal>DISPLAY</literal></para></listitem>
|
- {env}`HYPRLAND_INSTANCE_SIGNATURE`
|
||||||
<listitem><para><literal>WAYLAND_DISPLAY</literal></para></listitem>
|
- {env}`WAYLAND_DISPLAY`
|
||||||
<listitem><para><literal>HYPRLAND_INSTANCE_SIGNATURE</literal></para></listitem>
|
- {env}`XDG_CURRENT_DESKTOP`
|
||||||
<listitem><para><literal>XDG_CURRENT_DESKTOP</literal></para></listitem>
|
|
||||||
</itemizedlist>
|
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
xwayland = {
|
|
||||||
enable = lib.mkOption {
|
disableAutoreload =
|
||||||
type = lib.types.bool;
|
lib.mkEnableOption null
|
||||||
default = true;
|
// {
|
||||||
description = ''
|
description = lib.mdDoc ''
|
||||||
Enable XWayland.
|
Whether to disable automatically reloading Hyprland's configuration when
|
||||||
|
rebuilding the Home Manager profile.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
hidpi = lib.mkOption {
|
|
||||||
type = lib.types.bool;
|
xwayland.enable = lib.mkEnableOption (lib.mdDoc "XWayland") // {default = true;};
|
||||||
default = true;
|
|
||||||
description = ''
|
|
||||||
Enable HiDPI XWayland.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
extraConfig = lib.mkOption {
|
extraConfig = lib.mkOption {
|
||||||
type = lib.types.lines;
|
type = lib.types.nullOr lib.types.lines;
|
||||||
default = "";
|
default = "";
|
||||||
description = ''
|
description = lib.mdDoc ''
|
||||||
Extra configuration lines to add to ~/.config/hypr/hyprland.conf.
|
Extra configuration lines to add to {file}`~/.config/hypr/hyprland.conf`.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
recommendedEnvironment = lib.mkOption {
|
recommendedEnvironment =
|
||||||
type = lib.types.bool;
|
lib.mkEnableOption null
|
||||||
default = true;
|
// {
|
||||||
defaultText = lib.literalExpression "true";
|
description = lib.mdDoc ''
|
||||||
example = lib.literalExpression "false";
|
Whether to set the recommended environment variables.
|
||||||
description = ''
|
'';
|
||||||
Whether to set the recommended environment variables.
|
};
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
imports = [
|
|
||||||
(
|
|
||||||
lib.mkRenamedOptionModule
|
|
||||||
["wayland" "windowManager" "hyprland" "xwayland"]
|
|
||||||
["wayland" "windowManager" "hyprland" "xwayland" "enable"]
|
|
||||||
)
|
|
||||||
];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
config = lib.mkIf cfg.enable {
|
config = lib.mkIf cfg.enable {
|
||||||
|
warnings =
|
||||||
|
if (cfg.systemdIntegration || cfg.plugins != []) && cfg.extraConfig == null
|
||||||
|
then [
|
||||||
|
''
|
||||||
|
You have enabled hyprland.systemdIntegration or listed plugins in hyprland.plugins.
|
||||||
|
Your Hyprland config will be linked by home manager.
|
||||||
|
Set hyprland.extraConfig or unset hyprland.systemdIntegration and hyprland.plugins to remove this warning.
|
||||||
|
''
|
||||||
|
]
|
||||||
|
else [];
|
||||||
|
|
||||||
home.packages =
|
home.packages =
|
||||||
lib.optional (cfg.package != null) cfg.package
|
lib.optional (cfg.package != null) cfg.package
|
||||||
++ lib.optional cfg.xwayland.enable pkgs.xwayland;
|
++ lib.optional cfg.xwayland.enable pkgs.xwayland;
|
||||||
|
|
||||||
home.sessionVariables = lib.mkIf cfg.recommendedEnvironment {
|
home.sessionVariables =
|
||||||
GDK_BACKEND = "wayland,x11";
|
lib.mkIf cfg.recommendedEnvironment {NIXOS_OZONE_WL = "1";};
|
||||||
_JAVA_AWT_WM_NONREPARENTING = "1";
|
|
||||||
NIXOS_OZONE_WL = "1";
|
|
||||||
XCURSOR_SIZE = toString config.home.pointerCursor.size or "24";
|
|
||||||
XDG_SESSION_TYPE = "wayland";
|
|
||||||
};
|
|
||||||
|
|
||||||
xdg.configFile."hypr/hyprland.conf" = {
|
xdg.configFile."hypr/hyprland.conf" = lib.mkIf (cfg.systemdIntegration || cfg.extraConfig != null || cfg.plugins != []) {
|
||||||
text =
|
text =
|
||||||
(lib.optionalString cfg.systemdIntegration ''
|
(lib.optionalString cfg.systemdIntegration ''
|
||||||
exec-once=${pkgs.dbus}/bin/dbus-update-activation-environment --systemd DISPLAY WAYLAND_DISPLAY HYPRLAND_INSTANCE_SIGNATURE XDG_CURRENT_DESKTOP
|
exec-once=${pkgs.dbus}/bin/dbus-update-activation-environment --systemd DISPLAY WAYLAND_DISPLAY HYPRLAND_INSTANCE_SIGNATURE XDG_CURRENT_DESKTOP && systemctl --user start hyprland-session.target
|
||||||
exec-once=systemctl --user start hyprland-session.target
|
|
||||||
'')
|
'')
|
||||||
+ cfg.extraConfig;
|
+ lib.concatStrings (builtins.map (entry: let
|
||||||
|
plugin =
|
||||||
|
if lib.types.package.check entry
|
||||||
|
then "${entry}/lib/lib${entry.pname}.so"
|
||||||
|
else entry;
|
||||||
|
in "plugin = ${plugin}\n")
|
||||||
|
cfg.plugins)
|
||||||
|
+ (
|
||||||
|
if cfg.extraConfig != null
|
||||||
|
then cfg.extraConfig
|
||||||
|
else ""
|
||||||
|
);
|
||||||
|
|
||||||
onChange = let
|
onChange = let
|
||||||
hyprlandPackage =
|
hyprlandPackage =
|
||||||
if cfg.package == null
|
if cfg.package == null
|
||||||
then defaultHyprlandPackage
|
then defaultHyprlandPackage
|
||||||
else cfg.package;
|
else cfg.package;
|
||||||
in "HYPRLAND_INSTANCE_SIGNATURE=$(ls -w 1 /tmp/hypr | tail -1) ${hyprlandPackage}/bin/hyprctl reload config-only";
|
in
|
||||||
|
lib.mkIf (!cfg.disableAutoreload) ''
|
||||||
|
( # execute in subshell so that `shopt` won't affect other scripts
|
||||||
|
shopt -s nullglob # so that nothing is done if /tmp/hypr/ does not exist or is empty
|
||||||
|
for instance in /tmp/hypr/*; do
|
||||||
|
HYPRLAND_INSTANCE_SIGNATURE=''${instance##*/} ${hyprlandPackage}/bin/hyprctl reload config-only \
|
||||||
|
|| true # ignore dead instance(s)
|
||||||
|
done
|
||||||
|
)
|
||||||
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
systemd.user.targets.hyprland-session = lib.mkIf cfg.systemdIntegration {
|
systemd.user.targets.hyprland-session = lib.mkIf cfg.systemdIntegration {
|
||||||
Unit = {
|
Unit = {
|
||||||
Description = "hyprland compositor session";
|
Description = "Hyprland compositor session";
|
||||||
Documentation = ["man:systemd.special(7)"];
|
Documentation = ["man:systemd.special(7)"];
|
||||||
BindsTo = ["graphical-session.target"];
|
BindsTo = ["graphical-session.target"];
|
||||||
Wants = ["graphical-session-pre.target"];
|
Wants = ["graphical-session-pre.target"];
|
||||||
After = ["graphical-session-pre.target"];
|
After = ["graphical-session-pre.target"];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
systemd.user.targets.tray = {
|
|
||||||
Unit = {
|
|
||||||
Description = "Home Manager System Tray";
|
|
||||||
Requires = ["graphical-session-pre.target"];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
imports = [
|
||||||
|
(lib.mkRemovedOptionModule ["wayland" "windowManager" "hyprland" "xwayland" "hidpi"]
|
||||||
|
"Support for this option has been removed. Refer to https://wiki.hyprland.org/Configuring/XWayland for more info")
|
||||||
|
(lib.mkRemovedOptionModule ["wayland" "windowManager" "hyprland" "xwayland" "enableNvidiaPatches"]
|
||||||
|
"Nvidia patches are no longer needed for Hyprland")
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,36 +0,0 @@
|
|||||||
diff --git a/meson.build b/meson.build
|
|
||||||
index 22ee4bf..5528613 100644
|
|
||||||
--- a/meson.build
|
|
||||||
+++ b/meson.build
|
|
||||||
@@ -2,16 +2,10 @@ project('Hyprland', 'cpp', 'c',
|
|
||||||
version : '0.1',
|
|
||||||
default_options : ['warning_level=3', 'cpp_std=c++20', 'default_library=static'])
|
|
||||||
|
|
||||||
-wlroots = subproject('wlroots', default_options: ['examples=false'])
|
|
||||||
-have_xwlr = wlroots.get_variable('features').get('xwayland')
|
|
||||||
+wlroots = dependency('wlroots', version: '>=0.16.0')
|
|
||||||
xcb_dep = dependency('xcb', required: get_option('xwayland'))
|
|
||||||
|
|
||||||
-if get_option('xwayland').enabled() and not have_xwlr
|
|
||||||
- error('Cannot enable Xwayland in Hyprland: wlroots has been built without Xwayland support')
|
|
||||||
-endif
|
|
||||||
-have_xwayland = xcb_dep.found() and have_xwlr
|
|
||||||
-
|
|
||||||
-if not have_xwayland
|
|
||||||
+if not xcb_dep.found()
|
|
||||||
add_project_arguments('-DNO_XWAYLAND', language: 'cpp')
|
|
||||||
endif
|
|
||||||
|
|
||||||
diff --git a/src/meson.build b/src/meson.build
|
|
||||||
index 5d64188..a676333 100644
|
|
||||||
--- a/src/meson.build
|
|
||||||
+++ b/src/meson.build
|
|
||||||
@@ -7,7 +7,7 @@ executable('Hyprland', src,
|
|
||||||
server_protos,
|
|
||||||
dependency('wayland-server'),
|
|
||||||
dependency('wayland-client'),
|
|
||||||
- wlroots.get_variable('wlroots'),
|
|
||||||
+ wlroots,
|
|
||||||
dependency('cairo'),
|
|
||||||
dependency('pango'),
|
|
||||||
dependency('pangocairo'),
|
|
||||||
111
nix/module.nix
111
nix/module.nix
@@ -1,70 +1,97 @@
|
|||||||
# Copied from https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/programs/sway.nix
|
inputs: {
|
||||||
self: {
|
|
||||||
config,
|
config,
|
||||||
lib,
|
lib,
|
||||||
pkgs,
|
pkgs,
|
||||||
|
options,
|
||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
with lib; let
|
with lib; let
|
||||||
cfg = config.programs.hyprland;
|
cfg = config.programs.hyprland;
|
||||||
|
inherit (pkgs.stdenv.hostPlatform) system;
|
||||||
|
|
||||||
|
finalPortalPackage = cfg.portalPackage.override {
|
||||||
|
hyprland = cfg.finalPackage;
|
||||||
|
};
|
||||||
in {
|
in {
|
||||||
imports = [
|
# disables Nixpkgs Hyprland module to avoid conflicts
|
||||||
(mkRemovedOptionModule ["programs" "hyprland" "extraPackages"] "extraPackages has been removed. Use environment.systemPackages instead.")
|
disabledModules = ["programs/hyprland.nix"];
|
||||||
];
|
|
||||||
|
|
||||||
options.programs.hyprland = {
|
options.programs.hyprland = {
|
||||||
enable = mkEnableOption ''
|
enable =
|
||||||
Hyprland, the dynamic tiling Wayland compositor that doesn't sacrifice on its looks.
|
mkEnableOption null
|
||||||
You can manually launch Hyprland by executing "exec Hyprland" on a TTY.
|
// {
|
||||||
A configuration file will be generated in ~/.config/hypr/hyprland.conf.
|
description = mdDoc ''
|
||||||
See <link xlink:href="https://github.com/vaxerski/Hyprland/wiki" /> for
|
Hyprland, the dynamic tiling Wayland compositor that doesn't sacrifice on its looks.
|
||||||
more information.
|
|
||||||
'';
|
|
||||||
|
|
||||||
package = mkOption {
|
You can manually launch Hyprland by executing {command}`Hyprland` on a TTY.
|
||||||
type = types.nullOr types.package;
|
|
||||||
default = self.packages.${pkgs.system}.default;
|
A configuration file will be generated in {file}`~/.config/hypr/hyprland.conf`.
|
||||||
defaultText = literalExpression "<Hyprland flake>.packages.<system>.default";
|
See <https://wiki.hyprland.org> for more information.
|
||||||
example = literalExpression "<Hyprland flake>.packages.<system>.default.override { }";
|
'';
|
||||||
description = ''
|
};
|
||||||
Hyprland package to use.
|
|
||||||
|
package = mkPackageOptionMD inputs.self.packages.${system} "hyprland" { };
|
||||||
|
|
||||||
|
finalPackage = mkOption {
|
||||||
|
type = types.package;
|
||||||
|
readOnly = true;
|
||||||
|
default = cfg.package.override {
|
||||||
|
enableXWayland = cfg.xwayland.enable;
|
||||||
|
};
|
||||||
|
defaultText =
|
||||||
|
literalExpression
|
||||||
|
"`programs.hyprland.package` with applied configuration";
|
||||||
|
description = mdDoc ''
|
||||||
|
The Hyprland package after applying configuration.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
recommendedEnvironment = mkOption {
|
portalPackage = mkPackageOptionMD inputs.xdph.packages.${system} "xdg-desktop-portal-hyprland" {};
|
||||||
type = types.bool;
|
|
||||||
default = true;
|
xwayland.enable = mkEnableOption (mdDoc "support for XWayland") // {default = true;};
|
||||||
defaultText = literalExpression "true";
|
|
||||||
example = literalExpression "false";
|
|
||||||
description = ''
|
|
||||||
Whether to set the recommended environment variables.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
config = mkIf cfg.enable {
|
config = mkIf cfg.enable {
|
||||||
environment = {
|
environment.systemPackages = [cfg.finalPackage];
|
||||||
systemPackages = lib.optional (cfg.package != null) cfg.package;
|
|
||||||
|
# NixOS changed the name of this attribute between NixOS 23.05 and
|
||||||
|
# 23.11
|
||||||
|
fonts = if builtins.hasAttr "enableDefaultPackages" options.fonts
|
||||||
|
then {enableDefaultPackages = mkDefault true;}
|
||||||
|
else {enableDefaultFonts = mkDefault true;};
|
||||||
|
|
||||||
sessionVariables = mkIf cfg.recommendedEnvironment {
|
|
||||||
GDK_BACKEND = "wayland,x11";
|
|
||||||
_JAVA_AWT_WM_NONREPARENTING = "1";
|
|
||||||
NIXOS_OZONE_WL = "1";
|
|
||||||
XCURSOR_SIZE = "24";
|
|
||||||
XDG_SESSION_TYPE = "wayland";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
fonts.enableDefaultFonts = mkDefault true;
|
|
||||||
hardware.opengl.enable = mkDefault true;
|
hardware.opengl.enable = mkDefault true;
|
||||||
|
|
||||||
programs = {
|
programs = {
|
||||||
dconf.enable = mkDefault true;
|
dconf.enable = mkDefault true;
|
||||||
xwayland.enable = mkDefault true;
|
xwayland.enable = mkDefault cfg.xwayland.enable;
|
||||||
};
|
};
|
||||||
|
|
||||||
security.polkit.enable = true;
|
security.polkit.enable = true;
|
||||||
services.xserver.displayManager.sessionPackages = lib.optional (cfg.package != null) cfg.package;
|
|
||||||
|
services.xserver.displayManager.sessionPackages = [cfg.finalPackage];
|
||||||
|
|
||||||
xdg.portal = {
|
xdg.portal = {
|
||||||
enable = mkDefault true;
|
enable = mkDefault true;
|
||||||
extraPortals = [pkgs.xdg-desktop-portal-wlr];
|
extraPortals = [finalPortalPackage];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
imports = with lib; [
|
||||||
|
(
|
||||||
|
mkRemovedOptionModule
|
||||||
|
["programs" "hyprland" "xwayland" "hidpi"]
|
||||||
|
"XWayland patches are deprecated. Refer to https://wiki.hyprland.org/Configuring/XWayland"
|
||||||
|
)
|
||||||
|
(
|
||||||
|
mkRemovedOptionModule
|
||||||
|
["programs" "hyprland" "enableNvidiaPatches"]
|
||||||
|
"Nvidia patches are no longer needed"
|
||||||
|
)
|
||||||
|
(
|
||||||
|
mkRemovedOptionModule
|
||||||
|
["programs" "hyprland" "nvidiaPatches"]
|
||||||
|
"Nvidia patches are no longer needed"
|
||||||
|
)
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
99
nix/overlays.nix
Normal file
99
nix/overlays.nix
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
{
|
||||||
|
self,
|
||||||
|
lib,
|
||||||
|
inputs,
|
||||||
|
}: let
|
||||||
|
props = builtins.fromJSON (builtins.readFile ../props.json);
|
||||||
|
|
||||||
|
mkDate = longDate: (lib.concatStringsSep "-" [
|
||||||
|
(builtins.substring 0 4 longDate)
|
||||||
|
(builtins.substring 4 2 longDate)
|
||||||
|
(builtins.substring 6 2 longDate)
|
||||||
|
]);
|
||||||
|
|
||||||
|
mkJoinedOverlays = overlays: final: prev:
|
||||||
|
lib.foldl' (attrs: overlay: attrs // (overlay final prev)) {} overlays;
|
||||||
|
in {
|
||||||
|
# Contains what a user is most likely to care about:
|
||||||
|
# Hyprland itself, XDPH and the Share Picker.
|
||||||
|
default = mkJoinedOverlays (with self.overlays; [
|
||||||
|
hyprland-packages
|
||||||
|
hyprland-extras
|
||||||
|
]);
|
||||||
|
|
||||||
|
# Packages for variations of Hyprland, dependencies included.
|
||||||
|
hyprland-packages = mkJoinedOverlays [
|
||||||
|
# Dependencies
|
||||||
|
inputs.hyprland-protocols.overlays.default
|
||||||
|
self.overlays.wlroots-hyprland
|
||||||
|
self.overlays.udis86
|
||||||
|
# Hyprland packages themselves
|
||||||
|
(final: prev: {
|
||||||
|
hyprland = final.callPackage ./default.nix {
|
||||||
|
stdenv = final.gcc13Stdenv;
|
||||||
|
version = "${props.version}+date=${mkDate (self.lastModifiedDate or "19700101")}_${self.shortRev or "dirty"}";
|
||||||
|
wlroots = final.wlroots-hyprland;
|
||||||
|
commit = self.rev or "";
|
||||||
|
inherit (final) udis86 hyprland-protocols;
|
||||||
|
};
|
||||||
|
hyprland-unwrapped = final.hyprland.override {wrapRuntimeDeps = false;};
|
||||||
|
hyprland-debug = final.hyprland.override {debug = true;};
|
||||||
|
hyprland-nvidia =
|
||||||
|
builtins.trace ''
|
||||||
|
hyprland-nvidia was removed. Please use the hyprland package.
|
||||||
|
Nvidia patches are no longer needed.
|
||||||
|
''
|
||||||
|
final.hyprland;
|
||||||
|
hyprland-hidpi =
|
||||||
|
builtins.trace ''
|
||||||
|
hyprland-hidpi was removed. Please use the hyprland package.
|
||||||
|
For more information, refer to https://wiki.hyprland.org/Configuring/XWayland.
|
||||||
|
''
|
||||||
|
final.hyprland;
|
||||||
|
})
|
||||||
|
];
|
||||||
|
|
||||||
|
# Packages for extra software recommended for usage with Hyprland,
|
||||||
|
# including forked or patched packages for compatibility.
|
||||||
|
hyprland-extras = mkJoinedOverlays [
|
||||||
|
inputs.xdph.overlays.xdg-desktop-portal-hyprland
|
||||||
|
];
|
||||||
|
|
||||||
|
udis86 = final: prev: {
|
||||||
|
udis86 = final.callPackage ./udis86.nix {};
|
||||||
|
};
|
||||||
|
|
||||||
|
# Patched version of wlroots for Hyprland.
|
||||||
|
# It is under a new package name so as to not conflict with
|
||||||
|
# the standard version in nixpkgs.
|
||||||
|
wlroots-hyprland = final: prev: {
|
||||||
|
wlroots-hyprland = final.callPackage ./wlroots.nix {
|
||||||
|
version = "${mkDate (inputs.wlroots.lastModifiedDate or "19700101")}_${inputs.wlroots.shortRev or "dirty"}";
|
||||||
|
src = inputs.wlroots;
|
||||||
|
|
||||||
|
libdisplay-info = prev.libdisplay-info.overrideAttrs (old: {
|
||||||
|
version = "0.1.1+date=2023-03-02";
|
||||||
|
src = final.fetchFromGitLab {
|
||||||
|
domain = "gitlab.freedesktop.org";
|
||||||
|
owner = "emersion";
|
||||||
|
repo = old.pname;
|
||||||
|
rev = "147d6611a64a6ab04611b923e30efacaca6fc678";
|
||||||
|
sha256 = "sha256-/q79o13Zvu7x02SBGu0W5yQznQ+p7ltZ9L6cMW5t/o4=";
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
libliftoff = prev.libliftoff.overrideAttrs (old: {
|
||||||
|
version = "0.5.0-dev";
|
||||||
|
src = final.fetchFromGitLab {
|
||||||
|
domain = "gitlab.freedesktop.org";
|
||||||
|
owner = "emersion";
|
||||||
|
repo = old.pname;
|
||||||
|
rev = "d98ae243280074b0ba44bff92215ae8d785658c0";
|
||||||
|
sha256 = "sha256-DjwlS8rXE7srs7A8+tHqXyUsFGtucYSeq6X0T/pVOc8=";
|
||||||
|
};
|
||||||
|
|
||||||
|
NIX_CFLAGS_COMPILE = toString ["-Wno-error=sign-conversion"];
|
||||||
|
});
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
59
nix/patches/meson-build.patch
Normal file
59
nix/patches/meson-build.patch
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
diff --git a/meson.build b/meson.build
|
||||||
|
index 1d2c7f9f..c5ef4e67 100644
|
||||||
|
--- a/meson.build
|
||||||
|
+++ b/meson.build
|
||||||
|
@@ -33,20 +33,7 @@ if cpp_compiler.check_header('execinfo.h')
|
||||||
|
add_project_arguments('-DHAS_EXECINFO', language: 'cpp')
|
||||||
|
endif
|
||||||
|
|
||||||
|
-wlroots = subproject('wlroots', default_options: ['examples=false', 'renderers=gles2'])
|
||||||
|
-have_xwlr = wlroots.get_variable('features').get('xwayland')
|
||||||
|
-xcb_dep = dependency('xcb', required: get_option('xwayland'))
|
||||||
|
-
|
||||||
|
-cmake = import('cmake')
|
||||||
|
-udis = cmake.subproject('udis86')
|
||||||
|
-udis86 = udis.dependency('libudis86')
|
||||||
|
-
|
||||||
|
-if get_option('xwayland').enabled() and not have_xwlr
|
||||||
|
- error('Cannot enable Xwayland in Hyprland: wlroots has been built without Xwayland support')
|
||||||
|
-endif
|
||||||
|
-have_xwayland = xcb_dep.found() and have_xwlr
|
||||||
|
-
|
||||||
|
-if not have_xwayland
|
||||||
|
+if get_option('xwayland').disabled()
|
||||||
|
add_project_arguments('-DNO_XWAYLAND', language: 'cpp')
|
||||||
|
endif
|
||||||
|
|
||||||
|
@@ -69,8 +56,6 @@ if get_option('buildtype') == 'debug'
|
||||||
|
add_project_arguments('-DHYPRLAND_DEBUG', language: 'cpp')
|
||||||
|
endif
|
||||||
|
|
||||||
|
-version_h = run_command('sh', '-c', 'scripts/generateVersion.sh')
|
||||||
|
-
|
||||||
|
globber = run_command('find', 'src', '-name', '*.h*', check: true)
|
||||||
|
headers = globber.stdout().strip().split('\n')
|
||||||
|
foreach file : headers
|
||||||
|
diff --git a/src/meson.build b/src/meson.build
|
||||||
|
index 0af864b9..38723b8c 100644
|
||||||
|
--- a/src/meson.build
|
||||||
|
+++ b/src/meson.build
|
||||||
|
@@ -9,16 +9,16 @@ executable('Hyprland', src,
|
||||||
|
server_protos,
|
||||||
|
dependency('wayland-server'),
|
||||||
|
dependency('wayland-client'),
|
||||||
|
- wlroots.get_variable('wlroots'),
|
||||||
|
+ dependency('wlroots'),
|
||||||
|
dependency('cairo'),
|
||||||
|
dependency('libdrm'),
|
||||||
|
dependency('egl'),
|
||||||
|
dependency('xkbcommon'),
|
||||||
|
dependency('libinput'),
|
||||||
|
- xcb_dep,
|
||||||
|
+ dependency('xcb', required: get_option('xwayland')),
|
||||||
|
backtrace_dep,
|
||||||
|
systemd_dep,
|
||||||
|
- udis86,
|
||||||
|
+ dependency('udis86'),
|
||||||
|
|
||||||
|
dependency('pixman-1'),
|
||||||
|
dependency('gl', 'opengl'),
|
||||||
32
nix/udis86.nix
Normal file
32
nix/udis86.nix
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
{
|
||||||
|
lib,
|
||||||
|
stdenv,
|
||||||
|
fetchFromGitHub,
|
||||||
|
autoreconfHook,
|
||||||
|
python3,
|
||||||
|
}:
|
||||||
|
stdenv.mkDerivation {
|
||||||
|
pname = "udis86";
|
||||||
|
version = "unstable-2022-10-13";
|
||||||
|
|
||||||
|
src = fetchFromGitHub {
|
||||||
|
owner = "canihavesomecoffee";
|
||||||
|
repo = "udis86";
|
||||||
|
rev = "5336633af70f3917760a6d441ff02d93477b0c86";
|
||||||
|
hash = "sha256-HifdUQPGsKQKQprByeIznvRLONdOXeolOsU5nkwIv3g=";
|
||||||
|
};
|
||||||
|
|
||||||
|
nativeBuildInputs = [autoreconfHook python3];
|
||||||
|
|
||||||
|
configureFlags = ["--enable-shared"];
|
||||||
|
|
||||||
|
outputs = ["bin" "out" "dev" "lib"];
|
||||||
|
|
||||||
|
meta = with lib; {
|
||||||
|
homepage = "https://udis86.sourceforge.net";
|
||||||
|
license = licenses.bsd2;
|
||||||
|
mainProgram = "udcli";
|
||||||
|
description = "Easy-to-use, minimalistic x86 disassembler library (libudis86)";
|
||||||
|
platforms = platforms.all;
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -1,19 +1,19 @@
|
|||||||
#!/usr/bin/env -S nix shell nixpkgs#gawk nixpkgs#git nixpkgs#moreutils nixpkgs#jq -c bash
|
#!/usr/bin/env -S nix shell nixpkgs#jq -c bash
|
||||||
|
|
||||||
# get wlroots revision from submodule
|
# Update inputs when the Mesa version is outdated. We don't want
|
||||||
SUB_REV=$(git submodule status | awk '{ print substr($1,2)}')
|
# incompatibilities between the user's system and Hyprland.
|
||||||
# and from lockfile
|
|
||||||
CRT_REV=$(jq < flake.lock '.nodes.wlroots.locked.rev' -r)
|
|
||||||
|
|
||||||
if [ $SUB_REV != $CRT_REV ]; then
|
# get the current Nixpkgs revision
|
||||||
# update nixpkgs to latest version
|
REV=$(jq <flake.lock '.nodes.nixpkgs.locked.rev' -r)
|
||||||
nix flake lock --update-input nixpkgs
|
# check versions for current and remote nixpkgs' mesa
|
||||||
|
CRT_VER=$(nix eval --raw github:nixos/nixpkgs/"$REV"#mesa.version)
|
||||||
|
NEW_VER=$(nix eval --raw github:nixos/nixpkgs/nixos-unstable#mesa.version)
|
||||||
|
|
||||||
# update wlroots to submodule revision
|
if [ "$CRT_VER" != "$NEW_VER" ]; then
|
||||||
nix flake lock --override-input wlroots "gitlab:wlroots/wlroots/$SUB_REV?host=gitlab.freedesktop.org"
|
echo "Updating Mesa $CRT_VER -> $NEW_VER and flake inputs"
|
||||||
|
|
||||||
# remove "dirty" mark from lockfile
|
# update inputs to latest versions
|
||||||
jq < flake.lock 'del(.nodes.wlroots.original.rev)' | sponge flake.lock
|
nix flake update
|
||||||
else
|
else
|
||||||
echo "wlroots is up to date!"
|
echo "nixpkgs is up to date!"
|
||||||
fi
|
fi
|
||||||
|
|||||||
17
nix/update-wlroots.sh
Executable file
17
nix/update-wlroots.sh
Executable file
@@ -0,0 +1,17 @@
|
|||||||
|
#!/usr/bin/env -S nix shell nixpkgs#gawk nixpkgs#git nixpkgs#gnused nixpkgs#ripgrep -c bash
|
||||||
|
|
||||||
|
# get wlroots revision from submodule
|
||||||
|
SUB_REV=$(git submodule status | rg wlroots | awk '{ print substr($1,2) }')
|
||||||
|
# and from lockfile
|
||||||
|
CRT_REV=$(rg rev flake.nix | awk '{ print substr($3, 2, 40) }')
|
||||||
|
|
||||||
|
if [ "$SUB_REV" != "$CRT_REV" ]; then
|
||||||
|
echo "Updating wlroots..."
|
||||||
|
# update wlroots to submodule revision
|
||||||
|
sed -Ei "s/\w{40}/$SUB_REV/g" flake.nix subprojects/wlroots.wrap
|
||||||
|
nix flake lock
|
||||||
|
|
||||||
|
echo "wlroots: $CRT_REV -> $SUB_REV"
|
||||||
|
else
|
||||||
|
echo "wlroots is up to date!"
|
||||||
|
fi
|
||||||
@@ -1,64 +1,33 @@
|
|||||||
{
|
{
|
||||||
|
fetchurl,
|
||||||
version,
|
version,
|
||||||
src,
|
src,
|
||||||
#
|
|
||||||
wlroots,
|
wlroots,
|
||||||
xwayland,
|
hwdata,
|
||||||
fetchpatch,
|
libdisplay-info,
|
||||||
lib,
|
libliftoff,
|
||||||
hidpiXWayland ? true,
|
libdrm,
|
||||||
enableXWayland ? true,
|
enableXWayland ? true,
|
||||||
nvidiaPatches ? false,
|
|
||||||
}:
|
}:
|
||||||
assert (lib.assertMsg (hidpiXWayland -> enableXWayland) ''
|
let
|
||||||
wlroots-hyprland: cannot have hidpiXWayland when enableXWayland is false.
|
# NOTE: remove after https://github.com/NixOS/nixpkgs/pull/271096 reaches nixos-unstable
|
||||||
'');
|
libdrm_2_4_118 = libdrm.overrideAttrs(old: rec {
|
||||||
(wlroots.overrideAttrs
|
version = "2.4.118";
|
||||||
(old: {
|
src = fetchurl {
|
||||||
inherit version src;
|
url = "https://dri.freedesktop.org/${old.pname}/${old.pname}-${version}.tar.xz";
|
||||||
pname =
|
hash = "sha256-p3e9hfK1/JxX+IbIIFgwBXgxfK/bx30Kdp1+mpVnq4g=";
|
||||||
old.pname
|
};
|
||||||
+ "-hyprland"
|
});
|
||||||
+ (
|
in
|
||||||
if hidpiXWayland
|
wlroots.overrideAttrs (old: {
|
||||||
then "-hidpi"
|
inherit version src enableXWayland;
|
||||||
else ""
|
|
||||||
)
|
pname = "${old.pname}-hyprland";
|
||||||
+ (
|
|
||||||
if nvidiaPatches
|
# HACK: libdrm_2_4_118 is placed at the head of list to take precedence over libdrm in `old.buildInputs`
|
||||||
then "-nvidia"
|
buildInputs = [libdrm_2_4_118] ++ old.buildInputs ++ [hwdata libliftoff libdisplay-info];
|
||||||
else ""
|
|
||||||
);
|
NIX_CFLAGS_COMPILE = toString [
|
||||||
patches =
|
"-Wno-error=maybe-uninitialized"
|
||||||
(old.patches or [])
|
];
|
||||||
++ (lib.optionals (enableXWayland && hidpiXWayland) [
|
})
|
||||||
(fetchpatch {
|
|
||||||
url = "https://gitlab.freedesktop.org/lilydjwg/wlroots/-/commit/6c5ffcd1fee9e44780a6a8792f74ecfbe24a1ca7.diff";
|
|
||||||
sha256 = "sha256-Eo1pTa/PIiJsRZwIUnHGTIFFIedzODVf0ZeuXb0a3TQ=";
|
|
||||||
})
|
|
||||||
(fetchpatch {
|
|
||||||
url = "https://gitlab.freedesktop.org/wlroots/wlroots/-/commit/18595000f3a21502fd60bf213122859cc348f9af.diff";
|
|
||||||
sha256 = "sha256-jvfkAMh3gzkfuoRhB4E9T5X1Hu62wgUjj4tZkJm0mrI=";
|
|
||||||
revert = true;
|
|
||||||
})
|
|
||||||
]);
|
|
||||||
postPatch =
|
|
||||||
(old.postPatch or "")
|
|
||||||
+ (
|
|
||||||
if nvidiaPatches
|
|
||||||
then ''
|
|
||||||
substituteInPlace render/gles2/renderer.c --replace "glFlush();" "glFinish();"
|
|
||||||
''
|
|
||||||
else ""
|
|
||||||
);
|
|
||||||
}))
|
|
||||||
.override {
|
|
||||||
xwayland = xwayland.overrideAttrs (old: {
|
|
||||||
patches =
|
|
||||||
(old.patches or [])
|
|
||||||
++ (lib.optionals hidpiXWayland [
|
|
||||||
./xwayland-vsync.patch
|
|
||||||
./xwayland-hidpi.patch
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,498 +0,0 @@
|
|||||||
diff --git a/hw/xwayland/xwayland-cursor.c b/hw/xwayland/xwayland-cursor.c
|
|
||||||
index c4457cc2a61b2103b47f996b51dbbe9eb87bd715..4a33e1f33e73c35c1691564ef4852e7501b02245 100644
|
|
||||||
--- a/hw/xwayland/xwayland-cursor.c
|
|
||||||
+++ b/hw/xwayland/xwayland-cursor.c
|
|
||||||
@@ -171,6 +171,8 @@ xwl_cursor_attach_pixmap(struct xwl_seat *xwl_seat,
|
|
||||||
}
|
|
||||||
|
|
||||||
wl_surface_attach(xwl_cursor->surface, buffer, 0, 0);
|
|
||||||
+ wl_surface_set_buffer_scale(xwl_cursor->surface,
|
|
||||||
+ xwl_seat->xwl_screen->global_output_scale);
|
|
||||||
xwl_surface_damage(xwl_seat->xwl_screen, xwl_cursor->surface, 0, 0,
|
|
||||||
xwl_seat->x_cursor->bits->width,
|
|
||||||
xwl_seat->x_cursor->bits->height);
|
|
||||||
@@ -190,6 +192,7 @@ xwl_cursor_attach_pixmap(struct xwl_seat *xwl_seat,
|
|
||||||
void
|
|
||||||
xwl_seat_set_cursor(struct xwl_seat *xwl_seat)
|
|
||||||
{
|
|
||||||
+ struct xwl_screen *xwl_screen = xwl_seat->xwl_screen;
|
|
||||||
struct xwl_cursor *xwl_cursor = &xwl_seat->cursor;
|
|
||||||
PixmapPtr pixmap;
|
|
||||||
CursorPtr cursor;
|
|
||||||
@@ -220,8 +223,8 @@ xwl_seat_set_cursor(struct xwl_seat *xwl_seat)
|
|
||||||
wl_pointer_set_cursor(xwl_seat->wl_pointer,
|
|
||||||
xwl_seat->pointer_enter_serial,
|
|
||||||
xwl_cursor->surface,
|
|
||||||
- xwl_seat->x_cursor->bits->xhot,
|
|
||||||
- xwl_seat->x_cursor->bits->yhot);
|
|
||||||
+ xwl_scale_to(xwl_screen, xwl_seat->x_cursor->bits->xhot),
|
|
||||||
+ xwl_scale_to(xwl_screen, xwl_seat->x_cursor->bits->yhot));
|
|
||||||
|
|
||||||
xwl_cursor_attach_pixmap(xwl_seat, xwl_cursor, pixmap);
|
|
||||||
}
|
|
||||||
@@ -230,6 +233,7 @@ void
|
|
||||||
xwl_tablet_tool_set_cursor(struct xwl_tablet_tool *xwl_tablet_tool)
|
|
||||||
{
|
|
||||||
struct xwl_seat *xwl_seat = xwl_tablet_tool->seat;
|
|
||||||
+ struct xwl_screen *xwl_screen = xwl_seat->xwl_screen;
|
|
||||||
struct xwl_cursor *xwl_cursor = &xwl_tablet_tool->cursor;
|
|
||||||
PixmapPtr pixmap;
|
|
||||||
CursorPtr cursor;
|
|
||||||
@@ -258,9 +262,9 @@ xwl_tablet_tool_set_cursor(struct xwl_tablet_tool *xwl_tablet_tool)
|
|
||||||
zwp_tablet_tool_v2_set_cursor(xwl_tablet_tool->tool,
|
|
||||||
xwl_tablet_tool->proximity_in_serial,
|
|
||||||
xwl_cursor->surface,
|
|
||||||
- xwl_seat->x_cursor->bits->xhot,
|
|
||||||
- xwl_seat->x_cursor->bits->yhot);
|
|
||||||
-
|
|
||||||
+ xwl_scale_to(xwl_screen, xwl_seat->x_cursor->bits->xhot),
|
|
||||||
+ xwl_scale_to(xwl_screen, xwl_seat->x_cursor->bits->yhot));
|
|
||||||
+ wl_surface_set_buffer_scale(xwl_cursor->surface, xwl_screen->global_output_scale);
|
|
||||||
xwl_cursor_attach_pixmap(xwl_seat, xwl_cursor, pixmap);
|
|
||||||
}
|
|
||||||
|
|
||||||
diff --git a/hw/xwayland/xwayland-input.c b/hw/xwayland/xwayland-input.c
|
|
||||||
index 26b3630c73b62514fe3ba7824371f79868e953f3..55cd8d466a55db03948abe93ffa03bf129b5e17a 100644
|
|
||||||
--- a/hw/xwayland/xwayland-input.c
|
|
||||||
+++ b/hw/xwayland/xwayland-input.c
|
|
||||||
@@ -412,8 +412,8 @@ pointer_handle_enter(void *data, struct wl_pointer *pointer,
|
|
||||||
DeviceIntPtr dev = get_pointer_device(xwl_seat);
|
|
||||||
DeviceIntPtr master;
|
|
||||||
int i;
|
|
||||||
- int sx = wl_fixed_to_int(sx_w);
|
|
||||||
- int sy = wl_fixed_to_int(sy_w);
|
|
||||||
+ int sx = wl_fixed_to_int(sx_w) * xwl_seat->xwl_screen->global_output_scale;
|
|
||||||
+ int sy = wl_fixed_to_int(sy_w) * xwl_seat->xwl_screen->global_output_scale;
|
|
||||||
int dx, dy;
|
|
||||||
ScreenPtr pScreen = xwl_seat->xwl_screen->screen;
|
|
||||||
ValuatorMask mask;
|
|
||||||
@@ -592,13 +592,14 @@ pointer_handle_motion(void *data, struct wl_pointer *pointer,
|
|
||||||
uint32_t time, wl_fixed_t sx_w, wl_fixed_t sy_w)
|
|
||||||
{
|
|
||||||
struct xwl_seat *xwl_seat = data;
|
|
||||||
+ int32_t scale = xwl_seat->xwl_screen->global_output_scale;
|
|
||||||
|
|
||||||
if (!xwl_seat->focus_window)
|
|
||||||
return;
|
|
||||||
|
|
||||||
xwl_seat->pending_pointer_event.has_absolute = TRUE;
|
|
||||||
- xwl_seat->pending_pointer_event.x = sx_w;
|
|
||||||
- xwl_seat->pending_pointer_event.y = sy_w;
|
|
||||||
+ xwl_seat->pending_pointer_event.x = sx_w * scale;
|
|
||||||
+ xwl_seat->pending_pointer_event.y = sy_w * scale;
|
|
||||||
|
|
||||||
if (wl_proxy_get_version((struct wl_proxy *) xwl_seat->wl_pointer) < 5)
|
|
||||||
dispatch_pointer_motion_event(xwl_seat);
|
|
||||||
@@ -672,7 +673,8 @@ pointer_handle_axis(void *data, struct wl_pointer *pointer,
|
|
||||||
xorg_list_del(&pending->l);
|
|
||||||
free(pending);
|
|
||||||
} else {
|
|
||||||
- valuator_mask_set_double(&mask, index, wl_fixed_to_double(value) / divisor);
|
|
||||||
+ double scaled_value = wl_fixed_to_double(value);
|
|
||||||
+ valuator_mask_set_double(&mask, index, scaled_value / divisor);
|
|
||||||
}
|
|
||||||
|
|
||||||
QueuePointerEvents(get_pointer_device(xwl_seat),
|
|
||||||
@@ -740,12 +742,13 @@ relative_pointer_handle_relative_motion(void *data,
|
|
||||||
wl_fixed_t dy_unaccelf)
|
|
||||||
{
|
|
||||||
struct xwl_seat *xwl_seat = data;
|
|
||||||
+ int32_t scale = xwl_seat->xwl_screen->global_output_scale;
|
|
||||||
|
|
||||||
xwl_seat->pending_pointer_event.has_relative = TRUE;
|
|
||||||
- xwl_seat->pending_pointer_event.dx = wl_fixed_to_double(dxf);
|
|
||||||
- xwl_seat->pending_pointer_event.dy = wl_fixed_to_double(dyf);
|
|
||||||
- xwl_seat->pending_pointer_event.dx_unaccel = wl_fixed_to_double(dx_unaccelf);
|
|
||||||
- xwl_seat->pending_pointer_event.dy_unaccel = wl_fixed_to_double(dy_unaccelf);
|
|
||||||
+ xwl_seat->pending_pointer_event.dx = wl_fixed_to_double(dxf) * scale;
|
|
||||||
+ xwl_seat->pending_pointer_event.dy = wl_fixed_to_double(dyf) * scale;
|
|
||||||
+ xwl_seat->pending_pointer_event.dx_unaccel = wl_fixed_to_double(dx_unaccelf) * scale;
|
|
||||||
+ xwl_seat->pending_pointer_event.dy_unaccel = wl_fixed_to_double(dy_unaccelf) * scale;
|
|
||||||
|
|
||||||
if (!xwl_seat->focus_window)
|
|
||||||
return;
|
|
||||||
@@ -1057,8 +1060,8 @@ touch_handle_down(void *data, struct wl_touch *wl_touch,
|
|
||||||
|
|
||||||
xwl_touch->window = wl_surface_get_user_data(surface);
|
|
||||||
xwl_touch->id = id;
|
|
||||||
- xwl_touch->x = wl_fixed_to_int(sx_w);
|
|
||||||
- xwl_touch->y = wl_fixed_to_int(sy_w);
|
|
||||||
+ xwl_touch->x = wl_fixed_to_int(sx_w) * xwl_seat->xwl_screen->global_output_scale;
|
|
||||||
+ xwl_touch->y = wl_fixed_to_int(sy_w) * xwl_seat->xwl_screen->global_output_scale;
|
|
||||||
xorg_list_add(&xwl_touch->link_touch, &xwl_seat->touches);
|
|
||||||
|
|
||||||
xwl_touch_send_event(xwl_touch, xwl_seat, XI_TouchBegin);
|
|
||||||
@@ -1094,8 +1097,8 @@ touch_handle_motion(void *data, struct wl_touch *wl_touch,
|
|
||||||
if (!xwl_touch)
|
|
||||||
return;
|
|
||||||
|
|
||||||
- xwl_touch->x = wl_fixed_to_int(sx_w);
|
|
||||||
- xwl_touch->y = wl_fixed_to_int(sy_w);
|
|
||||||
+ xwl_touch->x = wl_fixed_to_int(sx_w) * xwl_seat->xwl_screen->global_output_scale;;
|
|
||||||
+ xwl_touch->y = wl_fixed_to_int(sy_w) * xwl_seat->xwl_screen->global_output_scale;;
|
|
||||||
xwl_touch_send_event(xwl_touch, xwl_seat, XI_TouchUpdate);
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1726,8 +1729,8 @@ tablet_tool_motion(void *data, struct zwp_tablet_tool_v2 *tool,
|
|
||||||
struct xwl_tablet_tool *xwl_tablet_tool = data;
|
|
||||||
struct xwl_seat *xwl_seat = xwl_tablet_tool->seat;
|
|
||||||
int32_t dx, dy;
|
|
||||||
- double sx = wl_fixed_to_double(x);
|
|
||||||
- double sy = wl_fixed_to_double(y);
|
|
||||||
+ double sx = wl_fixed_to_double(x) * xwl_seat->xwl_screen->global_output_scale;
|
|
||||||
+ double sy = wl_fixed_to_double(y) * xwl_seat->xwl_screen->global_output_scale;
|
|
||||||
|
|
||||||
if (!xwl_seat->tablet_focus_window)
|
|
||||||
return;
|
|
||||||
@@ -2714,6 +2717,7 @@ xwl_pointer_warp_emulator_set_fake_pos(struct xwl_pointer_warp_emulator *warp_em
|
|
||||||
int x,
|
|
||||||
int y)
|
|
||||||
{
|
|
||||||
+ struct xwl_screen *xwl_screen;
|
|
||||||
struct zwp_locked_pointer_v1 *locked_pointer =
|
|
||||||
warp_emulator->locked_pointer;
|
|
||||||
WindowPtr window;
|
|
||||||
@@ -2725,6 +2729,7 @@ xwl_pointer_warp_emulator_set_fake_pos(struct xwl_pointer_warp_emulator *warp_em
|
|
||||||
if (!warp_emulator->xwl_seat->focus_window)
|
|
||||||
return;
|
|
||||||
|
|
||||||
+ xwl_screen = warp_emulator->xwl_seat->xwl_screen;
|
|
||||||
window = warp_emulator->xwl_seat->focus_window->window;
|
|
||||||
if (x >= window->drawable.x ||
|
|
||||||
y >= window->drawable.y ||
|
|
||||||
@@ -2733,8 +2738,8 @@ xwl_pointer_warp_emulator_set_fake_pos(struct xwl_pointer_warp_emulator *warp_em
|
|
||||||
sx = x - window->drawable.x;
|
|
||||||
sy = y - window->drawable.y;
|
|
||||||
zwp_locked_pointer_v1_set_cursor_position_hint(locked_pointer,
|
|
||||||
- wl_fixed_from_int(sx),
|
|
||||||
- wl_fixed_from_int(sy));
|
|
||||||
+ wl_fixed_from_int(xwl_scale_to(xwl_screen, sx)),
|
|
||||||
+ wl_fixed_from_int(xwl_scale_to(xwl_screen, sy)));
|
|
||||||
wl_surface_commit(warp_emulator->xwl_seat->focus_window->surface);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
diff --git a/hw/xwayland/xwayland-output.c b/hw/xwayland/xwayland-output.c
|
|
||||||
index ef705bc01bf8c2d2f170cda9ba21ed8293f50559..b8f6cd51bd240ed5e16271eb4749db18868bea7b 100644
|
|
||||||
--- a/hw/xwayland/xwayland-output.c
|
|
||||||
+++ b/hw/xwayland/xwayland-output.c
|
|
||||||
@@ -191,6 +191,9 @@ update_screen_size(struct xwl_output *xwl_output, int width, int height)
|
|
||||||
{
|
|
||||||
struct xwl_screen *xwl_screen = xwl_output->xwl_screen;
|
|
||||||
|
|
||||||
+ width *= xwl_screen->global_output_scale;
|
|
||||||
+ height *= xwl_screen->global_output_scale;
|
|
||||||
+
|
|
||||||
if (xwl_screen->root_clip_mode == ROOT_CLIP_FULL)
|
|
||||||
SetRootClip(xwl_screen->screen, ROOT_CLIP_NONE);
|
|
||||||
|
|
||||||
@@ -497,14 +500,15 @@ xwl_output_set_emulated_mode(struct xwl_output *xwl_output, ClientPtr client,
|
|
||||||
xwl_output_set_randr_emu_props(xwl_output->xwl_screen, client);
|
|
||||||
}
|
|
||||||
|
|
||||||
-static void
|
|
||||||
-apply_output_change(struct xwl_output *xwl_output)
|
|
||||||
+void
|
|
||||||
+xwl_output_apply_changes(struct xwl_output *xwl_output)
|
|
||||||
{
|
|
||||||
struct xwl_screen *xwl_screen = xwl_output->xwl_screen;
|
|
||||||
struct xwl_output *it;
|
|
||||||
int mode_width, mode_height, count;
|
|
||||||
int width = 0, height = 0, has_this_output = 0;
|
|
||||||
RRModePtr *randr_modes;
|
|
||||||
+ int32_t scale = xwl_screen->global_output_scale;
|
|
||||||
|
|
||||||
/* Clear out the "done" received flags */
|
|
||||||
xwl_output->wl_output_done = FALSE;
|
|
||||||
@@ -523,10 +527,10 @@ apply_output_change(struct xwl_output *xwl_output)
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Build a fresh modes array using the current refresh rate */
|
|
||||||
- randr_modes = output_get_rr_modes(xwl_output, mode_width, mode_height, &count);
|
|
||||||
+ randr_modes = output_get_rr_modes(xwl_output, mode_width * scale, mode_height * scale, &count);
|
|
||||||
RROutputSetModes(xwl_output->randr_output, randr_modes, count, 1);
|
|
||||||
RRCrtcNotify(xwl_output->randr_crtc, randr_modes[0],
|
|
||||||
- xwl_output->x, xwl_output->y,
|
|
||||||
+ xwl_output->x * scale, xwl_output->y * scale,
|
|
||||||
xwl_output->rotation, NULL, 1, &xwl_output->randr_output);
|
|
||||||
/* RROutputSetModes takes ownership of the passed in modes, so we only
|
|
||||||
* have to free the pointer array.
|
|
||||||
@@ -567,7 +571,7 @@ output_handle_done(void *data, struct wl_output *wl_output)
|
|
||||||
*/
|
|
||||||
if (xwl_output->xdg_output_done || !xwl_output->xdg_output ||
|
|
||||||
zxdg_output_v1_get_version(xwl_output->xdg_output) >= 3)
|
|
||||||
- apply_output_change(xwl_output);
|
|
||||||
+ xwl_output_apply_changes(xwl_output);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
@@ -610,7 +614,7 @@ xdg_output_handle_done(void *data, struct zxdg_output_v1 *xdg_output)
|
|
||||||
xwl_output->xdg_output_done = TRUE;
|
|
||||||
if (xwl_output->wl_output_done &&
|
|
||||||
zxdg_output_v1_get_version(xdg_output) < 3)
|
|
||||||
- apply_output_change(xwl_output);
|
|
||||||
+ xwl_output_apply_changes(xwl_output);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
@@ -678,6 +682,8 @@ xwl_output_create(struct xwl_screen *xwl_screen, uint32_t id)
|
|
||||||
RROutputSetConnection(xwl_output->randr_output, RR_Connected);
|
|
||||||
RRTellChanged(xwl_screen->screen);
|
|
||||||
|
|
||||||
+ xwl_output->scale = 1;
|
|
||||||
+
|
|
||||||
/* We want the output to be in the list as soon as created so we can
|
|
||||||
* use it when binding to the xdg-output protocol...
|
|
||||||
*/
|
|
||||||
diff --git a/hw/xwayland/xwayland-output.h b/hw/xwayland/xwayland-output.h
|
|
||||||
index 02b9831083e82a33d85d4404e39d00f06f6c56fd..ec089757f44178dcd7f9c48907f790ce1b2a2729 100644
|
|
||||||
--- a/hw/xwayland/xwayland-output.h
|
|
||||||
+++ b/hw/xwayland/xwayland-output.h
|
|
||||||
@@ -53,7 +53,7 @@ struct xwl_output {
|
|
||||||
struct wl_output *output;
|
|
||||||
struct zxdg_output_v1 *xdg_output;
|
|
||||||
uint32_t server_output_id;
|
|
||||||
- int32_t x, y, width, height, refresh;
|
|
||||||
+ int32_t x, y, width, height, refresh, scale;
|
|
||||||
Rotation rotation;
|
|
||||||
Bool wl_output_done;
|
|
||||||
Bool xdg_output_done;
|
|
||||||
@@ -100,6 +100,8 @@ void xwl_output_set_emulated_mode(struct xwl_output *xwl_output,
|
|
||||||
void xwl_output_set_window_randr_emu_props(struct xwl_screen *xwl_screen,
|
|
||||||
WindowPtr window);
|
|
||||||
|
|
||||||
+void xwl_output_apply_changes(struct xwl_output *xwl_output);
|
|
||||||
+
|
|
||||||
void xwl_screen_init_xdg_output(struct xwl_screen *xwl_screen);
|
|
||||||
|
|
||||||
#endif /* XWAYLAND_OUTPUT_H */
|
|
||||||
diff --git a/hw/xwayland/xwayland-present.c b/hw/xwayland/xwayland-present.c
|
|
||||||
index c9cf8c2f569a319034e0789e7587414e50237065..5be0c208ca46b1a53a136885fdc8ab44251fe7ff 100644
|
|
||||||
--- a/hw/xwayland/xwayland-present.c
|
|
||||||
+++ b/hw/xwayland/xwayland-present.c
|
|
||||||
@@ -680,6 +680,8 @@ xwl_present_flip(WindowPtr present_window,
|
|
||||||
|
|
||||||
/* We can flip directly to the main surface (full screen window without clips) */
|
|
||||||
wl_surface_attach(xwl_window->surface, buffer, 0, 0);
|
|
||||||
+ wl_surface_set_buffer_scale(xwl_window->surface,
|
|
||||||
+ xwl_window->xwl_screen->global_output_scale);
|
|
||||||
|
|
||||||
if (!xwl_window->frame_callback)
|
|
||||||
xwl_window_create_frame_callback(xwl_window);
|
|
||||||
diff --git a/hw/xwayland/xwayland-screen.c b/hw/xwayland/xwayland-screen.c
|
|
||||||
index bb18e5c94fbc7134c801e4e1979e8184079d352e..4ec2de7d123dd36315df07a1e95b1f417925f0f8 100644
|
|
||||||
--- a/hw/xwayland/xwayland-screen.c
|
|
||||||
+++ b/hw/xwayland/xwayland-screen.c
|
|
||||||
@@ -51,6 +51,7 @@
|
|
||||||
#include "xwayland-pixmap.h"
|
|
||||||
#include "xwayland-present.h"
|
|
||||||
#include "xwayland-shm.h"
|
|
||||||
+#include "xwayland-window-buffers.h"
|
|
||||||
|
|
||||||
#ifdef MITSHM
|
|
||||||
#include "shmint.h"
|
|
||||||
@@ -110,6 +111,12 @@ xwl_screen_has_resolution_change_emulation(struct xwl_screen *xwl_screen)
|
|
||||||
return xwl_screen->rootless && xwl_screen_has_viewport_support(xwl_screen);
|
|
||||||
}
|
|
||||||
|
|
||||||
+int
|
|
||||||
+xwl_scale_to(struct xwl_screen *xwl_screen, int value)
|
|
||||||
+{
|
|
||||||
+ return value / (double)xwl_screen->global_output_scale + 0.5;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
/* Return the output @ 0x0, falling back to the first output in the list */
|
|
||||||
struct xwl_output *
|
|
||||||
xwl_screen_get_first_output(struct xwl_screen *xwl_screen)
|
|
||||||
@@ -127,6 +134,37 @@ xwl_screen_get_first_output(struct xwl_screen *xwl_screen)
|
|
||||||
return xorg_list_first_entry(&xwl_screen->output_list, struct xwl_output, link);
|
|
||||||
}
|
|
||||||
|
|
||||||
+static void
|
|
||||||
+xwl_screen_set_global_scale_from_property(struct xwl_screen *screen,
|
|
||||||
+ PropertyPtr prop)
|
|
||||||
+{
|
|
||||||
+ CARD32 *propdata;
|
|
||||||
+
|
|
||||||
+ if (prop->type != XA_CARDINAL || prop->format != 32 || prop->size != 1) {
|
|
||||||
+ // TODO: handle warnings more cleanly.
|
|
||||||
+ LogMessageVerb(X_WARNING, 0, "Bad value for property %s.\n",
|
|
||||||
+ NameForAtom(prop->propertyName));
|
|
||||||
+ return;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ propdata = prop->data;
|
|
||||||
+ xwl_screen_set_global_scale(screen, propdata[0]);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static void
|
|
||||||
+xwl_screen_update_property(struct xwl_screen *screen,
|
|
||||||
+ PropertyStateRec *propstate)
|
|
||||||
+{
|
|
||||||
+ switch (propstate->state) {
|
|
||||||
+ case PropertyNewValue:
|
|
||||||
+ xwl_screen_set_global_scale_from_property(screen, propstate->prop);
|
|
||||||
+ break;
|
|
||||||
+ case PropertyDelete:
|
|
||||||
+ xwl_screen_set_global_scale(screen, 1);
|
|
||||||
+ break;
|
|
||||||
+ }
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
static void
|
|
||||||
xwl_property_callback(CallbackListPtr *pcbl, void *closure,
|
|
||||||
void *calldata)
|
|
||||||
@@ -134,19 +172,24 @@ xwl_property_callback(CallbackListPtr *pcbl, void *closure,
|
|
||||||
ScreenPtr screen = closure;
|
|
||||||
PropertyStateRec *rec = calldata;
|
|
||||||
struct xwl_screen *xwl_screen;
|
|
||||||
- struct xwl_window *xwl_window;
|
|
||||||
|
|
||||||
if (rec->win->drawable.pScreen != screen)
|
|
||||||
return;
|
|
||||||
|
|
||||||
- xwl_window = xwl_window_get(rec->win);
|
|
||||||
- if (!xwl_window)
|
|
||||||
- return;
|
|
||||||
-
|
|
||||||
xwl_screen = xwl_screen_get(screen);
|
|
||||||
|
|
||||||
- if (rec->prop->propertyName == xwl_screen->allow_commits_prop)
|
|
||||||
+ if (rec->prop->propertyName == xwl_screen->allow_commits_prop) {
|
|
||||||
+ struct xwl_window *xwl_window;
|
|
||||||
+
|
|
||||||
+ xwl_window = xwl_window_get(rec->win);
|
|
||||||
+ if (!xwl_window)
|
|
||||||
+ return;
|
|
||||||
+
|
|
||||||
xwl_window_update_property(xwl_window, rec);
|
|
||||||
+ }
|
|
||||||
+ else if (rec->prop->propertyName == xwl_screen->global_output_scale_prop) {
|
|
||||||
+ xwl_screen_update_property(xwl_screen, rec);
|
|
||||||
+ }
|
|
||||||
}
|
|
||||||
|
|
||||||
Bool
|
|
||||||
@@ -521,8 +564,14 @@ void xwl_surface_damage(struct xwl_screen *xwl_screen,
|
|
||||||
{
|
|
||||||
if (wl_surface_get_version(surface) >= WL_SURFACE_DAMAGE_BUFFER_SINCE_VERSION)
|
|
||||||
wl_surface_damage_buffer(surface, x, y, width, height);
|
|
||||||
- else
|
|
||||||
+ else {
|
|
||||||
+ x = xwl_scale_to(xwl_screen, x);
|
|
||||||
+ y = xwl_scale_to(xwl_screen, y);
|
|
||||||
+ width = xwl_scale_to(xwl_screen, width);
|
|
||||||
+ height = xwl_scale_to(xwl_screen, height);
|
|
||||||
+
|
|
||||||
wl_surface_damage(surface, x, y, width, height);
|
|
||||||
+ }
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
@@ -538,10 +587,34 @@ xwl_screen_roundtrip(struct xwl_screen *xwl_screen)
|
|
||||||
xwl_give_up("could not connect to wayland server\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
+void
|
|
||||||
+xwl_screen_set_global_scale(struct xwl_screen *xwl_screen, int32_t scale)
|
|
||||||
+{
|
|
||||||
+ struct xwl_output *it;
|
|
||||||
+ struct xwl_window *xwl_window;
|
|
||||||
+
|
|
||||||
+ xwl_screen->global_output_scale = scale;
|
|
||||||
+
|
|
||||||
+ /* change randr resolutions and positions */
|
|
||||||
+ xorg_list_for_each_entry(it, &xwl_screen->output_list, link) {
|
|
||||||
+ xwl_output_apply_changes(it);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if (!xwl_screen->rootless && xwl_screen->screen->root) {
|
|
||||||
+ /* Clear all the buffers, so that they'll be remade with the new sizes
|
|
||||||
+ * (this doesn't occur automatically because as far as Xorg is
|
|
||||||
+ * concerned, the window's size is the same) */
|
|
||||||
+ xorg_list_for_each_entry(xwl_window, &xwl_screen->window_list, link_window) {
|
|
||||||
+ xwl_window_buffers_recycle(xwl_window);
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
Bool
|
|
||||||
xwl_screen_init(ScreenPtr pScreen, int argc, char **argv)
|
|
||||||
{
|
|
||||||
static const char allow_commits[] = "_XWAYLAND_ALLOW_COMMITS";
|
|
||||||
+ static const char global_output_scale[] = "_XWAYLAND_GLOBAL_OUTPUT_SCALE";
|
|
||||||
struct xwl_screen *xwl_screen;
|
|
||||||
Pixel red_mask, blue_mask, green_mask;
|
|
||||||
int ret, bpc, green_bpc, i;
|
|
||||||
@@ -573,6 +646,7 @@ xwl_screen_init(ScreenPtr pScreen, int argc, char **argv)
|
|
||||||
#ifdef XWL_HAS_GLAMOR
|
|
||||||
xwl_screen->glamor = 1;
|
|
||||||
#endif
|
|
||||||
+ xwl_screen->global_output_scale = 1;
|
|
||||||
|
|
||||||
for (i = 1; i < argc; i++) {
|
|
||||||
if (strcmp(argv[i], "-rootless") == 0) {
|
|
||||||
@@ -743,6 +817,12 @@ xwl_screen_init(ScreenPtr pScreen, int argc, char **argv)
|
|
||||||
if (xwl_screen->allow_commits_prop == BAD_RESOURCE)
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
+ xwl_screen->global_output_scale_prop = MakeAtom(global_output_scale,
|
|
||||||
+ strlen(global_output_scale),
|
|
||||||
+ TRUE);
|
|
||||||
+ if (xwl_screen->global_output_scale_prop == BAD_RESOURCE)
|
|
||||||
+ return FALSE;
|
|
||||||
+
|
|
||||||
AddCallback(&PropertyStateCallback, xwl_property_callback, pScreen);
|
|
||||||
|
|
||||||
xwl_screen_roundtrip(xwl_screen);
|
|
||||||
diff --git a/hw/xwayland/xwayland-screen.h b/hw/xwayland/xwayland-screen.h
|
|
||||||
index b965dddd7f964b1d100bbb9d10da1c35ab39810e..7446829d098fbe235e605084a016daff1a8eaea2 100644
|
|
||||||
--- a/hw/xwayland/xwayland-screen.h
|
|
||||||
+++ b/hw/xwayland/xwayland-screen.h
|
|
||||||
@@ -72,6 +72,8 @@ struct xwl_screen {
|
|
||||||
struct xorg_list damage_window_list;
|
|
||||||
struct xorg_list window_list;
|
|
||||||
|
|
||||||
+ int32_t global_output_scale;
|
|
||||||
+
|
|
||||||
int wayland_fd;
|
|
||||||
struct wl_display *display;
|
|
||||||
struct wl_registry *registry;
|
|
||||||
@@ -107,6 +109,7 @@ struct xwl_screen {
|
|
||||||
struct glamor_context *glamor_ctx;
|
|
||||||
|
|
||||||
Atom allow_commits_prop;
|
|
||||||
+ Atom global_output_scale_prop;
|
|
||||||
|
|
||||||
/* The preferred GLVND vendor. If NULL, "mesa" is assumed. */
|
|
||||||
const char *glvnd_vendor;
|
|
||||||
@@ -134,5 +137,7 @@ void xwl_screen_roundtrip (struct xwl_screen *xwl_screen);
|
|
||||||
void xwl_surface_damage(struct xwl_screen *xwl_screen,
|
|
||||||
struct wl_surface *surface,
|
|
||||||
int32_t x, int32_t y, int32_t width, int32_t height);
|
|
||||||
+int xwl_scale_to(struct xwl_screen *xwl_screen, int value);
|
|
||||||
+void xwl_screen_set_global_scale(struct xwl_screen *xwl_screen, int32_t scale);
|
|
||||||
|
|
||||||
#endif /* XWAYLAND_SCREEN_H */
|
|
||||||
diff --git a/hw/xwayland/xwayland-window.c b/hw/xwayland/xwayland-window.c
|
|
||||||
index 00f161eda084e335ac07471a2198176d75d9fcf0..ed3903853f0dab1dad390cd8429639541546157d 100644
|
|
||||||
--- a/hw/xwayland/xwayland-window.c
|
|
||||||
+++ b/hw/xwayland/xwayland-window.c
|
|
||||||
@@ -470,7 +470,8 @@ ensure_surface_for_window(WindowPtr window)
|
|
||||||
}
|
|
||||||
|
|
||||||
wl_region_add(region, 0, 0,
|
|
||||||
- window->drawable.width, window->drawable.height);
|
|
||||||
+ xwl_scale_to(xwl_screen, window->drawable.width),
|
|
||||||
+ xwl_scale_to(xwl_screen, window->drawable.height));
|
|
||||||
wl_surface_set_opaque_region(xwl_window->surface, region);
|
|
||||||
wl_region_destroy(region);
|
|
||||||
}
|
|
||||||
@@ -820,6 +821,7 @@ xwl_window_post_damage(struct xwl_window *xwl_window)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
wl_surface_attach(xwl_window->surface, buffer, 0, 0);
|
|
||||||
+ wl_surface_set_buffer_scale(xwl_window->surface, xwl_screen->global_output_scale);
|
|
||||||
|
|
||||||
/* Arbitrary limit to try to avoid flooding the Wayland
|
|
||||||
* connection. If we flood it too much anyway, this could
|
|
||||||
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
--- a/hw/xwayland/xwayland-present.c
|
|
||||||
+++ b/hw/xwayland/xwayland-present.c
|
|
||||||
@@ -824,7 +824,8 @@
|
|
||||||
dixDestroyPixmap(vblank->pixmap, vblank->pixmap->drawable.id);
|
|
||||||
vblank->pixmap = NULL;
|
|
||||||
|
|
||||||
- if (xwl_present_queue_vblank(screen, window, vblank->crtc,
|
|
||||||
+ if (vblank->target_msc > crtc_msc &&
|
|
||||||
+ xwl_present_queue_vblank(screen, window, vblank->crtc,
|
|
||||||
vblank->event_id, crtc_msc + 1)
|
|
||||||
== Success)
|
|
||||||
return;
|
|
||||||
3
props.json
Normal file
3
props.json
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"version": "0.33.1"
|
||||||
|
}
|
||||||
@@ -1,306 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<protocol name="ext_workspace_unstable_v1">
|
|
||||||
<copyright>
|
|
||||||
Copyright © 2019 Christopher Billington
|
|
||||||
Copyright © 2020 Ilia Bozhinov
|
|
||||||
|
|
||||||
Permission to use, copy, modify, distribute, and sell this
|
|
||||||
software and its documentation for any purpose is hereby granted
|
|
||||||
without fee, provided that the above copyright notice appear in
|
|
||||||
all copies and that both that copyright notice and this permission
|
|
||||||
notice appear in supporting documentation, and that the name of
|
|
||||||
the copyright holders not be used in advertising or publicity
|
|
||||||
pertaining to distribution of the software without specific,
|
|
||||||
written prior permission. The copyright holders make no
|
|
||||||
representations about the suitability of this software for any
|
|
||||||
purpose. It is provided "as is" without express or implied
|
|
||||||
warranty.
|
|
||||||
|
|
||||||
THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
|
|
||||||
SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
|
||||||
FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
||||||
SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
||||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
|
|
||||||
AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
|
|
||||||
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
|
|
||||||
THIS SOFTWARE.
|
|
||||||
</copyright>
|
|
||||||
|
|
||||||
<interface name="zext_workspace_manager_v1" version="1">
|
|
||||||
<description summary="list and control workspaces">
|
|
||||||
Workspaces, also called virtual desktops, are groups of surfaces. A
|
|
||||||
compositor with a concept of workspaces may only show some such groups of
|
|
||||||
surfaces (those of 'active' workspaces) at a time. 'Activating' a
|
|
||||||
workspace is a request for the compositor to display that workspace's
|
|
||||||
surfaces as normal, whereas the compositor may hide or otherwise
|
|
||||||
de-emphasise surfaces that are associated only with 'inactive' workspaces.
|
|
||||||
Workspaces are grouped by which sets of outputs they correspond to, and
|
|
||||||
may contain surfaces only from those outputs. In this way, it is possible
|
|
||||||
for each output to have its own set of workspaces, or for all outputs (or
|
|
||||||
any other arbitrary grouping) to share workspaces. Compositors may
|
|
||||||
optionally conceptually arrange each group of workspaces in an
|
|
||||||
N-dimensional grid.
|
|
||||||
|
|
||||||
The purpose of this protocol is to enable the creation of taskbars and
|
|
||||||
docks by providing them with a list of workspaces and their properties,
|
|
||||||
and allowing them to activate and deactivate workspaces.
|
|
||||||
|
|
||||||
After a client binds the zext_workspace_manager_v1, each workspace will be
|
|
||||||
sent via the workspace event.
|
|
||||||
</description>
|
|
||||||
|
|
||||||
<event name="workspace_group">
|
|
||||||
<description summary="a workspace group has been created">
|
|
||||||
This event is emitted whenever a new workspace group has been created.
|
|
||||||
|
|
||||||
All initial details of the workspace group (workspaces, outputs) will be
|
|
||||||
sent immediately after this event via the corresponding events in
|
|
||||||
zext_workspace_group_handle_v1.
|
|
||||||
</description>
|
|
||||||
<arg name="workspace_group" type="new_id" interface="zext_workspace_group_handle_v1"/>
|
|
||||||
</event>
|
|
||||||
|
|
||||||
<request name="commit">
|
|
||||||
<description summary="all requests about the workspaces have been sent">
|
|
||||||
The client must send this request after it has finished sending other
|
|
||||||
requests. The compositor must process a series of requests preceding a
|
|
||||||
commit request atomically.
|
|
||||||
|
|
||||||
This allows changes to the workspace properties to be seen as atomic,
|
|
||||||
even if they happen via multiple events, and even if they involve
|
|
||||||
multiple zext_workspace_handle_v1 objects, for example, deactivating one
|
|
||||||
workspace and activating another.
|
|
||||||
</description>
|
|
||||||
</request>
|
|
||||||
|
|
||||||
<event name="done">
|
|
||||||
<description summary="all information about the workspace groups has been sent">
|
|
||||||
This event is sent after all changes in all workspace groups have been
|
|
||||||
sent.
|
|
||||||
|
|
||||||
This allows changes to one or more zext_workspace_group_handle_v1
|
|
||||||
properties to be seen as atomic, even if they happen via multiple
|
|
||||||
events. In particular, an output moving from one workspace group to
|
|
||||||
another sends an output_enter event and an output_leave event to the two
|
|
||||||
zext_workspace_group_handle_v1 objects in question. The compositor sends
|
|
||||||
the done event only after updating the output information in both
|
|
||||||
workspace groups.
|
|
||||||
</description>
|
|
||||||
</event>
|
|
||||||
|
|
||||||
<event name="finished">
|
|
||||||
<description summary="the compositor has finished with the workspace_manager">
|
|
||||||
This event indicates that the compositor is done sending events to the
|
|
||||||
zext_workspace_manager_v1. The server will destroy the object
|
|
||||||
immediately after sending this request, so it will become invalid and
|
|
||||||
the client should free any resources associated with it.
|
|
||||||
</description>
|
|
||||||
</event>
|
|
||||||
|
|
||||||
<request name="stop">
|
|
||||||
<description summary="stop sending events">
|
|
||||||
Indicates the client no longer wishes to receive events for new
|
|
||||||
workspace groups. However the compositor may emit further workspace
|
|
||||||
events, until the finished event is emitted.
|
|
||||||
|
|
||||||
The client must not send any more requests after this one.
|
|
||||||
</description>
|
|
||||||
</request>
|
|
||||||
</interface>
|
|
||||||
|
|
||||||
<interface name="zext_workspace_group_handle_v1" version="1">
|
|
||||||
<description summary="a workspace group assigned to a set of outputs">
|
|
||||||
A zext_workspace_group_handle_v1 object represents a a workspace group
|
|
||||||
that is assigned a set of outputs and contains a number of workspaces.
|
|
||||||
|
|
||||||
The set of outputs assigned to the workspace group is conveyed to the client via
|
|
||||||
output_enter and output_leave events, and its workspaces are conveyed with
|
|
||||||
workspace events.
|
|
||||||
|
|
||||||
For example, a compositor which has a set of workspaces for each output may
|
|
||||||
advertise a workspace group (and its workspaces) per output, whereas a compositor
|
|
||||||
where a workspace spans all outputs may advertise a single workspace group for all
|
|
||||||
outputs.
|
|
||||||
</description>
|
|
||||||
|
|
||||||
<event name="output_enter">
|
|
||||||
<description summary="output assigned to workspace group">
|
|
||||||
This event is emitted whenever an output is assigned to the workspace
|
|
||||||
group.
|
|
||||||
</description>
|
|
||||||
<arg name="output" type="object" interface="wl_output"/>
|
|
||||||
</event>
|
|
||||||
|
|
||||||
<event name="output_leave">
|
|
||||||
<description summary="output removed from workspace group">
|
|
||||||
This event is emitted whenever an output is removed from the workspace
|
|
||||||
group.
|
|
||||||
</description>
|
|
||||||
<arg name="output" type="object" interface="wl_output"/>
|
|
||||||
</event>
|
|
||||||
|
|
||||||
<event name="workspace">
|
|
||||||
<description summary="workspace added to workspace group">
|
|
||||||
This event is emitted whenever a new workspace has been created.
|
|
||||||
|
|
||||||
All initial details of the workspace (name, coordinates, state) will
|
|
||||||
be sent immediately after this event via the corresponding events in
|
|
||||||
zext_workspace_handle_v1.
|
|
||||||
</description>
|
|
||||||
<arg name="workspace" type="new_id" interface="zext_workspace_handle_v1"/>
|
|
||||||
</event>
|
|
||||||
|
|
||||||
<event name="remove">
|
|
||||||
<description summary="this workspace group has been destroyed">
|
|
||||||
This event means the zext_workspace_group_handle_v1 has been destroyed.
|
|
||||||
It is guaranteed there won't be any more events for this
|
|
||||||
zext_workspace_group_handle_v1. The zext_workspace_group_handle_v1 becomes
|
|
||||||
inert so any requests will be ignored except the destroy request.
|
|
||||||
|
|
||||||
The compositor must remove all workspaces belonging to a workspace group
|
|
||||||
before removing the workspace group.
|
|
||||||
</description>
|
|
||||||
</event>
|
|
||||||
|
|
||||||
<request name="create_workspace">
|
|
||||||
<description summary="create a new workspace">
|
|
||||||
Request that the compositor create a new workspace with the given name.
|
|
||||||
|
|
||||||
There is no guarantee that the compositor will create a new workspace,
|
|
||||||
or that the created workspace will have the provided name.
|
|
||||||
</description>
|
|
||||||
<arg name="workspace" type="string"/>
|
|
||||||
</request>
|
|
||||||
|
|
||||||
<request name="destroy" type="destructor">
|
|
||||||
<description summary="destroy the zext_workspace_handle_v1 object">
|
|
||||||
Destroys the zext_workspace_handle_v1 object.
|
|
||||||
|
|
||||||
This request should be called either when the client does not want to
|
|
||||||
use the workspace object any more or after the remove event to finalize
|
|
||||||
the destruction of the object.
|
|
||||||
</description>
|
|
||||||
</request>
|
|
||||||
</interface>
|
|
||||||
|
|
||||||
<interface name="zext_workspace_handle_v1" version="1">
|
|
||||||
<description summary="a workspace handing a group of surfaces">
|
|
||||||
A zext_workspace_handle_v1 object represents a a workspace that handles a
|
|
||||||
group of surfaces.
|
|
||||||
|
|
||||||
Each workspace has a name, conveyed to the client with the name event; a
|
|
||||||
list of states, conveyed to the client with the state event; and
|
|
||||||
optionally a set of coordinates, conveyed to the client with the
|
|
||||||
coordinates event. The client may request that the compositor activate or
|
|
||||||
deactivate the workspace.
|
|
||||||
|
|
||||||
Each workspace can belong to only a single workspace group.
|
|
||||||
Depepending on the compositor policy, there might be workspaces with
|
|
||||||
the same name in different workspace groups, but these workspaces are still
|
|
||||||
separate (e.g. one of them might be active while the other is not).
|
|
||||||
</description>
|
|
||||||
|
|
||||||
<event name="name">
|
|
||||||
<description summary="workspace name changed">
|
|
||||||
This event is emitted immediately after the zext_workspace_handle_v1 is
|
|
||||||
created and whenever the name of the workspace changes.
|
|
||||||
</description>
|
|
||||||
<arg name="name" type="string"/>
|
|
||||||
</event>
|
|
||||||
|
|
||||||
<event name="coordinates">
|
|
||||||
<description summary="workspace coordinates changed">
|
|
||||||
This event is used to organize workspaces into an N-dimensional grid
|
|
||||||
within a workspace group, and if supported, is emitted immediately after
|
|
||||||
the zext_workspace_handle_v1 is created and whenever the coordinates of
|
|
||||||
the workspace change. Compositors may not send this event if they do not
|
|
||||||
conceptually arrange workspaces in this way. If compositors simply
|
|
||||||
number workspaces, without any geometric interpretation, they may send
|
|
||||||
1D coordinates, which clients should not interpret as implying any
|
|
||||||
geometry. Sending an empty array means that the compositor no longer
|
|
||||||
orders the workspace geometrically.
|
|
||||||
|
|
||||||
Coordinates have an arbitrary number of dimensions N with an uint32
|
|
||||||
position along each dimension. By convention if N > 1, the first
|
|
||||||
dimension is X, the second Y, the third Z, and so on. The compositor may
|
|
||||||
chose to utilize these events for a more novel workspace layout
|
|
||||||
convention, however. No guarantee is made about the grid being filled or
|
|
||||||
bounded; there may be a workspace at coordinate 1 and another at
|
|
||||||
coordinate 1000 and none in between. Within a workspace group, however,
|
|
||||||
workspaces must have unique coordinates of equal dimensionality.
|
|
||||||
</description>
|
|
||||||
<arg name="coordinates" type="array"/>
|
|
||||||
</event>
|
|
||||||
|
|
||||||
<event name="state">
|
|
||||||
<description summary="the state of the workspace changed">
|
|
||||||
This event is emitted immediately after the zext_workspace_handle_v1 is
|
|
||||||
created and each time the workspace state changes, either because of a
|
|
||||||
compositor action or because of a request in this protocol.
|
|
||||||
</description>
|
|
||||||
<arg name="state" type="array"/>
|
|
||||||
</event>
|
|
||||||
|
|
||||||
<enum name="state">
|
|
||||||
<description summary="types of states on the workspace">
|
|
||||||
The different states that a workspace can have.
|
|
||||||
</description>
|
|
||||||
|
|
||||||
<entry name="active" value="0" summary="the workspace is active"/>
|
|
||||||
<entry name="urgent" value="1" summary="the workspace requests attention"/>
|
|
||||||
<entry name="hidden" value="2">
|
|
||||||
<description summary="the workspace is not visible">
|
|
||||||
The workspace is not visible in its workspace group, and clients
|
|
||||||
attempting to visualize the compositor workspace state should not
|
|
||||||
display such workspaces.
|
|
||||||
</description>
|
|
||||||
</entry>
|
|
||||||
</enum>
|
|
||||||
|
|
||||||
<event name="remove">
|
|
||||||
<description summary="this workspace has been destroyed">
|
|
||||||
This event means the zext_workspace_handle_v1 has been destroyed. It is
|
|
||||||
guaranteed there won't be any more events for this
|
|
||||||
zext_workspace_handle_v1. The zext_workspace_handle_v1 becomes inert so
|
|
||||||
any requests will be ignored except the destroy request.
|
|
||||||
</description>
|
|
||||||
</event>
|
|
||||||
|
|
||||||
<request name="destroy" type="destructor">
|
|
||||||
<description summary="destroy the zext_workspace_handle_v1 object">
|
|
||||||
Destroys the zext_workspace_handle_v1 object.
|
|
||||||
|
|
||||||
This request should be called either when the client does not want to
|
|
||||||
use the workspace object any more or after the remove event to finalize
|
|
||||||
the destruction of the object.
|
|
||||||
</description>
|
|
||||||
</request>
|
|
||||||
|
|
||||||
<request name="activate">
|
|
||||||
<description summary="activate the workspace">
|
|
||||||
Request that this workspace be activated.
|
|
||||||
|
|
||||||
There is no guarantee the workspace will be actually activated, and
|
|
||||||
behaviour may be compositor-dependent. For example, activating a
|
|
||||||
workspace may or may not deactivate all other workspaces in the same
|
|
||||||
group.
|
|
||||||
</description>
|
|
||||||
</request>
|
|
||||||
|
|
||||||
<request name="deactivate">
|
|
||||||
<description summary="activate the workspace">
|
|
||||||
Request that this workspace be deactivated.
|
|
||||||
|
|
||||||
There is no guarantee the workspace will be actually deactivated.
|
|
||||||
</description>
|
|
||||||
</request>
|
|
||||||
|
|
||||||
<request name="remove">
|
|
||||||
<description summary="remove the workspace">
|
|
||||||
Request that this workspace be removed.
|
|
||||||
|
|
||||||
There is no guarantee the workspace will be actually removed.
|
|
||||||
</description>
|
|
||||||
</request>
|
|
||||||
</interface>
|
|
||||||
</protocol>
|
|
||||||
@@ -3,7 +3,14 @@ wayland_protos = dependency('wayland-protocols',
|
|||||||
fallback: 'wayland-protocols',
|
fallback: 'wayland-protocols',
|
||||||
default_options: ['tests=false'],
|
default_options: ['tests=false'],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
hyprland_protos = dependency('hyprland-protocols',
|
||||||
|
version: '>=0.2',
|
||||||
|
fallback: 'hyprland-protocols',
|
||||||
|
)
|
||||||
|
|
||||||
wl_protocol_dir = wayland_protos.get_variable('pkgdatadir')
|
wl_protocol_dir = wayland_protos.get_variable('pkgdatadir')
|
||||||
|
hl_protocol_dir = hyprland_protos.get_variable('pkgdatadir')
|
||||||
|
|
||||||
wayland_scanner_dep = dependency('wayland-scanner', native: true)
|
wayland_scanner_dep = dependency('wayland-scanner', native: true)
|
||||||
wayland_scanner = find_program(
|
wayland_scanner = find_program(
|
||||||
@@ -13,12 +20,21 @@ wayland_scanner = find_program(
|
|||||||
|
|
||||||
protocols = [
|
protocols = [
|
||||||
[wl_protocol_dir, 'stable/xdg-shell/xdg-shell.xml'],
|
[wl_protocol_dir, 'stable/xdg-shell/xdg-shell.xml'],
|
||||||
|
[wl_protocol_dir, 'unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml'],
|
||||||
|
[wl_protocol_dir, 'unstable/text-input/text-input-unstable-v1.xml'],
|
||||||
|
[wl_protocol_dir, 'unstable/xdg-output/xdg-output-unstable-v1.xml'],
|
||||||
|
[wl_protocol_dir, 'staging/fractional-scale/fractional-scale-v1.xml'],
|
||||||
|
[wl_protocol_dir, 'staging/cursor-shape/cursor-shape-v1.xml'],
|
||||||
|
[wl_protocol_dir, 'staging/tearing-control/tearing-control-v1.xml'],
|
||||||
|
['wlr-foreign-toplevel-management-unstable-v1.xml'],
|
||||||
['wlr-layer-shell-unstable-v1.xml'],
|
['wlr-layer-shell-unstable-v1.xml'],
|
||||||
['wlr-output-power-management-unstable-v1.xml'],
|
['wlr-output-power-management-unstable-v1.xml'],
|
||||||
['ext-workspace-unstable-v1.xml'],
|
['wlr-screencopy-unstable-v1.xml'],
|
||||||
['pointer-constraints-unstable-v1.xml'],
|
['pointer-constraints-unstable-v1.xml'],
|
||||||
['tablet-unstable-v2.xml'],
|
['tablet-unstable-v2.xml'],
|
||||||
['idle.xml']
|
['idle.xml'],
|
||||||
|
[hl_protocol_dir, 'protocols/hyprland-toplevel-export-v1.xml'],
|
||||||
|
[hl_protocol_dir, 'protocols/hyprland-global-shortcuts-v1.xml']
|
||||||
]
|
]
|
||||||
wl_protos_src = []
|
wl_protos_src = []
|
||||||
wl_protos_headers = []
|
wl_protos_headers = []
|
||||||
@@ -33,6 +49,8 @@ foreach p : protocols
|
|||||||
wl_protos_headers += custom_target(
|
wl_protos_headers += custom_target(
|
||||||
xml.underscorify() + '_server_h',
|
xml.underscorify() + '_server_h',
|
||||||
input: xml,
|
input: xml,
|
||||||
|
install: true,
|
||||||
|
install_dir: join_paths(get_option('includedir'), 'hyprland/protocols'),
|
||||||
output: '@BASENAME@-protocol.h',
|
output: '@BASENAME@-protocol.h',
|
||||||
command: [wayland_scanner, 'server-header', '@INPUT@', '@OUTPUT@'],
|
command: [wayland_scanner, 'server-header', '@INPUT@', '@OUTPUT@'],
|
||||||
)
|
)
|
||||||
|
|||||||
270
protocols/wlr-foreign-toplevel-management-unstable-v1.xml
Normal file
270
protocols/wlr-foreign-toplevel-management-unstable-v1.xml
Normal file
@@ -0,0 +1,270 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<protocol name="wlr_foreign_toplevel_management_unstable_v1">
|
||||||
|
<copyright>
|
||||||
|
Copyright © 2018 Ilia Bozhinov
|
||||||
|
|
||||||
|
Permission to use, copy, modify, distribute, and sell this
|
||||||
|
software and its documentation for any purpose is hereby granted
|
||||||
|
without fee, provided that the above copyright notice appear in
|
||||||
|
all copies and that both that copyright notice and this permission
|
||||||
|
notice appear in supporting documentation, and that the name of
|
||||||
|
the copyright holders not be used in advertising or publicity
|
||||||
|
pertaining to distribution of the software without specific,
|
||||||
|
written prior permission. The copyright holders make no
|
||||||
|
representations about the suitability of this software for any
|
||||||
|
purpose. It is provided "as is" without express or implied
|
||||||
|
warranty.
|
||||||
|
|
||||||
|
THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
|
||||||
|
SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||||
|
FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||||
|
SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
|
||||||
|
AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
|
||||||
|
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
|
||||||
|
THIS SOFTWARE.
|
||||||
|
</copyright>
|
||||||
|
|
||||||
|
<interface name="zwlr_foreign_toplevel_manager_v1" version="3">
|
||||||
|
<description summary="list and control opened apps">
|
||||||
|
The purpose of this protocol is to enable the creation of taskbars
|
||||||
|
and docks by providing them with a list of opened applications and
|
||||||
|
letting them request certain actions on them, like maximizing, etc.
|
||||||
|
|
||||||
|
After a client binds the zwlr_foreign_toplevel_manager_v1, each opened
|
||||||
|
toplevel window will be sent via the toplevel event
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<event name="toplevel">
|
||||||
|
<description summary="a toplevel has been created">
|
||||||
|
This event is emitted whenever a new toplevel window is created. It
|
||||||
|
is emitted for all toplevels, regardless of the app that has created
|
||||||
|
them.
|
||||||
|
|
||||||
|
All initial details of the toplevel(title, app_id, states, etc.) will
|
||||||
|
be sent immediately after this event via the corresponding events in
|
||||||
|
zwlr_foreign_toplevel_handle_v1.
|
||||||
|
</description>
|
||||||
|
<arg name="toplevel" type="new_id" interface="zwlr_foreign_toplevel_handle_v1"/>
|
||||||
|
</event>
|
||||||
|
|
||||||
|
<request name="stop">
|
||||||
|
<description summary="stop sending events">
|
||||||
|
Indicates the client no longer wishes to receive events for new toplevels.
|
||||||
|
However the compositor may emit further toplevel_created events, until
|
||||||
|
the finished event is emitted.
|
||||||
|
|
||||||
|
The client must not send any more requests after this one.
|
||||||
|
</description>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<event name="finished" type="destructor">
|
||||||
|
<description summary="the compositor has finished with the toplevel manager">
|
||||||
|
This event indicates that the compositor is done sending events to the
|
||||||
|
zwlr_foreign_toplevel_manager_v1. The server will destroy the object
|
||||||
|
immediately after sending this request, so it will become invalid and
|
||||||
|
the client should free any resources associated with it.
|
||||||
|
</description>
|
||||||
|
</event>
|
||||||
|
</interface>
|
||||||
|
|
||||||
|
<interface name="zwlr_foreign_toplevel_handle_v1" version="3">
|
||||||
|
<description summary="an opened toplevel">
|
||||||
|
A zwlr_foreign_toplevel_handle_v1 object represents an opened toplevel
|
||||||
|
window. Each app may have multiple opened toplevels.
|
||||||
|
|
||||||
|
Each toplevel has a list of outputs it is visible on, conveyed to the
|
||||||
|
client with the output_enter and output_leave events.
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<event name="title">
|
||||||
|
<description summary="title change">
|
||||||
|
This event is emitted whenever the title of the toplevel changes.
|
||||||
|
</description>
|
||||||
|
<arg name="title" type="string"/>
|
||||||
|
</event>
|
||||||
|
|
||||||
|
<event name="app_id">
|
||||||
|
<description summary="app-id change">
|
||||||
|
This event is emitted whenever the app-id of the toplevel changes.
|
||||||
|
</description>
|
||||||
|
<arg name="app_id" type="string"/>
|
||||||
|
</event>
|
||||||
|
|
||||||
|
<event name="output_enter">
|
||||||
|
<description summary="toplevel entered an output">
|
||||||
|
This event is emitted whenever the toplevel becomes visible on
|
||||||
|
the given output. A toplevel may be visible on multiple outputs.
|
||||||
|
</description>
|
||||||
|
<arg name="output" type="object" interface="wl_output"/>
|
||||||
|
</event>
|
||||||
|
|
||||||
|
<event name="output_leave">
|
||||||
|
<description summary="toplevel left an output">
|
||||||
|
This event is emitted whenever the toplevel stops being visible on
|
||||||
|
the given output. It is guaranteed that an entered-output event
|
||||||
|
with the same output has been emitted before this event.
|
||||||
|
</description>
|
||||||
|
<arg name="output" type="object" interface="wl_output"/>
|
||||||
|
</event>
|
||||||
|
|
||||||
|
<request name="set_maximized">
|
||||||
|
<description summary="requests that the toplevel be maximized">
|
||||||
|
Requests that the toplevel be maximized. If the maximized state actually
|
||||||
|
changes, this will be indicated by the state event.
|
||||||
|
</description>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<request name="unset_maximized">
|
||||||
|
<description summary="requests that the toplevel be unmaximized">
|
||||||
|
Requests that the toplevel be unmaximized. If the maximized state actually
|
||||||
|
changes, this will be indicated by the state event.
|
||||||
|
</description>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<request name="set_minimized">
|
||||||
|
<description summary="requests that the toplevel be minimized">
|
||||||
|
Requests that the toplevel be minimized. If the minimized state actually
|
||||||
|
changes, this will be indicated by the state event.
|
||||||
|
</description>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<request name="unset_minimized">
|
||||||
|
<description summary="requests that the toplevel be unminimized">
|
||||||
|
Requests that the toplevel be unminimized. If the minimized state actually
|
||||||
|
changes, this will be indicated by the state event.
|
||||||
|
</description>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<request name="activate">
|
||||||
|
<description summary="activate the toplevel">
|
||||||
|
Request that this toplevel be activated on the given seat.
|
||||||
|
There is no guarantee the toplevel will be actually activated.
|
||||||
|
</description>
|
||||||
|
<arg name="seat" type="object" interface="wl_seat"/>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<enum name="state">
|
||||||
|
<description summary="types of states on the toplevel">
|
||||||
|
The different states that a toplevel can have. These have the same meaning
|
||||||
|
as the states with the same names defined in xdg-toplevel
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<entry name="maximized" value="0" summary="the toplevel is maximized"/>
|
||||||
|
<entry name="minimized" value="1" summary="the toplevel is minimized"/>
|
||||||
|
<entry name="activated" value="2" summary="the toplevel is active"/>
|
||||||
|
<entry name="fullscreen" value="3" summary="the toplevel is fullscreen" since="2"/>
|
||||||
|
</enum>
|
||||||
|
|
||||||
|
<event name="state">
|
||||||
|
<description summary="the toplevel state changed">
|
||||||
|
This event is emitted immediately after the zlw_foreign_toplevel_handle_v1
|
||||||
|
is created and each time the toplevel state changes, either because of a
|
||||||
|
compositor action or because of a request in this protocol.
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<arg name="state" type="array"/>
|
||||||
|
</event>
|
||||||
|
|
||||||
|
<event name="done">
|
||||||
|
<description summary="all information about the toplevel has been sent">
|
||||||
|
This event is sent after all changes in the toplevel state have been
|
||||||
|
sent.
|
||||||
|
|
||||||
|
This allows changes to the zwlr_foreign_toplevel_handle_v1 properties
|
||||||
|
to be seen as atomic, even if they happen via multiple events.
|
||||||
|
</description>
|
||||||
|
</event>
|
||||||
|
|
||||||
|
<request name="close">
|
||||||
|
<description summary="request that the toplevel be closed">
|
||||||
|
Send a request to the toplevel to close itself. The compositor would
|
||||||
|
typically use a shell-specific method to carry out this request, for
|
||||||
|
example by sending the xdg_toplevel.close event. However, this gives
|
||||||
|
no guarantees the toplevel will actually be destroyed. If and when
|
||||||
|
this happens, the zwlr_foreign_toplevel_handle_v1.closed event will
|
||||||
|
be emitted.
|
||||||
|
</description>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<request name="set_rectangle">
|
||||||
|
<description summary="the rectangle which represents the toplevel">
|
||||||
|
The rectangle of the surface specified in this request corresponds to
|
||||||
|
the place where the app using this protocol represents the given toplevel.
|
||||||
|
It can be used by the compositor as a hint for some operations, e.g
|
||||||
|
minimizing. The client is however not required to set this, in which
|
||||||
|
case the compositor is free to decide some default value.
|
||||||
|
|
||||||
|
If the client specifies more than one rectangle, only the last one is
|
||||||
|
considered.
|
||||||
|
|
||||||
|
The dimensions are given in surface-local coordinates.
|
||||||
|
Setting width=height=0 removes the already-set rectangle.
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<arg name="surface" type="object" interface="wl_surface"/>
|
||||||
|
<arg name="x" type="int"/>
|
||||||
|
<arg name="y" type="int"/>
|
||||||
|
<arg name="width" type="int"/>
|
||||||
|
<arg name="height" type="int"/>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<enum name="error">
|
||||||
|
<entry name="invalid_rectangle" value="0"
|
||||||
|
summary="the provided rectangle is invalid"/>
|
||||||
|
</enum>
|
||||||
|
|
||||||
|
<event name="closed">
|
||||||
|
<description summary="this toplevel has been destroyed">
|
||||||
|
This event means the toplevel has been destroyed. It is guaranteed there
|
||||||
|
won't be any more events for this zwlr_foreign_toplevel_handle_v1. The
|
||||||
|
toplevel itself becomes inert so any requests will be ignored except the
|
||||||
|
destroy request.
|
||||||
|
</description>
|
||||||
|
</event>
|
||||||
|
|
||||||
|
<request name="destroy" type="destructor">
|
||||||
|
<description summary="destroy the zwlr_foreign_toplevel_handle_v1 object">
|
||||||
|
Destroys the zwlr_foreign_toplevel_handle_v1 object.
|
||||||
|
|
||||||
|
This request should be called either when the client does not want to
|
||||||
|
use the toplevel anymore or after the closed event to finalize the
|
||||||
|
destruction of the object.
|
||||||
|
</description>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<!-- Version 2 additions -->
|
||||||
|
|
||||||
|
<request name="set_fullscreen" since="2">
|
||||||
|
<description summary="request that the toplevel be fullscreened">
|
||||||
|
Requests that the toplevel be fullscreened on the given output. If the
|
||||||
|
fullscreen state and/or the outputs the toplevel is visible on actually
|
||||||
|
change, this will be indicated by the state and output_enter/leave
|
||||||
|
events.
|
||||||
|
|
||||||
|
The output parameter is only a hint to the compositor. Also, if output
|
||||||
|
is NULL, the compositor should decide which output the toplevel will be
|
||||||
|
fullscreened on, if at all.
|
||||||
|
</description>
|
||||||
|
<arg name="output" type="object" interface="wl_output" allow-null="true"/>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<request name="unset_fullscreen" since="2">
|
||||||
|
<description summary="request that the toplevel be unfullscreened">
|
||||||
|
Requests that the toplevel be unfullscreened. If the fullscreen state
|
||||||
|
actually changes, this will be indicated by the state event.
|
||||||
|
</description>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<!-- Version 3 additions -->
|
||||||
|
|
||||||
|
<event name="parent" since="3">
|
||||||
|
<description summary="parent change">
|
||||||
|
This event is emitted whenever the parent of the toplevel changes.
|
||||||
|
|
||||||
|
No event is emitted when the parent handle is destroyed by the client.
|
||||||
|
</description>
|
||||||
|
<arg name="parent" type="object" interface="zwlr_foreign_toplevel_handle_v1" allow-null="true"/>
|
||||||
|
</event>
|
||||||
|
</interface>
|
||||||
|
</protocol>
|
||||||
14
scripts/generateVersion.sh
Executable file
14
scripts/generateVersion.sh
Executable file
@@ -0,0 +1,14 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
cp -fr ./src/version.h.in ./src/version.h
|
||||||
|
|
||||||
|
HASH=$(git rev-parse HEAD)
|
||||||
|
BRANCH=$(git rev-parse --abbrev-ref HEAD)
|
||||||
|
MESSAGE=$(git show ${GIT_COMMIT_HASH} | head -n 5 | tail -n 1 | sed -e 's/#//g' -e 's/\"//g')
|
||||||
|
DIRTY=$(git diff-index --quiet HEAD -- || echo dirty)
|
||||||
|
TAG=$(git describe --tags)
|
||||||
|
|
||||||
|
sed -i -e "s#@HASH@#${HASH}#" ./src/version.h
|
||||||
|
sed -i -e "s#@BRANCH@#${BRANCH}#" ./src/version.h
|
||||||
|
sed -i -e "s#@MESSAGE@#${MESSAGE}#" ./src/version.h
|
||||||
|
sed -i -e "s#@DIRTY@#${DIRTY}#" ./src/version.h
|
||||||
|
sed -i -e "s#@TAG@#${TAG}#" ./src/version.h
|
||||||
2072
src/Compositor.cpp
2072
src/Compositor.cpp
File diff suppressed because it is too large
Load Diff
@@ -15,182 +15,224 @@
|
|||||||
#include "managers/KeybindManager.hpp"
|
#include "managers/KeybindManager.hpp"
|
||||||
#include "managers/AnimationManager.hpp"
|
#include "managers/AnimationManager.hpp"
|
||||||
#include "managers/EventManager.hpp"
|
#include "managers/EventManager.hpp"
|
||||||
|
#include "managers/ProtocolManager.hpp"
|
||||||
|
#include "managers/SessionLockManager.hpp"
|
||||||
|
#include "managers/HookSystemManager.hpp"
|
||||||
#include "debug/HyprDebugOverlay.hpp"
|
#include "debug/HyprDebugOverlay.hpp"
|
||||||
|
#include "debug/HyprNotificationOverlay.hpp"
|
||||||
#include "helpers/Monitor.hpp"
|
#include "helpers/Monitor.hpp"
|
||||||
#include "helpers/Workspace.hpp"
|
#include "helpers/Workspace.hpp"
|
||||||
#include "Window.hpp"
|
#include "Window.hpp"
|
||||||
#include "render/Renderer.hpp"
|
#include "render/Renderer.hpp"
|
||||||
#include "render/OpenGL.hpp"
|
#include "render/OpenGL.hpp"
|
||||||
#include "hyprerror/HyprError.hpp"
|
#include "hyprerror/HyprError.hpp"
|
||||||
|
#include "plugins/PluginSystem.hpp"
|
||||||
|
#include "helpers/Watchdog.hpp"
|
||||||
|
|
||||||
|
enum eManagersInitStage
|
||||||
|
{
|
||||||
|
STAGE_PRIORITY = 0,
|
||||||
|
STAGE_LATE
|
||||||
|
};
|
||||||
|
|
||||||
class CCompositor {
|
class CCompositor {
|
||||||
public:
|
public:
|
||||||
CCompositor();
|
CCompositor();
|
||||||
~CCompositor();
|
~CCompositor();
|
||||||
|
|
||||||
// ------------------ WLR BASICS ------------------ //
|
// ------------------ WLR BASICS ------------------ //
|
||||||
wl_display* m_sWLDisplay;
|
wl_display* m_sWLDisplay;
|
||||||
wl_event_loop* m_sWLEventLoop;
|
wl_event_loop* m_sWLEventLoop;
|
||||||
wlr_backend* m_sWLRBackend;
|
wlr_backend* m_sWLRBackend;
|
||||||
wlr_session* m_sWLRSession;
|
wlr_session* m_sWLRSession;
|
||||||
wlr_renderer* m_sWLRRenderer;
|
wlr_renderer* m_sWLRRenderer;
|
||||||
wlr_allocator* m_sWLRAllocator;
|
wlr_allocator* m_sWLRAllocator;
|
||||||
wlr_compositor* m_sWLRCompositor;
|
wlr_compositor* m_sWLRCompositor;
|
||||||
wlr_subcompositor* m_sWLRSubCompositor;
|
wlr_subcompositor* m_sWLRSubCompositor;
|
||||||
wlr_data_device_manager* m_sWLRDataDevMgr;
|
wlr_data_device_manager* m_sWLRDataDevMgr;
|
||||||
wlr_drm* m_sWRLDRM;
|
wlr_drm* m_sWRLDRM;
|
||||||
wlr_drm_lease_v1_manager* m_sWRLDRMLeaseMgr;
|
wlr_drm_lease_v1_manager* m_sWRLDRMLeaseMgr;
|
||||||
wlr_xdg_activation_v1* m_sWLRXDGActivation;
|
wlr_xdg_activation_v1* m_sWLRXDGActivation;
|
||||||
wlr_output_layout* m_sWLROutputLayout;
|
wlr_output_layout* m_sWLROutputLayout;
|
||||||
wlr_idle* m_sWLRIdle;
|
wlr_idle_notifier_v1* m_sWLRIdleNotifier;
|
||||||
wlr_layer_shell_v1* m_sWLRLayerShell;
|
wlr_layer_shell_v1* m_sWLRLayerShell;
|
||||||
wlr_xdg_shell* m_sWLRXDGShell;
|
wlr_xdg_shell* m_sWLRXDGShell;
|
||||||
wlr_cursor* m_sWLRCursor;
|
wlr_cursor* m_sWLRCursor;
|
||||||
wlr_xcursor_manager* m_sWLRXCursorMgr;
|
wlr_xcursor_manager* m_sWLRXCursorMgr;
|
||||||
wlr_virtual_keyboard_manager_v1* m_sWLRVKeyboardMgr;
|
wlr_virtual_keyboard_manager_v1* m_sWLRVKeyboardMgr;
|
||||||
wlr_output_manager_v1* m_sWLROutputMgr;
|
wlr_output_manager_v1* m_sWLROutputMgr;
|
||||||
wlr_presentation* m_sWLRPresentation;
|
wlr_presentation* m_sWLRPresentation;
|
||||||
wlr_scene* m_sWLRScene;
|
|
||||||
wlr_input_inhibit_manager* m_sWLRInhibitMgr;
|
|
||||||
wlr_keyboard_shortcuts_inhibit_manager_v1* m_sWLRKbShInhibitMgr;
|
wlr_keyboard_shortcuts_inhibit_manager_v1* m_sWLRKbShInhibitMgr;
|
||||||
wlr_egl* m_sWLREGL;
|
wlr_egl* m_sWLREGL;
|
||||||
int m_iDRMFD;
|
int m_iDRMFD;
|
||||||
wlr_ext_workspace_manager_v1* m_sWLREXTWorkspaceMgr;
|
wlr_pointer_constraints_v1* m_sWLRPointerConstraints;
|
||||||
wlr_pointer_constraints_v1* m_sWLRPointerConstraints;
|
wlr_relative_pointer_manager_v1* m_sWLRRelPointerMgr;
|
||||||
wlr_relative_pointer_manager_v1* m_sWLRRelPointerMgr;
|
wlr_server_decoration_manager* m_sWLRServerDecoMgr;
|
||||||
wlr_server_decoration_manager* m_sWLRServerDecoMgr;
|
wlr_xdg_decoration_manager_v1* m_sWLRXDGDecoMgr;
|
||||||
wlr_xdg_decoration_manager_v1* m_sWLRXDGDecoMgr;
|
wlr_virtual_pointer_manager_v1* m_sWLRVirtPtrMgr;
|
||||||
wlr_virtual_pointer_manager_v1* m_sWLRVirtPtrMgr;
|
wlr_foreign_toplevel_manager_v1* m_sWLRToplevelMgr;
|
||||||
wlr_foreign_toplevel_manager_v1* m_sWLRToplevelMgr;
|
wlr_tablet_manager_v2* m_sWLRTabletManager;
|
||||||
wlr_tablet_manager_v2* m_sWLRTabletManager;
|
wlr_xdg_foreign_registry* m_sWLRForeignRegistry;
|
||||||
wlr_xdg_foreign_registry* m_sWLRForeignRegistry;
|
wlr_idle_inhibit_manager_v1* m_sWLRIdleInhibitMgr;
|
||||||
wlr_idle_inhibit_manager_v1* m_sWLRIdleInhibitMgr;
|
wlr_pointer_gestures_v1* m_sWLRPointerGestures;
|
||||||
wlr_pointer_gestures_v1* m_sWLRPointerGestures;
|
wlr_output_power_manager_v1* m_sWLROutputPowerMgr;
|
||||||
wlr_output_power_manager_v1* m_sWLROutputPowerMgr;
|
wlr_input_method_manager_v2* m_sWLRIMEMgr;
|
||||||
wlr_input_method_manager_v2* m_sWLRIMEMgr;
|
wlr_text_input_manager_v3* m_sWLRTextInputMgr;
|
||||||
wlr_text_input_manager_v3* m_sWLRTextInputMgr;
|
wlr_xdg_activation_v1* m_sWLRActivation;
|
||||||
wlr_xdg_activation_v1* m_sWLRActivation;
|
wlr_linux_dmabuf_v1* m_sWLRLinuxDMABuf;
|
||||||
|
wlr_backend* m_sWLRHeadlessBackend;
|
||||||
|
wlr_session_lock_manager_v1* m_sWLRSessionLockMgr;
|
||||||
|
wlr_gamma_control_manager_v1* m_sWLRGammaCtrlMgr;
|
||||||
|
wlr_cursor_shape_manager_v1* m_sWLRCursorShapeMgr;
|
||||||
|
wlr_tearing_control_manager_v1* m_sWLRTearingControlMgr;
|
||||||
// ------------------------------------------------- //
|
// ------------------------------------------------- //
|
||||||
|
|
||||||
|
std::string m_szWLDisplaySocket = "";
|
||||||
|
std::string m_szInstanceSignature = "";
|
||||||
|
std::string m_szCurrentSplash = "error";
|
||||||
|
|
||||||
const char* m_szWLDisplaySocket;
|
std::vector<std::shared_ptr<CMonitor>> m_vMonitors;
|
||||||
std::string m_szInstanceSignature = "";
|
std::vector<std::shared_ptr<CMonitor>> m_vRealMonitors; // for all monitors, even those turned off
|
||||||
std::string m_szCurrentSplash = "error";
|
std::vector<std::unique_ptr<CWindow>> m_vWindows;
|
||||||
|
std::vector<std::unique_ptr<SXDGPopup>> m_vXDGPopups;
|
||||||
|
std::vector<std::unique_ptr<CWorkspace>> m_vWorkspaces;
|
||||||
|
std::vector<std::unique_ptr<SSubsurface>> m_vSubsurfaces;
|
||||||
|
std::vector<CWindow*> m_vWindowsFadingOut;
|
||||||
|
std::vector<SLayerSurface*> m_vSurfacesFadingOut;
|
||||||
|
|
||||||
std::vector<std::shared_ptr<CMonitor>> m_vMonitors;
|
std::unordered_map<std::string, uint64_t> m_mMonitorIDMap;
|
||||||
std::vector<std::shared_ptr<CMonitor>> m_vRealMonitors; // for all monitors, even those turned off
|
|
||||||
std::vector<std::unique_ptr<CWindow>> m_vWindows;
|
|
||||||
std::deque<std::unique_ptr<CWindow>> m_dUnmanagedX11Windows;
|
|
||||||
std::vector<std::unique_ptr<SXDGPopup>> m_vXDGPopups;
|
|
||||||
std::vector<std::unique_ptr<CWorkspace>> m_vWorkspaces;
|
|
||||||
std::vector<std::unique_ptr<SSubsurface>> m_vSubsurfaces;
|
|
||||||
std::vector<CWindow*> m_vWindowsFadingOut;
|
|
||||||
std::vector<SLayerSurface*> m_vSurfacesFadingOut;
|
|
||||||
|
|
||||||
void startCompositor();
|
void initServer();
|
||||||
void cleanup();
|
void startCompositor();
|
||||||
|
void cleanup();
|
||||||
|
void createLockFile();
|
||||||
|
void removeLockFile();
|
||||||
|
|
||||||
wlr_surface* m_pLastFocus = nullptr;
|
wlr_surface* m_pLastFocus = nullptr;
|
||||||
CWindow* m_pLastWindow = nullptr;
|
CWindow* m_pLastWindow = nullptr;
|
||||||
CMonitor* m_pLastMonitor = nullptr;
|
CMonitor* m_pLastMonitor = nullptr;
|
||||||
|
|
||||||
SSeat m_sSeat;
|
std::vector<CWindow*> m_vWindowFocusHistory; // first element is the most recently focused.
|
||||||
|
|
||||||
bool m_bReadyToProcess = false;
|
SSeat m_sSeat;
|
||||||
bool m_bSessionActive = true;
|
|
||||||
bool m_bDPMSStateON = true;
|
bool m_bReadyToProcess = false;
|
||||||
bool m_bUnsafeState = false; // unsafe state is when there is no monitors.
|
bool m_bSessionActive = true;
|
||||||
bool m_bIsShuttingDown = false;
|
bool m_bDPMSStateON = true;
|
||||||
std::deque<uint64_t> m_dProcessPIDsOnShutdown; // stores PIDs of apps to kill later when shutting down
|
bool m_bUnsafeState = false; // unsafe state is when there is no monitors.
|
||||||
|
bool m_bNextIsUnsafe = false; // because wlroots
|
||||||
|
CMonitor* m_pUnsafeOutput = nullptr; // fallback output for the unsafe state
|
||||||
|
bool m_bIsShuttingDown = false;
|
||||||
|
|
||||||
// ------------------------------------------------- //
|
// ------------------------------------------------- //
|
||||||
|
|
||||||
CMonitor* getMonitorFromID(const int&);
|
CMonitor* getMonitorFromID(const int&);
|
||||||
CMonitor* getMonitorFromName(const std::string&);
|
CMonitor* getMonitorFromName(const std::string&);
|
||||||
CMonitor* getMonitorFromCursor();
|
CMonitor* getMonitorFromDesc(const std::string&);
|
||||||
CMonitor* getMonitorFromVector(const Vector2D&);
|
CMonitor* getMonitorFromCursor();
|
||||||
void removeWindowFromVectorSafe(CWindow*);
|
CMonitor* getMonitorFromVector(const Vector2D&);
|
||||||
void focusWindow(CWindow*, wlr_surface* pSurface = nullptr);
|
void removeWindowFromVectorSafe(CWindow*);
|
||||||
void focusSurface(wlr_surface*, CWindow* pWindowOwner = nullptr);
|
void focusWindow(CWindow*, wlr_surface* pSurface = nullptr);
|
||||||
bool windowExists(CWindow*);
|
void focusSurface(wlr_surface*, CWindow* pWindowOwner = nullptr);
|
||||||
bool windowValidMapped(CWindow*);
|
bool windowExists(CWindow*);
|
||||||
CWindow* vectorToWindow(const Vector2D&);
|
bool windowValidMapped(CWindow*);
|
||||||
CWindow* vectorToWindowIdeal(const Vector2D&); // used only for finding a window to focus on, basically a "findFocusableWindow"
|
CWindow* vectorToWindowIdeal(const Vector2D&, CWindow* pIgnoreWindow = nullptr); // used only for finding a window to focus on, basically a "findFocusableWindow"
|
||||||
CWindow* vectorToWindowTiled(const Vector2D&);
|
CWindow* vectorToWindowTiled(const Vector2D&);
|
||||||
wlr_surface* vectorToLayerSurface(const Vector2D&, std::vector<std::unique_ptr<SLayerSurface>>*, Vector2D*, SLayerSurface**);
|
wlr_surface* vectorToLayerSurface(const Vector2D&, std::vector<std::unique_ptr<SLayerSurface>>*, Vector2D*, SLayerSurface**);
|
||||||
wlr_surface* vectorWindowToSurface(const Vector2D&, CWindow*, Vector2D& sl);
|
SIMEPopup* vectorToIMEPopup(const Vector2D& pos, std::list<SIMEPopup>& popups);
|
||||||
CWindow* windowFromCursor();
|
wlr_surface* vectorWindowToSurface(const Vector2D&, CWindow*, Vector2D& sl);
|
||||||
CWindow* windowFloatingFromCursor();
|
Vector2D vectorToSurfaceLocal(const Vector2D&, CWindow*, wlr_surface*);
|
||||||
CMonitor* getMonitorFromOutput(wlr_output*);
|
CWindow* windowFromCursor();
|
||||||
CWindow* getWindowForPopup(wlr_xdg_popup*);
|
CWindow* windowFloatingFromCursor();
|
||||||
CWindow* getWindowFromSurface(wlr_surface*);
|
CMonitor* getMonitorFromOutput(wlr_output*);
|
||||||
bool isWorkspaceVisible(const int&);
|
CWindow* getWindowForPopup(wlr_xdg_popup*);
|
||||||
CWorkspace* getWorkspaceByID(const int&);
|
CWindow* getWindowFromSurface(wlr_surface*);
|
||||||
CWorkspace* getWorkspaceByName(const std::string&);
|
CWindow* getWindowFromHandle(uint32_t);
|
||||||
CWorkspace* getWorkspaceByString(const std::string&);
|
CWindow* getWindowFromZWLRHandle(wl_resource*);
|
||||||
void sanityCheckWorkspaces();
|
bool isWorkspaceVisible(const int&);
|
||||||
void updateWorkspaceWindowDecos(const int&);
|
CWorkspace* getWorkspaceByID(const int&);
|
||||||
int getWindowsOnWorkspace(const int&);
|
CWorkspace* getWorkspaceByName(const std::string&);
|
||||||
CWindow* getFirstWindowOnWorkspace(const int&);
|
CWorkspace* getWorkspaceByString(const std::string&);
|
||||||
CWindow* getFullscreenWindowOnWorkspace(const int&);
|
void sanityCheckWorkspaces();
|
||||||
bool doesSeatAcceptInput(wlr_surface*);
|
void updateWorkspaceWindowDecos(const int&);
|
||||||
bool isWindowActive(CWindow*);
|
int getWindowsOnWorkspace(const int&);
|
||||||
void moveWindowToTop(CWindow*);
|
CWindow* getUrgentWindow();
|
||||||
void cleanupFadingOut(const int& monid);
|
bool hasUrgentWindowOnWorkspace(const int&);
|
||||||
CWindow* getWindowInDirection(CWindow*, char);
|
CWindow* getFirstWindowOnWorkspace(const int&);
|
||||||
void deactivateAllWLRWorkspaces(wlr_ext_workspace_handle_v1* exclude = nullptr);
|
CWindow* getTopLeftWindowOnWorkspace(const int&);
|
||||||
CWindow* getNextWindowOnWorkspace(CWindow*, bool focusableOnly = false);
|
CWindow* getFullscreenWindowOnWorkspace(const int&);
|
||||||
CWindow* getPrevWindowOnWorkspace(CWindow*, bool focusableOnly = false);
|
bool doesSeatAcceptInput(wlr_surface*);
|
||||||
int getNextAvailableNamedWorkspace();
|
bool isWindowActive(CWindow*);
|
||||||
bool isPointOnAnyMonitor(const Vector2D&);
|
void changeWindowZOrder(CWindow*, bool);
|
||||||
CWindow* getConstraintWindow(SMouse*);
|
void cleanupFadingOut(const int& monid);
|
||||||
CMonitor* getMonitorInDirection(const char&);
|
CWindow* getWindowInDirection(CWindow*, char);
|
||||||
void updateAllWindowsAnimatedDecorationValues();
|
CWindow* getNextWindowOnWorkspace(CWindow*, bool focusableOnly = false);
|
||||||
void updateWindowAnimatedDecorationValues(CWindow*);
|
CWindow* getPrevWindowOnWorkspace(CWindow*, bool focusableOnly = false);
|
||||||
int getNextAvailableMonitorID();
|
int getNextAvailableNamedWorkspace();
|
||||||
void moveWorkspaceToMonitor(CWorkspace*, CMonitor*);
|
bool isPointOnAnyMonitor(const Vector2D&);
|
||||||
void swapActiveWorkspaces(CMonitor*, CMonitor*);
|
CWindow* getConstraintWindow(SMouse*);
|
||||||
CMonitor* getMonitorFromString(const std::string&);
|
CMonitor* getMonitorInDirection(const char&);
|
||||||
bool workspaceIDOutOfBounds(const int&);
|
void updateAllWindowsAnimatedDecorationValues();
|
||||||
void setWindowFullscreen(CWindow*, bool, eFullscreenMode);
|
void updateWindowAnimatedDecorationValues(CWindow*);
|
||||||
void moveUnmanagedX11ToWindows(CWindow*);
|
int getNextAvailableMonitorID(std::string const& name);
|
||||||
CWindow* getX11Parent(CWindow*);
|
void moveWorkspaceToMonitor(CWorkspace*, CMonitor*);
|
||||||
void scheduleFrameForMonitor(CMonitor*);
|
void swapActiveWorkspaces(CMonitor*, CMonitor*);
|
||||||
void addToFadingOutSafe(SLayerSurface*);
|
CMonitor* getMonitorFromString(const std::string&);
|
||||||
void addToFadingOutSafe(CWindow*);
|
bool workspaceIDOutOfBounds(const int64_t&);
|
||||||
CWindow* getWindowByRegex(const std::string&);
|
void setWindowFullscreen(CWindow*, bool, eFullscreenMode);
|
||||||
void warpCursorTo(const Vector2D&);
|
void updateFullscreenFadeOnWorkspace(CWorkspace*);
|
||||||
SLayerSurface* getLayerSurfaceFromWlr(wlr_layer_surface_v1*);
|
CWindow* getX11Parent(CWindow*);
|
||||||
SLayerSurface* getLayerSurfaceFromSurface(wlr_surface*);
|
void scheduleFrameForMonitor(CMonitor*);
|
||||||
void closeWindow(CWindow*);
|
void addToFadingOutSafe(SLayerSurface*);
|
||||||
Vector2D parseWindowVectorArgsRelative(const std::string&, const Vector2D&);
|
void addToFadingOutSafe(CWindow*);
|
||||||
void forceReportSizesToWindowsOnWorkspace(const int&);
|
CWindow* getWindowByRegex(const std::string&);
|
||||||
bool cursorOnReservedArea();
|
void warpCursorTo(const Vector2D&, bool force = false);
|
||||||
CWorkspace* createNewWorkspace(const int&, const int&, const std::string& name = ""); // will be deleted next frame if left empty and unfocused!
|
SLayerSurface* getLayerSurfaceFromWlr(wlr_layer_surface_v1*);
|
||||||
|
SLayerSurface* getLayerSurfaceFromSurface(wlr_surface*);
|
||||||
|
void closeWindow(CWindow*);
|
||||||
|
Vector2D parseWindowVectorArgsRelative(const std::string&, const Vector2D&);
|
||||||
|
void forceReportSizesToWindowsOnWorkspace(const int&);
|
||||||
|
bool cursorOnReservedArea();
|
||||||
|
CWorkspace* createNewWorkspace(const int&, const int&, const std::string& name = ""); // will be deleted next frame if left empty and unfocused!
|
||||||
|
void renameWorkspace(const int&, const std::string& name = "");
|
||||||
|
void setActiveMonitor(CMonitor*);
|
||||||
|
bool isWorkspaceSpecial(const int&);
|
||||||
|
int getNewSpecialID();
|
||||||
|
void performUserChecks();
|
||||||
|
void moveWindowToWorkspaceSafe(CWindow* pWindow, CWorkspace* pWorkspace);
|
||||||
|
CWindow* getForceFocus();
|
||||||
|
void notifyIdleActivity();
|
||||||
|
void setIdleActivityInhibit(bool inhibit);
|
||||||
|
void arrangeMonitors();
|
||||||
|
void enterUnsafeState();
|
||||||
|
void leaveUnsafeState();
|
||||||
|
void setPreferredScaleForSurface(wlr_surface* pSurface, double scale);
|
||||||
|
void setPreferredTransformForSurface(wlr_surface* pSurface, wl_output_transform transform);
|
||||||
|
|
||||||
std::string explicitConfigPath;
|
std::string explicitConfigPath;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void initAllSignals();
|
void initAllSignals();
|
||||||
void setRandomSplash();
|
void setRandomSplash();
|
||||||
|
void initManagers(eManagersInitStage stage);
|
||||||
|
void prepareFallbackOutput();
|
||||||
|
|
||||||
uint64_t m_iHyprlandPID = 0;
|
uint64_t m_iHyprlandPID = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
inline std::unique_ptr<CCompositor> g_pCompositor;
|
inline std::unique_ptr<CCompositor> g_pCompositor;
|
||||||
|
|
||||||
// For XWayland
|
// For XWayland
|
||||||
inline std::map<std::string, xcb_atom_t> HYPRATOMS = {
|
inline std::map<std::string, xcb_atom_t> HYPRATOMS = {HYPRATOM("_NET_WM_WINDOW_TYPE"),
|
||||||
HYPRATOM("_NET_WM_WINDOW_TYPE"),
|
HYPRATOM("_NET_WM_WINDOW_TYPE_NORMAL"),
|
||||||
HYPRATOM("_NET_WM_WINDOW_TYPE_NORMAL"),
|
HYPRATOM("_NET_WM_WINDOW_TYPE_DOCK"),
|
||||||
HYPRATOM("_NET_WM_WINDOW_TYPE_DOCK"),
|
HYPRATOM("_NET_WM_WINDOW_TYPE_DIALOG"),
|
||||||
HYPRATOM("_NET_WM_WINDOW_TYPE_DIALOG"),
|
HYPRATOM("_NET_WM_WINDOW_TYPE_UTILITY"),
|
||||||
HYPRATOM("_NET_WM_WINDOW_TYPE_UTILITY"),
|
HYPRATOM("_NET_WM_WINDOW_TYPE_TOOLBAR"),
|
||||||
HYPRATOM("_NET_WM_WINDOW_TYPE_TOOLBAR"),
|
HYPRATOM("_NET_WM_WINDOW_TYPE_SPLASH"),
|
||||||
HYPRATOM("_NET_WM_WINDOW_TYPE_SPLASH"),
|
HYPRATOM("_NET_WM_WINDOW_TYPE_MENU"),
|
||||||
HYPRATOM("_NET_WM_WINDOW_TYPE_MENU"),
|
HYPRATOM("_NET_WM_WINDOW_TYPE_DROPDOWN_MENU"),
|
||||||
HYPRATOM("_NET_WM_WINDOW_TYPE_DROPDOWN_MENU"),
|
HYPRATOM("_NET_WM_WINDOW_TYPE_POPUP_MENU"),
|
||||||
HYPRATOM("_NET_WM_WINDOW_TYPE_POPUP_MENU"),
|
HYPRATOM("_NET_WM_WINDOW_TYPE_TOOLTIP"),
|
||||||
HYPRATOM("_NET_WM_WINDOW_TYPE_TOOLTIP"),
|
HYPRATOM("_NET_WM_WINDOW_TYPE_NOTIFICATION"),
|
||||||
HYPRATOM("_NET_WM_WINDOW_TYPE_NOTIFICATION")};
|
HYPRATOM("_KDE_NET_WM_WINDOW_TYPE_OVERRIDE")};
|
||||||
|
|||||||
49
src/SharedDefs.hpp
Normal file
49
src/SharedDefs.hpp
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "helpers/Vector2D.hpp"
|
||||||
|
|
||||||
|
enum eIcons
|
||||||
|
{
|
||||||
|
ICON_WARNING = 0,
|
||||||
|
ICON_INFO,
|
||||||
|
ICON_HINT,
|
||||||
|
ICON_ERROR,
|
||||||
|
ICON_CONFUSED,
|
||||||
|
ICON_OK,
|
||||||
|
ICON_NONE
|
||||||
|
};
|
||||||
|
|
||||||
|
enum eRenderStage
|
||||||
|
{
|
||||||
|
RENDER_PRE = 0, /* Before binding the gl context */
|
||||||
|
RENDER_BEGIN, /* Just when the rendering begins, nothing has been rendered yet. Damage, current render data in opengl valid. */
|
||||||
|
RENDER_PRE_WINDOWS, /* Pre windows, post bottom and overlay layers */
|
||||||
|
RENDER_POST_WINDOWS, /* Post windows, pre top/overlay layers, etc */
|
||||||
|
RENDER_LAST_MOMENT, /* Last moment to render with the gl context */
|
||||||
|
RENDER_POST, /* After rendering is finished, gl context not available anymore */
|
||||||
|
RENDER_POST_MIRROR, /* After rendering a mirror */
|
||||||
|
RENDER_PRE_WINDOW, /* Before rendering a window (any pass) Note some windows (e.g. tiled) may have 2 passes (main & popup) */
|
||||||
|
RENDER_POST_WINDOW, /* After rendering a window (any pass) */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SCallbackInfo {
|
||||||
|
bool cancelled = false; /* on cancellable events, will cancel the event. */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SWindowDecorationExtents {
|
||||||
|
Vector2D topLeft;
|
||||||
|
Vector2D bottomRight;
|
||||||
|
|
||||||
|
//
|
||||||
|
SWindowDecorationExtents operator*(const double& scale) const {
|
||||||
|
return SWindowDecorationExtents{topLeft * scale, bottomRight * scale};
|
||||||
|
}
|
||||||
|
|
||||||
|
SWindowDecorationExtents round() {
|
||||||
|
return {topLeft.round(), bottomRight.round()};
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const SWindowDecorationExtents& other) const {
|
||||||
|
return topLeft == other.topLeft && bottomRight == other.bottomRight;
|
||||||
|
}
|
||||||
|
};
|
||||||
855
src/Window.cpp
855
src/Window.cpp
@@ -1,63 +1,123 @@
|
|||||||
#include "Window.hpp"
|
#include "Window.hpp"
|
||||||
#include "Compositor.hpp"
|
#include "Compositor.hpp"
|
||||||
#include "render/decorations/CHyprDropShadowDecoration.hpp"
|
#include "render/decorations/CHyprDropShadowDecoration.hpp"
|
||||||
|
#include "render/decorations/CHyprGroupBarDecoration.hpp"
|
||||||
|
|
||||||
CWindow::CWindow() {
|
CWindow::CWindow() {
|
||||||
m_vRealPosition.create(AVARTYPE_VECTOR, g_pConfigManager->getAnimationPropertyConfig("windowsIn"), (void*) this, AVARDAMAGE_ENTIRE);
|
m_vRealPosition.create(AVARTYPE_VECTOR, g_pConfigManager->getAnimationPropertyConfig("windowsIn"), (void*)this, AVARDAMAGE_ENTIRE);
|
||||||
m_vRealSize.create(AVARTYPE_VECTOR, g_pConfigManager->getAnimationPropertyConfig("windowsIn"), (void*)this, AVARDAMAGE_ENTIRE);
|
m_vRealSize.create(AVARTYPE_VECTOR, g_pConfigManager->getAnimationPropertyConfig("windowsIn"), (void*)this, AVARDAMAGE_ENTIRE);
|
||||||
m_cRealBorderColor.create(AVARTYPE_COLOR, g_pConfigManager->getAnimationPropertyConfig("border"), (void*)this, AVARDAMAGE_BORDER);
|
m_fBorderFadeAnimationProgress.create(AVARTYPE_FLOAT, g_pConfigManager->getAnimationPropertyConfig("border"), (void*)this, AVARDAMAGE_BORDER);
|
||||||
|
m_fBorderAngleAnimationProgress.create(AVARTYPE_FLOAT, g_pConfigManager->getAnimationPropertyConfig("borderangle"), (void*)this, AVARDAMAGE_BORDER);
|
||||||
m_fAlpha.create(AVARTYPE_FLOAT, g_pConfigManager->getAnimationPropertyConfig("fadeIn"), (void*)this, AVARDAMAGE_ENTIRE);
|
m_fAlpha.create(AVARTYPE_FLOAT, g_pConfigManager->getAnimationPropertyConfig("fadeIn"), (void*)this, AVARDAMAGE_ENTIRE);
|
||||||
m_fActiveInactiveAlpha.create(AVARTYPE_FLOAT, g_pConfigManager->getAnimationPropertyConfig("fadeSwitch"), (void*)this, AVARDAMAGE_ENTIRE);
|
m_fActiveInactiveAlpha.create(AVARTYPE_FLOAT, g_pConfigManager->getAnimationPropertyConfig("fadeSwitch"), (void*)this, AVARDAMAGE_ENTIRE);
|
||||||
m_cRealShadowColor.create(AVARTYPE_COLOR, g_pConfigManager->getAnimationPropertyConfig("fadeShadow"), (void*)this, AVARDAMAGE_SHADOW);
|
m_cRealShadowColor.create(AVARTYPE_COLOR, g_pConfigManager->getAnimationPropertyConfig("fadeShadow"), (void*)this, AVARDAMAGE_SHADOW);
|
||||||
m_fDimPercent.create(AVARTYPE_FLOAT, g_pConfigManager->getAnimationPropertyConfig("fadeDim"), (void*)this, AVARDAMAGE_ENTIRE);
|
m_fDimPercent.create(AVARTYPE_FLOAT, g_pConfigManager->getAnimationPropertyConfig("fadeDim"), (void*)this, AVARDAMAGE_ENTIRE);
|
||||||
|
|
||||||
m_dWindowDecorations.emplace_back(std::make_unique<CHyprDropShadowDecoration>(this)); // put the shadow so it's the first deco (has to be rendered first)
|
addWindowDeco(std::make_unique<CHyprDropShadowDecoration>(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
CWindow::~CWindow() {
|
CWindow::~CWindow() {
|
||||||
if (g_pCompositor->isWindowActive(this)) {
|
if (g_pCompositor->isWindowActive(this)) {
|
||||||
g_pCompositor->m_pLastFocus = nullptr;
|
g_pCompositor->m_pLastFocus = nullptr;
|
||||||
g_pCompositor->m_pLastWindow = nullptr;
|
g_pCompositor->m_pLastWindow = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!g_pHyprOpenGL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
g_pHyprRenderer->makeEGLCurrent();
|
||||||
|
std::erase_if(g_pHyprOpenGL->m_mWindowFramebuffers, [&](const auto& other) { return other.first == this; });
|
||||||
}
|
}
|
||||||
|
|
||||||
wlr_box CWindow::getFullWindowBoundingBox() {
|
SWindowDecorationExtents CWindow::getFullWindowExtents() {
|
||||||
static auto *const PBORDERSIZE = &g_pConfigManager->getConfigValuePtr("general:border_size")->intValue;
|
if (m_bFadingOut)
|
||||||
|
return m_eOriginalClosedExtents;
|
||||||
|
|
||||||
SWindowDecorationExtents maxExtents = {{*PBORDERSIZE + 2, *PBORDERSIZE + 2}, {*PBORDERSIZE + 2, *PBORDERSIZE + 2}};
|
const int BORDERSIZE = getRealBorderSize();
|
||||||
|
|
||||||
for (auto& wd : m_dWindowDecorations) {
|
if (m_sAdditionalConfigData.dimAround) {
|
||||||
|
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
|
||||||
const auto EXTENTS = wd->getWindowDecorationExtents();
|
return {{m_vRealPosition.vec().x - PMONITOR->vecPosition.x, m_vRealPosition.vec().y - PMONITOR->vecPosition.y},
|
||||||
|
{PMONITOR->vecSize.x - (m_vRealPosition.vec().x - PMONITOR->vecPosition.x), PMONITOR->vecSize.y - (m_vRealPosition.vec().y - PMONITOR->vecPosition.y)}};
|
||||||
if (EXTENTS.topLeft.x > maxExtents.topLeft.x)
|
|
||||||
maxExtents.topLeft.x = EXTENTS.topLeft.x;
|
|
||||||
|
|
||||||
if (EXTENTS.topLeft.y > maxExtents.topLeft.y)
|
|
||||||
maxExtents.topLeft.y = EXTENTS.topLeft.y;
|
|
||||||
|
|
||||||
if (EXTENTS.bottomRight.x > maxExtents.bottomRight.x)
|
|
||||||
maxExtents.bottomRight.x = EXTENTS.bottomRight.x;
|
|
||||||
|
|
||||||
if (EXTENTS.bottomRight.y > maxExtents.bottomRight.y)
|
|
||||||
maxExtents.bottomRight.y = EXTENTS.bottomRight.y;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add extents to the real base BB and return
|
SWindowDecorationExtents maxExtents = {{BORDERSIZE + 2, BORDERSIZE + 2}, {BORDERSIZE + 2, BORDERSIZE + 2}};
|
||||||
wlr_box finalBox = {m_vRealPosition.vec().x - maxExtents.topLeft.x,
|
|
||||||
m_vRealPosition.vec().y - maxExtents.topLeft.y,
|
const auto EXTENTS = g_pDecorationPositioner->getWindowDecorationExtents(this);
|
||||||
m_vRealSize.vec().x + maxExtents.topLeft.x + maxExtents.bottomRight.x,
|
|
||||||
m_vRealSize.vec().y + maxExtents.topLeft.y + maxExtents.bottomRight.y};
|
if (EXTENTS.topLeft.x > maxExtents.topLeft.x)
|
||||||
|
maxExtents.topLeft.x = EXTENTS.topLeft.x;
|
||||||
|
|
||||||
|
if (EXTENTS.topLeft.y > maxExtents.topLeft.y)
|
||||||
|
maxExtents.topLeft.y = EXTENTS.topLeft.y;
|
||||||
|
|
||||||
|
if (EXTENTS.bottomRight.x > maxExtents.bottomRight.x)
|
||||||
|
maxExtents.bottomRight.x = EXTENTS.bottomRight.x;
|
||||||
|
|
||||||
|
if (EXTENTS.bottomRight.y > maxExtents.bottomRight.y)
|
||||||
|
maxExtents.bottomRight.y = EXTENTS.bottomRight.y;
|
||||||
|
|
||||||
|
if (m_pWLSurface.exists() && !m_bIsX11) {
|
||||||
|
CBox surfaceExtents = {0, 0, 0, 0};
|
||||||
|
// TODO: this could be better, perhaps make a getFullWindowRegion?
|
||||||
|
wlr_xdg_surface_for_each_popup_surface(
|
||||||
|
m_uSurface.xdg,
|
||||||
|
[](wlr_surface* surf, int sx, int sy, void* data) {
|
||||||
|
CBox* pSurfaceExtents = (CBox*)data;
|
||||||
|
if (sx < pSurfaceExtents->x)
|
||||||
|
pSurfaceExtents->x = sx;
|
||||||
|
if (sy < pSurfaceExtents->y)
|
||||||
|
pSurfaceExtents->y = sy;
|
||||||
|
if (sx + surf->current.width > pSurfaceExtents->width)
|
||||||
|
pSurfaceExtents->width = sx + surf->current.width - pSurfaceExtents->x;
|
||||||
|
if (sy + surf->current.height > pSurfaceExtents->height)
|
||||||
|
pSurfaceExtents->height = sy + surf->current.height - pSurfaceExtents->y;
|
||||||
|
},
|
||||||
|
&surfaceExtents);
|
||||||
|
|
||||||
|
if (-surfaceExtents.x > maxExtents.topLeft.x)
|
||||||
|
maxExtents.topLeft.x = -surfaceExtents.x;
|
||||||
|
|
||||||
|
if (-surfaceExtents.y > maxExtents.topLeft.y)
|
||||||
|
maxExtents.topLeft.y = -surfaceExtents.y;
|
||||||
|
|
||||||
|
if (surfaceExtents.x + surfaceExtents.width > m_pWLSurface.wlr()->current.width + maxExtents.bottomRight.x)
|
||||||
|
maxExtents.bottomRight.x = surfaceExtents.x + surfaceExtents.width - m_pWLSurface.wlr()->current.width;
|
||||||
|
|
||||||
|
if (surfaceExtents.y + surfaceExtents.height > m_pWLSurface.wlr()->current.height + maxExtents.bottomRight.y)
|
||||||
|
maxExtents.bottomRight.y = surfaceExtents.y + surfaceExtents.height - m_pWLSurface.wlr()->current.height;
|
||||||
|
}
|
||||||
|
|
||||||
|
return maxExtents;
|
||||||
|
}
|
||||||
|
|
||||||
|
CBox CWindow::getFullWindowBoundingBox() {
|
||||||
|
if (m_sAdditionalConfigData.dimAround) {
|
||||||
|
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
|
||||||
|
return {PMONITOR->vecPosition.x, PMONITOR->vecPosition.y, PMONITOR->vecSize.x, PMONITOR->vecSize.y};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto maxExtents = getFullWindowExtents();
|
||||||
|
|
||||||
|
CBox finalBox = {m_vRealPosition.vec().x - maxExtents.topLeft.x, m_vRealPosition.vec().y - maxExtents.topLeft.y,
|
||||||
|
m_vRealSize.vec().x + maxExtents.topLeft.x + maxExtents.bottomRight.x, m_vRealSize.vec().y + maxExtents.topLeft.y + maxExtents.bottomRight.y};
|
||||||
|
|
||||||
return finalBox;
|
return finalBox;
|
||||||
}
|
}
|
||||||
|
|
||||||
wlr_box CWindow::getWindowIdealBoundingBoxIgnoreReserved() {
|
CBox CWindow::getWindowIdealBoundingBoxIgnoreReserved() {
|
||||||
|
|
||||||
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
|
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
|
||||||
|
|
||||||
auto POS = m_vPosition;
|
auto POS = m_vPosition;
|
||||||
auto SIZE = m_vSize;
|
auto SIZE = m_vSize;
|
||||||
|
|
||||||
|
if (m_bIsFullscreen) {
|
||||||
|
POS = PMONITOR->vecPosition;
|
||||||
|
SIZE = PMONITOR->vecSize;
|
||||||
|
|
||||||
|
return CBox{(int)POS.x, (int)POS.y, (int)SIZE.x, (int)SIZE.y};
|
||||||
|
}
|
||||||
|
|
||||||
if (DELTALESSTHAN(POS.y - PMONITOR->vecPosition.y, PMONITOR->vecReservedTopLeft.y, 1)) {
|
if (DELTALESSTHAN(POS.y - PMONITOR->vecPosition.y, PMONITOR->vecReservedTopLeft.y, 1)) {
|
||||||
POS.y = PMONITOR->vecPosition.y;
|
POS.y = PMONITOR->vecPosition.y;
|
||||||
@@ -74,31 +134,104 @@ wlr_box CWindow::getWindowIdealBoundingBoxIgnoreReserved() {
|
|||||||
SIZE.y += PMONITOR->vecReservedBottomRight.y;
|
SIZE.y += PMONITOR->vecReservedBottomRight.y;
|
||||||
}
|
}
|
||||||
|
|
||||||
return wlr_box{(int)POS.x, (int)POS.y, (int)SIZE.x, (int)SIZE.y};
|
return CBox{(int)POS.x, (int)POS.y, (int)SIZE.x, (int)SIZE.y};
|
||||||
|
}
|
||||||
|
|
||||||
|
CBox CWindow::getWindowInputBox() {
|
||||||
|
const int BORDERSIZE = getRealBorderSize();
|
||||||
|
|
||||||
|
if (m_sAdditionalConfigData.dimAround) {
|
||||||
|
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
|
||||||
|
return {PMONITOR->vecPosition.x, PMONITOR->vecPosition.y, PMONITOR->vecSize.x, PMONITOR->vecSize.y};
|
||||||
|
}
|
||||||
|
|
||||||
|
SWindowDecorationExtents maxExtents = {{BORDERSIZE + 2, BORDERSIZE + 2}, {BORDERSIZE + 2, BORDERSIZE + 2}};
|
||||||
|
|
||||||
|
const auto EXTENTS = g_pDecorationPositioner->getWindowDecorationExtents(this, true);
|
||||||
|
|
||||||
|
if (EXTENTS.topLeft.x > maxExtents.topLeft.x)
|
||||||
|
maxExtents.topLeft.x = EXTENTS.topLeft.x;
|
||||||
|
|
||||||
|
if (EXTENTS.topLeft.y > maxExtents.topLeft.y)
|
||||||
|
maxExtents.topLeft.y = EXTENTS.topLeft.y;
|
||||||
|
|
||||||
|
if (EXTENTS.bottomRight.x > maxExtents.bottomRight.x)
|
||||||
|
maxExtents.bottomRight.x = EXTENTS.bottomRight.x;
|
||||||
|
|
||||||
|
if (EXTENTS.bottomRight.y > maxExtents.bottomRight.y)
|
||||||
|
maxExtents.bottomRight.y = EXTENTS.bottomRight.y;
|
||||||
|
|
||||||
|
// Add extents to the real base BB and return
|
||||||
|
CBox finalBox = {m_vRealPosition.vec().x - maxExtents.topLeft.x, m_vRealPosition.vec().y - maxExtents.topLeft.y,
|
||||||
|
m_vRealSize.vec().x + maxExtents.topLeft.x + maxExtents.bottomRight.x, m_vRealSize.vec().y + maxExtents.topLeft.y + maxExtents.bottomRight.y};
|
||||||
|
|
||||||
|
return finalBox;
|
||||||
|
}
|
||||||
|
|
||||||
|
CBox CWindow::getWindowMainSurfaceBox() {
|
||||||
|
return {m_vRealPosition.vec().x, m_vRealPosition.vec().y, m_vRealSize.vec().x, m_vRealSize.vec().y};
|
||||||
|
}
|
||||||
|
|
||||||
|
SWindowDecorationExtents CWindow::getFullWindowReservedArea() {
|
||||||
|
return g_pDecorationPositioner->getWindowDecorationReserved(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CWindow::updateWindowDecos() {
|
void CWindow::updateWindowDecos() {
|
||||||
for (auto& wd : m_dWindowDecorations)
|
bool recalc = false;
|
||||||
wd->updateWindow(this);
|
|
||||||
|
if (!m_bIsMapped || isHidden())
|
||||||
|
return;
|
||||||
|
|
||||||
for (auto& wd : m_vDecosToRemove) {
|
for (auto& wd : m_vDecosToRemove) {
|
||||||
for (auto it = m_dWindowDecorations.begin(); it != m_dWindowDecorations.end(); it++) {
|
for (auto it = m_dWindowDecorations.begin(); it != m_dWindowDecorations.end(); it++) {
|
||||||
if (it->get() == wd) {
|
if (it->get() == wd) {
|
||||||
it = m_dWindowDecorations.erase(it);
|
g_pDecorationPositioner->uncacheDecoration(it->get());
|
||||||
|
it = m_dWindowDecorations.erase(it);
|
||||||
|
recalc = true;
|
||||||
if (it == m_dWindowDecorations.end())
|
if (it == m_dWindowDecorations.end())
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
g_pDecorationPositioner->onWindowUpdate(this);
|
||||||
|
|
||||||
|
if (recalc)
|
||||||
|
g_pLayoutManager->getCurrentLayout()->recalculateWindow(this);
|
||||||
|
|
||||||
m_vDecosToRemove.clear();
|
m_vDecosToRemove.clear();
|
||||||
|
|
||||||
|
for (auto& wd : m_dWindowDecorations) {
|
||||||
|
wd->updateWindow(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CWindow::addWindowDeco(std::unique_ptr<IHyprWindowDecoration> deco) {
|
||||||
|
m_dWindowDecorations.emplace_back(std::move(deco));
|
||||||
|
g_pDecorationPositioner->forceRecalcFor(this);
|
||||||
|
updateWindowDecos();
|
||||||
|
g_pLayoutManager->getCurrentLayout()->recalculateWindow(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CWindow::removeWindowDeco(IHyprWindowDecoration* deco) {
|
||||||
|
m_vDecosToRemove.push_back(deco);
|
||||||
|
g_pDecorationPositioner->forceRecalcFor(this);
|
||||||
|
updateWindowDecos();
|
||||||
|
g_pLayoutManager->getCurrentLayout()->recalculateWindow(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
pid_t CWindow::getPID() {
|
pid_t CWindow::getPID() {
|
||||||
pid_t PID = -1;
|
pid_t PID = -1;
|
||||||
if (!m_bIsX11) {
|
if (!m_bIsX11) {
|
||||||
|
|
||||||
|
if (!m_bIsMapped)
|
||||||
|
return -1;
|
||||||
|
|
||||||
wl_client_get_credentials(wl_resource_get_client(m_uSurface.xdg->resource), &PID, nullptr, nullptr);
|
wl_client_get_credentials(wl_resource_get_client(m_uSurface.xdg->resource), &PID, nullptr, nullptr);
|
||||||
} else {
|
} else {
|
||||||
|
if (!m_bIsMapped || !m_bMappedX11)
|
||||||
|
return -1;
|
||||||
|
|
||||||
PID = m_uSurface.xwayland->pid;
|
PID = m_uSurface.xwayland->pid;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -128,25 +261,20 @@ void CWindow::createToplevelHandle() {
|
|||||||
wlr_foreign_toplevel_handle_v1_set_fullscreen(m_phForeignToplevel, false);
|
wlr_foreign_toplevel_handle_v1_set_fullscreen(m_phForeignToplevel, false);
|
||||||
|
|
||||||
// handle events
|
// handle events
|
||||||
hyprListener_toplevelActivate.initCallback(&m_phForeignToplevel->events.request_activate, [&](void* owner, void* data) {
|
hyprListener_toplevelActivate.initCallback(
|
||||||
|
&m_phForeignToplevel->events.request_activate, [&](void* owner, void* data) { g_pLayoutManager->getCurrentLayout()->requestFocusForWindow(this); }, this, "Toplevel");
|
||||||
|
|
||||||
g_pCompositor->focusWindow(this);
|
hyprListener_toplevelFullscreen.initCallback(
|
||||||
|
&m_phForeignToplevel->events.request_fullscreen,
|
||||||
|
[&](void* owner, void* data) {
|
||||||
|
const auto EV = (wlr_foreign_toplevel_handle_v1_fullscreen_event*)data;
|
||||||
|
|
||||||
}, this, "Toplevel");
|
g_pCompositor->setWindowFullscreen(this, EV->fullscreen, FULLSCREEN_FULL);
|
||||||
|
},
|
||||||
|
this, "Toplevel");
|
||||||
|
|
||||||
hyprListener_toplevelFullscreen.initCallback(&m_phForeignToplevel->events.request_fullscreen, [&](void* owner, void* data) {
|
hyprListener_toplevelClose.initCallback(
|
||||||
|
&m_phForeignToplevel->events.request_close, [&](void* owner, void* data) { g_pCompositor->closeWindow(this); }, this, "Toplevel");
|
||||||
const auto EV = (wlr_foreign_toplevel_handle_v1_fullscreen_event*)data;
|
|
||||||
|
|
||||||
g_pCompositor->setWindowFullscreen(this, EV->fullscreen, FULLSCREEN_FULL);
|
|
||||||
|
|
||||||
}, this, "Toplevel");
|
|
||||||
|
|
||||||
hyprListener_toplevelClose.initCallback(&m_phForeignToplevel->events.request_close, [&](void* owner, void* data) {
|
|
||||||
|
|
||||||
g_pCompositor->closeWindow(this);
|
|
||||||
|
|
||||||
}, this, "Toplevel");
|
|
||||||
|
|
||||||
m_iLastToplevelMonitorID = m_iMonitorID;
|
m_iLastToplevelMonitorID = m_iMonitorID;
|
||||||
}
|
}
|
||||||
@@ -202,17 +330,53 @@ void CWindow::updateSurfaceOutputs() {
|
|||||||
const auto PNEWMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
|
const auto PNEWMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
|
||||||
|
|
||||||
if (PLASTMONITOR && PLASTMONITOR->m_bEnabled)
|
if (PLASTMONITOR && PLASTMONITOR->m_bEnabled)
|
||||||
wlr_surface_for_each_surface(g_pXWaylandManager->getWindowSurface(this), sendLeaveIter, PLASTMONITOR->output);
|
wlr_surface_for_each_surface(m_pWLSurface.wlr(), sendLeaveIter, PLASTMONITOR->output);
|
||||||
|
|
||||||
wlr_surface_for_each_surface(g_pXWaylandManager->getWindowSurface(this), sendEnterIter, PNEWMONITOR->output);
|
wlr_surface_for_each_surface(m_pWLSurface.wlr(), sendEnterIter, PNEWMONITOR->output);
|
||||||
|
|
||||||
|
wlr_surface_for_each_surface(
|
||||||
|
m_pWLSurface.wlr(),
|
||||||
|
[](wlr_surface* surf, int x, int y, void* data) {
|
||||||
|
const auto PMONITOR = g_pCompositor->getMonitorFromID(((CWindow*)data)->m_iMonitorID);
|
||||||
|
g_pCompositor->setPreferredScaleForSurface(surf, PMONITOR ? PMONITOR->scale : 1.f);
|
||||||
|
g_pCompositor->setPreferredTransformForSurface(surf, PMONITOR->transform);
|
||||||
|
},
|
||||||
|
this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CWindow::moveToWorkspace(int workspaceID) {
|
void CWindow::moveToWorkspace(int workspaceID) {
|
||||||
if (m_iWorkspaceID != workspaceID) {
|
if (m_iWorkspaceID == workspaceID)
|
||||||
m_iWorkspaceID = workspaceID;
|
return;
|
||||||
|
|
||||||
if (const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(m_iWorkspaceID); PWORKSPACE) {
|
static auto* const PCLOSEONLASTSPECIAL = &g_pConfigManager->getConfigValuePtr("misc:close_special_on_empty")->intValue;
|
||||||
g_pEventManager->postEvent(SHyprIPCEvent{"movewindow", getFormat("%x,%s", this, PWORKSPACE->m_szName.c_str())});
|
|
||||||
|
const int OLDWORKSPACE = m_iWorkspaceID;
|
||||||
|
|
||||||
|
m_iWorkspaceID = workspaceID;
|
||||||
|
|
||||||
|
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(m_iWorkspaceID);
|
||||||
|
|
||||||
|
updateSpecialRenderData();
|
||||||
|
|
||||||
|
if (PWORKSPACE) {
|
||||||
|
g_pEventManager->postEvent(SHyprIPCEvent{"movewindow", std::format("{:x},{}", (uintptr_t)this, PWORKSPACE->m_szName)});
|
||||||
|
EMIT_HOOK_EVENT("moveWindow", (std::vector<void*>{this, PWORKSPACE}));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_pSwallowed) {
|
||||||
|
m_pSwallowed->moveToWorkspace(workspaceID);
|
||||||
|
m_pSwallowed->m_iMonitorID = m_iMonitorID;
|
||||||
|
}
|
||||||
|
|
||||||
|
// update xwayland coords
|
||||||
|
g_pXWaylandManager->setWindowSize(this, m_vRealSize.vec());
|
||||||
|
|
||||||
|
if (g_pCompositor->isWorkspaceSpecial(OLDWORKSPACE) && g_pCompositor->getWindowsOnWorkspace(OLDWORKSPACE) == 0 && *PCLOSEONLASTSPECIAL) {
|
||||||
|
const auto PWS = g_pCompositor->getWorkspaceByID(OLDWORKSPACE);
|
||||||
|
|
||||||
|
if (PWS) {
|
||||||
|
if (const auto PMONITOR = g_pCompositor->getMonitorFromID(PWS->m_iMonitorID); PMONITOR)
|
||||||
|
PMONITOR->setSpecialWorkspace(nullptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -245,19 +409,592 @@ void CWindow::removeDecorationByType(eDecorationType type) {
|
|||||||
updateWindowDecos();
|
updateWindowDecos();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void unregisterVar(void* ptr) {
|
||||||
|
((CAnimatedVariable*)ptr)->unregister();
|
||||||
|
}
|
||||||
|
|
||||||
void CWindow::onUnmap() {
|
void CWindow::onUnmap() {
|
||||||
|
static auto* const PCLOSEONLASTSPECIAL = &g_pConfigManager->getConfigValuePtr("misc:close_special_on_empty")->intValue;
|
||||||
|
|
||||||
if (g_pCompositor->m_pLastWindow == this)
|
if (g_pCompositor->m_pLastWindow == this)
|
||||||
g_pCompositor->m_pLastWindow = nullptr;
|
g_pCompositor->m_pLastWindow = nullptr;
|
||||||
|
|
||||||
|
m_vRealPosition.setCallbackOnEnd(unregisterVar);
|
||||||
|
m_vRealSize.setCallbackOnEnd(unregisterVar);
|
||||||
|
m_fBorderFadeAnimationProgress.setCallbackOnEnd(unregisterVar);
|
||||||
|
m_fBorderAngleAnimationProgress.setCallbackOnEnd(unregisterVar);
|
||||||
|
m_fActiveInactiveAlpha.setCallbackOnEnd(unregisterVar);
|
||||||
|
m_fAlpha.setCallbackOnEnd(unregisterVar);
|
||||||
|
m_cRealShadowColor.setCallbackOnEnd(unregisterVar);
|
||||||
|
m_fDimPercent.setCallbackOnEnd(unregisterVar);
|
||||||
|
|
||||||
|
m_vRealSize.setCallbackOnBegin(nullptr);
|
||||||
|
|
||||||
|
std::erase_if(g_pCompositor->m_vWindowFocusHistory, [&](const auto& other) { return other == this; });
|
||||||
|
|
||||||
|
m_pWLSurface.unassign();
|
||||||
|
|
||||||
|
hyprListener_unmapWindow.removeCallback();
|
||||||
|
|
||||||
|
if (*PCLOSEONLASTSPECIAL && g_pCompositor->getWindowsOnWorkspace(m_iWorkspaceID) == 0 && g_pCompositor->isWorkspaceSpecial(m_iWorkspaceID)) {
|
||||||
|
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
|
||||||
|
if (PMONITOR && PMONITOR->specialWorkspaceID == m_iWorkspaceID)
|
||||||
|
PMONITOR->setSpecialWorkspace(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
|
||||||
|
|
||||||
|
if (PMONITOR && PMONITOR->solitaryClient == this)
|
||||||
|
PMONITOR->solitaryClient = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CWindow::onMap() {
|
||||||
|
|
||||||
|
m_pWLSurface.assign(g_pXWaylandManager->getWindowSurface(this));
|
||||||
|
m_pWLSurface.m_pOwner = this;
|
||||||
|
|
||||||
|
// JIC, reset the callbacks. If any are set, we'll make sure they are cleared so we don't accidentally unset them. (In case a window got remapped)
|
||||||
|
m_vRealPosition.resetAllCallbacks();
|
||||||
|
m_vRealSize.resetAllCallbacks();
|
||||||
|
m_fBorderFadeAnimationProgress.resetAllCallbacks();
|
||||||
|
m_fBorderAngleAnimationProgress.resetAllCallbacks();
|
||||||
|
m_fActiveInactiveAlpha.resetAllCallbacks();
|
||||||
|
m_fAlpha.resetAllCallbacks();
|
||||||
|
m_cRealShadowColor.resetAllCallbacks();
|
||||||
|
m_fDimPercent.resetAllCallbacks();
|
||||||
|
|
||||||
|
m_vRealPosition.registerVar();
|
||||||
|
m_vRealSize.registerVar();
|
||||||
|
m_fBorderFadeAnimationProgress.registerVar();
|
||||||
|
m_fBorderAngleAnimationProgress.registerVar();
|
||||||
|
m_fActiveInactiveAlpha.registerVar();
|
||||||
|
m_fAlpha.registerVar();
|
||||||
|
m_cRealShadowColor.registerVar();
|
||||||
|
m_fDimPercent.registerVar();
|
||||||
|
|
||||||
|
m_fBorderAngleAnimationProgress.setCallbackOnEnd([&](void* ptr) { onBorderAngleAnimEnd(ptr); }, false);
|
||||||
|
|
||||||
|
m_fBorderAngleAnimationProgress.setValueAndWarp(0.f);
|
||||||
|
m_fBorderAngleAnimationProgress = 1.f;
|
||||||
|
|
||||||
|
g_pCompositor->m_vWindowFocusHistory.push_back(this);
|
||||||
|
|
||||||
|
hyprListener_unmapWindow.initCallback(m_bIsX11 ? &m_uSurface.xwayland->surface->events.unmap : &m_uSurface.xdg->surface->events.unmap, &Events::listener_unmapWindow, this,
|
||||||
|
"CWindow");
|
||||||
|
|
||||||
|
m_vReportedSize = m_vPendingReportedSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CWindow::onBorderAngleAnimEnd(void* ptr) {
|
||||||
|
const auto PANIMVAR = (CAnimatedVariable*)ptr;
|
||||||
|
|
||||||
|
const std::string STYLE = PANIMVAR->getConfig()->pValues->internalStyle;
|
||||||
|
|
||||||
|
if (STYLE != "loop" || !PANIMVAR->getConfig()->pValues->internalEnabled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
PANIMVAR->setCallbackOnEnd(nullptr); // we remove the callback here because otherwise setvalueandwarp will recurse this
|
||||||
|
|
||||||
|
PANIMVAR->setValueAndWarp(0);
|
||||||
|
*PANIMVAR = 1.f;
|
||||||
|
|
||||||
|
PANIMVAR->setCallbackOnEnd([&](void* ptr) { onBorderAngleAnimEnd(ptr); }, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CWindow::setHidden(bool hidden) {
|
void CWindow::setHidden(bool hidden) {
|
||||||
m_bHidden = hidden;
|
m_bHidden = hidden;
|
||||||
|
|
||||||
if (hidden) {
|
if (hidden && g_pCompositor->m_pLastWindow == this) {
|
||||||
onUnmap();
|
g_pCompositor->m_pLastWindow = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CWindow::isHidden() {
|
bool CWindow::isHidden() {
|
||||||
return m_bHidden;
|
return m_bHidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CWindow::applyDynamicRule(const SWindowRule& r) {
|
||||||
|
if (r.szRule == "noblur") {
|
||||||
|
m_sAdditionalConfigData.forceNoBlur = true;
|
||||||
|
} else if (r.szRule == "noborder") {
|
||||||
|
m_sAdditionalConfigData.forceNoBorder = true;
|
||||||
|
} else if (r.szRule == "noshadow") {
|
||||||
|
m_sAdditionalConfigData.forceNoShadow = true;
|
||||||
|
} else if (r.szRule == "nodim") {
|
||||||
|
m_sAdditionalConfigData.forceNoDim = true;
|
||||||
|
} else if (r.szRule == "forcergbx") {
|
||||||
|
m_sAdditionalConfigData.forceRGBX = true;
|
||||||
|
} else if (r.szRule == "opaque") {
|
||||||
|
if (!m_sAdditionalConfigData.forceOpaqueOverridden)
|
||||||
|
m_sAdditionalConfigData.forceOpaque = true;
|
||||||
|
} else if (r.szRule == "immediate") {
|
||||||
|
m_sAdditionalConfigData.forceTearing = true;
|
||||||
|
} else if (r.szRule == "nearestneighbor") {
|
||||||
|
m_sAdditionalConfigData.nearestNeighbor = true;
|
||||||
|
} else if (r.szRule.starts_with("rounding")) {
|
||||||
|
try {
|
||||||
|
m_sAdditionalConfigData.rounding = std::stoi(r.szRule.substr(r.szRule.find_first_of(' ') + 1));
|
||||||
|
} catch (std::exception& e) { Debug::log(ERR, "Rounding rule \"{}\" failed with: {}", r.szRule, e.what()); }
|
||||||
|
} else if (r.szRule.starts_with("bordersize")) {
|
||||||
|
try {
|
||||||
|
m_sAdditionalConfigData.borderSize = std::stoi(r.szRule.substr(r.szRule.find_first_of(' ') + 1));
|
||||||
|
} catch (std::exception& e) { Debug::log(ERR, "Bordersize rule \"{}\" failed with: {}", r.szRule, e.what()); }
|
||||||
|
} else if (r.szRule.starts_with("opacity")) {
|
||||||
|
try {
|
||||||
|
CVarList vars(r.szRule, 0, ' ');
|
||||||
|
|
||||||
|
int opacityIDX = 0;
|
||||||
|
|
||||||
|
for (auto& r : vars) {
|
||||||
|
if (r == "opacity")
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (r == "override") {
|
||||||
|
if (opacityIDX == 1) {
|
||||||
|
m_sSpecialRenderData.alphaOverride = true;
|
||||||
|
m_sSpecialRenderData.alphaInactiveOverride = true;
|
||||||
|
} else if (opacityIDX == 2)
|
||||||
|
m_sSpecialRenderData.alphaInactiveOverride = true;
|
||||||
|
} else {
|
||||||
|
if (opacityIDX == 0) {
|
||||||
|
m_sSpecialRenderData.alpha = std::stof(r);
|
||||||
|
m_sSpecialRenderData.alphaInactive = std::stof(r);
|
||||||
|
} else if (opacityIDX == 1) {
|
||||||
|
m_sSpecialRenderData.alphaInactive = std::stof(r);
|
||||||
|
m_sSpecialRenderData.alphaInactiveOverride = false;
|
||||||
|
} else {
|
||||||
|
throw std::runtime_error("more than 2 alpha values");
|
||||||
|
}
|
||||||
|
|
||||||
|
opacityIDX++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (std::exception& e) { Debug::log(ERR, "Opacity rule \"{}\" failed with: {}", r.szRule, e.what()); }
|
||||||
|
} else if (r.szRule == "noanim") {
|
||||||
|
m_sAdditionalConfigData.forceNoAnims = true;
|
||||||
|
} else if (r.szRule.starts_with("animation")) {
|
||||||
|
auto STYLE = r.szRule.substr(r.szRule.find_first_of(' ') + 1);
|
||||||
|
m_sAdditionalConfigData.animationStyle = STYLE;
|
||||||
|
} else if (r.szRule.starts_with("bordercolor")) {
|
||||||
|
try {
|
||||||
|
std::string colorPart = removeBeginEndSpacesTabs(r.szRule.substr(r.szRule.find_first_of(' ') + 1));
|
||||||
|
|
||||||
|
if (colorPart.contains(' ')) {
|
||||||
|
// we have a space, 2 values
|
||||||
|
m_sSpecialRenderData.activeBorderColor = configStringToInt(colorPart.substr(0, colorPart.find_first_of(' ')));
|
||||||
|
m_sSpecialRenderData.inactiveBorderColor = configStringToInt(colorPart.substr(colorPart.find_first_of(' ') + 1));
|
||||||
|
} else {
|
||||||
|
m_sSpecialRenderData.activeBorderColor = configStringToInt(colorPart);
|
||||||
|
}
|
||||||
|
} catch (std::exception& e) { Debug::log(ERR, "BorderColor rule \"{}\" failed with: {}", r.szRule, e.what()); }
|
||||||
|
} else if (r.szRule == "dimaround") {
|
||||||
|
m_sAdditionalConfigData.dimAround = true;
|
||||||
|
} else if (r.szRule == "keepaspectratio") {
|
||||||
|
m_sAdditionalConfigData.keepAspectRatio = true;
|
||||||
|
} else if (r.szRule.starts_with("xray")) {
|
||||||
|
CVarList vars(r.szRule, 0, ' ');
|
||||||
|
|
||||||
|
try {
|
||||||
|
m_sAdditionalConfigData.xray = configStringToInt(vars[1]);
|
||||||
|
} catch (...) {}
|
||||||
|
} else if (r.szRule.starts_with("idleinhibit")) {
|
||||||
|
auto IDLERULE = r.szRule.substr(r.szRule.find_first_of(' ') + 1);
|
||||||
|
|
||||||
|
if (IDLERULE == "none")
|
||||||
|
m_eIdleInhibitMode = IDLEINHIBIT_NONE;
|
||||||
|
else if (IDLERULE == "always")
|
||||||
|
m_eIdleInhibitMode = IDLEINHIBIT_ALWAYS;
|
||||||
|
else if (IDLERULE == "focus")
|
||||||
|
m_eIdleInhibitMode = IDLEINHIBIT_FOCUS;
|
||||||
|
else if (IDLERULE == "fullscreen")
|
||||||
|
m_eIdleInhibitMode = IDLEINHIBIT_FULLSCREEN;
|
||||||
|
else
|
||||||
|
Debug::log(ERR, "Rule idleinhibit: unknown mode {}", IDLERULE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CWindow::updateDynamicRules() {
|
||||||
|
m_sSpecialRenderData.activeBorderColor = -1;
|
||||||
|
m_sSpecialRenderData.inactiveBorderColor = -1;
|
||||||
|
m_sSpecialRenderData.alpha = 1.f;
|
||||||
|
m_sSpecialRenderData.alphaInactive = -1.f;
|
||||||
|
m_sAdditionalConfigData.forceNoBlur = false;
|
||||||
|
m_sAdditionalConfigData.forceNoBorder = false;
|
||||||
|
m_sAdditionalConfigData.forceNoShadow = false;
|
||||||
|
m_sAdditionalConfigData.forceNoDim = false;
|
||||||
|
if (!m_sAdditionalConfigData.forceOpaqueOverridden)
|
||||||
|
m_sAdditionalConfigData.forceOpaque = false;
|
||||||
|
m_sAdditionalConfigData.forceNoAnims = false;
|
||||||
|
m_sAdditionalConfigData.animationStyle = std::string("");
|
||||||
|
m_sAdditionalConfigData.rounding = -1;
|
||||||
|
m_sAdditionalConfigData.dimAround = false;
|
||||||
|
m_sAdditionalConfigData.forceRGBX = false;
|
||||||
|
m_sAdditionalConfigData.borderSize = -1;
|
||||||
|
m_sAdditionalConfigData.keepAspectRatio = false;
|
||||||
|
m_sAdditionalConfigData.xray = -1;
|
||||||
|
m_sAdditionalConfigData.forceTearing = false;
|
||||||
|
m_sAdditionalConfigData.nearestNeighbor = false;
|
||||||
|
m_eIdleInhibitMode = IDLEINHIBIT_NONE;
|
||||||
|
|
||||||
|
const auto WINDOWRULES = g_pConfigManager->getMatchingRules(this);
|
||||||
|
for (auto& r : WINDOWRULES) {
|
||||||
|
applyDynamicRule(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m_iMonitorID);
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if the point is "hidden" under a rounded corner of the window
|
||||||
|
// it is assumed that the point is within the real window box (m_vRealPosition, m_vRealSize)
|
||||||
|
// otherwise behaviour is undefined
|
||||||
|
bool CWindow::isInCurvedCorner(double x, double y) {
|
||||||
|
const int ROUNDING = rounding();
|
||||||
|
if (getRealBorderSize() >= ROUNDING)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// (x0, y0), (x0, y1), ... are the center point of rounding at each corner
|
||||||
|
double x0 = m_vRealPosition.vec().x + ROUNDING;
|
||||||
|
double y0 = m_vRealPosition.vec().y + ROUNDING;
|
||||||
|
double x1 = m_vRealPosition.vec().x + m_vRealSize.vec().x - ROUNDING;
|
||||||
|
double y1 = m_vRealPosition.vec().y + m_vRealSize.vec().y - ROUNDING;
|
||||||
|
|
||||||
|
if (x < x0 && y < y0) {
|
||||||
|
return Vector2D{x0, y0}.distance(Vector2D{x, y}) > (double)ROUNDING;
|
||||||
|
}
|
||||||
|
if (x > x1 && y < y0) {
|
||||||
|
return Vector2D{x1, y0}.distance(Vector2D{x, y}) > (double)ROUNDING;
|
||||||
|
}
|
||||||
|
if (x < x0 && y > y1) {
|
||||||
|
return Vector2D{x0, y1}.distance(Vector2D{x, y}) > (double)ROUNDING;
|
||||||
|
}
|
||||||
|
if (x > x1 && y > y1) {
|
||||||
|
return Vector2D{x1, y1}.distance(Vector2D{x, y}) > (double)ROUNDING;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void findExtensionForVector2D(wlr_surface* surface, int x, int y, void* data) {
|
||||||
|
const auto DATA = (SExtensionFindingData*)data;
|
||||||
|
|
||||||
|
CBox box = {DATA->origin.x + x, DATA->origin.y + y, surface->current.width, surface->current.height};
|
||||||
|
|
||||||
|
if (box.containsPoint(DATA->vec))
|
||||||
|
*DATA->found = surface;
|
||||||
|
}
|
||||||
|
|
||||||
|
// checks if the wayland window has a popup at pos
|
||||||
|
bool CWindow::hasPopupAt(const Vector2D& pos) {
|
||||||
|
if (m_bIsX11)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
wlr_surface* resultSurf = nullptr;
|
||||||
|
Vector2D origin = m_vRealPosition.vec();
|
||||||
|
SExtensionFindingData data = {origin, pos, &resultSurf};
|
||||||
|
wlr_xdg_surface_for_each_popup_surface(m_uSurface.xdg, findExtensionForVector2D, &data);
|
||||||
|
|
||||||
|
return resultSurf;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CWindow::applyGroupRules() {
|
||||||
|
if ((m_eGroupRules & GROUP_SET && m_bFirstMap) || m_eGroupRules & GROUP_SET_ALWAYS)
|
||||||
|
createGroup();
|
||||||
|
|
||||||
|
if (m_sGroupData.pNextWindow && ((m_eGroupRules & GROUP_LOCK && m_bFirstMap) || m_eGroupRules & GROUP_LOCK_ALWAYS))
|
||||||
|
getGroupHead()->m_sGroupData.locked = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CWindow::createGroup() {
|
||||||
|
if (m_sGroupData.deny) {
|
||||||
|
Debug::log(LOG, "createGroup: window:{:x},title:{} is denied as a group, ignored", (uintptr_t)this, this->m_szTitle);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_sGroupData.pNextWindow) {
|
||||||
|
m_sGroupData.pNextWindow = this;
|
||||||
|
m_sGroupData.head = true;
|
||||||
|
m_sGroupData.locked = false;
|
||||||
|
m_sGroupData.deny = false;
|
||||||
|
|
||||||
|
addWindowDeco(std::make_unique<CHyprGroupBarDecoration>(this));
|
||||||
|
|
||||||
|
g_pLayoutManager->getCurrentLayout()->recalculateWindow(this);
|
||||||
|
g_pCompositor->updateAllWindowsAnimatedDecorationValues();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CWindow::destroyGroup() {
|
||||||
|
if (m_sGroupData.pNextWindow == this) {
|
||||||
|
if (m_eGroupRules & GROUP_SET_ALWAYS) {
|
||||||
|
Debug::log(LOG, "destoryGroup: window:{:x},title:{} has rule [group set always], ignored", (uintptr_t)this, this->m_szTitle);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_sGroupData.pNextWindow = nullptr;
|
||||||
|
updateWindowDecos();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CWindow* curr = this;
|
||||||
|
std::vector<CWindow*> members;
|
||||||
|
do {
|
||||||
|
const auto PLASTWIN = curr;
|
||||||
|
curr = curr->m_sGroupData.pNextWindow;
|
||||||
|
PLASTWIN->m_sGroupData.pNextWindow = nullptr;
|
||||||
|
curr->setHidden(false);
|
||||||
|
members.push_back(curr);
|
||||||
|
} while (curr != this);
|
||||||
|
|
||||||
|
for (auto& w : members) {
|
||||||
|
if (w->m_sGroupData.head)
|
||||||
|
g_pLayoutManager->getCurrentLayout()->onWindowRemoved(curr);
|
||||||
|
w->m_sGroupData.head = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool GROUPSLOCKEDPREV = g_pKeybindManager->m_bGroupsLocked;
|
||||||
|
g_pKeybindManager->m_bGroupsLocked = true;
|
||||||
|
for (auto& w : members) {
|
||||||
|
g_pLayoutManager->getCurrentLayout()->onWindowCreated(w);
|
||||||
|
w->updateWindowDecos();
|
||||||
|
}
|
||||||
|
g_pKeybindManager->m_bGroupsLocked = GROUPSLOCKEDPREV;
|
||||||
|
}
|
||||||
|
|
||||||
|
CWindow* CWindow::getGroupHead() {
|
||||||
|
CWindow* curr = this;
|
||||||
|
while (!curr->m_sGroupData.head)
|
||||||
|
curr = curr->m_sGroupData.pNextWindow;
|
||||||
|
return curr;
|
||||||
|
}
|
||||||
|
|
||||||
|
CWindow* CWindow::getGroupTail() {
|
||||||
|
CWindow* curr = this;
|
||||||
|
while (!curr->m_sGroupData.pNextWindow->m_sGroupData.head)
|
||||||
|
curr = curr->m_sGroupData.pNextWindow;
|
||||||
|
return curr;
|
||||||
|
}
|
||||||
|
|
||||||
|
CWindow* CWindow::getGroupCurrent() {
|
||||||
|
CWindow* curr = this;
|
||||||
|
while (curr->isHidden())
|
||||||
|
curr = curr->m_sGroupData.pNextWindow;
|
||||||
|
return curr;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CWindow::getGroupSize() {
|
||||||
|
int size = 1;
|
||||||
|
CWindow* curr = this;
|
||||||
|
while (curr->m_sGroupData.pNextWindow != this) {
|
||||||
|
curr = curr->m_sGroupData.pNextWindow;
|
||||||
|
size++;
|
||||||
|
}
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CWindow::canBeGroupedInto(CWindow* pWindow) {
|
||||||
|
return !g_pKeybindManager->m_bGroupsLocked // global group lock disengaged
|
||||||
|
&& ((m_eGroupRules & GROUP_INVADE && m_bFirstMap) // window ignore local group locks, or
|
||||||
|
|| (!pWindow->getGroupHead()->m_sGroupData.locked // target unlocked
|
||||||
|
&& !(m_sGroupData.pNextWindow && getGroupHead()->m_sGroupData.locked))) // source unlocked or isn't group
|
||||||
|
&& !m_sGroupData.deny // source is not denied entry
|
||||||
|
&& !(m_eGroupRules & GROUP_BARRED && m_bFirstMap); // group rule doesn't prevent adding window
|
||||||
|
}
|
||||||
|
|
||||||
|
CWindow* CWindow::getGroupWindowByIndex(int index) {
|
||||||
|
const int SIZE = getGroupSize();
|
||||||
|
index = ((index % SIZE) + SIZE) % SIZE;
|
||||||
|
CWindow* curr = getGroupHead();
|
||||||
|
while (index > 0) {
|
||||||
|
curr = curr->m_sGroupData.pNextWindow;
|
||||||
|
index--;
|
||||||
|
}
|
||||||
|
return curr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CWindow::setGroupCurrent(CWindow* pWindow) {
|
||||||
|
CWindow* curr = this->m_sGroupData.pNextWindow;
|
||||||
|
bool isMember = false;
|
||||||
|
while (curr != this) {
|
||||||
|
if (curr == pWindow) {
|
||||||
|
isMember = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
curr = curr->m_sGroupData.pNextWindow;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isMember && pWindow != this)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const auto PCURRENT = getGroupCurrent();
|
||||||
|
const bool FULLSCREEN = PCURRENT->m_bIsFullscreen;
|
||||||
|
const auto WORKSPACE = g_pCompositor->getWorkspaceByID(PCURRENT->m_iWorkspaceID);
|
||||||
|
|
||||||
|
const auto PWINDOWSIZE = PCURRENT->m_vRealSize.goalv();
|
||||||
|
const auto PWINDOWPOS = PCURRENT->m_vRealPosition.goalv();
|
||||||
|
|
||||||
|
const auto CURRENTISFOCUS = PCURRENT == g_pCompositor->m_pLastWindow;
|
||||||
|
|
||||||
|
if (FULLSCREEN)
|
||||||
|
g_pCompositor->setWindowFullscreen(PCURRENT, false, WORKSPACE->m_efFullscreenMode);
|
||||||
|
|
||||||
|
PCURRENT->setHidden(true);
|
||||||
|
pWindow->setHidden(false); // can remove m_pLastWindow
|
||||||
|
|
||||||
|
g_pLayoutManager->getCurrentLayout()->replaceWindowDataWith(PCURRENT, pWindow);
|
||||||
|
|
||||||
|
if (PCURRENT->m_bIsFloating) {
|
||||||
|
pWindow->m_vRealPosition.setValueAndWarp(PWINDOWPOS);
|
||||||
|
pWindow->m_vRealSize.setValueAndWarp(PWINDOWSIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_pCompositor->updateAllWindowsAnimatedDecorationValues();
|
||||||
|
|
||||||
|
if (CURRENTISFOCUS)
|
||||||
|
g_pCompositor->focusWindow(pWindow);
|
||||||
|
|
||||||
|
if (FULLSCREEN)
|
||||||
|
g_pCompositor->setWindowFullscreen(pWindow, true, WORKSPACE->m_efFullscreenMode);
|
||||||
|
|
||||||
|
g_pHyprRenderer->damageWindow(pWindow);
|
||||||
|
|
||||||
|
pWindow->updateWindowDecos();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CWindow::insertWindowToGroup(CWindow* pWindow) {
|
||||||
|
const auto BEGINAT = this;
|
||||||
|
const auto ENDAT = m_sGroupData.pNextWindow;
|
||||||
|
|
||||||
|
if (!pWindow->getDecorationByType(DECORATION_GROUPBAR))
|
||||||
|
pWindow->addWindowDeco(std::make_unique<CHyprGroupBarDecoration>(pWindow));
|
||||||
|
|
||||||
|
if (!pWindow->m_sGroupData.pNextWindow) {
|
||||||
|
BEGINAT->m_sGroupData.pNextWindow = pWindow;
|
||||||
|
pWindow->m_sGroupData.pNextWindow = ENDAT;
|
||||||
|
pWindow->m_sGroupData.head = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto SHEAD = pWindow->getGroupHead();
|
||||||
|
const auto STAIL = pWindow->getGroupTail();
|
||||||
|
|
||||||
|
SHEAD->m_sGroupData.head = false;
|
||||||
|
BEGINAT->m_sGroupData.pNextWindow = SHEAD;
|
||||||
|
STAIL->m_sGroupData.pNextWindow = ENDAT;
|
||||||
|
}
|
||||||
|
|
||||||
|
CWindow* CWindow::getGroupPrevious() {
|
||||||
|
CWindow* curr = m_sGroupData.pNextWindow;
|
||||||
|
|
||||||
|
while (curr != this && curr->m_sGroupData.pNextWindow != this)
|
||||||
|
curr = curr->m_sGroupData.pNextWindow;
|
||||||
|
|
||||||
|
return curr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CWindow::switchWithWindowInGroup(CWindow* pWindow) {
|
||||||
|
if (!m_sGroupData.pNextWindow || !pWindow->m_sGroupData.pNextWindow)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (m_sGroupData.pNextWindow == pWindow) { // A -> this -> pWindow -> B >> A -> pWindow -> this -> B
|
||||||
|
getGroupPrevious()->m_sGroupData.pNextWindow = pWindow;
|
||||||
|
m_sGroupData.pNextWindow = pWindow->m_sGroupData.pNextWindow;
|
||||||
|
pWindow->m_sGroupData.pNextWindow = this;
|
||||||
|
|
||||||
|
} else if (pWindow->m_sGroupData.pNextWindow == this) { // A -> pWindow -> this -> B >> A -> this -> pWindow -> B
|
||||||
|
pWindow->getGroupPrevious()->m_sGroupData.pNextWindow = this;
|
||||||
|
pWindow->m_sGroupData.pNextWindow = m_sGroupData.pNextWindow;
|
||||||
|
m_sGroupData.pNextWindow = pWindow;
|
||||||
|
|
||||||
|
} else { // A -> this -> B | C -> pWindow -> D >> A -> pWindow -> B | C -> this -> D
|
||||||
|
std::swap(m_sGroupData.pNextWindow, pWindow->m_sGroupData.pNextWindow);
|
||||||
|
std::swap(getGroupPrevious()->m_sGroupData.pNextWindow, pWindow->getGroupPrevious()->m_sGroupData.pNextWindow);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::swap(m_sGroupData.head, pWindow->m_sGroupData.head);
|
||||||
|
std::swap(m_sGroupData.locked, pWindow->m_sGroupData.locked);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CWindow::updateGroupOutputs() {
|
||||||
|
if (!m_sGroupData.pNextWindow)
|
||||||
|
return;
|
||||||
|
|
||||||
|
CWindow* curr = m_sGroupData.pNextWindow;
|
||||||
|
|
||||||
|
while (curr != this) {
|
||||||
|
curr->m_iMonitorID = m_iMonitorID;
|
||||||
|
curr->moveToWorkspace(m_iWorkspaceID);
|
||||||
|
|
||||||
|
curr->m_vRealPosition = m_vRealPosition.goalv();
|
||||||
|
curr->m_vRealSize = m_vRealSize.goalv();
|
||||||
|
|
||||||
|
curr = curr->m_sGroupData.pNextWindow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector2D CWindow::middle() {
|
||||||
|
return m_vRealPosition.goalv() + m_vRealSize.goalv() / 2.f;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CWindow::opaque() {
|
||||||
|
if (m_fAlpha.fl() != 1.f || m_fActiveInactiveAlpha.fl() != 1.f)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(m_iWorkspaceID);
|
||||||
|
|
||||||
|
if (m_pWLSurface.small() && !m_pWLSurface.m_bFillIgnoreSmall)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (PWORKSPACE->m_fAlpha.fl() != 1.f)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (m_bIsX11)
|
||||||
|
return !m_uSurface.xwayland->has_alpha;
|
||||||
|
|
||||||
|
if (m_uSurface.xdg->surface->opaque)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
const auto EXTENTS = pixman_region32_extents(&m_uSurface.xdg->surface->opaque_region);
|
||||||
|
if (EXTENTS->x2 - EXTENTS->x1 >= m_uSurface.xdg->surface->current.buffer_width && EXTENTS->y2 - EXTENTS->y1 >= m_uSurface.xdg->surface->current.buffer_height)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
float CWindow::rounding() {
|
||||||
|
static auto* const PROUNDING = &g_pConfigManager->getConfigValuePtr("decoration:rounding")->intValue;
|
||||||
|
|
||||||
|
float rounding = m_sAdditionalConfigData.rounding.toUnderlying() == -1 ? *PROUNDING : m_sAdditionalConfigData.rounding.toUnderlying();
|
||||||
|
|
||||||
|
return rounding;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CWindow::updateSpecialRenderData() {
|
||||||
|
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(m_iWorkspaceID);
|
||||||
|
const auto WORKSPACERULE = PWORKSPACE ? g_pConfigManager->getWorkspaceRuleFor(PWORKSPACE) : SWorkspaceRule{};
|
||||||
|
bool border = true;
|
||||||
|
|
||||||
|
if (m_bIsFloating && g_pConfigManager->getConfigValuePtr("general:no_border_on_floating")->intValue == 1)
|
||||||
|
border = false;
|
||||||
|
|
||||||
|
m_sSpecialRenderData.border = WORKSPACERULE.border.value_or(border);
|
||||||
|
m_sSpecialRenderData.borderSize = WORKSPACERULE.borderSize.value_or(-1);
|
||||||
|
m_sSpecialRenderData.decorate = WORKSPACERULE.decorate.value_or(true);
|
||||||
|
m_sSpecialRenderData.rounding = WORKSPACERULE.rounding.value_or(true);
|
||||||
|
m_sSpecialRenderData.shadow = WORKSPACERULE.shadow.value_or(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
int CWindow::getRealBorderSize() {
|
||||||
|
if (!m_sSpecialRenderData.border || m_sAdditionalConfigData.forceNoBorder)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (m_sAdditionalConfigData.borderSize.toUnderlying() != -1)
|
||||||
|
return m_sAdditionalConfigData.borderSize.toUnderlying();
|
||||||
|
|
||||||
|
if (m_sSpecialRenderData.borderSize.toUnderlying() != -1)
|
||||||
|
return m_sSpecialRenderData.borderSize.toUnderlying();
|
||||||
|
|
||||||
|
return g_pConfigManager->getConfigValuePtr("general:border_size")->intValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CWindow::canBeTorn() {
|
||||||
|
return (m_sAdditionalConfigData.forceTearing.toUnderlying() || m_bTearingHint) && g_pHyprRenderer->m_bTearingEnvSatisfied;
|
||||||
|
}
|
||||||
|
|||||||
410
src/Window.hpp
410
src/Window.hpp
@@ -1,36 +1,167 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "defines.hpp"
|
#include "defines.hpp"
|
||||||
#include "events/Events.hpp"
|
|
||||||
#include "helpers/SubsurfaceTree.hpp"
|
#include "helpers/SubsurfaceTree.hpp"
|
||||||
#include "helpers/AnimatedVariable.hpp"
|
#include "helpers/AnimatedVariable.hpp"
|
||||||
#include "render/decorations/IHyprWindowDecoration.hpp"
|
#include "render/decorations/IHyprWindowDecoration.hpp"
|
||||||
#include <deque>
|
#include <deque>
|
||||||
|
#include "config/ConfigDataValues.hpp"
|
||||||
|
#include "helpers/Vector2D.hpp"
|
||||||
|
#include "helpers/WLSurface.hpp"
|
||||||
|
#include "macros.hpp"
|
||||||
|
#include "managers/XWaylandManager.hpp"
|
||||||
|
|
||||||
|
enum eIdleInhibitMode
|
||||||
|
{
|
||||||
|
IDLEINHIBIT_NONE = 0,
|
||||||
|
IDLEINHIBIT_ALWAYS,
|
||||||
|
IDLEINHIBIT_FULLSCREEN,
|
||||||
|
IDLEINHIBIT_FOCUS
|
||||||
|
};
|
||||||
|
|
||||||
|
enum eGroupRules
|
||||||
|
{
|
||||||
|
// effective only during first map, except for _ALWAYS variant
|
||||||
|
GROUP_NONE = 0,
|
||||||
|
GROUP_SET = 1 << 0, // Open as new group or add to focused group
|
||||||
|
GROUP_SET_ALWAYS = 1 << 1,
|
||||||
|
GROUP_BARRED = 1 << 2, // Don't insert to focused group.
|
||||||
|
GROUP_LOCK = 1 << 3, // Lock m_sGroupData.lock
|
||||||
|
GROUP_LOCK_ALWAYS = 1 << 4,
|
||||||
|
GROUP_INVADE = 1 << 5, // Force enter a group, event if lock is engaged
|
||||||
|
GROUP_OVERRIDE = 1 << 6, // Override other rules
|
||||||
|
};
|
||||||
|
|
||||||
|
class IWindowTransformer;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class CWindowOverridableVar {
|
||||||
|
public:
|
||||||
|
CWindowOverridableVar(T val) {
|
||||||
|
value = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
~CWindowOverridableVar() = default;
|
||||||
|
|
||||||
|
CWindowOverridableVar<T>& operator=(CWindowOverridableVar<T> other) {
|
||||||
|
if (locked)
|
||||||
|
return *this;
|
||||||
|
|
||||||
|
locked = other.locked;
|
||||||
|
value = other.value;
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
T operator=(T& other) {
|
||||||
|
if (locked)
|
||||||
|
return value;
|
||||||
|
value = other;
|
||||||
|
return other;
|
||||||
|
}
|
||||||
|
|
||||||
|
void forceSetIgnoreLocked(T val, bool lock = false) {
|
||||||
|
value = val;
|
||||||
|
locked = lock;
|
||||||
|
}
|
||||||
|
|
||||||
|
T operator*(T& other) {
|
||||||
|
return value * other;
|
||||||
|
}
|
||||||
|
|
||||||
|
T operator+(T& other) {
|
||||||
|
return value + other;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(T& other) {
|
||||||
|
return other == value;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator>=(T& other) {
|
||||||
|
return value >= other;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator<=(T& other) {
|
||||||
|
return value <= other;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator>(T& other) {
|
||||||
|
return value > other;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator<(T& other) {
|
||||||
|
return value < other;
|
||||||
|
}
|
||||||
|
|
||||||
|
explicit operator bool() {
|
||||||
|
return static_cast<bool>(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
T toUnderlying() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool locked = false;
|
||||||
|
|
||||||
|
private:
|
||||||
|
T value;
|
||||||
|
};
|
||||||
|
|
||||||
struct SWindowSpecialRenderData {
|
struct SWindowSpecialRenderData {
|
||||||
float alpha = 1.f;
|
CWindowOverridableVar<bool> alphaOverride = false;
|
||||||
float alphaInactive = -1.f; // -1 means unset
|
CWindowOverridableVar<float> alpha = 1.f;
|
||||||
|
CWindowOverridableVar<bool> alphaInactiveOverride = false;
|
||||||
|
CWindowOverridableVar<float> alphaInactive = -1.f; // -1 means unset
|
||||||
|
|
||||||
|
CWindowOverridableVar<int64_t> activeBorderColor = -1; // -1 means unset
|
||||||
|
CWindowOverridableVar<int64_t> inactiveBorderColor = -1; // -1 means unset
|
||||||
|
|
||||||
// set by the layout
|
// set by the layout
|
||||||
bool rounding = true;
|
CWindowOverridableVar<int> borderSize = -1; // -1 means unset
|
||||||
bool border = true;
|
bool rounding = true;
|
||||||
bool decorate = true;
|
bool border = true;
|
||||||
|
bool decorate = true;
|
||||||
|
bool shadow = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SWindowAdditionalConfigData {
|
struct SWindowAdditionalConfigData {
|
||||||
std::string animationStyle = "";
|
std::string animationStyle = std::string("");
|
||||||
int rounding = -1; // -1 means no
|
CWindowOverridableVar<int> rounding = -1; // -1 means no
|
||||||
bool forceNoBlur = false;
|
CWindowOverridableVar<bool> forceNoBlur = false;
|
||||||
bool forceOpaque = false;
|
CWindowOverridableVar<bool> forceOpaque = false;
|
||||||
bool forceAllowsInput = false;
|
CWindowOverridableVar<bool> forceOpaqueOverridden = false; // if true, a rule will not change the forceOpaque state. This is for the force opaque dispatcher.
|
||||||
bool forceNoAnims = false;
|
CWindowOverridableVar<bool> forceAllowsInput = false;
|
||||||
bool forceNoBorder = false;
|
CWindowOverridableVar<bool> forceNoAnims = false;
|
||||||
bool forceNoShadow = false;
|
CWindowOverridableVar<bool> forceNoBorder = false;
|
||||||
bool windowDanceCompat = false;
|
CWindowOverridableVar<bool> forceNoShadow = false;
|
||||||
|
CWindowOverridableVar<bool> forceNoDim = false;
|
||||||
|
CWindowOverridableVar<bool> windowDanceCompat = false;
|
||||||
|
CWindowOverridableVar<bool> noMaxSize = false;
|
||||||
|
CWindowOverridableVar<bool> dimAround = false;
|
||||||
|
CWindowOverridableVar<bool> forceRGBX = false;
|
||||||
|
CWindowOverridableVar<bool> keepAspectRatio = false;
|
||||||
|
CWindowOverridableVar<int> xray = -1; // -1 means unset, takes precedence over the renderdata one
|
||||||
|
CWindowOverridableVar<int> borderSize = -1; // -1 means unset, takes precedence over the renderdata one
|
||||||
|
CWindowOverridableVar<bool> forceTearing = false;
|
||||||
|
CWindowOverridableVar<bool> nearestNeighbor = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SWindowRule {
|
||||||
|
std::string szRule;
|
||||||
|
std::string szValue;
|
||||||
|
|
||||||
|
bool v2 = false;
|
||||||
|
std::string szTitle;
|
||||||
|
std::string szClass;
|
||||||
|
int bX11 = -1; // -1 means "ANY"
|
||||||
|
int bFloating = -1;
|
||||||
|
int bFullscreen = -1;
|
||||||
|
int bPinned = -1;
|
||||||
|
std::string szWorkspace = ""; // empty means any
|
||||||
};
|
};
|
||||||
|
|
||||||
class CWindow {
|
class CWindow {
|
||||||
public:
|
public:
|
||||||
CWindow();
|
CWindow();
|
||||||
~CWindow();
|
~CWindow();
|
||||||
|
|
||||||
@@ -51,93 +182,123 @@ public:
|
|||||||
DYNLISTENER(toplevelClose);
|
DYNLISTENER(toplevelClose);
|
||||||
DYNLISTENER(toplevelActivate);
|
DYNLISTENER(toplevelActivate);
|
||||||
DYNLISTENER(toplevelFullscreen);
|
DYNLISTENER(toplevelFullscreen);
|
||||||
// DYNLISTENER(newSubsurfaceWindow);
|
DYNLISTENER(setOverrideRedirect);
|
||||||
|
DYNLISTENER(associateX11);
|
||||||
|
DYNLISTENER(dissociateX11);
|
||||||
|
DYNLISTENER(ackConfigure);
|
||||||
|
// DYNLISTENER(newSubsurfaceWindow);
|
||||||
|
|
||||||
|
CWLSurface m_pWLSurface;
|
||||||
|
std::list<CWLSurface> m_lPopupSurfaces;
|
||||||
|
|
||||||
union {
|
union {
|
||||||
wlr_xdg_surface* xdg;
|
wlr_xdg_surface* xdg;
|
||||||
wlr_xwayland_surface* xwayland;
|
wlr_xwayland_surface* xwayland;
|
||||||
} m_uSurface;
|
} m_uSurface;
|
||||||
|
|
||||||
// this is the position and size of the "bounding box"
|
// this is the position and size of the "bounding box"
|
||||||
Vector2D m_vPosition = Vector2D(0,0);
|
Vector2D m_vPosition = Vector2D(0, 0);
|
||||||
Vector2D m_vSize = Vector2D(0,0);
|
Vector2D m_vSize = Vector2D(0, 0);
|
||||||
|
|
||||||
// this is the real position and size used to draw the thing
|
// this is the real position and size used to draw the thing
|
||||||
CAnimatedVariable m_vRealPosition;
|
CAnimatedVariable m_vRealPosition;
|
||||||
CAnimatedVariable m_vRealSize;
|
CAnimatedVariable m_vRealSize;
|
||||||
|
|
||||||
// for not spamming the protocols
|
// for not spamming the protocols
|
||||||
Vector2D m_vReportedPosition;
|
Vector2D m_vReportedPosition;
|
||||||
Vector2D m_vReportedSize;
|
Vector2D m_vReportedSize;
|
||||||
|
Vector2D m_vPendingReportedSize;
|
||||||
|
std::optional<std::pair<uint32_t, Vector2D>> m_pPendingSizeAck;
|
||||||
|
std::vector<std::pair<uint32_t, Vector2D>> m_vPendingSizeAcks;
|
||||||
|
|
||||||
// for restoring floating statuses
|
// for restoring floating statuses
|
||||||
Vector2D m_vLastFloatingSize;
|
Vector2D m_vLastFloatingSize;
|
||||||
|
Vector2D m_vLastFloatingPosition;
|
||||||
|
|
||||||
// this is used for pseudotiling
|
// this is used for pseudotiling
|
||||||
bool m_bIsPseudotiled = false;
|
bool m_bIsPseudotiled = false;
|
||||||
Vector2D m_vPseudoSize = Vector2D(0,0);
|
Vector2D m_vPseudoSize = Vector2D(0, 0);
|
||||||
|
|
||||||
uint64_t m_iTags = 0;
|
bool m_bFirstMap = false; // for layouts
|
||||||
bool m_bIsFloating = false;
|
bool m_bIsFloating = false;
|
||||||
bool m_bDraggingTiled = false; // for dragging around tiled windows
|
bool m_bDraggingTiled = false; // for dragging around tiled windows
|
||||||
bool m_bIsFullscreen = false;
|
bool m_bIsFullscreen = false;
|
||||||
uint64_t m_iMonitorID = -1;
|
bool m_bWasMaximized = false;
|
||||||
std::string m_szTitle = "";
|
uint64_t m_iMonitorID = -1;
|
||||||
int m_iWorkspaceID = -1;
|
std::string m_szTitle = "";
|
||||||
|
std::string m_szInitialTitle = "";
|
||||||
|
std::string m_szInitialClass = "";
|
||||||
|
int m_iWorkspaceID = -1;
|
||||||
|
|
||||||
bool m_bIsMapped = false;
|
bool m_bIsMapped = false;
|
||||||
|
|
||||||
bool m_bRequestsFloat = false;
|
bool m_bRequestsFloat = false;
|
||||||
|
|
||||||
// This is for fullscreen apps
|
// This is for fullscreen apps
|
||||||
bool m_bCreatedOverFullscreen = false;
|
bool m_bCreatedOverFullscreen = false;
|
||||||
|
|
||||||
// XWayland stuff
|
// XWayland stuff
|
||||||
bool m_bIsX11 = false;
|
bool m_bIsX11 = false;
|
||||||
bool m_bMappedX11 = false;
|
bool m_bMappedX11 = false;
|
||||||
CWindow* m_pX11Parent = nullptr;
|
CWindow* m_pX11Parent = nullptr;
|
||||||
uint64_t m_iX11Type = 0;
|
uint64_t m_iX11Type = 0;
|
||||||
bool m_bIsModal = false;
|
bool m_bIsModal = false;
|
||||||
bool m_bX11DoesntWantBorders = false;
|
bool m_bX11DoesntWantBorders = false;
|
||||||
bool m_bX11ShouldntFocus = false;
|
bool m_bX11ShouldntFocus = false;
|
||||||
|
float m_fX11SurfaceScaledBy = 1.f;
|
||||||
//
|
//
|
||||||
|
|
||||||
// For nofocus
|
// For nofocus
|
||||||
bool m_bNoFocus = false;
|
bool m_bNoFocus = false;
|
||||||
bool m_bNoInitialFocus = false;
|
bool m_bNoInitialFocus = false;
|
||||||
|
|
||||||
// initial fullscreen
|
// Fullscreen and Maximize
|
||||||
bool m_bWantsInitialFullscreen = false;
|
bool m_bWantsInitialFullscreen = false;
|
||||||
|
bool m_bNoFullscreenRequest = false;
|
||||||
|
bool m_bNoMaximizeRequest = false;
|
||||||
|
|
||||||
SSurfaceTreeNode* m_pSurfaceTree = nullptr;
|
SSurfaceTreeNode* m_pSurfaceTree = nullptr;
|
||||||
|
|
||||||
// Animated border
|
// Animated border
|
||||||
CAnimatedVariable m_cRealBorderColor;
|
CGradientValueData m_cRealBorderColor = {0};
|
||||||
|
CGradientValueData m_cRealBorderColorPrevious = {0};
|
||||||
|
CAnimatedVariable m_fBorderFadeAnimationProgress;
|
||||||
|
CAnimatedVariable m_fBorderAngleAnimationProgress;
|
||||||
|
|
||||||
// Fade in-out
|
// Fade in-out
|
||||||
CAnimatedVariable m_fAlpha;
|
CAnimatedVariable m_fAlpha;
|
||||||
bool m_bFadingOut = false;
|
bool m_bFadingOut = false;
|
||||||
bool m_bReadyToDelete = false;
|
bool m_bReadyToDelete = false;
|
||||||
Vector2D m_vOriginalClosedPos; // these will be used for calculations later on in
|
Vector2D m_vOriginalClosedPos; // these will be used for calculations later on in
|
||||||
Vector2D m_vOriginalClosedSize; // drawing the closing animations
|
Vector2D m_vOriginalClosedSize; // drawing the closing animations
|
||||||
|
SWindowDecorationExtents m_eOriginalClosedExtents;
|
||||||
|
|
||||||
// For pinned (sticky) windows
|
// For pinned (sticky) windows
|
||||||
bool m_bPinned = false;
|
bool m_bPinned = false;
|
||||||
|
|
||||||
|
// urgency hint
|
||||||
|
bool m_bIsUrgent = false;
|
||||||
|
|
||||||
|
// fakefullscreen
|
||||||
|
bool m_bFakeFullscreenState = false;
|
||||||
|
|
||||||
// for proper cycling. While cycling we can't just move the pointers, so we need to keep track of the last cycled window.
|
// for proper cycling. While cycling we can't just move the pointers, so we need to keep track of the last cycled window.
|
||||||
CWindow* m_pLastCycledWindow = nullptr;
|
CWindow* m_pLastCycledWindow = nullptr;
|
||||||
|
|
||||||
// Foreign Toplevel proto
|
// Foreign Toplevel proto
|
||||||
wlr_foreign_toplevel_handle_v1* m_phForeignToplevel = nullptr;
|
wlr_foreign_toplevel_handle_v1* m_phForeignToplevel = nullptr;
|
||||||
|
|
||||||
// Window decorations
|
// Window decorations
|
||||||
std::deque<std::unique_ptr<IHyprWindowDecoration>> m_dWindowDecorations;
|
std::deque<std::unique_ptr<IHyprWindowDecoration>> m_dWindowDecorations;
|
||||||
std::vector<IHyprWindowDecoration*> m_vDecosToRemove;
|
std::vector<IHyprWindowDecoration*> m_vDecosToRemove;
|
||||||
|
|
||||||
// Special render data, rules, etc
|
// Special render data, rules, etc
|
||||||
SWindowSpecialRenderData m_sSpecialRenderData;
|
SWindowSpecialRenderData m_sSpecialRenderData;
|
||||||
SWindowAdditionalConfigData m_sAdditionalConfigData;
|
SWindowAdditionalConfigData m_sAdditionalConfigData;
|
||||||
|
|
||||||
|
// Transformers
|
||||||
|
std::vector<std::unique_ptr<IWindowTransformer>> m_vTransformers;
|
||||||
|
|
||||||
// for alpha
|
// for alpha
|
||||||
CAnimatedVariable m_fActiveInactiveAlpha;
|
CAnimatedVariable m_fActiveInactiveAlpha;
|
||||||
|
|
||||||
@@ -148,36 +309,129 @@ public:
|
|||||||
CAnimatedVariable m_fDimPercent;
|
CAnimatedVariable m_fDimPercent;
|
||||||
|
|
||||||
// swallowing
|
// swallowing
|
||||||
CWindow* m_pSwallowed = nullptr;
|
CWindow* m_pSwallowed = nullptr;
|
||||||
|
|
||||||
|
// focus stuff
|
||||||
|
bool m_bStayFocused = false;
|
||||||
|
|
||||||
// for toplevel monitor events
|
// for toplevel monitor events
|
||||||
uint64_t m_iLastToplevelMonitorID = -1;
|
uint64_t m_iLastToplevelMonitorID = -1;
|
||||||
uint64_t m_iLastSurfaceMonitorID = -1;
|
uint64_t m_iLastSurfaceMonitorID = -1;
|
||||||
|
|
||||||
|
// for idle inhibiting windows
|
||||||
|
eIdleInhibitMode m_eIdleInhibitMode = IDLEINHIBIT_NONE;
|
||||||
|
|
||||||
|
// for groups
|
||||||
|
struct SGroupData {
|
||||||
|
CWindow* pNextWindow = nullptr; // nullptr means no grouping. Self means single group.
|
||||||
|
bool head = false;
|
||||||
|
bool locked = false; // per group lock
|
||||||
|
bool deny = false; // deny window from enter a group or made a group
|
||||||
|
} m_sGroupData;
|
||||||
|
uint16_t m_eGroupRules = GROUP_NONE;
|
||||||
|
|
||||||
|
bool m_bTearingHint = false;
|
||||||
|
|
||||||
// For the list lookup
|
// For the list lookup
|
||||||
bool operator==(const CWindow& rhs) {
|
bool operator==(const CWindow& rhs) {
|
||||||
return m_uSurface.xdg == rhs.m_uSurface.xdg && m_uSurface.xwayland == rhs.m_uSurface.xwayland && m_vPosition == rhs.m_vPosition && m_vSize == rhs.m_vSize && m_bFadingOut == rhs.m_bFadingOut;
|
return m_uSurface.xdg == rhs.m_uSurface.xdg && m_uSurface.xwayland == rhs.m_uSurface.xwayland && m_vPosition == rhs.m_vPosition && m_vSize == rhs.m_vSize &&
|
||||||
|
m_bFadingOut == rhs.m_bFadingOut;
|
||||||
}
|
}
|
||||||
|
|
||||||
// methods
|
// methods
|
||||||
wlr_box getFullWindowBoundingBox();
|
CBox getFullWindowBoundingBox();
|
||||||
wlr_box getWindowIdealBoundingBoxIgnoreReserved();
|
SWindowDecorationExtents getFullWindowExtents();
|
||||||
void updateWindowDecos();
|
CBox getWindowInputBox();
|
||||||
pid_t getPID();
|
CBox getWindowMainSurfaceBox();
|
||||||
IHyprWindowDecoration* getDecorationByType(eDecorationType);
|
CBox getWindowIdealBoundingBoxIgnoreReserved();
|
||||||
void removeDecorationByType(eDecorationType);
|
void addWindowDeco(std::unique_ptr<IHyprWindowDecoration> deco);
|
||||||
void createToplevelHandle();
|
void updateWindowDecos();
|
||||||
void destroyToplevelHandle();
|
void removeWindowDeco(IHyprWindowDecoration* deco);
|
||||||
void updateToplevel();
|
pid_t getPID();
|
||||||
void updateSurfaceOutputs();
|
IHyprWindowDecoration* getDecorationByType(eDecorationType);
|
||||||
void moveToWorkspace(int);
|
void removeDecorationByType(eDecorationType);
|
||||||
CWindow* X11TransientFor();
|
void createToplevelHandle();
|
||||||
void onUnmap();
|
void destroyToplevelHandle();
|
||||||
void setHidden(bool hidden);
|
void updateToplevel();
|
||||||
bool isHidden();
|
void updateSurfaceOutputs();
|
||||||
|
void moveToWorkspace(int);
|
||||||
|
CWindow* X11TransientFor();
|
||||||
|
void onUnmap();
|
||||||
|
void onMap();
|
||||||
|
void setHidden(bool hidden);
|
||||||
|
bool isHidden();
|
||||||
|
void applyDynamicRule(const SWindowRule& r);
|
||||||
|
void updateDynamicRules();
|
||||||
|
SWindowDecorationExtents getFullWindowReservedArea();
|
||||||
|
Vector2D middle();
|
||||||
|
bool opaque();
|
||||||
|
float rounding();
|
||||||
|
bool canBeTorn();
|
||||||
|
|
||||||
private:
|
int getRealBorderSize();
|
||||||
|
void updateSpecialRenderData();
|
||||||
|
|
||||||
|
void onBorderAngleAnimEnd(void* ptr);
|
||||||
|
bool isInCurvedCorner(double x, double y);
|
||||||
|
bool hasPopupAt(const Vector2D& pos);
|
||||||
|
|
||||||
|
void applyGroupRules();
|
||||||
|
void createGroup();
|
||||||
|
void destroyGroup();
|
||||||
|
CWindow* getGroupHead();
|
||||||
|
CWindow* getGroupTail();
|
||||||
|
CWindow* getGroupCurrent();
|
||||||
|
CWindow* getGroupPrevious();
|
||||||
|
CWindow* getGroupWindowByIndex(int);
|
||||||
|
int getGroupSize();
|
||||||
|
bool canBeGroupedInto(CWindow* pWindow);
|
||||||
|
void setGroupCurrent(CWindow* pWindow);
|
||||||
|
void insertWindowToGroup(CWindow* pWindow);
|
||||||
|
void updateGroupOutputs();
|
||||||
|
void switchWithWindowInGroup(CWindow* pWindow);
|
||||||
|
|
||||||
|
private:
|
||||||
// For hidden windows and stuff
|
// For hidden windows and stuff
|
||||||
bool m_bHidden = false;
|
bool m_bHidden = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
format specification
|
||||||
|
- 'x', only address, equivalent of (uintpr_t)CWindow*
|
||||||
|
- 'm', with monitor id
|
||||||
|
- 'w', with workspace id
|
||||||
|
- 'c', with application class
|
||||||
|
*/
|
||||||
|
|
||||||
|
template <typename CharT>
|
||||||
|
struct std::formatter<CWindow*, CharT> : std::formatter<CharT> {
|
||||||
|
bool formatAddressOnly = false;
|
||||||
|
bool formatWorkspace = false;
|
||||||
|
bool formatMonitor = false;
|
||||||
|
bool formatClass = false;
|
||||||
|
FORMAT_PARSE( //
|
||||||
|
FORMAT_FLAG('x', formatAddressOnly) //
|
||||||
|
FORMAT_FLAG('m', formatMonitor) //
|
||||||
|
FORMAT_FLAG('w', formatWorkspace) //
|
||||||
|
FORMAT_FLAG('c', formatClass),
|
||||||
|
CWindow*)
|
||||||
|
|
||||||
|
template <typename FormatContext>
|
||||||
|
auto format(CWindow* const& w, FormatContext& ctx) const {
|
||||||
|
auto&& out = ctx.out();
|
||||||
|
if (formatAddressOnly)
|
||||||
|
return std::format_to(out, "{:x}", (uintptr_t)w);
|
||||||
|
if (!w)
|
||||||
|
return std::format_to(out, "[Window nullptr]");
|
||||||
|
|
||||||
|
std::format_to(out, "[");
|
||||||
|
std::format_to(out, "Window {:x}: title: \"{}\"", (uintptr_t)w, w->m_szTitle);
|
||||||
|
if (formatWorkspace)
|
||||||
|
std::format_to(out, ", workspace: {}", w->m_iWorkspaceID);
|
||||||
|
if (formatMonitor)
|
||||||
|
std::format_to(out, ", monitor: {}", w->m_iMonitorID);
|
||||||
|
if (formatClass)
|
||||||
|
std::format_to(out, ", class: {}", g_pXWaylandManager->getAppIDClass(w));
|
||||||
|
return std::format_to(out, "]");
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
51
src/config/ConfigDataValues.hpp
Normal file
51
src/config/ConfigDataValues.hpp
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "../defines.hpp"
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
enum eConfigValueDataTypes {
|
||||||
|
CVD_TYPE_INVALID = -1,
|
||||||
|
CVD_TYPE_GRADIENT = 0
|
||||||
|
};
|
||||||
|
|
||||||
|
class ICustomConfigValueData {
|
||||||
|
public:
|
||||||
|
virtual ~ICustomConfigValueData() = 0;
|
||||||
|
|
||||||
|
virtual eConfigValueDataTypes getDataType() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CGradientValueData : public ICustomConfigValueData {
|
||||||
|
public:
|
||||||
|
CGradientValueData(CColor col) {
|
||||||
|
m_vColors.push_back(col);
|
||||||
|
};
|
||||||
|
virtual ~CGradientValueData(){};
|
||||||
|
|
||||||
|
virtual eConfigValueDataTypes getDataType() {
|
||||||
|
return CVD_TYPE_GRADIENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset(CColor col) {
|
||||||
|
m_vColors.clear();
|
||||||
|
m_vColors.emplace_back(col);
|
||||||
|
m_fAngle = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Vector containing the colors */
|
||||||
|
std::vector<CColor> m_vColors;
|
||||||
|
|
||||||
|
/* Float corresponding to the angle (rad) */
|
||||||
|
float m_fAngle = 0;
|
||||||
|
|
||||||
|
//
|
||||||
|
bool operator==(const CGradientValueData& other) const {
|
||||||
|
if (other.m_vColors.size() != m_vColors.size() || m_fAngle != other.m_fAngle)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < m_vColors.size(); ++i)
|
||||||
|
if (m_vColors[i] != other.m_vColors[i])
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -10,211 +10,218 @@
|
|||||||
#include <deque>
|
#include <deque>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <regex>
|
#include <regex>
|
||||||
|
#include <optional>
|
||||||
|
#include <functional>
|
||||||
|
#include <xf86drmMode.h>
|
||||||
#include "../Window.hpp"
|
#include "../Window.hpp"
|
||||||
|
#include "../helpers/WLClasses.hpp"
|
||||||
|
#include "../helpers/Monitor.hpp"
|
||||||
|
#include "../helpers/VarList.hpp"
|
||||||
|
|
||||||
#include "defaultConfig.hpp"
|
#include "defaultConfig.hpp"
|
||||||
|
#include "ConfigDataValues.hpp"
|
||||||
|
|
||||||
#define STRVAL_EMPTY "[[EMPTY]]"
|
#define INITANIMCFG(name) animationConfig[name] = {}
|
||||||
|
|
||||||
#define INITANIMCFG(name) animationConfig[name] = {}
|
|
||||||
#define CREATEANIMCFG(name, parent) animationConfig[name] = {false, "", "", 0.f, -1, &animationConfig["global"], &animationConfig[parent]}
|
#define CREATEANIMCFG(name, parent) animationConfig[name] = {false, "", "", 0.f, -1, &animationConfig["global"], &animationConfig[parent]}
|
||||||
|
|
||||||
struct SConfigValue {
|
#define HANDLE void*
|
||||||
int64_t intValue = -INT64_MAX;
|
|
||||||
float floatValue = -__FLT_MAX__;
|
|
||||||
std::string strValue = "";
|
|
||||||
Vector2D vecValue = Vector2D(-__FLT_MAX__, -__FLT_MAX__);
|
|
||||||
|
|
||||||
bool set = false; // used for device configs
|
struct SConfigValue {
|
||||||
|
int64_t intValue = -INT64_MAX;
|
||||||
|
float floatValue = -__FLT_MAX__;
|
||||||
|
std::string strValue = "";
|
||||||
|
Vector2D vecValue = Vector2D(-__FLT_MAX__, -__FLT_MAX__);
|
||||||
|
std::shared_ptr<ICustomConfigValueData> data;
|
||||||
|
|
||||||
|
bool set = false; // used for device configs
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SMonitorRule {
|
struct SWorkspaceRule {
|
||||||
std::string name = "";
|
std::string monitor = "";
|
||||||
Vector2D resolution = Vector2D(1280,720);
|
std::string workspaceString = "";
|
||||||
Vector2D offset = Vector2D(0,0);
|
std::string workspaceName = "";
|
||||||
float scale = 1;
|
int workspaceId = -1;
|
||||||
float refreshRate = 60;
|
bool isDefault = false;
|
||||||
std::string defaultWorkspace = "";
|
bool isPersistent = false;
|
||||||
bool disabled = false;
|
std::optional<int64_t> gapsIn;
|
||||||
wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL;
|
std::optional<int64_t> gapsOut;
|
||||||
std::string mirrorOf = "";
|
std::optional<int64_t> borderSize;
|
||||||
bool enable10bit = false;
|
std::optional<int> border;
|
||||||
|
std::optional<int> rounding;
|
||||||
|
std::optional<int> decorate;
|
||||||
|
std::optional<int> shadow;
|
||||||
|
std::optional<std::string> onCreatedEmptyRunCmd;
|
||||||
|
std::map<std::string, std::any> layoutopts;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SMonitorAdditionalReservedArea {
|
struct SMonitorAdditionalReservedArea {
|
||||||
int top = 0;
|
int top = 0;
|
||||||
int bottom = 0;
|
int bottom = 0;
|
||||||
int left = 0;
|
int left = 0;
|
||||||
int right = 0;
|
int right = 0;
|
||||||
};
|
|
||||||
|
|
||||||
struct SWindowRule {
|
|
||||||
std::string szRule;
|
|
||||||
std::string szValue;
|
|
||||||
|
|
||||||
bool v2 = false;
|
|
||||||
std::string szTitle;
|
|
||||||
std::string szClass;
|
|
||||||
int bX11 = -1; // -1 means "ANY"
|
|
||||||
int bFloating = -1;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SAnimationPropertyConfig {
|
struct SAnimationPropertyConfig {
|
||||||
bool overriden = true;
|
bool overridden = true;
|
||||||
|
|
||||||
std::string internalBezier = "";
|
std::string internalBezier = "";
|
||||||
std::string internalStyle = "";
|
std::string internalStyle = "";
|
||||||
float internalSpeed = 0.f;
|
float internalSpeed = 0.f;
|
||||||
int internalEnabled = -1;
|
int internalEnabled = -1;
|
||||||
|
|
||||||
SAnimationPropertyConfig* pValues = nullptr;
|
SAnimationPropertyConfig* pValues = nullptr;
|
||||||
SAnimationPropertyConfig* pParentAnimation = nullptr;
|
SAnimationPropertyConfig* pParentAnimation = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
class CVarList {
|
struct SPluginKeyword {
|
||||||
public:
|
HANDLE handle = 0;
|
||||||
CVarList(const std::string& in, long unsigned int lastArgNo = 0) {
|
std::string name = "";
|
||||||
std::string curitem = "";
|
std::function<void(const std::string&, const std::string&)> fn;
|
||||||
std::string argZ = in;
|
};
|
||||||
|
|
||||||
auto nextItem = [&]() {
|
struct SExecRequestedRule {
|
||||||
auto idx = lastArgNo != 0 && m_vArgs.size() >= lastArgNo - 1 ? std::string::npos : argZ.find_first_of(',');
|
std::string szRule = "";
|
||||||
|
uint64_t iPid = 0;
|
||||||
if (idx != std::string::npos) {
|
|
||||||
curitem = argZ.substr(0, idx);
|
|
||||||
argZ = argZ.substr(idx + 1);
|
|
||||||
} else {
|
|
||||||
curitem = argZ;
|
|
||||||
argZ = STRVAL_EMPTY;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
nextItem();
|
|
||||||
|
|
||||||
while (curitem != STRVAL_EMPTY) {
|
|
||||||
m_vArgs.push_back(removeBeginEndSpacesTabs(curitem));
|
|
||||||
nextItem();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
~CVarList() = default;
|
|
||||||
|
|
||||||
int size() const {
|
|
||||||
return m_vArgs.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string operator[](const long unsigned int& idx) const {
|
|
||||||
if (idx >= m_vArgs.size())
|
|
||||||
return "";
|
|
||||||
return m_vArgs[idx];
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::vector<std::string> m_vArgs;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class CConfigManager {
|
class CConfigManager {
|
||||||
public:
|
public:
|
||||||
CConfigManager();
|
CConfigManager();
|
||||||
|
|
||||||
void tick();
|
void tick();
|
||||||
void init();
|
void init();
|
||||||
|
|
||||||
int getInt(const std::string&);
|
int getInt(const std::string&);
|
||||||
float getFloat(const std::string&);
|
float getFloat(const std::string&);
|
||||||
std::string getString(const std::string&);
|
Vector2D getVec(const std::string&);
|
||||||
void setFloat(std::string, float);
|
std::string getString(const std::string&);
|
||||||
void setInt(std::string, int);
|
void setFloat(const std::string&, float);
|
||||||
void setString(std::string, std::string);
|
void setInt(const std::string&, int);
|
||||||
|
void setVec(const std::string&, Vector2D);
|
||||||
|
void setString(const std::string&, const std::string&);
|
||||||
|
|
||||||
int getDeviceInt(const std::string&, const std::string&);
|
int getDeviceInt(const std::string&, const std::string&, const std::string& fallback = "");
|
||||||
float getDeviceFloat(const std::string&, const std::string&);
|
float getDeviceFloat(const std::string&, const std::string&, const std::string& fallback = "");
|
||||||
std::string getDeviceString(const std::string&, const std::string&);
|
Vector2D getDeviceVec(const std::string&, const std::string&, const std::string& fallback = "");
|
||||||
bool deviceConfigExists(const std::string&);
|
std::string getDeviceString(const std::string&, const std::string&, const std::string& fallback = "");
|
||||||
bool shouldBlurLS(const std::string&);
|
bool deviceConfigExists(const std::string&);
|
||||||
|
bool shouldBlurLS(const std::string&);
|
||||||
|
|
||||||
SConfigValue* getConfigValuePtr(std::string);
|
SConfigValue* getConfigValuePtr(const std::string&);
|
||||||
SConfigValue* getConfigValuePtrSafe(std::string);
|
SConfigValue* getConfigValuePtrSafe(const std::string&);
|
||||||
|
static std::string getConfigDir();
|
||||||
|
static std::string getMainConfigPath();
|
||||||
|
|
||||||
SMonitorRule getMonitorRuleFor(std::string, std::string displayName = "");
|
SMonitorRule getMonitorRuleFor(const std::string&, const std::string& displayName = "");
|
||||||
|
SWorkspaceRule getWorkspaceRuleFor(CWorkspace*);
|
||||||
|
std::string getDefaultWorkspaceFor(const std::string&);
|
||||||
|
|
||||||
CMonitor* getBoundMonitorForWS(std::string);
|
CMonitor* getBoundMonitorForWS(const std::string&);
|
||||||
|
std::string getBoundMonitorStringForWS(const std::string&);
|
||||||
|
const std::deque<SWorkspaceRule>& getAllWorkspaceRules();
|
||||||
|
|
||||||
std::vector<SWindowRule> getMatchingRules(CWindow*);
|
std::vector<SWindowRule> getMatchingRules(CWindow*);
|
||||||
|
std::vector<SLayerRule> getMatchingRules(SLayerSurface*);
|
||||||
|
|
||||||
std::unordered_map<std::string, SMonitorAdditionalReservedArea> m_mAdditionalReservedAreas;
|
std::unordered_map<std::string, SMonitorAdditionalReservedArea> m_mAdditionalReservedAreas;
|
||||||
|
|
||||||
|
std::unordered_map<std::string, SAnimationPropertyConfig> getAnimationConfig();
|
||||||
|
|
||||||
|
void addPluginConfigVar(HANDLE handle, const std::string& name, const SConfigValue& value);
|
||||||
|
void addPluginKeyword(HANDLE handle, const std::string& name, std::function<void(const std::string& cmd, const std::string& val)> fun);
|
||||||
|
void removePluginConfig(HANDLE handle);
|
||||||
|
|
||||||
// no-op when done.
|
// no-op when done.
|
||||||
void dispatchExecOnce();
|
void dispatchExecOnce();
|
||||||
|
|
||||||
void performMonitorReload();
|
void performMonitorReload();
|
||||||
bool m_bWantsMonitorReload = false;
|
bool m_bWantsMonitorReload = false;
|
||||||
bool m_bForceReload = false;
|
bool m_bForceReload = false;
|
||||||
bool m_bNoMonitorReload = false;
|
bool m_bNoMonitorReload = false;
|
||||||
void ensureDPMS();
|
void ensureMonitorStatus();
|
||||||
void ensureVRR(CMonitor* pMonitor = nullptr);
|
void ensureVRR(CMonitor* pMonitor = nullptr);
|
||||||
|
|
||||||
std::string parseKeyword(const std::string&, const std::string&, bool dynamic = false);
|
std::string parseKeyword(const std::string&, const std::string&, bool dynamic = false);
|
||||||
|
|
||||||
void addParseError(const std::string&);
|
void addParseError(const std::string&);
|
||||||
|
|
||||||
SAnimationPropertyConfig* getAnimationPropertyConfig(const std::string&);
|
SAnimationPropertyConfig* getAnimationPropertyConfig(const std::string&);
|
||||||
|
|
||||||
std::string configCurrentPath;
|
void addExecRule(const SExecRequestedRule&);
|
||||||
|
|
||||||
private:
|
void handlePluginLoads();
|
||||||
std::deque<std::string> configPaths; // stores all the config paths
|
|
||||||
std::unordered_map<std::string, time_t> configModifyTimes; // stores modify times
|
|
||||||
std::unordered_map<std::string, std::string> configDynamicVars; // stores dynamic vars declared by the user
|
|
||||||
std::unordered_map<std::string, SConfigValue> configValues;
|
|
||||||
std::unordered_map<std::string, std::unordered_map<std::string, SConfigValue>> deviceConfigs; // stores device configs
|
|
||||||
|
|
||||||
std::unordered_map<std::string, SAnimationPropertyConfig> animationConfig; // stores all the animations with their set values
|
std::string configCurrentPath;
|
||||||
|
|
||||||
std::string currentCategory = ""; // For storing the category of the current item
|
private:
|
||||||
|
std::deque<std::string> configPaths; // stores all the config paths
|
||||||
|
std::unordered_map<std::string, time_t> configModifyTimes; // stores modify times
|
||||||
|
std::vector<std::pair<std::string, std::string>> configDynamicVars; // stores dynamic vars declared by the user
|
||||||
|
std::unordered_map<std::string, SConfigValue> configValues;
|
||||||
|
std::unordered_map<std::string, std::unordered_map<std::string, SConfigValue>> deviceConfigs; // stores device configs
|
||||||
|
|
||||||
std::string parseError = ""; // For storing a parse error to display later
|
std::unordered_map<std::string, SAnimationPropertyConfig> animationConfig; // stores all the animations with their set values
|
||||||
|
|
||||||
std::string m_szCurrentSubmap = ""; // For storing the current keybind submap
|
std::string currentCategory = ""; // For storing the category of the current item
|
||||||
|
|
||||||
std::vector<std::pair<std::string, std::string>> boundWorkspaces;
|
std::string parseError = ""; // For storing a parse error to display later
|
||||||
|
|
||||||
bool isFirstLaunch = true; // For exec-once
|
std::string m_szCurrentSubmap = ""; // For storing the current keybind submap
|
||||||
|
|
||||||
std::deque<SMonitorRule> m_dMonitorRules;
|
std::vector<SExecRequestedRule> execRequestedRules; // rules requested with exec, e.g. [workspace 2] kitty
|
||||||
std::deque<SWindowRule> m_dWindowRules;
|
|
||||||
std::deque<std::string> m_dBlurLSNamespaces;
|
|
||||||
|
|
||||||
bool firstExecDispatched = false;
|
std::vector<std::string> m_vDeclaredPlugins;
|
||||||
std::deque<std::string> firstExecRequests;
|
std::unordered_map<HANDLE, std::unique_ptr<std::unordered_map<std::string, SConfigValue>>> pluginConfigs; // stores plugin configs
|
||||||
|
std::vector<SPluginKeyword> pluginKeywords;
|
||||||
|
|
||||||
|
bool isFirstLaunch = true; // For exec-once
|
||||||
|
|
||||||
|
std::deque<SMonitorRule> m_dMonitorRules;
|
||||||
|
std::deque<SWorkspaceRule> m_dWorkspaceRules;
|
||||||
|
std::deque<SWindowRule> m_dWindowRules;
|
||||||
|
std::deque<SLayerRule> m_dLayerRules;
|
||||||
|
std::deque<std::string> m_dBlurLSNamespaces;
|
||||||
|
|
||||||
|
bool firstExecDispatched = false;
|
||||||
|
bool m_bManualCrashInitiated = false;
|
||||||
|
std::deque<std::string> firstExecRequests;
|
||||||
|
|
||||||
|
std::vector<std::pair<std::string, std::string>> environmentVariables;
|
||||||
|
|
||||||
|
std::vector<std::pair<std::string, std::string>> m_vFailedPluginConfigValues; // for plugin values of unloaded plugins
|
||||||
|
|
||||||
// internal methods
|
// internal methods
|
||||||
void setDefaultVars();
|
void setDefaultVars();
|
||||||
void setDefaultAnimationVars();
|
void setDefaultAnimationVars();
|
||||||
void setDeviceDefaultVars(const std::string&);
|
void setDeviceDefaultVars(const std::string&);
|
||||||
|
void populateEnvironment();
|
||||||
|
|
||||||
void setAnimForChildren(SAnimationPropertyConfig *const);
|
void setAnimForChildren(SAnimationPropertyConfig* const);
|
||||||
|
void updateBlurredLS(const std::string&, const bool);
|
||||||
|
|
||||||
void applyUserDefinedVars(std::string&, const size_t);
|
void applyUserDefinedVars(std::string&, const size_t);
|
||||||
void loadConfigLoadVars();
|
void loadConfigLoadVars();
|
||||||
SConfigValue getConfigValueSafe(const std::string&);
|
SConfigValue getConfigValueSafe(const std::string&);
|
||||||
SConfigValue getConfigValueSafeDevice(const std::string&, const std::string&);
|
SConfigValue getConfigValueSafeDevice(const std::string&, const std::string&, const std::string& fallback = "");
|
||||||
void parseLine(std::string&);
|
void parseLine(std::string&);
|
||||||
void configSetValueSafe(const std::string&, const std::string&);
|
void configSetValueSafe(const std::string&, const std::string&);
|
||||||
void handleDeviceConfig(const std::string&, const std::string&);
|
void handleDeviceConfig(const std::string&, const std::string&);
|
||||||
void handleRawExec(const std::string&, const std::string&);
|
void handleRawExec(const std::string&, const std::string&);
|
||||||
void handleMonitor(const std::string&, const std::string&);
|
void handleMonitor(const std::string&, const std::string&);
|
||||||
void handleBind(const std::string&, const std::string&);
|
void handleBind(const std::string&, const std::string&);
|
||||||
void handleUnbind(const std::string&, const std::string&);
|
void handleUnbind(const std::string&, const std::string&);
|
||||||
void handleWindowRule(const std::string&, const std::string&);
|
void handleWindowRule(const std::string&, const std::string&);
|
||||||
void handleWindowRuleV2(const std::string&, const std::string&);
|
void handleLayerRule(const std::string&, const std::string&);
|
||||||
void handleDefaultWorkspace(const std::string&, const std::string&);
|
void handleWindowRuleV2(const std::string&, const std::string&);
|
||||||
void handleBezier(const std::string&, const std::string&);
|
void handleWorkspaceRules(const std::string&, const std::string&);
|
||||||
void handleAnimation(const std::string&, const std::string&);
|
void handleBezier(const std::string&, const std::string&);
|
||||||
void handleSource(const std::string&, const std::string&);
|
void handleAnimation(const std::string&, const std::string&);
|
||||||
void handleSubmap(const std::string&, const std::string&);
|
void handleSource(const std::string&, const std::string&);
|
||||||
void handleBlurLS(const std::string&, const std::string&);
|
void handleSubmap(const std::string&, const std::string&);
|
||||||
void handleBindWS(const std::string&, const std::string&);
|
void handleBlurLS(const std::string&, const std::string&);
|
||||||
|
void handleBindWS(const std::string&, const std::string&);
|
||||||
|
void handleEnv(const std::string&, const std::string&);
|
||||||
|
void handlePlugin(const std::string&, const std::string&);
|
||||||
};
|
};
|
||||||
|
|
||||||
inline std::unique_ptr<CConfigManager> g_pConfigManager;
|
inline std::unique_ptr<CConfigManager> g_pConfigManager;
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ OR EDIT THIS ONE ACCORDING TO THE WIKI INSTRUCTIONS.
|
|||||||
autogenerated = 1 # remove this line to remove the warning
|
autogenerated = 1 # remove this line to remove the warning
|
||||||
|
|
||||||
# See https://wiki.hyprland.org/Configuring/Monitors/
|
# See https://wiki.hyprland.org/Configuring/Monitors/
|
||||||
monitor=,preferred,auto,1
|
monitor=,preferred,auto,auto
|
||||||
|
|
||||||
|
|
||||||
# See https://wiki.hyprland.org/Configuring/Keywords/ for more
|
# See https://wiki.hyprland.org/Configuring/Keywords/ for more
|
||||||
@@ -28,6 +28,14 @@ monitor=,preferred,auto,1
|
|||||||
# Source a file (multi-file configs)
|
# Source a file (multi-file configs)
|
||||||
# source = ~/.config/hypr/myColors.conf
|
# source = ~/.config/hypr/myColors.conf
|
||||||
|
|
||||||
|
# Set programs that you use
|
||||||
|
$terminal = kitty
|
||||||
|
$fileManager = dolphin
|
||||||
|
$menu = wofi --show drun
|
||||||
|
|
||||||
|
# Some default env vars.
|
||||||
|
env = XCURSOR_SIZE,24
|
||||||
|
|
||||||
# For all categories, see https://wiki.hyprland.org/Configuring/Variables/
|
# For all categories, see https://wiki.hyprland.org/Configuring/Variables/
|
||||||
input {
|
input {
|
||||||
kb_layout = us
|
kb_layout = us
|
||||||
@@ -51,20 +59,25 @@ general {
|
|||||||
gaps_in = 5
|
gaps_in = 5
|
||||||
gaps_out = 20
|
gaps_out = 20
|
||||||
border_size = 2
|
border_size = 2
|
||||||
col.active_border = rgba(1affffee)
|
col.active_border = rgba(33ccffee) rgba(00ff99ee) 45deg
|
||||||
col.inactive_border = rgba(595959aa)
|
col.inactive_border = rgba(595959aa)
|
||||||
|
|
||||||
layout = dwindle
|
layout = dwindle
|
||||||
|
|
||||||
|
# Please see https://wiki.hyprland.org/Configuring/Tearing/ before you turn this on
|
||||||
|
allow_tearing = false
|
||||||
}
|
}
|
||||||
|
|
||||||
decoration {
|
decoration {
|
||||||
# See https://wiki.hyprland.org/Configuring/Variables/ for more
|
# See https://wiki.hyprland.org/Configuring/Variables/ for more
|
||||||
|
|
||||||
rounding = 10
|
rounding = 10
|
||||||
blur = yes
|
|
||||||
blur_size = 3
|
blur {
|
||||||
blur_passes = 1
|
enabled = true
|
||||||
blur_new_optimizations = on
|
size = 3
|
||||||
|
passes = 1
|
||||||
|
}
|
||||||
|
|
||||||
drop_shadow = yes
|
drop_shadow = yes
|
||||||
shadow_range = 4
|
shadow_range = 4
|
||||||
@@ -82,6 +95,7 @@ animations {
|
|||||||
animation = windows, 1, 7, myBezier
|
animation = windows, 1, 7, myBezier
|
||||||
animation = windowsOut, 1, 7, default, popin 80%
|
animation = windowsOut, 1, 7, default, popin 80%
|
||||||
animation = border, 1, 10, default
|
animation = border, 1, 10, default
|
||||||
|
animation = borderangle, 1, 8, default
|
||||||
animation = fade, 1, 7, default
|
animation = fade, 1, 7, default
|
||||||
animation = workspaces, 1, 6, default
|
animation = workspaces, 1, 6, default
|
||||||
}
|
}
|
||||||
@@ -102,9 +116,14 @@ gestures {
|
|||||||
workspace_swipe = off
|
workspace_swipe = off
|
||||||
}
|
}
|
||||||
|
|
||||||
|
misc {
|
||||||
|
# See https://wiki.hyprland.org/Configuring/Variables/ for more
|
||||||
|
force_default_wallpaper = -1 # Set to 0 to disable the anime mascot wallpapers
|
||||||
|
}
|
||||||
|
|
||||||
# Example per-device config
|
# Example per-device config
|
||||||
# See https://wiki.hyprland.org/Configuring/Keywords/#executing for more
|
# See https://wiki.hyprland.org/Configuring/Keywords/#executing for more
|
||||||
device:epic mouse V1 {
|
device:epic-mouse-v1 {
|
||||||
sensitivity = -0.5
|
sensitivity = -0.5
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -113,18 +132,19 @@ device:epic mouse V1 {
|
|||||||
# Example windowrule v2
|
# Example windowrule v2
|
||||||
# windowrulev2 = float,class:^(kitty)$,title:^(kitty)$
|
# windowrulev2 = float,class:^(kitty)$,title:^(kitty)$
|
||||||
# See https://wiki.hyprland.org/Configuring/Window-Rules/ for more
|
# See https://wiki.hyprland.org/Configuring/Window-Rules/ for more
|
||||||
|
windowrulev2 = nomaximizerequest, class:.* # You'll probably like this.
|
||||||
|
|
||||||
|
|
||||||
# See https://wiki.hyprland.org/Configuring/Keywords/ for more
|
# See https://wiki.hyprland.org/Configuring/Keywords/ for more
|
||||||
$mainMod = SUPER
|
$mainMod = SUPER
|
||||||
|
|
||||||
# Example binds, see https://wiki.hyprland.org/Configuring/Binds/ for more
|
# Example binds, see https://wiki.hyprland.org/Configuring/Binds/ for more
|
||||||
bind = $mainMod, Q, exec, kitty
|
bind = $mainMod, Q, exec, $terminal
|
||||||
bind = $mainMod, C, killactive,
|
bind = $mainMod, C, killactive,
|
||||||
bind = $mainMod, M, exit,
|
bind = $mainMod, M, exit,
|
||||||
bind = $mainMod, E, exec, dolphin
|
bind = $mainMod, E, exec, $fileManager
|
||||||
bind = $mainMod, V, togglefloating,
|
bind = $mainMod, V, togglefloating,
|
||||||
bind = $mainMod, R, exec, wofi --show drun
|
bind = $mainMod, R, exec, $menu
|
||||||
bind = $mainMod, P, pseudo, # dwindle
|
bind = $mainMod, P, pseudo, # dwindle
|
||||||
bind = $mainMod, J, togglesplit, # dwindle
|
bind = $mainMod, J, togglesplit, # dwindle
|
||||||
|
|
||||||
@@ -158,6 +178,10 @@ bind = $mainMod SHIFT, 8, movetoworkspace, 8
|
|||||||
bind = $mainMod SHIFT, 9, movetoworkspace, 9
|
bind = $mainMod SHIFT, 9, movetoworkspace, 9
|
||||||
bind = $mainMod SHIFT, 0, movetoworkspace, 10
|
bind = $mainMod SHIFT, 0, movetoworkspace, 10
|
||||||
|
|
||||||
|
# Example special workspace (scratchpad)
|
||||||
|
bind = $mainMod, S, togglespecialworkspace, magic
|
||||||
|
bind = $mainMod SHIFT, S, movetoworkspace, special:magic
|
||||||
|
|
||||||
# Scroll through existing workspaces with mainMod + scroll
|
# Scroll through existing workspaces with mainMod + scroll
|
||||||
bind = $mainMod, mouse_down, workspace, e+1
|
bind = $mainMod, mouse_down, workspace, e+1
|
||||||
bind = $mainMod, mouse_up, workspace, e-1
|
bind = $mainMod, mouse_up, workspace, e-1
|
||||||
|
|||||||
157
src/debug/CrashReporter.cpp
Normal file
157
src/debug/CrashReporter.cpp
Normal file
@@ -0,0 +1,157 @@
|
|||||||
|
#include "CrashReporter.hpp"
|
||||||
|
#include <random>
|
||||||
|
#include <sys/utsname.h>
|
||||||
|
#include <fstream>
|
||||||
|
#include <signal.h>
|
||||||
|
|
||||||
|
#include "../plugins/PluginSystem.hpp"
|
||||||
|
|
||||||
|
#if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__)
|
||||||
|
#include <sys/sysctl.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
std::string getRandomMessage() {
|
||||||
|
|
||||||
|
const std::vector<std::string> MESSAGES = {"Sorry, didn't mean to...",
|
||||||
|
"This was an accident, I swear!",
|
||||||
|
"Calm down, it was a misinput! MISINPUT!",
|
||||||
|
"Oops",
|
||||||
|
"Vaxry is going to be upset.",
|
||||||
|
"Who tried dividing by zero?!",
|
||||||
|
"Maybe you should try dusting your PC in the meantime?",
|
||||||
|
"I tried so hard, and got so far...",
|
||||||
|
"I don't feel so good...",
|
||||||
|
"*thud*",
|
||||||
|
"Well this is awkward.",
|
||||||
|
"\"stable\"",
|
||||||
|
"I hope you didn't have any unsaved progress.",
|
||||||
|
"All these computers..."};
|
||||||
|
|
||||||
|
std::random_device dev;
|
||||||
|
std::mt19937 engine(dev());
|
||||||
|
std::uniform_int_distribution<> distribution(0, MESSAGES.size() - 1);
|
||||||
|
|
||||||
|
return MESSAGES[distribution(engine)];
|
||||||
|
}
|
||||||
|
|
||||||
|
void CrashReporter::createAndSaveCrash(int sig) {
|
||||||
|
|
||||||
|
// get the backtrace
|
||||||
|
const int PID = getpid();
|
||||||
|
|
||||||
|
std::string finalCrashReport = "";
|
||||||
|
|
||||||
|
finalCrashReport += "--------------------------------------------\n Hyprland Crash Report\n--------------------------------------------\n";
|
||||||
|
finalCrashReport += getRandomMessage() + "\n\n";
|
||||||
|
|
||||||
|
finalCrashReport += std::format("Hyprland received signal {} ({})\n\n", sig, (const char*)strsignal(sig));
|
||||||
|
|
||||||
|
finalCrashReport += std::format("Version: {}\nTag: {}\n\n", GIT_COMMIT_HASH, GIT_TAG);
|
||||||
|
|
||||||
|
if (g_pPluginSystem && !g_pPluginSystem->getAllPlugins().empty()) {
|
||||||
|
finalCrashReport += "Hyprland seems to be running with plugins. This crash might not be Hyprland's fault.\nPlugins:\n";
|
||||||
|
|
||||||
|
for (auto& p : g_pPluginSystem->getAllPlugins()) {
|
||||||
|
finalCrashReport += std::format("\t{} ({}) {}\n", p->name, p->author, p->version);
|
||||||
|
}
|
||||||
|
|
||||||
|
finalCrashReport += "\n\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
finalCrashReport += "System info:\n";
|
||||||
|
|
||||||
|
struct utsname unameInfo;
|
||||||
|
uname(&unameInfo);
|
||||||
|
|
||||||
|
finalCrashReport +=
|
||||||
|
std::format("\tSystem name: {}\n\tNode name: {}\n\tRelease: {}\n\tVersion: {}\n\n", unameInfo.sysname, unameInfo.nodename, unameInfo.release, unameInfo.version);
|
||||||
|
|
||||||
|
#if defined(__DragonFly__) || defined(__FreeBSD__)
|
||||||
|
const std::string GPUINFO = execAndGet("pciconf -lv | fgrep -A4 vga");
|
||||||
|
#else
|
||||||
|
const std::string GPUINFO = execAndGet("lspci -vnn | grep VGA");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
finalCrashReport += "GPU:\n\t" + GPUINFO;
|
||||||
|
|
||||||
|
finalCrashReport += std::format("\n\nos-release:\n\t{}\n\n\n", replaceInString(execAndGet("cat /etc/os-release"), "\n", "\n\t"));
|
||||||
|
|
||||||
|
finalCrashReport += "Backtrace:\n";
|
||||||
|
|
||||||
|
const auto CALLSTACK = getBacktrace();
|
||||||
|
|
||||||
|
#if defined(KERN_PROC_PATHNAME)
|
||||||
|
int mib[] = {
|
||||||
|
CTL_KERN,
|
||||||
|
#if defined(__NetBSD__)
|
||||||
|
KERN_PROC_ARGS,
|
||||||
|
-1,
|
||||||
|
KERN_PROC_PATHNAME,
|
||||||
|
#else
|
||||||
|
KERN_PROC,
|
||||||
|
KERN_PROC_PATHNAME,
|
||||||
|
-1,
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
u_int miblen = sizeof(mib) / sizeof(mib[0]);
|
||||||
|
char exe[PATH_MAX] = "";
|
||||||
|
size_t sz = sizeof(exe);
|
||||||
|
sysctl(mib, miblen, &exe, &sz, NULL, 0);
|
||||||
|
const auto FPATH = std::filesystem::canonical(exe);
|
||||||
|
#elif defined(__OpenBSD__)
|
||||||
|
// Neither KERN_PROC_PATHNAME nor /proc are supported
|
||||||
|
const auto FPATH = std::filesystem::canonical("/usr/local/bin/Hyprland");
|
||||||
|
#else
|
||||||
|
const auto FPATH = std::filesystem::canonical("/proc/self/exe");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
for (size_t i = 0; i < CALLSTACK.size(); ++i) {
|
||||||
|
finalCrashReport += std::format("\t#{} | {}\n", i, CALLSTACK[i].desc);
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
const auto CMD = std::format("llvm-addr2line -e {} -f 0x{:x}", FPATH.c_str(), (uint64_t)CALLSTACK[i].adr);
|
||||||
|
#else
|
||||||
|
const auto CMD = std::format("addr2line -e {} -f 0x{:x}", FPATH.c_str(), (uint64_t)CALLSTACK[i].adr);
|
||||||
|
#endif
|
||||||
|
const auto ADDR2LINE = replaceInString(execAndGet(CMD.c_str()), "\n", "\n\t\t");
|
||||||
|
finalCrashReport += "\t\t" + ADDR2LINE.substr(0, ADDR2LINE.length() - 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
finalCrashReport += "\n\nLog tail:\n";
|
||||||
|
|
||||||
|
finalCrashReport += Debug::rollingLog;
|
||||||
|
|
||||||
|
const auto HOME = getenv("HOME");
|
||||||
|
const auto CACHE_HOME = getenv("XDG_CACHE_HOME");
|
||||||
|
|
||||||
|
if (!HOME)
|
||||||
|
return;
|
||||||
|
|
||||||
|
std::ofstream ofs;
|
||||||
|
std::string path;
|
||||||
|
if (!CACHE_HOME || std::string(CACHE_HOME).empty()) {
|
||||||
|
if (!std::filesystem::exists(std::string(HOME) + "/.hyprland")) {
|
||||||
|
std::filesystem::create_directory(std::string(HOME) + "/.hyprland");
|
||||||
|
std::filesystem::permissions(std::string(HOME) + "/.hyprland", std::filesystem::perms::all, std::filesystem::perm_options::replace);
|
||||||
|
}
|
||||||
|
|
||||||
|
path = std::string(HOME) + "/.hyprland/hyprlandCrashReport" + std::to_string(PID) + ".txt";
|
||||||
|
ofs.open(path, std::ios::trunc);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
if (!std::filesystem::exists(std::string(CACHE_HOME) + "/hyprland")) {
|
||||||
|
std::filesystem::create_directory(std::string(CACHE_HOME) + "/hyprland");
|
||||||
|
std::filesystem::permissions(std::string(CACHE_HOME) + "/hyprland", std::filesystem::perms::all, std::filesystem::perm_options::replace);
|
||||||
|
}
|
||||||
|
|
||||||
|
path = std::string(CACHE_HOME) + "/hyprland/hyprlandCrashReport" + std::to_string(PID) + ".txt";
|
||||||
|
ofs.open(path, std::ios::trunc);
|
||||||
|
}
|
||||||
|
|
||||||
|
ofs << finalCrashReport;
|
||||||
|
|
||||||
|
ofs.close();
|
||||||
|
|
||||||
|
Debug::disableStdout = false;
|
||||||
|
Debug::log(CRIT, "Hyprland has crashed :( Consult the crash report at {} for more information.", path);
|
||||||
|
}
|
||||||
7
src/debug/CrashReporter.hpp
Normal file
7
src/debug/CrashReporter.hpp
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../defines.hpp"
|
||||||
|
|
||||||
|
namespace CrashReporter {
|
||||||
|
void createAndSaveCrash(int sig);
|
||||||
|
};
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -5,20 +5,22 @@
|
|||||||
#include "../helpers/MiscFunctions.hpp"
|
#include "../helpers/MiscFunctions.hpp"
|
||||||
|
|
||||||
namespace HyprCtl {
|
namespace HyprCtl {
|
||||||
void startHyprCtlSocket();
|
void startHyprCtlSocket();
|
||||||
|
std::string makeDynamicCall(const std::string& input);
|
||||||
|
|
||||||
// very simple thread-safe request method
|
// very simple thread-safe request method
|
||||||
inline bool requestMade = false;
|
inline bool requestMade = false;
|
||||||
inline bool requestReady = false;
|
inline bool requestReady = false;
|
||||||
inline std::string request = "";
|
inline std::string request = "";
|
||||||
|
|
||||||
inline std::ifstream requestStream;
|
inline std::ifstream requestStream;
|
||||||
|
|
||||||
inline wl_event_source* hyprCtlTickSource = nullptr;
|
inline wl_event_source* hyprCtlTickSource = nullptr;
|
||||||
|
|
||||||
inline int iSocketFD = -1;
|
inline int iSocketFD = -1;
|
||||||
|
|
||||||
enum eHyprCtlOutputFormat {
|
enum eHyprCtlOutputFormat
|
||||||
|
{
|
||||||
FORMAT_NORMAL = 0,
|
FORMAT_NORMAL = 0,
|
||||||
FORMAT_JSON
|
FORMAT_JSON
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -31,6 +31,15 @@ void CHyprMonitorDebugOverlay::frameData(CMonitor* pMonitor) {
|
|||||||
|
|
||||||
if (!m_pMonitor)
|
if (!m_pMonitor)
|
||||||
m_pMonitor = pMonitor;
|
m_pMonitor = pMonitor;
|
||||||
|
|
||||||
|
// anim data too
|
||||||
|
const auto PMONITORFORTICKS = g_pHyprRenderer->m_pMostHzMonitor ? g_pHyprRenderer->m_pMostHzMonitor : g_pCompositor->m_pLastMonitor;
|
||||||
|
if (PMONITORFORTICKS) {
|
||||||
|
if (m_dLastAnimationTicks.size() > (long unsigned int)PMONITORFORTICKS->refreshRate)
|
||||||
|
m_dLastAnimationTicks.pop_front();
|
||||||
|
|
||||||
|
m_dLastAnimationTicks.push_back(g_pAnimationManager->m_fLastTickTime);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int CHyprMonitorDebugOverlay::draw(int offset) {
|
int CHyprMonitorDebugOverlay::draw(int offset) {
|
||||||
@@ -38,34 +47,68 @@ int CHyprMonitorDebugOverlay::draw(int offset) {
|
|||||||
if (!m_pMonitor)
|
if (!m_pMonitor)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
int yOffset = offset;
|
int yOffset = offset;
|
||||||
cairo_text_extents_t cairoExtents;
|
cairo_text_extents_t cairoExtents;
|
||||||
float maxX = 0;
|
float maxX = 0;
|
||||||
std::string text = "";
|
std::string text = "";
|
||||||
|
|
||||||
// get avg fps
|
// get avg fps
|
||||||
float avgFrametime = 0;
|
float avgFrametime = 0;
|
||||||
|
float maxFrametime = 0;
|
||||||
|
float minFrametime = 9999;
|
||||||
for (auto& ft : m_dLastFrametimes) {
|
for (auto& ft : m_dLastFrametimes) {
|
||||||
|
if (ft > maxFrametime)
|
||||||
|
maxFrametime = ft;
|
||||||
|
if (ft < minFrametime)
|
||||||
|
minFrametime = ft;
|
||||||
avgFrametime += ft;
|
avgFrametime += ft;
|
||||||
}
|
}
|
||||||
|
float varFrametime = maxFrametime - minFrametime;
|
||||||
avgFrametime /= m_dLastFrametimes.size() == 0 ? 1 : m_dLastFrametimes.size();
|
avgFrametime /= m_dLastFrametimes.size() == 0 ? 1 : m_dLastFrametimes.size();
|
||||||
|
|
||||||
float avgRenderTime = 0;
|
float avgRenderTime = 0;
|
||||||
|
float maxRenderTime = 0;
|
||||||
|
float minRenderTime = 9999;
|
||||||
for (auto& rt : m_dLastRenderTimes) {
|
for (auto& rt : m_dLastRenderTimes) {
|
||||||
|
if (rt > maxRenderTime)
|
||||||
|
maxRenderTime = rt;
|
||||||
|
if (rt < minRenderTime)
|
||||||
|
minRenderTime = rt;
|
||||||
avgRenderTime += rt;
|
avgRenderTime += rt;
|
||||||
}
|
}
|
||||||
|
float varRenderTime = maxRenderTime - minRenderTime;
|
||||||
avgRenderTime /= m_dLastRenderTimes.size() == 0 ? 1 : m_dLastRenderTimes.size();
|
avgRenderTime /= m_dLastRenderTimes.size() == 0 ? 1 : m_dLastRenderTimes.size();
|
||||||
|
|
||||||
float avgRenderTimeNoOverlay = 0;
|
float avgRenderTimeNoOverlay = 0;
|
||||||
|
float maxRenderTimeNoOverlay = 0;
|
||||||
|
float minRenderTimeNoOverlay = 9999;
|
||||||
for (auto& rt : m_dLastRenderTimesNoOverlay) {
|
for (auto& rt : m_dLastRenderTimesNoOverlay) {
|
||||||
|
if (rt > maxRenderTimeNoOverlay)
|
||||||
|
maxRenderTimeNoOverlay = rt;
|
||||||
|
if (rt < minRenderTimeNoOverlay)
|
||||||
|
minRenderTimeNoOverlay = rt;
|
||||||
avgRenderTimeNoOverlay += rt;
|
avgRenderTimeNoOverlay += rt;
|
||||||
}
|
}
|
||||||
|
float varRenderTimeNoOverlay = maxRenderTimeNoOverlay - minRenderTimeNoOverlay;
|
||||||
avgRenderTimeNoOverlay /= m_dLastRenderTimes.size() == 0 ? 1 : m_dLastRenderTimes.size();
|
avgRenderTimeNoOverlay /= m_dLastRenderTimes.size() == 0 ? 1 : m_dLastRenderTimes.size();
|
||||||
|
|
||||||
const float FPS = 1.f / (avgFrametime / 1000.f); // frametimes are in ms
|
float avgAnimMgrTick = 0;
|
||||||
|
float maxAnimMgrTick = 0;
|
||||||
|
float minAnimMgrTick = 9999;
|
||||||
|
for (auto& at : m_dLastAnimationTicks) {
|
||||||
|
if (at > maxAnimMgrTick)
|
||||||
|
maxAnimMgrTick = at;
|
||||||
|
if (at < minAnimMgrTick)
|
||||||
|
minAnimMgrTick = at;
|
||||||
|
avgAnimMgrTick += at;
|
||||||
|
}
|
||||||
|
float varAnimMgrTick = maxAnimMgrTick - minAnimMgrTick;
|
||||||
|
avgAnimMgrTick /= m_dLastAnimationTicks.size() == 0 ? 1 : m_dLastAnimationTicks.size();
|
||||||
|
|
||||||
|
const float FPS = 1.f / (avgFrametime / 1000.f); // frametimes are in ms
|
||||||
const float idealFPS = m_dLastFrametimes.size();
|
const float idealFPS = m_dLastFrametimes.size();
|
||||||
|
|
||||||
cairo_select_font_face(g_pDebugOverlay->m_pCairo, "Noto Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
|
cairo_select_font_face(g_pDebugOverlay->m_pCairo, "Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
|
||||||
|
|
||||||
cairo_set_font_size(g_pDebugOverlay->m_pCairo, 10);
|
cairo_set_font_size(g_pDebugOverlay->m_pCairo, 10);
|
||||||
cairo_set_source_rgba(g_pDebugOverlay->m_pCairo, 1.f, 1.f, 1.f, 1.f);
|
cairo_set_source_rgba(g_pDebugOverlay->m_pCairo, 1.f, 1.f, 1.f, 1.f);
|
||||||
@@ -75,7 +118,8 @@ int CHyprMonitorDebugOverlay::draw(int offset) {
|
|||||||
text = m_pMonitor->szName;
|
text = m_pMonitor->szName;
|
||||||
cairo_show_text(g_pDebugOverlay->m_pCairo, text.c_str());
|
cairo_show_text(g_pDebugOverlay->m_pCairo, text.c_str());
|
||||||
cairo_text_extents(g_pDebugOverlay->m_pCairo, text.c_str(), &cairoExtents);
|
cairo_text_extents(g_pDebugOverlay->m_pCairo, text.c_str(), &cairoExtents);
|
||||||
if (cairoExtents.width > maxX) maxX = cairoExtents.width;
|
if (cairoExtents.width > maxX)
|
||||||
|
maxX = cairoExtents.width;
|
||||||
|
|
||||||
cairo_set_font_size(g_pDebugOverlay->m_pCairo, 16);
|
cairo_set_font_size(g_pDebugOverlay->m_pCairo, 16);
|
||||||
|
|
||||||
@@ -88,39 +132,52 @@ int CHyprMonitorDebugOverlay::draw(int offset) {
|
|||||||
|
|
||||||
yOffset += 17;
|
yOffset += 17;
|
||||||
cairo_move_to(g_pDebugOverlay->m_pCairo, 0, yOffset);
|
cairo_move_to(g_pDebugOverlay->m_pCairo, 0, yOffset);
|
||||||
text = std::string(std::to_string((int)FPS) + " FPS");
|
text = std::format("{} FPS", (int)FPS);
|
||||||
cairo_show_text(g_pDebugOverlay->m_pCairo, text.c_str());
|
cairo_show_text(g_pDebugOverlay->m_pCairo, text.c_str());
|
||||||
cairo_text_extents(g_pDebugOverlay->m_pCairo, text.c_str(), &cairoExtents);
|
cairo_text_extents(g_pDebugOverlay->m_pCairo, text.c_str(), &cairoExtents);
|
||||||
if (cairoExtents.width > maxX) maxX = cairoExtents.width;
|
if (cairoExtents.width > maxX)
|
||||||
|
maxX = cairoExtents.width;
|
||||||
|
|
||||||
cairo_set_font_size(g_pDebugOverlay->m_pCairo, 10);
|
cairo_set_font_size(g_pDebugOverlay->m_pCairo, 10);
|
||||||
cairo_set_source_rgba(g_pDebugOverlay->m_pCairo, 1.f, 1.f, 1.f, 1.f);
|
cairo_set_source_rgba(g_pDebugOverlay->m_pCairo, 1.f, 1.f, 1.f, 1.f);
|
||||||
|
|
||||||
yOffset += 11;
|
yOffset += 11;
|
||||||
cairo_move_to(g_pDebugOverlay->m_pCairo, 0, yOffset);
|
cairo_move_to(g_pDebugOverlay->m_pCairo, 0, yOffset);
|
||||||
text = std::string("Avg Frametime: " + std::to_string((int)avgFrametime) + "." + std::to_string((int)(avgFrametime * 10.f) % 10) + "ms");
|
text = std::format("Avg Frametime: {:.2f}ms (var {:.2f}ms)", avgFrametime, varFrametime);
|
||||||
cairo_show_text(g_pDebugOverlay->m_pCairo, text.c_str());
|
cairo_show_text(g_pDebugOverlay->m_pCairo, text.c_str());
|
||||||
cairo_text_extents(g_pDebugOverlay->m_pCairo, text.c_str(), &cairoExtents);
|
cairo_text_extents(g_pDebugOverlay->m_pCairo, text.c_str(), &cairoExtents);
|
||||||
if (cairoExtents.width > maxX) maxX = cairoExtents.width;
|
if (cairoExtents.width > maxX)
|
||||||
|
maxX = cairoExtents.width;
|
||||||
|
|
||||||
yOffset += 11;
|
yOffset += 11;
|
||||||
cairo_move_to(g_pDebugOverlay->m_pCairo, 0, yOffset);
|
cairo_move_to(g_pDebugOverlay->m_pCairo, 0, yOffset);
|
||||||
text = std::string("Avg Rendertime: " + std::to_string((int)avgRenderTime) + "." + std::to_string((int)(avgRenderTime * 10.f) % 10) + "ms");
|
text = std::format("Avg Rendertime: {:.2f}ms (var {:.2f}ms)", avgRenderTime, varRenderTime);
|
||||||
cairo_show_text(g_pDebugOverlay->m_pCairo, text.c_str());
|
cairo_show_text(g_pDebugOverlay->m_pCairo, text.c_str());
|
||||||
cairo_text_extents(g_pDebugOverlay->m_pCairo, text.c_str(), &cairoExtents);
|
cairo_text_extents(g_pDebugOverlay->m_pCairo, text.c_str(), &cairoExtents);
|
||||||
if (cairoExtents.width > maxX) maxX = cairoExtents.width;
|
if (cairoExtents.width > maxX)
|
||||||
|
maxX = cairoExtents.width;
|
||||||
|
|
||||||
yOffset += 11;
|
yOffset += 11;
|
||||||
cairo_move_to(g_pDebugOverlay->m_pCairo, 0, yOffset);
|
cairo_move_to(g_pDebugOverlay->m_pCairo, 0, yOffset);
|
||||||
text = std::string("Avg Rendertime (no overlay): " + std::to_string((int)avgRenderTimeNoOverlay) + "." + std::to_string((int)(avgRenderTimeNoOverlay * 10.f) % 10) + "ms");
|
text = std::format("Avg Rendertime (No Overlay): {:.2f}ms (var {:.2f}ms)", avgRenderTimeNoOverlay, varRenderTimeNoOverlay);
|
||||||
cairo_show_text(g_pDebugOverlay->m_pCairo, text.c_str());
|
cairo_show_text(g_pDebugOverlay->m_pCairo, text.c_str());
|
||||||
cairo_text_extents(g_pDebugOverlay->m_pCairo, text.c_str(), &cairoExtents);
|
cairo_text_extents(g_pDebugOverlay->m_pCairo, text.c_str(), &cairoExtents);
|
||||||
if (cairoExtents.width > maxX) maxX = cairoExtents.width;
|
if (cairoExtents.width > maxX)
|
||||||
|
maxX = cairoExtents.width;
|
||||||
|
|
||||||
|
yOffset += 11;
|
||||||
|
cairo_move_to(g_pDebugOverlay->m_pCairo, 0, yOffset);
|
||||||
|
text = std::format("Avg Anim Tick: {:.2f}ms (var {:.2f}ms) ({:.2f} TPS)", avgAnimMgrTick, varAnimMgrTick, 1.0 / (avgAnimMgrTick / 1000.0));
|
||||||
|
cairo_show_text(g_pDebugOverlay->m_pCairo, text.c_str());
|
||||||
|
cairo_text_extents(g_pDebugOverlay->m_pCairo, text.c_str(), &cairoExtents);
|
||||||
|
if (cairoExtents.width > maxX)
|
||||||
|
maxX = cairoExtents.width;
|
||||||
|
|
||||||
yOffset += 11;
|
yOffset += 11;
|
||||||
|
|
||||||
g_pHyprRenderer->damageBox(&m_wbLastDrawnBox);
|
g_pHyprRenderer->damageBox(&m_wbLastDrawnBox);
|
||||||
m_wbLastDrawnBox = {(int)g_pCompositor->m_vMonitors.front()->vecPosition.x, (int)g_pCompositor->m_vMonitors.front()->vecPosition.y + offset - 1, (int)maxX + 2, yOffset - offset + 2};
|
m_wbLastDrawnBox = {(int)g_pCompositor->m_vMonitors.front()->vecPosition.x, (int)g_pCompositor->m_vMonitors.front()->vecPosition.y + offset - 1, (int)maxX + 2,
|
||||||
|
yOffset - offset + 2};
|
||||||
g_pHyprRenderer->damageBox(&m_wbLastDrawnBox);
|
g_pHyprRenderer->damageBox(&m_wbLastDrawnBox);
|
||||||
|
|
||||||
return yOffset - offset;
|
return yOffset - offset;
|
||||||
@@ -143,8 +200,8 @@ void CHyprDebugOverlay::draw() {
|
|||||||
const auto PMONITOR = g_pCompositor->m_vMonitors.front().get();
|
const auto PMONITOR = g_pCompositor->m_vMonitors.front().get();
|
||||||
|
|
||||||
if (!m_pCairoSurface || !m_pCairo) {
|
if (!m_pCairoSurface || !m_pCairo) {
|
||||||
m_pCairoSurface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, PMONITOR->vecSize.x, PMONITOR->vecSize.y);
|
m_pCairoSurface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y);
|
||||||
m_pCairo = cairo_create(m_pCairoSurface);
|
m_pCairo = cairo_create(m_pCairoSurface);
|
||||||
}
|
}
|
||||||
|
|
||||||
// clear the pixmap
|
// clear the pixmap
|
||||||
@@ -174,8 +231,8 @@ void CHyprDebugOverlay::draw() {
|
|||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, PMONITOR->vecSize.x, PMONITOR->vecSize.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, DATA);
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, DATA);
|
||||||
|
|
||||||
wlr_box pMonBox = {0,0,PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y};
|
CBox pMonBox = {0, 0, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y};
|
||||||
g_pHyprOpenGL->renderTexture(m_tTexture, &pMonBox, 255.f);
|
g_pHyprOpenGL->renderTexture(m_tTexture, &pMonBox, 1.f);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,41 +7,45 @@
|
|||||||
#include <cairo/cairo.h>
|
#include <cairo/cairo.h>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
|
class CHyprRenderer;
|
||||||
|
|
||||||
class CHyprMonitorDebugOverlay {
|
class CHyprMonitorDebugOverlay {
|
||||||
public:
|
public:
|
||||||
int draw(int offset);
|
int draw(int offset);
|
||||||
|
|
||||||
void renderData(CMonitor* pMonitor, float µs);
|
void renderData(CMonitor* pMonitor, float µs);
|
||||||
void renderDataNoOverlay(CMonitor* pMonitor, float µs);
|
void renderDataNoOverlay(CMonitor* pMonitor, float µs);
|
||||||
void frameData(CMonitor* pMonitor);
|
void frameData(CMonitor* pMonitor);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::deque<float> m_dLastFrametimes;
|
std::deque<float> m_dLastFrametimes;
|
||||||
std::deque<float> m_dLastRenderTimes;
|
std::deque<float> m_dLastRenderTimes;
|
||||||
std::deque<float> m_dLastRenderTimesNoOverlay;
|
std::deque<float> m_dLastRenderTimesNoOverlay;
|
||||||
|
std::deque<float> m_dLastAnimationTicks;
|
||||||
std::chrono::high_resolution_clock::time_point m_tpLastFrame;
|
std::chrono::high_resolution_clock::time_point m_tpLastFrame;
|
||||||
CMonitor* m_pMonitor = nullptr;
|
CMonitor* m_pMonitor = nullptr;
|
||||||
wlr_box m_wbLastDrawnBox;
|
CBox m_wbLastDrawnBox;
|
||||||
|
|
||||||
|
friend class CHyprRenderer;
|
||||||
};
|
};
|
||||||
|
|
||||||
class CHyprDebugOverlay {
|
class CHyprDebugOverlay {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
void draw();
|
void draw();
|
||||||
void renderData(CMonitor*, float µs);
|
void renderData(CMonitor*, float µs);
|
||||||
void renderDataNoOverlay(CMonitor*, float µs);
|
void renderDataNoOverlay(CMonitor*, float µs);
|
||||||
void frameData(CMonitor*);
|
void frameData(CMonitor*);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
std::unordered_map<CMonitor*, CHyprMonitorDebugOverlay> m_mMonitorOverlays;
|
std::unordered_map<CMonitor*, CHyprMonitorDebugOverlay> m_mMonitorOverlays;
|
||||||
|
|
||||||
cairo_surface_t* m_pCairoSurface = nullptr;
|
cairo_surface_t* m_pCairoSurface = nullptr;
|
||||||
cairo_t* m_pCairo = nullptr;
|
cairo_t* m_pCairo = nullptr;
|
||||||
|
|
||||||
CTexture m_tTexture;
|
CTexture m_tTexture;
|
||||||
|
|
||||||
friend class CHyprMonitorDebugOverlay;
|
friend class CHyprMonitorDebugOverlay;
|
||||||
|
friend class CHyprRenderer;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline std::unique_ptr<CHyprDebugOverlay> g_pDebugOverlay;
|
inline std::unique_ptr<CHyprDebugOverlay> g_pDebugOverlay;
|
||||||
229
src/debug/HyprNotificationOverlay.cpp
Normal file
229
src/debug/HyprNotificationOverlay.cpp
Normal file
@@ -0,0 +1,229 @@
|
|||||||
|
#include "HyprNotificationOverlay.hpp"
|
||||||
|
#include "../Compositor.hpp"
|
||||||
|
#include <pango/pangocairo.h>
|
||||||
|
|
||||||
|
CHyprNotificationOverlay::CHyprNotificationOverlay() {
|
||||||
|
g_pHookSystem->hookDynamic("focusedMon", [&](void* self, SCallbackInfo& info, std::any param) {
|
||||||
|
if (m_dNotifications.size() == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
g_pHyprRenderer->damageBox(&m_bLastDamage);
|
||||||
|
});
|
||||||
|
|
||||||
|
// check for the icon backend
|
||||||
|
std::string fonts = execAndGet("fc-list");
|
||||||
|
std::string fontsLower = fonts;
|
||||||
|
std::transform(fontsLower.begin(), fontsLower.end(), fontsLower.begin(), [&](char& i) { return std::tolower(i); });
|
||||||
|
|
||||||
|
size_t index = 0;
|
||||||
|
|
||||||
|
if (index = fontsLower.find("nerd"); index != std::string::npos) {
|
||||||
|
m_eIconBackend = ICONS_BACKEND_NF;
|
||||||
|
} else if (index = fontsLower.find("font awesome"); index != std::string::npos) {
|
||||||
|
m_eIconBackend = ICONS_BACKEND_FA;
|
||||||
|
} else if (index = fontsLower.find("fontawesome"); index != std::string::npos) {
|
||||||
|
m_eIconBackend = ICONS_BACKEND_FA;
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto LASTNEWLINE = fonts.find_last_of('\n', index);
|
||||||
|
const auto COLON = fonts.find(':', LASTNEWLINE);
|
||||||
|
const auto COMMA = fonts.find(',', COLON);
|
||||||
|
const auto NEWLINE = fonts.find('\n', COLON);
|
||||||
|
const auto LASTCHAR = COMMA < NEWLINE ? COMMA : NEWLINE;
|
||||||
|
|
||||||
|
m_szIconFontName = fonts.substr(COLON + 2, LASTCHAR - (COLON + 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
void CHyprNotificationOverlay::addNotification(const std::string& text, const CColor& color, const float timeMs, const eIcons icon) {
|
||||||
|
const auto PNOTIF = m_dNotifications.emplace_back(std::make_unique<SNotification>()).get();
|
||||||
|
|
||||||
|
PNOTIF->text = text;
|
||||||
|
PNOTIF->color = color == CColor(0) ? ICONS_COLORS[icon] : color;
|
||||||
|
PNOTIF->started.reset();
|
||||||
|
PNOTIF->timeMs = timeMs;
|
||||||
|
PNOTIF->icon = icon;
|
||||||
|
|
||||||
|
for (auto& m : g_pCompositor->m_vMonitors) {
|
||||||
|
g_pCompositor->scheduleFrameForMonitor(m.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CBox CHyprNotificationOverlay::drawNotifications(CMonitor* pMonitor) {
|
||||||
|
static constexpr auto ANIM_DURATION_MS = 600.0;
|
||||||
|
static constexpr auto ANIM_LAG_MS = 100.0;
|
||||||
|
static constexpr auto NOTIF_LEFTBAR_SIZE = 5.0;
|
||||||
|
static constexpr auto ICON_PAD = 3.0;
|
||||||
|
static constexpr auto ICON_SCALE = 0.9;
|
||||||
|
static constexpr auto GRADIENT_SIZE = 60.0;
|
||||||
|
|
||||||
|
float offsetY = 10;
|
||||||
|
float maxWidth = 0;
|
||||||
|
|
||||||
|
const auto SCALE = pMonitor->scale;
|
||||||
|
const auto FONTSIZE = std::clamp((int)(13.f * ((pMonitor->vecPixelSize.x * SCALE) / 1920.f)), 8, 40);
|
||||||
|
|
||||||
|
const auto MONSIZE = pMonitor->vecPixelSize;
|
||||||
|
|
||||||
|
cairo_text_extents_t cairoExtents;
|
||||||
|
int iconW = 0, iconH = 0;
|
||||||
|
|
||||||
|
PangoLayout* pangoLayout;
|
||||||
|
PangoFontDescription* pangoFD;
|
||||||
|
|
||||||
|
pangoLayout = pango_cairo_create_layout(m_pCairo);
|
||||||
|
pangoFD = pango_font_description_from_string(("Sans " + std::to_string(FONTSIZE * ICON_SCALE)).c_str());
|
||||||
|
pango_layout_set_font_description(pangoLayout, pangoFD);
|
||||||
|
|
||||||
|
cairo_select_font_face(m_pCairo, "Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
|
||||||
|
cairo_set_font_size(m_pCairo, FONTSIZE);
|
||||||
|
|
||||||
|
const auto PBEZIER = g_pAnimationManager->getBezier("default");
|
||||||
|
|
||||||
|
for (auto& notif : m_dNotifications) {
|
||||||
|
const auto ICONPADFORNOTIF = notif->icon == ICON_NONE ? 0 : ICON_PAD;
|
||||||
|
|
||||||
|
// first rect (bg, col)
|
||||||
|
const float FIRSTRECTANIMP =
|
||||||
|
(notif->started.getMillis() > (ANIM_DURATION_MS - ANIM_LAG_MS) ?
|
||||||
|
(notif->started.getMillis() > notif->timeMs - (ANIM_DURATION_MS - ANIM_LAG_MS) ? notif->timeMs - notif->started.getMillis() : (ANIM_DURATION_MS - ANIM_LAG_MS)) :
|
||||||
|
notif->started.getMillis()) /
|
||||||
|
(ANIM_DURATION_MS - ANIM_LAG_MS);
|
||||||
|
|
||||||
|
const float FIRSTRECTPERC = FIRSTRECTANIMP >= 0.99f ? 1.f : PBEZIER->getYForPoint(FIRSTRECTANIMP);
|
||||||
|
|
||||||
|
// second rect (fg, black)
|
||||||
|
const float SECONDRECTANIMP = (notif->started.getMillis() > ANIM_DURATION_MS ?
|
||||||
|
(notif->started.getMillis() > notif->timeMs - ANIM_DURATION_MS ? notif->timeMs - notif->started.getMillis() : ANIM_DURATION_MS) :
|
||||||
|
notif->started.getMillis()) /
|
||||||
|
ANIM_DURATION_MS;
|
||||||
|
|
||||||
|
const float SECONDRECTPERC = SECONDRECTANIMP >= 0.99f ? 1.f : PBEZIER->getYForPoint(SECONDRECTANIMP);
|
||||||
|
|
||||||
|
// third rect (horiz, col)
|
||||||
|
const float THIRDRECTPERC = notif->started.getMillis() / notif->timeMs;
|
||||||
|
|
||||||
|
// get text size
|
||||||
|
cairo_text_extents(m_pCairo, notif->text.c_str(), &cairoExtents);
|
||||||
|
const auto ICON = ICONS_ARRAY[m_eIconBackend][notif->icon];
|
||||||
|
const auto ICONCOLOR = ICONS_COLORS[notif->icon];
|
||||||
|
pango_layout_set_text(pangoLayout, ICON.c_str(), -1);
|
||||||
|
pango_layout_set_font_description(pangoLayout, pangoFD);
|
||||||
|
pango_cairo_update_layout(m_pCairo, pangoLayout);
|
||||||
|
pango_layout_get_size(pangoLayout, &iconW, &iconH);
|
||||||
|
iconW /= PANGO_SCALE;
|
||||||
|
iconH /= PANGO_SCALE;
|
||||||
|
|
||||||
|
cairo_set_source_rgba(m_pCairo, notif->color.r, notif->color.g, notif->color.b, notif->color.a);
|
||||||
|
|
||||||
|
const auto NOTIFSIZE = Vector2D{cairoExtents.width + 20 + iconW + 2 * ICONPADFORNOTIF, cairoExtents.height + 10};
|
||||||
|
|
||||||
|
// draw rects
|
||||||
|
cairo_rectangle(m_pCairo, MONSIZE.x - (NOTIFSIZE.x + NOTIF_LEFTBAR_SIZE) * FIRSTRECTPERC, offsetY, (NOTIFSIZE.x + NOTIF_LEFTBAR_SIZE) * FIRSTRECTPERC, NOTIFSIZE.y);
|
||||||
|
cairo_fill(m_pCairo);
|
||||||
|
|
||||||
|
cairo_set_source_rgb(m_pCairo, 0.f, 0.f, 0.f);
|
||||||
|
|
||||||
|
cairo_rectangle(m_pCairo, MONSIZE.x - NOTIFSIZE.x * SECONDRECTPERC, offsetY, NOTIFSIZE.x * SECONDRECTPERC, NOTIFSIZE.y);
|
||||||
|
cairo_fill(m_pCairo);
|
||||||
|
|
||||||
|
cairo_set_source_rgba(m_pCairo, notif->color.r, notif->color.g, notif->color.b, notif->color.a);
|
||||||
|
|
||||||
|
cairo_rectangle(m_pCairo, MONSIZE.x - NOTIFSIZE.x * SECONDRECTPERC + 3, offsetY + NOTIFSIZE.y - 4, THIRDRECTPERC * (NOTIFSIZE.x - 6), 2);
|
||||||
|
cairo_fill(m_pCairo);
|
||||||
|
|
||||||
|
// draw gradient
|
||||||
|
if (notif->icon != ICON_NONE) {
|
||||||
|
cairo_pattern_t* pattern;
|
||||||
|
pattern = cairo_pattern_create_linear(MONSIZE.x - (NOTIFSIZE.x + NOTIF_LEFTBAR_SIZE) * FIRSTRECTPERC, offsetY,
|
||||||
|
MONSIZE.x - (NOTIFSIZE.x + NOTIF_LEFTBAR_SIZE) * FIRSTRECTPERC + GRADIENT_SIZE, offsetY);
|
||||||
|
cairo_pattern_add_color_stop_rgba(pattern, 0, ICONCOLOR.r, ICONCOLOR.g, ICONCOLOR.b, ICONCOLOR.a / 3.0);
|
||||||
|
cairo_pattern_add_color_stop_rgba(pattern, 1, ICONCOLOR.r, ICONCOLOR.g, ICONCOLOR.b, 0);
|
||||||
|
cairo_rectangle(m_pCairo, MONSIZE.x - (NOTIFSIZE.x + NOTIF_LEFTBAR_SIZE) * FIRSTRECTPERC, offsetY, GRADIENT_SIZE, NOTIFSIZE.y);
|
||||||
|
cairo_set_source(m_pCairo, pattern);
|
||||||
|
cairo_fill(m_pCairo);
|
||||||
|
cairo_pattern_destroy(pattern);
|
||||||
|
|
||||||
|
// draw icon
|
||||||
|
cairo_set_source_rgb(m_pCairo, 1.f, 1.f, 1.f);
|
||||||
|
cairo_move_to(m_pCairo, MONSIZE.x - NOTIFSIZE.x * SECONDRECTPERC + NOTIF_LEFTBAR_SIZE + ICONPADFORNOTIF - 1, offsetY + std::round((NOTIFSIZE.y - iconH - 4) / 2.0));
|
||||||
|
pango_cairo_show_layout(m_pCairo, pangoLayout);
|
||||||
|
}
|
||||||
|
|
||||||
|
// draw text
|
||||||
|
cairo_set_font_size(m_pCairo, FONTSIZE);
|
||||||
|
cairo_set_source_rgb(m_pCairo, 1.f, 1.f, 1.f);
|
||||||
|
cairo_move_to(m_pCairo, MONSIZE.x - NOTIFSIZE.x * SECONDRECTPERC + NOTIF_LEFTBAR_SIZE + iconW + 2 * ICONPADFORNOTIF, offsetY + FONTSIZE + (FONTSIZE / 10.0));
|
||||||
|
cairo_show_text(m_pCairo, notif->text.c_str());
|
||||||
|
|
||||||
|
// adjust offset and move on
|
||||||
|
offsetY += NOTIFSIZE.y + 10;
|
||||||
|
|
||||||
|
if (maxWidth < NOTIFSIZE.x)
|
||||||
|
maxWidth = NOTIFSIZE.x;
|
||||||
|
}
|
||||||
|
|
||||||
|
pango_font_description_free(pangoFD);
|
||||||
|
g_object_unref(pangoLayout);
|
||||||
|
|
||||||
|
// cleanup notifs
|
||||||
|
std::erase_if(m_dNotifications, [](const auto& notif) { return notif->started.getMillis() > notif->timeMs; });
|
||||||
|
|
||||||
|
return CBox{(int)(pMonitor->vecPosition.x + pMonitor->vecSize.x - maxWidth - 20), (int)pMonitor->vecPosition.y, (int)maxWidth + 20, (int)offsetY + 10};
|
||||||
|
}
|
||||||
|
|
||||||
|
void CHyprNotificationOverlay::draw(CMonitor* pMonitor) {
|
||||||
|
|
||||||
|
if (m_pLastMonitor != pMonitor || !m_pCairo || !m_pCairoSurface) {
|
||||||
|
|
||||||
|
if (m_pCairo && m_pCairoSurface) {
|
||||||
|
cairo_destroy(m_pCairo);
|
||||||
|
cairo_surface_destroy(m_pCairoSurface);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_pCairoSurface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y);
|
||||||
|
m_pCairo = cairo_create(m_pCairoSurface);
|
||||||
|
m_pLastMonitor = pMonitor;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw the notifications
|
||||||
|
if (m_dNotifications.size() == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Render to the monitor
|
||||||
|
|
||||||
|
// clear the pixmap
|
||||||
|
cairo_save(m_pCairo);
|
||||||
|
cairo_set_operator(m_pCairo, CAIRO_OPERATOR_CLEAR);
|
||||||
|
cairo_paint(m_pCairo);
|
||||||
|
cairo_restore(m_pCairo);
|
||||||
|
|
||||||
|
cairo_surface_flush(m_pCairoSurface);
|
||||||
|
|
||||||
|
CBox damage = drawNotifications(pMonitor);
|
||||||
|
|
||||||
|
g_pHyprRenderer->damageBox(&damage);
|
||||||
|
g_pHyprRenderer->damageBox(&m_bLastDamage);
|
||||||
|
|
||||||
|
g_pCompositor->scheduleFrameForMonitor(pMonitor);
|
||||||
|
|
||||||
|
m_bLastDamage = damage;
|
||||||
|
|
||||||
|
// copy the data to an OpenGL texture we have
|
||||||
|
const auto DATA = cairo_image_surface_get_data(m_pCairoSurface);
|
||||||
|
m_tTexture.allocate();
|
||||||
|
glBindTexture(GL_TEXTURE_2D, m_tTexture.m_iTexID);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||||
|
|
||||||
|
#ifndef GLES2
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_BLUE);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, DATA);
|
||||||
|
|
||||||
|
CBox pMonBox = {0, 0, pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y};
|
||||||
|
g_pHyprOpenGL->renderTexture(m_tTexture, &pMonBox, 1.f);
|
||||||
|
}
|
||||||
63
src/debug/HyprNotificationOverlay.hpp
Normal file
63
src/debug/HyprNotificationOverlay.hpp
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../defines.hpp"
|
||||||
|
#include "../helpers/Timer.hpp"
|
||||||
|
#include "../helpers/Monitor.hpp"
|
||||||
|
#include "../render/Texture.hpp"
|
||||||
|
#include "../SharedDefs.hpp"
|
||||||
|
|
||||||
|
#include <deque>
|
||||||
|
|
||||||
|
#include <cairo/cairo.h>
|
||||||
|
|
||||||
|
enum eIconBackend
|
||||||
|
{
|
||||||
|
ICONS_BACKEND_NONE = 0,
|
||||||
|
ICONS_BACKEND_NF,
|
||||||
|
ICONS_BACKEND_FA
|
||||||
|
};
|
||||||
|
|
||||||
|
static const std::array<std::array<std::string, ICON_NONE + 1>, 3 /* backends */> ICONS_ARRAY = {
|
||||||
|
std::array<std::string, ICON_NONE + 1>{"[!]", "[i]", "[Hint]", "[Err]", "[?]", "[ok]", ""}, std::array<std::string, ICON_NONE + 1>{"", "", "", "", "", "", ""},
|
||||||
|
std::array<std::string, ICON_NONE + 1>{"", "", "", "", "", ""}};
|
||||||
|
static const std::array<CColor, ICON_NONE + 1> ICONS_COLORS = {CColor{255.0 / 255.0, 204 / 255.0, 102 / 255.0, 1.0},
|
||||||
|
CColor{128 / 255.0, 255 / 255.0, 255 / 255.0, 1.0},
|
||||||
|
CColor{179 / 255.0, 255 / 255.0, 204 / 255.0, 1.0},
|
||||||
|
CColor{255 / 255.0, 77 / 255.0, 77 / 255.0, 1.0},
|
||||||
|
CColor{255 / 255.0, 204 / 255.0, 153 / 255.0, 1.0},
|
||||||
|
CColor{128 / 255.0, 255 / 255.0, 128 / 255.0, 1.0},
|
||||||
|
CColor{0, 0, 0, 1.0}};
|
||||||
|
|
||||||
|
struct SNotification {
|
||||||
|
std::string text = "";
|
||||||
|
CColor color;
|
||||||
|
CTimer started;
|
||||||
|
float timeMs = 0;
|
||||||
|
eIcons icon = ICON_NONE;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CHyprNotificationOverlay {
|
||||||
|
public:
|
||||||
|
CHyprNotificationOverlay();
|
||||||
|
|
||||||
|
void draw(CMonitor* pMonitor);
|
||||||
|
void addNotification(const std::string& text, const CColor& color, const float timeMs, const eIcons icon = ICON_NONE);
|
||||||
|
|
||||||
|
private:
|
||||||
|
CBox drawNotifications(CMonitor* pMonitor);
|
||||||
|
CBox m_bLastDamage;
|
||||||
|
|
||||||
|
std::deque<std::unique_ptr<SNotification>> m_dNotifications;
|
||||||
|
|
||||||
|
cairo_surface_t* m_pCairoSurface = nullptr;
|
||||||
|
cairo_t* m_pCairo = nullptr;
|
||||||
|
|
||||||
|
CMonitor* m_pLastMonitor = nullptr;
|
||||||
|
|
||||||
|
CTexture m_tTexture;
|
||||||
|
|
||||||
|
eIconBackend m_eIconBackend = ICONS_BACKEND_NONE;
|
||||||
|
std::string m_szIconFontName = "Sans";
|
||||||
|
};
|
||||||
|
|
||||||
|
inline std::unique_ptr<CHyprNotificationOverlay> g_pHyprNotificationOverlay;
|
||||||
@@ -5,86 +5,30 @@
|
|||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
void Debug::init(std::string IS) {
|
void Debug::init(const std::string& IS) {
|
||||||
logFile = "/tmp/hypr/" + IS + (ISDEBUG ? "/hyprlandd.log" : "/hyprland.log");
|
logFile = "/tmp/hypr/" + IS + (ISDEBUG ? "/hyprlandd.log" : "/hyprland.log");
|
||||||
}
|
}
|
||||||
|
|
||||||
void Debug::wlrLog(wlr_log_importance level, const char* fmt, va_list args) {
|
void Debug::wlrLog(wlr_log_importance level, const char* fmt, va_list args) {
|
||||||
char* outputStr = nullptr;
|
if (level > wlr_log_get_verbosity())
|
||||||
|
|
||||||
std::ofstream ofs;
|
|
||||||
ofs.open(logFile, std::ios::out | std::ios::app);
|
|
||||||
|
|
||||||
vasprintf(&outputStr, fmt, args);
|
|
||||||
|
|
||||||
std::string output = std::string(outputStr);
|
|
||||||
free(outputStr);
|
|
||||||
|
|
||||||
ofs << "[wlr] " << output << "\n";
|
|
||||||
|
|
||||||
ofs.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Debug::log(LogLevel level, const char* fmt, ...) {
|
|
||||||
|
|
||||||
if (disableLogs && *disableLogs)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// log to a file
|
|
||||||
std::ofstream ofs;
|
|
||||||
ofs.open(logFile, std::ios::out | std::ios::app);
|
|
||||||
|
|
||||||
switch (level) {
|
|
||||||
case LOG:
|
|
||||||
ofs << "[LOG] ";
|
|
||||||
break;
|
|
||||||
case WARN:
|
|
||||||
ofs << "[WARN] ";
|
|
||||||
break;
|
|
||||||
case ERR:
|
|
||||||
ofs << "[ERR] ";
|
|
||||||
break;
|
|
||||||
case CRIT:
|
|
||||||
ofs << "[CRITICAL] ";
|
|
||||||
break;
|
|
||||||
case INFO:
|
|
||||||
ofs << "[INFO] ";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// print date and time to the ofs
|
|
||||||
if (disableTime && !*disableTime) {
|
|
||||||
auto timet = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
|
|
||||||
const auto MILLIS = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count() % 1000;
|
|
||||||
|
|
||||||
ofs << std::put_time(std::localtime(&timet), "[%H:%M:%S:");
|
|
||||||
|
|
||||||
if (MILLIS > 99)
|
|
||||||
ofs << MILLIS;
|
|
||||||
else if (MILLIS > 9)
|
|
||||||
ofs << "0" << MILLIS;
|
|
||||||
else
|
|
||||||
ofs << "00" << MILLIS;
|
|
||||||
|
|
||||||
ofs << "] ";
|
|
||||||
}
|
|
||||||
|
|
||||||
char* outputStr = nullptr;
|
char* outputStr = nullptr;
|
||||||
|
|
||||||
va_list args;
|
|
||||||
va_start(args, fmt);
|
|
||||||
vasprintf(&outputStr, fmt, args);
|
vasprintf(&outputStr, fmt, args);
|
||||||
va_end(args);
|
|
||||||
|
|
||||||
std::string output = std::string(outputStr);
|
std::string output = std::string(outputStr);
|
||||||
free(outputStr);
|
free(outputStr);
|
||||||
|
|
||||||
ofs << output << "\n";
|
rollingLog += output + "\n";
|
||||||
|
|
||||||
ofs.close();
|
if (!disableLogs || !*disableLogs) {
|
||||||
|
std::ofstream ofs;
|
||||||
|
ofs.open(logFile, std::ios::out | std::ios::app);
|
||||||
|
ofs << "[wlr] " << output << "\n";
|
||||||
|
ofs.close();
|
||||||
|
}
|
||||||
|
|
||||||
// log it to the stdout too.
|
if (!disableStdout)
|
||||||
std::cout << output << "\n";
|
std::cout << output << "\n";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,24 +1,92 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <wlr/util/log.h>
|
#include <format>
|
||||||
|
#include <iostream>
|
||||||
|
#include <fstream>
|
||||||
|
#include <chrono>
|
||||||
|
#include "../includes.hpp"
|
||||||
|
#include "../helpers/MiscFunctions.hpp"
|
||||||
|
|
||||||
#define LOGMESSAGESIZE 1024
|
#define LOGMESSAGESIZE 1024
|
||||||
|
#define ROLLING_LOG_SIZE 4096
|
||||||
|
|
||||||
enum LogLevel {
|
enum LogLevel
|
||||||
|
{
|
||||||
NONE = -1,
|
NONE = -1,
|
||||||
LOG = 0,
|
LOG = 0,
|
||||||
WARN,
|
WARN,
|
||||||
ERR,
|
ERR,
|
||||||
CRIT,
|
CRIT,
|
||||||
INFO
|
INFO,
|
||||||
|
TRACE
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace Debug {
|
namespace Debug {
|
||||||
void init(std::string IS);
|
|
||||||
void log(LogLevel level, const char* fmt, ...);
|
|
||||||
void wlrLog(wlr_log_importance level, const char* fmt, va_list args);
|
|
||||||
|
|
||||||
inline std::string logFile;
|
inline std::string logFile;
|
||||||
inline int64_t* disableLogs = nullptr;
|
inline int64_t* disableLogs = nullptr;
|
||||||
inline int64_t* disableTime = nullptr;
|
inline int64_t* disableTime = nullptr;
|
||||||
};
|
inline bool disableStdout = false;
|
||||||
|
inline bool trace = false;
|
||||||
|
inline bool shuttingDown = false;
|
||||||
|
|
||||||
|
inline std::string rollingLog = ""; // rolling log contains the ROLLING_LOG_SIZE tail of the log
|
||||||
|
|
||||||
|
void init(const std::string& IS);
|
||||||
|
template <typename... Args>
|
||||||
|
void log(LogLevel level, std::format_string<Args...> fmt, Args&&... args) {
|
||||||
|
if (level == TRACE && !trace)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (shuttingDown)
|
||||||
|
return;
|
||||||
|
|
||||||
|
std::string logMsg = "";
|
||||||
|
|
||||||
|
switch (level) {
|
||||||
|
case LOG: logMsg += "[LOG] "; break;
|
||||||
|
case WARN: logMsg += "[WARN] "; break;
|
||||||
|
case ERR: logMsg += "[ERR] "; break;
|
||||||
|
case CRIT: logMsg += "[CRITICAL] "; break;
|
||||||
|
case INFO: logMsg += "[INFO] "; break;
|
||||||
|
case TRACE: logMsg += "[TRACE] "; break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// print date and time to the ofs
|
||||||
|
if (disableTime && !*disableTime) {
|
||||||
|
#ifndef _LIBCPP_VERSION
|
||||||
|
logMsg += std::format("[{:%T}] ", std::chrono::hh_mm_ss{std::chrono::system_clock::now() - std::chrono::floor<std::chrono::days>(std::chrono::system_clock::now())});
|
||||||
|
#else
|
||||||
|
auto c = std::chrono::hh_mm_ss{std::chrono::system_clock::now() - std::chrono::floor<std::chrono::days>(std::chrono::system_clock::now())};
|
||||||
|
logMsg += std::format("{:%H}:{:%M}:{:%S}", c.hours(), c.minutes(), c.subseconds());
|
||||||
|
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// no need for try {} catch {} because std::format_string<Args...> ensures that vformat never throw std::format_error
|
||||||
|
// because
|
||||||
|
// 1. any faulty format specifier that sucks will cause a compilation error.
|
||||||
|
// 2. and `std::bad_alloc` is catastrophic, (Almost any operation in stdlib could throw this.)
|
||||||
|
// 3. this is actually what std::format in stdlib does
|
||||||
|
logMsg += std::vformat(fmt.get(), std::make_format_args(args...));
|
||||||
|
|
||||||
|
rollingLog += logMsg + "\n";
|
||||||
|
if (rollingLog.size() > ROLLING_LOG_SIZE)
|
||||||
|
rollingLog = rollingLog.substr(rollingLog.size() - ROLLING_LOG_SIZE);
|
||||||
|
|
||||||
|
if (!disableLogs || !*disableLogs) {
|
||||||
|
// log to a file
|
||||||
|
std::ofstream ofs;
|
||||||
|
ofs.open(logFile, std::ios::out | std::ios::app);
|
||||||
|
ofs << logMsg << "\n";
|
||||||
|
|
||||||
|
ofs.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
// log it to the stdout too.
|
||||||
|
if (!disableStdout)
|
||||||
|
std::cout << logMsg << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
void wlrLog(wlr_log_importance level, const char* fmt, va_list args);
|
||||||
|
};
|
||||||
|
|||||||
26
src/debug/TracyDefines.hpp
Normal file
26
src/debug/TracyDefines.hpp
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef USE_TRACY_GPU
|
||||||
|
|
||||||
|
#include "Log.hpp"
|
||||||
|
|
||||||
|
#include <GL/gl.h>
|
||||||
|
#include <GLES2/gl2ext.h>
|
||||||
|
|
||||||
|
inline PFNGLQUERYCOUNTEREXTPROC glQueryCounter;
|
||||||
|
inline PFNGLGETQUERYOBJECTIVEXTPROC glGetQueryObjectiv;
|
||||||
|
inline PFNGLGETQUERYOBJECTUI64VEXTPROC glGetQueryObjectui64v;
|
||||||
|
|
||||||
|
#include "../../subprojects/tracy/public/tracy/TracyOpenGL.hpp"
|
||||||
|
|
||||||
|
#define TRACY_GPU_CONTEXT TracyGpuContext
|
||||||
|
#define TRACY_GPU_ZONE(e) TracyGpuZone(e)
|
||||||
|
#define TRACY_GPU_COLLECT TracyGpuCollect
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define TRACY_GPU_CONTEXT
|
||||||
|
#define TRACY_GPU_ZONE(e)
|
||||||
|
#define TRACY_GPU_COLLECT
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,77 +1,5 @@
|
|||||||
#include "includes.hpp"
|
#include "includes.hpp"
|
||||||
#include "debug/Log.hpp"
|
#include "debug/Log.hpp"
|
||||||
#include "helpers/MiscFunctions.hpp"
|
|
||||||
#include "helpers/WLListener.hpp"
|
#include "helpers/WLListener.hpp"
|
||||||
#include "helpers/Color.hpp"
|
#include "helpers/Color.hpp"
|
||||||
|
#include "macros.hpp"
|
||||||
#include "wlrunstable/wlr_ext_workspace_v1.hpp"
|
|
||||||
|
|
||||||
#ifndef NDEBUG
|
|
||||||
#ifdef HYPRLAND_DEBUG
|
|
||||||
#define ISDEBUG true
|
|
||||||
#else
|
|
||||||
#define ISDEBUG false
|
|
||||||
#endif
|
|
||||||
#else
|
|
||||||
#define ISDEBUG false
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define LISTENER(name) void listener_##name(wl_listener*, void*); inline wl_listener listen_##name = { .notify = listener_##name };
|
|
||||||
#define DYNLISTENFUNC(name) void listener_##name(void*, void*);
|
|
||||||
#define DYNLISTENER(name) CHyprWLListener hyprListener_##name;
|
|
||||||
#define DYNMULTILISTENER(name) wl_listener listen_##name;
|
|
||||||
|
|
||||||
#define VECINRECT(vec, x1, y1, x2, y2) (vec.x >= (x1) && vec.x <= (x2) && vec.y >= (y1) && vec.y <= (y2))
|
|
||||||
|
|
||||||
#define DELTALESSTHAN(a, b, delta) (abs((a) - (b)) < delta)
|
|
||||||
|
|
||||||
#define PIXMAN_DAMAGE_FOREACH(region) int rectsNum = 0; \
|
|
||||||
const auto RECTSARR = pixman_region32_rectangles(region, &rectsNum); \
|
|
||||||
for (int i = 0; i < rectsNum; ++i)
|
|
||||||
|
|
||||||
|
|
||||||
#define interface class
|
|
||||||
|
|
||||||
#define STICKS(a, b) abs((a) - (b)) < 2
|
|
||||||
|
|
||||||
#define ALPHA(c) ((double)(((c) >> 24) & 0xff) / 255.0)
|
|
||||||
#define RED(c) ((double)(((c) >> 16) & 0xff) / 255.0)
|
|
||||||
#define GREEN(c) ((double)(((c) >> 8) & 0xff) / 255.0)
|
|
||||||
#define BLUE(c) ((double)(((c)) & 0xff) / 255.0)
|
|
||||||
|
|
||||||
#define HYPRATOM(name) {name, 0}
|
|
||||||
|
|
||||||
#ifndef __INTELLISENSE__
|
|
||||||
#define RASSERT(expr, reason, ...) \
|
|
||||||
if (!(expr)) { \
|
|
||||||
Debug::log(CRIT, "\n==========================================================================================\nASSERTION FAILED! \n\n%s\n\nat: line %d in %s", getFormat(reason, ##__VA_ARGS__).c_str(), __LINE__, ([]() constexpr->std::string { return std::string(__FILE__).substr(std::string(__FILE__).find_last_of('/') + 1); })().c_str()); \
|
|
||||||
printf("Assertion failed! See the log in /tmp/hypr/hyprland.log for more info."); \
|
|
||||||
*((int*)nullptr) = 1; /* so that we crash and get a coredump */ \
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
#define RASSERT(expr, reason, ...)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define ASSERT(expr) RASSERT(expr, "?")
|
|
||||||
|
|
||||||
#if ISDEBUG
|
|
||||||
#define UNREACHABLE() { Debug::log(CRIT, "\n\nMEMORY CORRUPTED: Unreachable failed! (Reached an unreachable position, memory corruption!!!)"); *((int*)nullptr) = 1; }
|
|
||||||
#else
|
|
||||||
#define UNREACHABLE() std::unreachable();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// git stuff
|
|
||||||
#ifndef GIT_COMMIT_HASH
|
|
||||||
#define GIT_COMMIT_HASH "?"
|
|
||||||
#endif
|
|
||||||
#ifndef GIT_BRANCH
|
|
||||||
#define GIT_BRANCH "?"
|
|
||||||
#endif
|
|
||||||
#ifndef GIT_COMMIT_MESSAGE
|
|
||||||
#define GIT_COMMIT_MESSAGE "?"
|
|
||||||
#endif
|
|
||||||
#ifndef GIT_DIRTY
|
|
||||||
#define GIT_DIRTY "?"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define SPECIAL_WORKSPACE_ID -99
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ void Events::listener_keyboardDestroy(void* owner, void* data) {
|
|||||||
SKeyboard* PKEYBOARD = (SKeyboard*)owner;
|
SKeyboard* PKEYBOARD = (SKeyboard*)owner;
|
||||||
g_pInputManager->destroyKeyboard(PKEYBOARD);
|
g_pInputManager->destroyKeyboard(PKEYBOARD);
|
||||||
|
|
||||||
Debug::log(LOG, "Destroyed keyboard %x", PKEYBOARD);
|
Debug::log(LOG, "Destroyed keyboard {:x}", (uintptr_t)PKEYBOARD);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Events::listener_keyboardKey(void* owner, void* data) {
|
void Events::listener_keyboardKey(void* owner, void* data) {
|
||||||
@@ -61,48 +61,46 @@ void Events::listener_requestMouse(wl_listener* listener, void* data) {
|
|||||||
void Events::listener_newInput(wl_listener* listener, void* data) {
|
void Events::listener_newInput(wl_listener* listener, void* data) {
|
||||||
const auto DEVICE = (wlr_input_device*)data;
|
const auto DEVICE = (wlr_input_device*)data;
|
||||||
|
|
||||||
switch(DEVICE->type) {
|
switch (DEVICE->type) {
|
||||||
case WLR_INPUT_DEVICE_KEYBOARD:
|
case WLR_INPUT_DEVICE_KEYBOARD:
|
||||||
Debug::log(LOG, "Attached a keyboard with name %s", DEVICE->name);
|
Debug::log(LOG, "Attached a keyboard with name {}", DEVICE->name);
|
||||||
g_pInputManager->newKeyboard(DEVICE);
|
g_pInputManager->newKeyboard(DEVICE);
|
||||||
break;
|
break;
|
||||||
case WLR_INPUT_DEVICE_POINTER:
|
case WLR_INPUT_DEVICE_POINTER:
|
||||||
Debug::log(LOG, "Attached a mouse with name %s", DEVICE->name);
|
Debug::log(LOG, "Attached a mouse with name {}", DEVICE->name);
|
||||||
g_pInputManager->newMouse(DEVICE);
|
g_pInputManager->newMouse(DEVICE);
|
||||||
break;
|
break;
|
||||||
case WLR_INPUT_DEVICE_TOUCH:
|
case WLR_INPUT_DEVICE_TOUCH:
|
||||||
Debug::log(LOG, "Attached a touch device with name %s", DEVICE->name);
|
Debug::log(LOG, "Attached a touch device with name {}", DEVICE->name);
|
||||||
g_pInputManager->newTouchDevice(DEVICE);
|
g_pInputManager->newTouchDevice(DEVICE);
|
||||||
break;
|
break;
|
||||||
case WLR_INPUT_DEVICE_TABLET_TOOL:
|
case WLR_INPUT_DEVICE_TABLET_TOOL:
|
||||||
Debug::log(LOG, "Attached a tablet tool with name %s", DEVICE->name);
|
Debug::log(LOG, "Attached a tablet tool with name {}", DEVICE->name);
|
||||||
g_pInputManager->newTabletTool(DEVICE);
|
g_pInputManager->newTabletTool(DEVICE);
|
||||||
break;
|
break;
|
||||||
case WLR_INPUT_DEVICE_TABLET_PAD:
|
case WLR_INPUT_DEVICE_TABLET_PAD:
|
||||||
Debug::log(LOG, "Attached a tablet pad with name %s", DEVICE->name);
|
Debug::log(LOG, "Attached a tablet pad with name {}", DEVICE->name);
|
||||||
g_pInputManager->newTabletPad(DEVICE);
|
g_pInputManager->newTabletPad(DEVICE);
|
||||||
break;
|
break;
|
||||||
case WLR_INPUT_DEVICE_SWITCH:
|
case WLR_INPUT_DEVICE_SWITCH:
|
||||||
Debug::log(LOG, "Attached a switch device with name %s", DEVICE->name);
|
Debug::log(LOG, "Attached a switch device with name {}", DEVICE->name);
|
||||||
g_pInputManager->newSwitch(DEVICE);
|
g_pInputManager->newSwitch(DEVICE);
|
||||||
break;
|
break;
|
||||||
default:
|
default: Debug::log(WARN, "Unrecognized input device plugged in: {}", DEVICE->name); break;
|
||||||
Debug::log(WARN, "Unrecognized input device plugged in: %s", DEVICE->name);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
g_pInputManager->updateCapabilities(DEVICE);
|
g_pInputManager->updateCapabilities();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Events::listener_newConstraint(wl_listener* listener, void* data) {
|
void Events::listener_newConstraint(wl_listener* listener, void* data) {
|
||||||
const auto PCONSTRAINT = (wlr_pointer_constraint_v1*)data;
|
const auto PCONSTRAINT = (wlr_pointer_constraint_v1*)data;
|
||||||
|
|
||||||
Debug::log(LOG, "New mouse constraint at %x", PCONSTRAINT);
|
Debug::log(LOG, "New mouse constraint at {:x}", (uintptr_t)PCONSTRAINT);
|
||||||
|
|
||||||
g_pInputManager->m_lConstraints.emplace_back();
|
g_pInputManager->m_lConstraints.emplace_back();
|
||||||
const auto CONSTRAINT = &g_pInputManager->m_lConstraints.back();
|
const auto CONSTRAINT = &g_pInputManager->m_lConstraints.back();
|
||||||
|
|
||||||
CONSTRAINT->pMouse = g_pCompositor->m_sSeat.mouse;
|
CONSTRAINT->pMouse = g_pCompositor->m_sSeat.mouse;
|
||||||
CONSTRAINT->constraint = PCONSTRAINT;
|
CONSTRAINT->constraint = PCONSTRAINT;
|
||||||
|
|
||||||
CONSTRAINT->hyprListener_destroyConstraint.initCallback(&PCONSTRAINT->events.destroy, &Events::listener_destroyConstraint, CONSTRAINT, "Constraint");
|
CONSTRAINT->hyprListener_destroyConstraint.initCallback(&PCONSTRAINT->events.destroy, &Events::listener_destroyConstraint, CONSTRAINT, "Constraint");
|
||||||
@@ -110,6 +108,9 @@ void Events::listener_newConstraint(wl_listener* listener, void* data) {
|
|||||||
|
|
||||||
if (g_pCompositor->m_pLastFocus == PCONSTRAINT->surface) {
|
if (g_pCompositor->m_pLastFocus == PCONSTRAINT->surface) {
|
||||||
g_pInputManager->constrainMouse(CONSTRAINT->pMouse, PCONSTRAINT);
|
g_pInputManager->constrainMouse(CONSTRAINT->pMouse, PCONSTRAINT);
|
||||||
|
|
||||||
|
if (!CONSTRAINT->hintSet)
|
||||||
|
CONSTRAINT->positionHint = Vector2D{-1, -1};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -121,24 +122,13 @@ void Events::listener_destroyConstraint(void* owner, void* data) {
|
|||||||
|
|
||||||
const auto PWINDOW = g_pCompositor->getConstraintWindow(g_pCompositor->m_sSeat.mouse);
|
const auto PWINDOW = g_pCompositor->getConstraintWindow(g_pCompositor->m_sSeat.mouse);
|
||||||
|
|
||||||
if (PWINDOW) {
|
if (PWINDOW && PCONSTRAINT->active && PCONSTRAINT->constraint->type == WLR_POINTER_CONSTRAINT_V1_LOCKED)
|
||||||
if (PWINDOW->m_bIsX11) {
|
g_pInputManager->warpMouseToConstraintMiddle(PCONSTRAINT);
|
||||||
wlr_cursor_warp(g_pCompositor->m_sWLRCursor, nullptr,
|
|
||||||
PCONSTRAINT->constraint->current.cursor_hint.x + PWINDOW->m_uSurface.xwayland->x, PWINDOW->m_uSurface.xwayland->y + PCONSTRAINT->constraint->current.cursor_hint.y);
|
|
||||||
|
|
||||||
wlr_seat_pointer_warp(PCONSTRAINT->constraint->seat, PCONSTRAINT->constraint->current.cursor_hint.x, PCONSTRAINT->constraint->current.cursor_hint.y);
|
|
||||||
} else {
|
|
||||||
wlr_cursor_warp(g_pCompositor->m_sWLRCursor, nullptr,
|
|
||||||
PCONSTRAINT->constraint->current.cursor_hint.x + PWINDOW->m_vRealPosition.vec().x, PCONSTRAINT->constraint->current.cursor_hint.y + PWINDOW->m_vRealPosition.vec().y);
|
|
||||||
|
|
||||||
wlr_seat_pointer_warp(PCONSTRAINT->constraint->seat, PCONSTRAINT->constraint->current.cursor_hint.x, PCONSTRAINT->constraint->current.cursor_hint.y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PCONSTRAINT->pMouse->currentConstraint = nullptr;
|
PCONSTRAINT->pMouse->currentConstraint = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Debug::log(LOG, "Unconstrained mouse from %x", PCONSTRAINT->constraint);
|
Debug::log(LOG, "Unconstrained mouse from {:x}", (uintptr_t)PCONSTRAINT->constraint);
|
||||||
|
|
||||||
g_pInputManager->m_lConstraints.remove(*PCONSTRAINT);
|
g_pInputManager->m_lConstraints.remove(*PCONSTRAINT);
|
||||||
}
|
}
|
||||||
@@ -148,9 +138,9 @@ void Events::listener_setConstraintRegion(void* owner, void* data) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Events::listener_newVirtPtr(wl_listener* listener, void* data) {
|
void Events::listener_newVirtPtr(wl_listener* listener, void* data) {
|
||||||
const auto EV = (wlr_virtual_pointer_v1_new_pointer_event*)data;
|
const auto EV = (wlr_virtual_pointer_v1_new_pointer_event*)data;
|
||||||
const auto POINTER = EV->new_pointer;
|
const auto POINTER = EV->new_pointer;
|
||||||
const auto DEVICE = &POINTER->pointer.base;
|
const auto DEVICE = &POINTER->pointer.base;
|
||||||
|
|
||||||
g_pInputManager->newMouse(DEVICE, true);
|
g_pInputManager->newMouse(DEVICE, true);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ namespace Events {
|
|||||||
DYNLISTENFUNC(commitSubsurface);
|
DYNLISTENFUNC(commitSubsurface);
|
||||||
|
|
||||||
// Popups
|
// Popups
|
||||||
DYNLISTENFUNC(newPopup); // LayerSurface
|
DYNLISTENFUNC(newPopup); // LayerSurface
|
||||||
|
|
||||||
DYNLISTENFUNC(newPopupXDG);
|
DYNLISTENFUNC(newPopupXDG);
|
||||||
DYNLISTENFUNC(mapPopupXDG);
|
DYNLISTENFUNC(mapPopupXDG);
|
||||||
@@ -39,9 +39,10 @@ namespace Events {
|
|||||||
DYNLISTENFUNC(destroyPopupXDG);
|
DYNLISTENFUNC(destroyPopupXDG);
|
||||||
DYNLISTENFUNC(commitPopupXDG);
|
DYNLISTENFUNC(commitPopupXDG);
|
||||||
DYNLISTENFUNC(newPopupFromPopupXDG);
|
DYNLISTENFUNC(newPopupFromPopupXDG);
|
||||||
|
DYNLISTENFUNC(repositionPopupXDG);
|
||||||
|
|
||||||
// Surface XDG (window)
|
// Surface XDG (window)
|
||||||
LISTENER(newXDGSurface);
|
LISTENER(newXDGToplevel);
|
||||||
LISTENER(activateXDG);
|
LISTENER(activateXDG);
|
||||||
|
|
||||||
// Window events
|
// Window events
|
||||||
@@ -58,9 +59,13 @@ namespace Events {
|
|||||||
DYNLISTENFUNC(requestResize);
|
DYNLISTENFUNC(requestResize);
|
||||||
DYNLISTENFUNC(requestMinimize);
|
DYNLISTENFUNC(requestMinimize);
|
||||||
DYNLISTENFUNC(requestMaximize);
|
DYNLISTENFUNC(requestMaximize);
|
||||||
|
DYNLISTENFUNC(setOverrideRedirect);
|
||||||
|
DYNLISTENFUNC(associateX11);
|
||||||
|
DYNLISTENFUNC(dissociateX11);
|
||||||
|
DYNLISTENFUNC(ackConfigure);
|
||||||
|
|
||||||
// Window subsurfaces
|
// Window subsurfaces
|
||||||
// LISTENER(newSubsurfaceWindow);
|
// LISTENER(newSubsurfaceWindow);
|
||||||
|
|
||||||
// Input events
|
// Input events
|
||||||
LISTENER(mouseMove);
|
LISTENER(mouseMove);
|
||||||
@@ -96,6 +101,11 @@ namespace Events {
|
|||||||
// Monitor part 2 the sequel
|
// Monitor part 2 the sequel
|
||||||
DYNLISTENFUNC(monitorFrame);
|
DYNLISTENFUNC(monitorFrame);
|
||||||
DYNLISTENFUNC(monitorDestroy);
|
DYNLISTENFUNC(monitorDestroy);
|
||||||
|
DYNLISTENFUNC(monitorStateRequest);
|
||||||
|
DYNLISTENFUNC(monitorDamage);
|
||||||
|
DYNLISTENFUNC(monitorNeedsFrame);
|
||||||
|
DYNLISTENFUNC(monitorCommit);
|
||||||
|
DYNLISTENFUNC(monitorBind);
|
||||||
|
|
||||||
// XWayland
|
// XWayland
|
||||||
LISTENER(readyXWayland);
|
LISTENER(readyXWayland);
|
||||||
@@ -111,10 +121,6 @@ namespace Events {
|
|||||||
DYNLISTENFUNC(destroyDragIcon);
|
DYNLISTENFUNC(destroyDragIcon);
|
||||||
DYNLISTENFUNC(commitDragIcon);
|
DYNLISTENFUNC(commitDragIcon);
|
||||||
|
|
||||||
// Inhibit
|
|
||||||
LISTENER(InhibitActivate);
|
|
||||||
LISTENER(InhibitDeactivate);
|
|
||||||
|
|
||||||
// Deco XDG
|
// Deco XDG
|
||||||
LISTENER(NewXDGDeco);
|
LISTENER(NewXDGDeco);
|
||||||
|
|
||||||
@@ -156,4 +162,16 @@ namespace Events {
|
|||||||
|
|
||||||
LISTENER(holdBegin);
|
LISTENER(holdBegin);
|
||||||
LISTENER(holdEnd);
|
LISTENER(holdEnd);
|
||||||
|
|
||||||
|
// Session Lock
|
||||||
|
LISTENER(newSessionLock);
|
||||||
|
|
||||||
|
// Gamma control
|
||||||
|
LISTENER(setGamma);
|
||||||
|
|
||||||
|
// Cursor shape
|
||||||
|
LISTENER(setCursorShape);
|
||||||
|
|
||||||
|
// Tearing hints
|
||||||
|
LISTENER(newTearingHint);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -26,40 +26,43 @@ void Events::listener_newLayerSurface(wl_listener* listener, void* data) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Debug::log(LOG, "New LayerSurface has no preferred monitor. Assigning Monitor %s", PMONITOR->szName.c_str());
|
Debug::log(LOG, "New LayerSurface has no preferred monitor. Assigning Monitor {}", PMONITOR->szName);
|
||||||
|
|
||||||
WLRLAYERSURFACE->output = PMONITOR->output;
|
WLRLAYERSURFACE->output = PMONITOR->output;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto PMONITOR = (CMonitor*)g_pCompositor->getMonitorFromOutput(WLRLAYERSURFACE->output);
|
auto PMONITOR = (CMonitor*)g_pCompositor->getMonitorFromOutput(WLRLAYERSURFACE->output);
|
||||||
SLayerSurface* layerSurface = PMONITOR->m_aLayerSurfaceLists[WLRLAYERSURFACE->pending.layer].emplace_back(std::make_unique<SLayerSurface>()).get();
|
|
||||||
|
if (!WLRLAYERSURFACE->output || !PMONITOR || PMONITOR->pMirrorOf) {
|
||||||
|
PMONITOR = g_pCompositor->m_vMonitors.front().get();
|
||||||
|
WLRLAYERSURFACE->output = PMONITOR->output; // TODO: current mon
|
||||||
|
}
|
||||||
|
|
||||||
|
SLayerSurface* layerSurface = PMONITOR->m_aLayerSurfaceLayers[WLRLAYERSURFACE->pending.layer].emplace_back(std::make_unique<SLayerSurface>()).get();
|
||||||
|
|
||||||
layerSurface->szNamespace = WLRLAYERSURFACE->_namespace;
|
layerSurface->szNamespace = WLRLAYERSURFACE->_namespace;
|
||||||
|
|
||||||
if (!WLRLAYERSURFACE->output) {
|
|
||||||
WLRLAYERSURFACE->output = g_pCompositor->m_vMonitors.front()->output; // TODO: current mon
|
|
||||||
}
|
|
||||||
|
|
||||||
layerSurface->hyprListener_commitLayerSurface.initCallback(&WLRLAYERSURFACE->surface->events.commit, &Events::listener_commitLayerSurface, layerSurface, "layerSurface");
|
layerSurface->hyprListener_commitLayerSurface.initCallback(&WLRLAYERSURFACE->surface->events.commit, &Events::listener_commitLayerSurface, layerSurface, "layerSurface");
|
||||||
layerSurface->hyprListener_destroyLayerSurface.initCallback(&WLRLAYERSURFACE->events.destroy, &Events::listener_destroyLayerSurface, layerSurface, "layerSurface");
|
layerSurface->hyprListener_destroyLayerSurface.initCallback(&WLRLAYERSURFACE->events.destroy, &Events::listener_destroyLayerSurface, layerSurface, "layerSurface");
|
||||||
layerSurface->hyprListener_mapLayerSurface.initCallback(&WLRLAYERSURFACE->events.map, &Events::listener_mapLayerSurface, layerSurface, "layerSurface");
|
layerSurface->hyprListener_mapLayerSurface.initCallback(&WLRLAYERSURFACE->surface->events.map, &Events::listener_mapLayerSurface, layerSurface, "layerSurface");
|
||||||
layerSurface->hyprListener_unmapLayerSurface.initCallback(&WLRLAYERSURFACE->events.unmap, &Events::listener_unmapLayerSurface, layerSurface, "layerSurface");
|
layerSurface->hyprListener_unmapLayerSurface.initCallback(&WLRLAYERSURFACE->surface->events.unmap, &Events::listener_unmapLayerSurface, layerSurface, "layerSurface");
|
||||||
layerSurface->hyprListener_newPopup.initCallback(&WLRLAYERSURFACE->events.new_popup, &Events::listener_newPopup, layerSurface, "layerSurface");
|
layerSurface->hyprListener_newPopup.initCallback(&WLRLAYERSURFACE->events.new_popup, &Events::listener_newPopup, layerSurface, "layerSurface");
|
||||||
|
|
||||||
layerSurface->layerSurface = WLRLAYERSURFACE;
|
layerSurface->layerSurface = WLRLAYERSURFACE;
|
||||||
layerSurface->layer = WLRLAYERSURFACE->current.layer;
|
layerSurface->layer = WLRLAYERSURFACE->current.layer;
|
||||||
WLRLAYERSURFACE->data = layerSurface;
|
WLRLAYERSURFACE->data = layerSurface;
|
||||||
layerSurface->monitorID = PMONITOR->ID;
|
layerSurface->monitorID = PMONITOR->ID;
|
||||||
|
|
||||||
layerSurface->forceBlur = g_pConfigManager->shouldBlurLS(layerSurface->szNamespace);
|
layerSurface->forceBlur = g_pConfigManager->shouldBlurLS(layerSurface->szNamespace);
|
||||||
|
|
||||||
Debug::log(LOG, "LayerSurface %x (namespace %s layer %d) created on monitor %s", layerSurface->layerSurface, layerSurface->layerSurface->_namespace, layerSurface->layer, PMONITOR->szName.c_str());
|
Debug::log(LOG, "LayerSurface {:x} (namespace {} layer {}) created on monitor {}", (uintptr_t)layerSurface->layerSurface, layerSurface->layerSurface->_namespace,
|
||||||
|
(int)layerSurface->layer, PMONITOR->szName);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Events::listener_destroyLayerSurface(void* owner, void* data) {
|
void Events::listener_destroyLayerSurface(void* owner, void* data) {
|
||||||
SLayerSurface* layersurface = (SLayerSurface*)owner;
|
SLayerSurface* layersurface = (SLayerSurface*)owner;
|
||||||
|
|
||||||
Debug::log(LOG, "LayerSurface %x destroyed", layersurface->layerSurface);
|
Debug::log(LOG, "LayerSurface {:x} destroyed", (uintptr_t)layersurface->layerSurface);
|
||||||
|
|
||||||
const auto PMONITOR = g_pCompositor->getMonitorFromID(layersurface->monitorID);
|
const auto PMONITOR = g_pCompositor->getMonitorFromID(layersurface->monitorID);
|
||||||
|
|
||||||
@@ -92,21 +95,23 @@ void Events::listener_destroyLayerSurface(void* owner, void* data) {
|
|||||||
PMONITOR->scheduledRecalc = true;
|
PMONITOR->scheduledRecalc = true;
|
||||||
|
|
||||||
// and damage
|
// and damage
|
||||||
wlr_box geomFixed = {layersurface->geometry.x + PMONITOR->vecPosition.x, layersurface->geometry.y + PMONITOR->vecPosition.y, layersurface->geometry.width, layersurface->geometry.height};
|
CBox geomFixed = {layersurface->geometry.x + PMONITOR->vecPosition.x, layersurface->geometry.y + PMONITOR->vecPosition.y, layersurface->geometry.width,
|
||||||
|
layersurface->geometry.height};
|
||||||
g_pHyprRenderer->damageBox(&geomFixed);
|
g_pHyprRenderer->damageBox(&geomFixed);
|
||||||
}
|
}
|
||||||
|
|
||||||
layersurface->readyToDelete = true;
|
layersurface->readyToDelete = true;
|
||||||
layersurface->layerSurface = nullptr;
|
layersurface->layerSurface = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Events::listener_mapLayerSurface(void* owner, void* data) {
|
void Events::listener_mapLayerSurface(void* owner, void* data) {
|
||||||
SLayerSurface* layersurface = (SLayerSurface*)owner;
|
SLayerSurface* layersurface = (SLayerSurface*)owner;
|
||||||
|
|
||||||
Debug::log(LOG, "LayerSurface %x mapped", layersurface->layerSurface);
|
Debug::log(LOG, "LayerSurface {:x} mapped", (uintptr_t)layersurface->layerSurface);
|
||||||
|
|
||||||
layersurface->layerSurface->mapped = true;
|
layersurface->mapped = true;
|
||||||
layersurface->mapped = true;
|
layersurface->keyboardExclusive = layersurface->layerSurface->current.keyboard_interactive;
|
||||||
|
layersurface->surface = layersurface->layerSurface->surface;
|
||||||
|
|
||||||
// anim
|
// anim
|
||||||
layersurface->alpha.setConfig(g_pConfigManager->getAnimationPropertyConfig("fadeIn"));
|
layersurface->alpha.setConfig(g_pConfigManager->getAnimationPropertyConfig("fadeIn"));
|
||||||
@@ -117,16 +122,18 @@ void Events::listener_mapLayerSurface(void* owner, void* data) {
|
|||||||
if (!PMONITOR)
|
if (!PMONITOR)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
layersurface->applyRules();
|
||||||
|
|
||||||
if ((uint64_t)layersurface->monitorID != PMONITOR->ID) {
|
if ((uint64_t)layersurface->monitorID != PMONITOR->ID) {
|
||||||
const auto POLDMON = g_pCompositor->getMonitorFromID(layersurface->monitorID);
|
const auto POLDMON = g_pCompositor->getMonitorFromID(layersurface->monitorID);
|
||||||
for (auto it = POLDMON->m_aLayerSurfaceLists[layersurface->layer].begin(); it != POLDMON->m_aLayerSurfaceLists[layersurface->layer].end(); it++) {
|
for (auto it = POLDMON->m_aLayerSurfaceLayers[layersurface->layer].begin(); it != POLDMON->m_aLayerSurfaceLayers[layersurface->layer].end(); it++) {
|
||||||
if (it->get() == layersurface) {
|
if (it->get() == layersurface) {
|
||||||
PMONITOR->m_aLayerSurfaceLists[layersurface->layer].emplace_back(std::move(*it));
|
PMONITOR->m_aLayerSurfaceLayers[layersurface->layer].emplace_back(std::move(*it));
|
||||||
POLDMON->m_aLayerSurfaceLists[layersurface->layer].erase(it);
|
POLDMON->m_aLayerSurfaceLayers[layersurface->layer].erase(it);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
layersurface->monitorID = PMONITOR->ID;
|
layersurface->monitorID = PMONITOR->ID;
|
||||||
PMONITOR->scheduledRecalc = true;
|
PMONITOR->scheduledRecalc = true;
|
||||||
g_pHyprRenderer->arrangeLayersForMonitor(POLDMON->ID);
|
g_pHyprRenderer->arrangeLayersForMonitor(POLDMON->ID);
|
||||||
}
|
}
|
||||||
@@ -135,33 +142,46 @@ void Events::listener_mapLayerSurface(void* owner, void* data) {
|
|||||||
|
|
||||||
wlr_surface_send_enter(layersurface->layerSurface->surface, layersurface->layerSurface->output);
|
wlr_surface_send_enter(layersurface->layerSurface->surface, layersurface->layerSurface->output);
|
||||||
|
|
||||||
if (layersurface->layerSurface->current.keyboard_interactive && (!g_pCompositor->m_sSeat.mouse || !g_pCompositor->m_sSeat.mouse->currentConstraint)) { // don't focus if constrained
|
const bool GRABSFOCUS = layersurface->layerSurface->current.keyboard_interactive != ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE &&
|
||||||
|
// don't focus if constrained
|
||||||
|
(!g_pCompositor->m_sSeat.mouse || !g_pCompositor->m_sSeat.mouse->currentConstraint);
|
||||||
|
|
||||||
|
if (GRABSFOCUS) {
|
||||||
g_pCompositor->focusSurface(layersurface->layerSurface->surface);
|
g_pCompositor->focusSurface(layersurface->layerSurface->surface);
|
||||||
|
|
||||||
const auto LOCAL = g_pInputManager->getMouseCoordsInternal() - Vector2D(layersurface->geometry.x + PMONITOR->vecPosition.x, layersurface->geometry.y + PMONITOR->vecPosition.y);
|
const auto LOCAL =
|
||||||
|
g_pInputManager->getMouseCoordsInternal() - Vector2D(layersurface->geometry.x + PMONITOR->vecPosition.x, layersurface->geometry.y + PMONITOR->vecPosition.y);
|
||||||
wlr_seat_pointer_notify_enter(g_pCompositor->m_sSeat.seat, layersurface->layerSurface->surface, LOCAL.x, LOCAL.y);
|
wlr_seat_pointer_notify_enter(g_pCompositor->m_sSeat.seat, layersurface->layerSurface->surface, LOCAL.x, LOCAL.y);
|
||||||
wlr_seat_pointer_notify_motion(g_pCompositor->m_sSeat.seat, 0, LOCAL.x, LOCAL.y);
|
wlr_seat_pointer_notify_motion(g_pCompositor->m_sSeat.seat, 0, LOCAL.x, LOCAL.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
layersurface->position = Vector2D(layersurface->geometry.x, layersurface->geometry.y);
|
layersurface->position = Vector2D(layersurface->geometry.x, layersurface->geometry.y);
|
||||||
|
|
||||||
wlr_box geomFixed = {layersurface->geometry.x + PMONITOR->vecPosition.x, layersurface->geometry.y + PMONITOR->vecPosition.y, layersurface->geometry.width, layersurface->geometry.height};
|
CBox geomFixed = {layersurface->geometry.x + PMONITOR->vecPosition.x, layersurface->geometry.y + PMONITOR->vecPosition.y, layersurface->geometry.width,
|
||||||
|
layersurface->geometry.height};
|
||||||
g_pHyprRenderer->damageBox(&geomFixed);
|
g_pHyprRenderer->damageBox(&geomFixed);
|
||||||
|
const auto WORKSPACE = g_pCompositor->getWorkspaceByID(PMONITOR->activeWorkspace);
|
||||||
|
const bool FULLSCREEN = WORKSPACE->m_bHasFullscreenWindow && WORKSPACE->m_efFullscreenMode == FULLSCREEN_FULL;
|
||||||
|
|
||||||
layersurface->alpha.setValue(0);
|
layersurface->alpha.setValue(0);
|
||||||
layersurface->alpha = 255.f;
|
layersurface->alpha = ((layersurface->layer == ZWLR_LAYER_SHELL_V1_LAYER_TOP && FULLSCREEN && !GRABSFOCUS) ? 0.f : 1.f);
|
||||||
layersurface->readyToDelete = false;
|
layersurface->readyToDelete = false;
|
||||||
layersurface->fadingOut = false;
|
layersurface->fadingOut = false;
|
||||||
|
|
||||||
g_pEventManager->postEvent(SHyprIPCEvent{"openlayer", std::string(layersurface->layerSurface->_namespace ? layersurface->layerSurface->_namespace : "")});
|
g_pEventManager->postEvent(SHyprIPCEvent{"openlayer", std::string(layersurface->layerSurface->_namespace ? layersurface->layerSurface->_namespace : "")});
|
||||||
|
EMIT_HOOK_EVENT("openLayer", layersurface);
|
||||||
|
|
||||||
|
g_pCompositor->setPreferredScaleForSurface(layersurface->layerSurface->surface, PMONITOR->scale);
|
||||||
|
g_pCompositor->setPreferredTransformForSurface(layersurface->layerSurface->surface, PMONITOR->transform);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Events::listener_unmapLayerSurface(void* owner, void* data) {
|
void Events::listener_unmapLayerSurface(void* owner, void* data) {
|
||||||
SLayerSurface* layersurface = (SLayerSurface*)owner;
|
SLayerSurface* layersurface = (SLayerSurface*)owner;
|
||||||
|
|
||||||
Debug::log(LOG, "LayerSurface %x unmapped", layersurface->layerSurface);
|
Debug::log(LOG, "LayerSurface {:x} unmapped", (uintptr_t)layersurface->layerSurface);
|
||||||
|
|
||||||
g_pEventManager->postEvent(SHyprIPCEvent{"closelayer", std::string(layersurface->layerSurface->_namespace ? layersurface->layerSurface->_namespace : "")});
|
g_pEventManager->postEvent(SHyprIPCEvent{"closelayer", std::string(layersurface->layerSurface->_namespace ? layersurface->layerSurface->_namespace : "")});
|
||||||
|
EMIT_HOOK_EVENT("closeLayer", layersurface);
|
||||||
|
|
||||||
if (!g_pCompositor->getMonitorFromID(layersurface->monitorID) || g_pCompositor->m_bUnsafeState) {
|
if (!g_pCompositor->getMonitorFromID(layersurface->monitorID) || g_pCompositor->m_bUnsafeState) {
|
||||||
Debug::log(WARN, "Layersurface unmapping on invalid monitor (removed?) ignoring.");
|
Debug::log(WARN, "Layersurface unmapping on invalid monitor (removed?) ignoring.");
|
||||||
@@ -189,29 +209,32 @@ void Events::listener_unmapLayerSurface(void* owner, void* data) {
|
|||||||
|
|
||||||
g_pCompositor->addToFadingOutSafe(layersurface);
|
g_pCompositor->addToFadingOutSafe(layersurface);
|
||||||
|
|
||||||
if (layersurface->layerSurface->mapped)
|
|
||||||
layersurface->layerSurface->mapped = false;
|
|
||||||
|
|
||||||
const auto PMONITOR = g_pCompositor->getMonitorFromOutput(layersurface->layerSurface->output);
|
const auto PMONITOR = g_pCompositor->getMonitorFromOutput(layersurface->layerSurface->output);
|
||||||
|
|
||||||
|
const bool WASLASTFOCUS = g_pCompositor->m_pLastFocus == layersurface->layerSurface->surface;
|
||||||
|
|
||||||
|
layersurface->surface = nullptr;
|
||||||
|
|
||||||
if (!PMONITOR)
|
if (!PMONITOR)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// refocus if needed
|
// refocus if needed
|
||||||
if (layersurface->layerSurface->surface == g_pCompositor->m_pLastFocus) {
|
if (WASLASTFOCUS) {
|
||||||
|
g_pInputManager->releaseAllMouseButtons();
|
||||||
Vector2D surfaceCoords;
|
|
||||||
|
Vector2D surfaceCoords;
|
||||||
SLayerSurface* pFoundLayerSurface = nullptr;
|
SLayerSurface* pFoundLayerSurface = nullptr;
|
||||||
wlr_surface* foundSurface = nullptr;
|
wlr_surface* foundSurface = nullptr;
|
||||||
|
|
||||||
g_pCompositor->m_pLastFocus = nullptr;
|
g_pCompositor->m_pLastFocus = nullptr;
|
||||||
|
|
||||||
// find LS-es to focus
|
// find LS-es to focus
|
||||||
foundSurface = g_pCompositor->vectorToLayerSurface(g_pInputManager->getMouseCoordsInternal(), &PMONITOR->m_aLayerSurfaceLists[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], &surfaceCoords, &pFoundLayerSurface);
|
foundSurface = g_pCompositor->vectorToLayerSurface(g_pInputManager->getMouseCoordsInternal(), &PMONITOR->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY],
|
||||||
|
&surfaceCoords, &pFoundLayerSurface);
|
||||||
|
|
||||||
if (!foundSurface)
|
if (!foundSurface)
|
||||||
foundSurface = g_pCompositor->vectorToLayerSurface(g_pInputManager->getMouseCoordsInternal(), &PMONITOR->m_aLayerSurfaceLists[ZWLR_LAYER_SHELL_V1_LAYER_TOP], &surfaceCoords, &pFoundLayerSurface);
|
foundSurface = g_pCompositor->vectorToLayerSurface(g_pInputManager->getMouseCoordsInternal(), &PMONITOR->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_TOP],
|
||||||
|
&surfaceCoords, &pFoundLayerSurface);
|
||||||
|
|
||||||
if (!foundSurface) {
|
if (!foundSurface) {
|
||||||
// if there isn't any, focus the last window
|
// if there isn't any, focus the last window
|
||||||
@@ -224,14 +247,15 @@ void Events::listener_unmapLayerSurface(void* owner, void* data) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
wlr_box geomFixed = {layersurface->geometry.x + PMONITOR->vecPosition.x, layersurface->geometry.y + PMONITOR->vecPosition.y, layersurface->geometry.width, layersurface->geometry.height};
|
CBox geomFixed = {layersurface->geometry.x + PMONITOR->vecPosition.x, layersurface->geometry.y + PMONITOR->vecPosition.y, layersurface->geometry.width,
|
||||||
|
layersurface->geometry.height};
|
||||||
g_pHyprRenderer->damageBox(&geomFixed);
|
g_pHyprRenderer->damageBox(&geomFixed);
|
||||||
|
|
||||||
geomFixed = {layersurface->geometry.x + (int)PMONITOR->vecPosition.x, layersurface->geometry.y + (int)PMONITOR->vecPosition.y, (int)layersurface->layerSurface->surface->current.width, (int)layersurface->layerSurface->surface->current.height};
|
geomFixed = {layersurface->geometry.x + (int)PMONITOR->vecPosition.x, layersurface->geometry.y + (int)PMONITOR->vecPosition.y,
|
||||||
|
(int)layersurface->layerSurface->surface->current.width, (int)layersurface->layerSurface->surface->current.height};
|
||||||
g_pHyprRenderer->damageBox(&geomFixed);
|
g_pHyprRenderer->damageBox(&geomFixed);
|
||||||
|
|
||||||
geomFixed = {layersurface->geometry.x, layersurface->geometry.y, (int)layersurface->layerSurface->surface->current.width, (int)layersurface->layerSurface->surface->current.height};
|
g_pInputManager->simulateMouseMovement();
|
||||||
layersurface->geometry = geomFixed; // because the surface can overflow... for some reason?
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Events::listener_commitLayerSurface(void* owner, void* data) {
|
void Events::listener_commitLayerSurface(void* owner, void* data) {
|
||||||
@@ -246,24 +270,24 @@ void Events::listener_commitLayerSurface(void* owner, void* data) {
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
if (layersurface->layer == ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND || layersurface->layer == ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM)
|
if (layersurface->layer == ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND || layersurface->layer == ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM)
|
||||||
g_pHyprOpenGL->markBlurDirtyForMonitor(PMONITOR); // so that blur is recalc'd
|
g_pHyprOpenGL->markBlurDirtyForMonitor(PMONITOR); // so that blur is recalc'd
|
||||||
|
|
||||||
wlr_box geomFixed = {layersurface->geometry.x, layersurface->geometry.y, layersurface->geometry.width, layersurface->geometry.height};
|
CBox geomFixed = {layersurface->geometry.x, layersurface->geometry.y, layersurface->geometry.width, layersurface->geometry.height};
|
||||||
g_pHyprRenderer->damageBox(&geomFixed);
|
g_pHyprRenderer->damageBox(&geomFixed);
|
||||||
|
|
||||||
// fix if it changed its mon
|
// fix if it changed its mon
|
||||||
if ((uint64_t)layersurface->monitorID != PMONITOR->ID) {
|
if ((uint64_t)layersurface->monitorID != PMONITOR->ID) {
|
||||||
const auto POLDMON = g_pCompositor->getMonitorFromID(layersurface->monitorID);
|
const auto POLDMON = g_pCompositor->getMonitorFromID(layersurface->monitorID);
|
||||||
|
|
||||||
for (auto it = POLDMON->m_aLayerSurfaceLists[layersurface->layer].begin(); it != POLDMON->m_aLayerSurfaceLists[layersurface->layer].end(); it++) {
|
for (auto it = POLDMON->m_aLayerSurfaceLayers[layersurface->layer].begin(); it != POLDMON->m_aLayerSurfaceLayers[layersurface->layer].end(); it++) {
|
||||||
if (it->get() == layersurface) {
|
if (it->get() == layersurface) {
|
||||||
PMONITOR->m_aLayerSurfaceLists[layersurface->layer].emplace_back(std::move(*it));
|
PMONITOR->m_aLayerSurfaceLayers[layersurface->layer].emplace_back(std::move(*it));
|
||||||
POLDMON->m_aLayerSurfaceLists[layersurface->layer].erase(it);
|
POLDMON->m_aLayerSurfaceLayers[layersurface->layer].erase(it);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
layersurface->monitorID = PMONITOR->ID;
|
layersurface->monitorID = PMONITOR->ID;
|
||||||
PMONITOR->scheduledRecalc = true;
|
PMONITOR->scheduledRecalc = true;
|
||||||
g_pHyprRenderer->arrangeLayersForMonitor(POLDMON->ID);
|
g_pHyprRenderer->arrangeLayersForMonitor(POLDMON->ID);
|
||||||
}
|
}
|
||||||
@@ -271,10 +295,10 @@ void Events::listener_commitLayerSurface(void* owner, void* data) {
|
|||||||
if (layersurface->layerSurface->current.committed != 0) {
|
if (layersurface->layerSurface->current.committed != 0) {
|
||||||
if (layersurface->layer != layersurface->layerSurface->current.layer) {
|
if (layersurface->layer != layersurface->layerSurface->current.layer) {
|
||||||
|
|
||||||
for (auto it = PMONITOR->m_aLayerSurfaceLists[layersurface->layer].begin(); it != PMONITOR->m_aLayerSurfaceLists[layersurface->layer].end(); it++) {
|
for (auto it = PMONITOR->m_aLayerSurfaceLayers[layersurface->layer].begin(); it != PMONITOR->m_aLayerSurfaceLayers[layersurface->layer].end(); it++) {
|
||||||
if (it->get() == layersurface) {
|
if (it->get() == layersurface) {
|
||||||
PMONITOR->m_aLayerSurfaceLists[layersurface->layerSurface->current.layer].emplace_back(std::move(*it));
|
PMONITOR->m_aLayerSurfaceLayers[layersurface->layerSurface->current.layer].emplace_back(std::move(*it));
|
||||||
PMONITOR->m_aLayerSurfaceLists[layersurface->layer].erase(it);
|
PMONITOR->m_aLayerSurfaceLayers[layersurface->layer].erase(it);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -282,18 +306,45 @@ void Events::listener_commitLayerSurface(void* owner, void* data) {
|
|||||||
layersurface->layer = layersurface->layerSurface->current.layer;
|
layersurface->layer = layersurface->layerSurface->current.layer;
|
||||||
|
|
||||||
if (layersurface->layer == ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND || layersurface->layer == ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM)
|
if (layersurface->layer == ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND || layersurface->layer == ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM)
|
||||||
g_pHyprOpenGL->markBlurDirtyForMonitor(PMONITOR); // so that blur is recalc'd
|
g_pHyprOpenGL->markBlurDirtyForMonitor(PMONITOR); // so that blur is recalc'd
|
||||||
}
|
}
|
||||||
|
|
||||||
g_pHyprRenderer->arrangeLayersForMonitor(PMONITOR->ID);
|
g_pHyprRenderer->arrangeLayersForMonitor(PMONITOR->ID);
|
||||||
|
|
||||||
PMONITOR->scheduledRecalc = true;
|
PMONITOR->scheduledRecalc = true;
|
||||||
|
} else {
|
||||||
|
layersurface->position = Vector2D(layersurface->geometry.x, layersurface->geometry.y);
|
||||||
|
|
||||||
|
// update geom if it changed
|
||||||
|
if (layersurface->layerSurface->surface->current.scale == 1 && PMONITOR->scale != 1.f && layersurface->layerSurface->surface->current.viewport.has_dst) {
|
||||||
|
// fractional scaling. Dirty hack.
|
||||||
|
layersurface->geometry = {layersurface->geometry.x, layersurface->geometry.y, (int)(layersurface->layerSurface->surface->current.viewport.dst_width),
|
||||||
|
(int)(layersurface->layerSurface->surface->current.viewport.dst_height)};
|
||||||
|
} else {
|
||||||
|
// this is because some apps like e.g. rofi-lbonn can't fucking use the protocol correctly.
|
||||||
|
layersurface->geometry = {layersurface->geometry.x, layersurface->geometry.y, (int)layersurface->layerSurface->surface->current.width,
|
||||||
|
(int)layersurface->layerSurface->surface->current.height};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
layersurface->position = Vector2D(layersurface->geometry.x, layersurface->geometry.y);
|
if (layersurface->layerSurface->current.keyboard_interactive &&
|
||||||
|
(!g_pCompositor->m_sSeat.mouse || !g_pCompositor->m_sSeat.mouse->currentConstraint) // don't focus if constrained
|
||||||
|
&& !layersurface->keyboardExclusive && layersurface->mapped) {
|
||||||
|
g_pCompositor->focusSurface(layersurface->layerSurface->surface);
|
||||||
|
|
||||||
// update geom if it changed
|
const auto LOCAL =
|
||||||
layersurface->geometry = {layersurface->geometry.x, layersurface->geometry.y, layersurface->layerSurface->surface->current.width, layersurface->layerSurface->surface->current.height};
|
g_pInputManager->getMouseCoordsInternal() - Vector2D(layersurface->geometry.x + PMONITOR->vecPosition.x, layersurface->geometry.y + PMONITOR->vecPosition.y);
|
||||||
|
wlr_seat_pointer_notify_enter(g_pCompositor->m_sSeat.seat, layersurface->layerSurface->surface, LOCAL.x, LOCAL.y);
|
||||||
|
wlr_seat_pointer_notify_motion(g_pCompositor->m_sSeat.seat, 0, LOCAL.x, LOCAL.y);
|
||||||
|
} else if (!layersurface->layerSurface->current.keyboard_interactive && (!g_pCompositor->m_sSeat.mouse || !g_pCompositor->m_sSeat.mouse->currentConstraint) &&
|
||||||
|
layersurface->keyboardExclusive) {
|
||||||
|
g_pInputManager->refocus();
|
||||||
|
}
|
||||||
|
|
||||||
|
layersurface->keyboardExclusive = layersurface->layerSurface->current.keyboard_interactive;
|
||||||
|
|
||||||
g_pHyprRenderer->damageSurface(layersurface->layerSurface->surface, layersurface->position.x, layersurface->position.y);
|
g_pHyprRenderer->damageSurface(layersurface->layerSurface->surface, layersurface->position.x, layersurface->position.y);
|
||||||
|
|
||||||
|
g_pCompositor->setPreferredScaleForSurface(layersurface->layerSurface->surface, PMONITOR->scale);
|
||||||
|
g_pCompositor->setPreferredTransformForSurface(layersurface->layerSurface->surface, PMONITOR->transform);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,8 +26,8 @@ void Events::listener_outputMgrTest(wl_listener* listener, void* data) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Events::listener_leaseRequest(wl_listener* listener, void* data) {
|
void Events::listener_leaseRequest(wl_listener* listener, void* data) {
|
||||||
const auto REQUEST = (wlr_drm_lease_request_v1*)data;
|
const auto REQUEST = (wlr_drm_lease_request_v1*)data;
|
||||||
struct wlr_drm_lease_v1* lease = wlr_drm_lease_request_v1_grant(REQUEST);
|
struct wlr_drm_lease_v1* lease = wlr_drm_lease_request_v1_grant(REQUEST);
|
||||||
if (!lease) {
|
if (!lease) {
|
||||||
Debug::log(ERR, "Failed to grant lease request!");
|
Debug::log(ERR, "Failed to grant lease request!");
|
||||||
wlr_drm_lease_request_v1_reject(REQUEST);
|
wlr_drm_lease_request_v1_reject(REQUEST);
|
||||||
@@ -47,18 +47,18 @@ void Events::listener_requestSetSel(wl_listener* listener, void* data) {
|
|||||||
void Events::listener_readyXWayland(wl_listener* listener, void* data) {
|
void Events::listener_readyXWayland(wl_listener* listener, void* data) {
|
||||||
#ifndef NO_XWAYLAND
|
#ifndef NO_XWAYLAND
|
||||||
const auto XCBCONNECTION = xcb_connect(g_pXWaylandManager->m_sWLRXWayland->display_name, NULL);
|
const auto XCBCONNECTION = xcb_connect(g_pXWaylandManager->m_sWLRXWayland->display_name, NULL);
|
||||||
const auto ERR = xcb_connection_has_error(XCBCONNECTION);
|
const auto ERR = xcb_connection_has_error(XCBCONNECTION);
|
||||||
if (ERR) {
|
if (ERR) {
|
||||||
Debug::log(LogLevel::ERR, "XWayland -> xcb_connection_has_error failed with %i", ERR);
|
Debug::log(LogLevel::ERR, "XWayland -> xcb_connection_has_error failed with {}", ERR);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto& ATOM : HYPRATOMS) {
|
for (auto& ATOM : HYPRATOMS) {
|
||||||
xcb_intern_atom_cookie_t cookie = xcb_intern_atom(XCBCONNECTION, 0, ATOM.first.length(), ATOM.first.c_str());
|
xcb_intern_atom_cookie_t cookie = xcb_intern_atom(XCBCONNECTION, 0, ATOM.first.length(), ATOM.first.c_str());
|
||||||
xcb_intern_atom_reply_t* reply = xcb_intern_atom_reply(XCBCONNECTION, cookie, NULL);
|
xcb_intern_atom_reply_t* reply = xcb_intern_atom_reply(XCBCONNECTION, cookie, NULL);
|
||||||
|
|
||||||
if (!reply) {
|
if (!reply) {
|
||||||
Debug::log(LogLevel::ERR, "XWayland -> Atom failed: %s", ATOM.first.c_str());
|
Debug::log(LogLevel::ERR, "XWayland -> Atom failed: {}", ATOM.first);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -69,7 +69,8 @@ void Events::listener_readyXWayland(wl_listener* listener, void* data) {
|
|||||||
|
|
||||||
const auto XCURSOR = wlr_xcursor_manager_get_xcursor(g_pCompositor->m_sWLRXCursorMgr, "left_ptr", 1);
|
const auto XCURSOR = wlr_xcursor_manager_get_xcursor(g_pCompositor->m_sWLRXCursorMgr, "left_ptr", 1);
|
||||||
if (XCURSOR) {
|
if (XCURSOR) {
|
||||||
wlr_xwayland_set_cursor(g_pXWaylandManager->m_sWLRXWayland, XCURSOR->images[0]->buffer, XCURSOR->images[0]->width * 4, XCURSOR->images[0]->width, XCURSOR->images[0]->height, XCURSOR->images[0]->hotspot_x, XCURSOR->images[0]->hotspot_y);
|
wlr_xwayland_set_cursor(g_pXWaylandManager->m_sWLRXWayland, XCURSOR->images[0]->buffer, XCURSOR->images[0]->width * 4, XCURSOR->images[0]->width,
|
||||||
|
XCURSOR->images[0]->height, XCURSOR->images[0]->hotspot_x, XCURSOR->images[0]->hotspot_y);
|
||||||
}
|
}
|
||||||
|
|
||||||
xcb_disconnect(XCBCONNECTION);
|
xcb_disconnect(XCBCONNECTION);
|
||||||
@@ -97,48 +98,36 @@ void Events::listener_startDrag(wl_listener* listener, void* data) {
|
|||||||
|
|
||||||
wlr_drag* wlrDrag = (wlr_drag*)data;
|
wlr_drag* wlrDrag = (wlr_drag*)data;
|
||||||
|
|
||||||
Debug::log(LOG, "Started drag %x", wlrDrag);
|
Debug::log(LOG, "Started drag {:x}", (uintptr_t)wlrDrag);
|
||||||
|
|
||||||
wlrDrag->data = data;
|
wlrDrag->data = data;
|
||||||
|
|
||||||
g_pInputManager->m_sDrag.hyprListener_destroy.initCallback(&wlrDrag->events.destroy, &Events::listener_destroyDrag, &g_pInputManager->m_sDrag, "Drag");
|
g_pInputManager->m_sDrag.hyprListener_destroy.initCallback(&wlrDrag->events.destroy, &Events::listener_destroyDrag, &g_pInputManager->m_sDrag, "Drag");
|
||||||
|
|
||||||
if (wlrDrag->icon) {
|
if (wlrDrag->icon) {
|
||||||
Debug::log(LOG, "Drag started with an icon %x", wlrDrag->icon);
|
Debug::log(LOG, "Drag started with an icon {:x}", (uintptr_t)wlrDrag->icon);
|
||||||
|
|
||||||
g_pInputManager->m_sDrag.dragIcon = wlrDrag->icon;
|
g_pInputManager->m_sDrag.dragIcon = wlrDrag->icon;
|
||||||
wlrDrag->icon->data = g_pInputManager->m_sDrag.dragIcon;
|
wlrDrag->icon->data = g_pInputManager->m_sDrag.dragIcon;
|
||||||
|
|
||||||
g_pInputManager->m_sDrag.hyprListener_mapIcon.initCallback(&wlrDrag->icon->events.map, &Events::listener_mapDragIcon, &g_pInputManager->m_sDrag, "DragIcon");
|
g_pInputManager->m_sDrag.hyprListener_mapIcon.initCallback(&wlrDrag->icon->surface->events.map, &Events::listener_mapDragIcon, &g_pInputManager->m_sDrag, "DragIcon");
|
||||||
g_pInputManager->m_sDrag.hyprListener_unmapIcon.initCallback(&wlrDrag->icon->events.unmap, &Events::listener_unmapDragIcon, &g_pInputManager->m_sDrag, "DragIcon");
|
g_pInputManager->m_sDrag.hyprListener_unmapIcon.initCallback(&wlrDrag->icon->surface->events.unmap, &Events::listener_unmapDragIcon, &g_pInputManager->m_sDrag, "DragIcon");
|
||||||
g_pInputManager->m_sDrag.hyprListener_destroyIcon.initCallback(&wlrDrag->icon->events.destroy, &Events::listener_destroyDragIcon, &g_pInputManager->m_sDrag, "DragIcon");
|
g_pInputManager->m_sDrag.hyprListener_destroyIcon.initCallback(&wlrDrag->icon->events.destroy, &Events::listener_destroyDragIcon, &g_pInputManager->m_sDrag, "DragIcon");
|
||||||
g_pInputManager->m_sDrag.hyprListener_commitIcon.initCallback(&wlrDrag->icon->surface->events.commit, &Events::listener_commitDragIcon, &g_pInputManager->m_sDrag, "DragIcon");
|
g_pInputManager->m_sDrag.hyprListener_commitIcon.initCallback(&wlrDrag->icon->surface->events.commit, &Events::listener_commitDragIcon, &g_pInputManager->m_sDrag,
|
||||||
|
"DragIcon");
|
||||||
}
|
}
|
||||||
|
|
||||||
static auto *const PFOLLOWONDND = &g_pConfigManager->getConfigValuePtr("misc:always_follow_on_dnd")->intValue;
|
|
||||||
|
|
||||||
if (*PFOLLOWONDND)
|
|
||||||
g_pInputManager->m_pFollowOnDnDBegin = g_pCompositor->m_pLastWindow;
|
|
||||||
else
|
|
||||||
g_pInputManager->m_pFollowOnDnDBegin = nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Events::listener_destroyDrag(void* owner, void* data) {
|
void Events::listener_destroyDrag(void* owner, void* data) {
|
||||||
Debug::log(LOG, "Drag destroyed.");
|
Debug::log(LOG, "Drag destroyed.");
|
||||||
|
|
||||||
if (g_pInputManager->m_sDrag.drag && g_pInputManager->m_sDrag.dragIcon && g_pInputManager->m_sDrag.dragIcon->surface)
|
if (g_pInputManager->m_sDrag.drag && g_pInputManager->m_sDrag.dragIcon && g_pInputManager->m_sDrag.dragIcon->surface)
|
||||||
g_pHyprRenderer->damageBox(g_pInputManager->m_sDrag.pos.x - 2, g_pInputManager->m_sDrag.pos.y - 2, g_pInputManager->m_sDrag.dragIcon->surface->current.width + 4, g_pInputManager->m_sDrag.dragIcon->surface->current.height + 4);
|
g_pHyprRenderer->damageBox(g_pInputManager->m_sDrag.pos.x - 2, g_pInputManager->m_sDrag.pos.y - 2, g_pInputManager->m_sDrag.dragIcon->surface->current.width + 4,
|
||||||
|
g_pInputManager->m_sDrag.dragIcon->surface->current.height + 4);
|
||||||
|
|
||||||
g_pInputManager->m_sDrag.drag = nullptr;
|
g_pInputManager->m_sDrag.drag = nullptr;
|
||||||
g_pInputManager->m_sDrag.dragIcon = nullptr;
|
g_pInputManager->m_sDrag.dragIcon = nullptr;
|
||||||
g_pInputManager->m_sDrag.hyprListener_destroy.removeCallback();
|
g_pInputManager->m_sDrag.hyprListener_destroy.removeCallback();
|
||||||
|
|
||||||
g_pInputManager->refocus();
|
|
||||||
|
|
||||||
if (g_pInputManager->m_pFollowOnDnDBegin)
|
|
||||||
g_pCompositor->focusWindow(g_pInputManager->m_pFollowOnDnDBegin);
|
|
||||||
|
|
||||||
g_pInputManager->m_pFollowOnDnDBegin = nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Events::listener_mapDragIcon(void* owner, void* data) {
|
void Events::listener_mapDragIcon(void* owner, void* data) {
|
||||||
@@ -167,20 +156,6 @@ void Events::listener_commitDragIcon(void* owner, void* data) {
|
|||||||
Debug::log(LOG, "Drag icon committed.");
|
Debug::log(LOG, "Drag icon committed.");
|
||||||
}
|
}
|
||||||
|
|
||||||
void Events::listener_InhibitActivate(wl_listener* listener, void* data) {
|
|
||||||
Debug::log(LOG, "Activated exclusive for %x.", g_pCompositor->m_sSeat.exclusiveClient);
|
|
||||||
|
|
||||||
g_pInputManager->refocus();
|
|
||||||
g_pCompositor->m_sSeat.exclusiveClient = g_pCompositor->m_sWLRInhibitMgr->active_client;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Events::listener_InhibitDeactivate(wl_listener* listener, void* data) {
|
|
||||||
Debug::log(LOG, "Deactivated exclusive.");
|
|
||||||
|
|
||||||
g_pCompositor->m_sSeat.exclusiveClient = nullptr;
|
|
||||||
g_pInputManager->refocus();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Events::listener_RendererDestroy(wl_listener* listener, void* data) {
|
void Events::listener_RendererDestroy(wl_listener* listener, void* data) {
|
||||||
Debug::log(LOG, "!!Renderer destroyed!!");
|
Debug::log(LOG, "!!Renderer destroyed!!");
|
||||||
}
|
}
|
||||||
@@ -189,6 +164,12 @@ void Events::listener_sessionActive(wl_listener* listener, void* data) {
|
|||||||
Debug::log(LOG, "Session got activated!");
|
Debug::log(LOG, "Session got activated!");
|
||||||
|
|
||||||
g_pCompositor->m_bSessionActive = true;
|
g_pCompositor->m_bSessionActive = true;
|
||||||
|
|
||||||
|
for (auto& m : g_pCompositor->m_vMonitors) {
|
||||||
|
g_pCompositor->scheduleFrameForMonitor(m.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
g_pConfigManager->m_bWantsMonitorReload = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Events::listener_powerMgrSetMode(wl_listener* listener, void* data) {
|
void Events::listener_powerMgrSetMode(wl_listener* listener, void* data) {
|
||||||
@@ -213,3 +194,72 @@ void Events::listener_newTextInput(wl_listener* listener, void* data) {
|
|||||||
|
|
||||||
g_pInputManager->m_sIMERelay.onNewTextInput((wlr_text_input_v3*)data);
|
g_pInputManager->m_sIMERelay.onNewTextInput((wlr_text_input_v3*)data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Events::listener_newSessionLock(wl_listener* listener, void* data) {
|
||||||
|
Debug::log(LOG, "New session lock!");
|
||||||
|
|
||||||
|
g_pSessionLockManager->onNewSessionLock((wlr_session_lock_v1*)data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Events::listener_setGamma(wl_listener* listener, void* data) {
|
||||||
|
Debug::log(LOG, "New Gamma event at {:x}", (uintptr_t)data);
|
||||||
|
|
||||||
|
const auto E = (wlr_gamma_control_manager_v1_set_gamma_event*)data;
|
||||||
|
|
||||||
|
const auto PMONITOR = g_pCompositor->getMonitorFromOutput(E->output);
|
||||||
|
|
||||||
|
if (!PMONITOR) {
|
||||||
|
Debug::log(ERR, "Gamma event object references non-existent output {:x} ?", (uintptr_t)E->output);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
PMONITOR->gammaChanged = true;
|
||||||
|
|
||||||
|
g_pCompositor->scheduleFrameForMonitor(PMONITOR);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Events::listener_setCursorShape(wl_listener* listener, void* data) {
|
||||||
|
const auto E = (wlr_cursor_shape_manager_v1_request_set_shape_event*)data;
|
||||||
|
|
||||||
|
g_pInputManager->processMouseRequest(E);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Events::listener_newTearingHint(wl_listener* listener, void* data) {
|
||||||
|
const auto TCTL = (wlr_tearing_control_v1*)data;
|
||||||
|
|
||||||
|
const auto PWINDOW = g_pCompositor->getWindowFromSurface(TCTL->surface);
|
||||||
|
|
||||||
|
if (!PWINDOW) {
|
||||||
|
Debug::log(ERR, "Tearing hint {} was attached to an unknown surface", (uintptr_t)data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Debug::log(LOG, "New tearing hint for window {} at {}", PWINDOW, (uintptr_t)data);
|
||||||
|
|
||||||
|
const auto NEWCTRL = g_pHyprRenderer->m_vTearingControllers.emplace_back(std::make_unique<STearingController>()).get();
|
||||||
|
NEWCTRL->pWlrHint = (wlr_tearing_control_v1*)data;
|
||||||
|
|
||||||
|
NEWCTRL->hyprListener_destroy.initCallback(
|
||||||
|
&NEWCTRL->pWlrHint->events.destroy,
|
||||||
|
[&](void* owner, void* data) {
|
||||||
|
Debug::log(LOG, "Destroyed {} tearing hint", (uintptr_t)((STearingController*)owner)->pWlrHint);
|
||||||
|
|
||||||
|
std::erase_if(g_pHyprRenderer->m_vTearingControllers, [&](const auto& other) { return other.get() == owner; });
|
||||||
|
},
|
||||||
|
NEWCTRL, "TearingController");
|
||||||
|
|
||||||
|
NEWCTRL->hyprListener_set.initCallback(
|
||||||
|
&NEWCTRL->pWlrHint->events.set_hint,
|
||||||
|
[&](void* owner, void* data) {
|
||||||
|
const auto TEARINGHINT = (STearingController*)owner;
|
||||||
|
|
||||||
|
const auto PWINDOW = g_pCompositor->getWindowFromSurface(TEARINGHINT->pWlrHint->surface);
|
||||||
|
|
||||||
|
if (PWINDOW) {
|
||||||
|
PWINDOW->m_bTearingHint = TEARINGHINT->pWlrHint->hint;
|
||||||
|
|
||||||
|
Debug::log(LOG, "Hint {} (window {}) set tearing hint to {}", (uintptr_t)TEARINGHINT->pWlrHint, PWINDOW, (uint32_t)TEARINGHINT->pWlrHint->hint);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
NEWCTRL, "TearingController");
|
||||||
|
}
|
||||||
|
|||||||
@@ -15,79 +15,104 @@
|
|||||||
// //
|
// //
|
||||||
// --------------------------------------------------------- //
|
// --------------------------------------------------------- //
|
||||||
|
|
||||||
CMonitor* pMostHzMonitor = nullptr;
|
|
||||||
|
|
||||||
void Events::listener_change(wl_listener* listener, void* data) {
|
void Events::listener_change(wl_listener* listener, void* data) {
|
||||||
// layout got changed, let's update monitors.
|
// layout got changed, let's update monitors.
|
||||||
const auto CONFIG = wlr_output_configuration_v1_create();
|
const auto CONFIG = wlr_output_configuration_v1_create();
|
||||||
|
|
||||||
for (auto& m : g_pCompositor->m_vMonitors) {
|
if (!CONFIG)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (auto& m : g_pCompositor->m_vRealMonitors) {
|
||||||
|
if (!m->output)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (g_pCompositor->m_pUnsafeOutput == m.get())
|
||||||
|
continue;
|
||||||
|
|
||||||
const auto CONFIGHEAD = wlr_output_configuration_head_v1_create(CONFIG, m->output);
|
const auto CONFIGHEAD = wlr_output_configuration_head_v1_create(CONFIG, m->output);
|
||||||
|
|
||||||
// TODO: clients off of disabled
|
CBox BOX;
|
||||||
wlr_box BOX;
|
wlr_output_layout_get_box(g_pCompositor->m_sWLROutputLayout, m->output, BOX.pWlr());
|
||||||
wlr_output_layout_get_box(g_pCompositor->m_sWLROutputLayout, m->output, &BOX);
|
BOX.applyFromWlr();
|
||||||
|
|
||||||
//m->vecSize.x = BOX.width;
|
//m->vecSize.x = BOX.width;
|
||||||
// m->vecSize.y = BOX.height;
|
// m->vecSize.y = BOX.height;
|
||||||
m->vecPosition.x = BOX.x;
|
m->vecPosition.x = BOX.x;
|
||||||
m->vecPosition.y = BOX.y;
|
m->vecPosition.y = BOX.y;
|
||||||
|
|
||||||
CONFIGHEAD->state.enabled = m->output->enabled;
|
CONFIGHEAD->state.enabled = m->output->enabled;
|
||||||
CONFIGHEAD->state.mode = m->output->current_mode;
|
CONFIGHEAD->state.mode = m->output->current_mode;
|
||||||
CONFIGHEAD->state.x = m->vecPosition.x;
|
if (!m->output->current_mode) {
|
||||||
CONFIGHEAD->state.y = m->vecPosition.y;
|
CONFIGHEAD->state.custom_mode = {
|
||||||
|
m->output->width,
|
||||||
|
m->output->height,
|
||||||
|
m->output->refresh,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
CONFIGHEAD->state.x = m->vecPosition.x;
|
||||||
|
CONFIGHEAD->state.y = m->vecPosition.y;
|
||||||
|
CONFIGHEAD->state.transform = m->transform;
|
||||||
|
CONFIGHEAD->state.scale = m->scale;
|
||||||
|
CONFIGHEAD->state.adaptive_sync_enabled = m->vrrActive;
|
||||||
}
|
}
|
||||||
|
|
||||||
wlr_output_manager_v1_set_configuration(g_pCompositor->m_sWLROutputMgr, CONFIG);
|
wlr_output_manager_v1_set_configuration(g_pCompositor->m_sWLROutputMgr, CONFIG);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Events::listener_newOutput(wl_listener* listener, void* data) {
|
void Events::listener_newOutput(wl_listener* listener, void* data) {
|
||||||
// new monitor added, let's accomodate for that.
|
// new monitor added, let's accommodate for that.
|
||||||
const auto OUTPUT = (wlr_output*)data;
|
const auto OUTPUT = (wlr_output*)data;
|
||||||
|
|
||||||
|
// for warping the cursor on launch
|
||||||
|
static bool firstLaunch = true;
|
||||||
|
|
||||||
if (!OUTPUT->name) {
|
if (!OUTPUT->name) {
|
||||||
Debug::log(ERR, "New monitor has no name?? Ignoring");
|
Debug::log(ERR, "New monitor has no name?? Ignoring");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (g_pCompositor->m_bUnsafeState) {
|
|
||||||
Debug::log(WARN, "Recovering from an unsafe state. May you be lucky.");
|
|
||||||
}
|
|
||||||
|
|
||||||
// add it to real
|
// add it to real
|
||||||
std::shared_ptr<CMonitor>* PNEWMONITORWRAP = nullptr;
|
std::shared_ptr<CMonitor>* PNEWMONITORWRAP = nullptr;
|
||||||
|
|
||||||
for (auto& rm : g_pCompositor->m_vRealMonitors) {
|
PNEWMONITORWRAP = &g_pCompositor->m_vRealMonitors.emplace_back(std::make_shared<CMonitor>());
|
||||||
if (rm->szName == OUTPUT->name) {
|
if (std::string("HEADLESS-1") == OUTPUT->name)
|
||||||
PNEWMONITORWRAP = &rm;
|
g_pCompositor->m_pUnsafeOutput = PNEWMONITORWRAP->get();
|
||||||
Debug::log(LOG, "Recovering a removed monitor.");
|
|
||||||
break;
|
(*PNEWMONITORWRAP)->output = OUTPUT;
|
||||||
|
const bool FALLBACK = g_pCompositor->m_pUnsafeOutput ? OUTPUT == g_pCompositor->m_pUnsafeOutput->output : false;
|
||||||
|
(*PNEWMONITORWRAP)->ID = FALLBACK ? -1 : g_pCompositor->getNextAvailableMonitorID(OUTPUT->name);
|
||||||
|
const auto PNEWMONITOR = PNEWMONITORWRAP->get();
|
||||||
|
PNEWMONITOR->isUnsafeFallback = FALLBACK;
|
||||||
|
|
||||||
|
if (!FALLBACK)
|
||||||
|
PNEWMONITOR->onConnect(false);
|
||||||
|
|
||||||
|
if (!PNEWMONITOR->m_bEnabled || FALLBACK)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// ready to process if we have a real monitor
|
||||||
|
|
||||||
|
if ((!g_pHyprRenderer->m_pMostHzMonitor || PNEWMONITOR->refreshRate > g_pHyprRenderer->m_pMostHzMonitor->refreshRate) && PNEWMONITOR->m_bEnabled)
|
||||||
|
g_pHyprRenderer->m_pMostHzMonitor = PNEWMONITOR;
|
||||||
|
|
||||||
|
g_pCompositor->m_bReadyToProcess = true;
|
||||||
|
|
||||||
|
g_pConfigManager->m_bWantsMonitorReload = true;
|
||||||
|
g_pCompositor->scheduleFrameForMonitor(PNEWMONITOR);
|
||||||
|
|
||||||
|
if (firstLaunch) {
|
||||||
|
firstLaunch = false;
|
||||||
|
const auto POS = PNEWMONITOR->middle();
|
||||||
|
if (g_pCompositor->m_sSeat.mouse)
|
||||||
|
wlr_cursor_warp(g_pCompositor->m_sWLRCursor, g_pCompositor->m_sSeat.mouse->mouse, POS.x, POS.y);
|
||||||
|
} else {
|
||||||
|
for (auto& w : g_pCompositor->m_vWindows) {
|
||||||
|
if (w->m_iMonitorID == PNEWMONITOR->ID) {
|
||||||
|
w->m_iLastSurfaceMonitorID = -1;
|
||||||
|
w->updateSurfaceOutputs();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!PNEWMONITORWRAP) {
|
|
||||||
Debug::log(LOG, "Adding completely new monitor.");
|
|
||||||
PNEWMONITORWRAP = &g_pCompositor->m_vRealMonitors.emplace_back(std::make_shared<CMonitor>());
|
|
||||||
|
|
||||||
(*PNEWMONITORWRAP)->ID = g_pCompositor->getNextAvailableMonitorID();
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto PNEWMONITOR = PNEWMONITORWRAP->get();
|
|
||||||
|
|
||||||
PNEWMONITOR->output = OUTPUT;
|
|
||||||
PNEWMONITOR->m_pThisWrap = PNEWMONITORWRAP;
|
|
||||||
|
|
||||||
PNEWMONITOR->onConnect(false);
|
|
||||||
|
|
||||||
if ((!pMostHzMonitor || PNEWMONITOR->refreshRate > pMostHzMonitor->refreshRate) && PNEWMONITOR->m_bEnabled)
|
|
||||||
pMostHzMonitor = PNEWMONITOR;
|
|
||||||
|
|
||||||
// ready to process cuz we have a monitor
|
|
||||||
if (PNEWMONITOR->m_bEnabled) {
|
|
||||||
g_pCompositor->m_bReadyToProcess = true;
|
|
||||||
g_pCompositor->m_bUnsafeState = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Events::listener_monitorFrame(void* owner, void* data) {
|
void Events::listener_monitorFrame(void* owner, void* data) {
|
||||||
@@ -95,218 +120,74 @@ void Events::listener_monitorFrame(void* owner, void* data) {
|
|||||||
|
|
||||||
if ((g_pCompositor->m_sWLRSession && !g_pCompositor->m_sWLRSession->active) || !g_pCompositor->m_bSessionActive || g_pCompositor->m_bUnsafeState) {
|
if ((g_pCompositor->m_sWLRSession && !g_pCompositor->m_sWLRSession->active) || !g_pCompositor->m_bSessionActive || g_pCompositor->m_bUnsafeState) {
|
||||||
Debug::log(WARN, "Attempted to render frame on inactive session!");
|
Debug::log(WARN, "Attempted to render frame on inactive session!");
|
||||||
|
|
||||||
|
if (g_pCompositor->m_bUnsafeState && std::ranges::any_of(g_pCompositor->m_vMonitors.begin(), g_pCompositor->m_vMonitors.end(), [&](auto& m) {
|
||||||
|
return m->output != g_pCompositor->m_pUnsafeOutput->output;
|
||||||
|
})) {
|
||||||
|
// restore from unsafe state
|
||||||
|
g_pCompositor->leaveUnsafeState();
|
||||||
|
}
|
||||||
|
|
||||||
return; // cannot draw on session inactive (different tty)
|
return; // cannot draw on session inactive (different tty)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!PMONITOR->m_bEnabled)
|
if (!PMONITOR->m_bEnabled)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
static std::chrono::high_resolution_clock::time_point startRender = std::chrono::high_resolution_clock::now();
|
g_pHyprRenderer->recheckSolitaryForMonitor(PMONITOR);
|
||||||
static std::chrono::high_resolution_clock::time_point startRenderOverlay = std::chrono::high_resolution_clock::now();
|
|
||||||
static std::chrono::high_resolution_clock::time_point endRenderOverlay = std::chrono::high_resolution_clock::now();
|
|
||||||
|
|
||||||
static auto *const PDEBUGOVERLAY = &g_pConfigManager->getConfigValuePtr("debug:overlay")->intValue;
|
PMONITOR->tearingState.busy = false;
|
||||||
static auto *const PDAMAGETRACKINGMODE = &g_pConfigManager->getConfigValuePtr("general:damage_tracking_internal")->intValue;
|
|
||||||
static auto *const PDAMAGEBLINK = &g_pConfigManager->getConfigValuePtr("debug:damage_blink")->intValue;
|
|
||||||
static auto *const PNOVFR = &g_pConfigManager->getConfigValuePtr("misc:no_vfr")->intValue;
|
|
||||||
|
|
||||||
static int damageBlinkCleanup = 0; // because double-buffered
|
if (PMONITOR->tearingState.activelyTearing && PMONITOR->solitaryClient /* can be invalidated by a recheck */) {
|
||||||
|
|
||||||
if (!*PDAMAGEBLINK)
|
if (!PMONITOR->tearingState.frameScheduledWhileBusy)
|
||||||
damageBlinkCleanup = 0;
|
return; // we did not schedule a frame yet to be displayed, but we are tearing. Why render?
|
||||||
|
|
||||||
if (*PDEBUGOVERLAY == 1) {
|
PMONITOR->tearingState.nextRenderTorn = true;
|
||||||
startRender = std::chrono::high_resolution_clock::now();
|
PMONITOR->tearingState.frameScheduledWhileBusy = false;
|
||||||
g_pDebugOverlay->frameData(PMONITOR);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (PMONITOR->framesToSkip > 0) {
|
static auto* const PENABLERAT = &g_pConfigManager->getConfigValuePtr("misc:render_ahead_of_time")->intValue;
|
||||||
PMONITOR->framesToSkip -= 1;
|
static auto* const PRATSAFE = &g_pConfigManager->getConfigValuePtr("misc:render_ahead_safezone")->intValue;
|
||||||
|
|
||||||
if (!PMONITOR->noFrameSchedule)
|
PMONITOR->lastPresentationTimer.reset();
|
||||||
g_pCompositor->scheduleFrameForMonitor(PMONITOR);
|
|
||||||
else {
|
if (*PENABLERAT && !PMONITOR->tearingState.nextRenderTorn) {
|
||||||
Debug::log(LOG, "NoFrameSchedule hit for %s.", PMONITOR->szName.c_str());
|
if (!PMONITOR->RATScheduled) {
|
||||||
|
// render
|
||||||
|
g_pHyprRenderer->renderMonitor(PMONITOR);
|
||||||
}
|
}
|
||||||
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PMONITOR->ID);
|
|
||||||
|
|
||||||
if (PMONITOR->framesToSkip > 10)
|
PMONITOR->RATScheduled = false;
|
||||||
PMONITOR->framesToSkip = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// checks //
|
const auto& [avg, max, min] = g_pHyprRenderer->getRenderTimes(PMONITOR);
|
||||||
if (PMONITOR->ID == pMostHzMonitor->ID || !*PNOVFR) { // unfortunately with VFR we don't have the guarantee mostHz is going to be updated all the time, so we have to ignore that
|
|
||||||
g_pCompositor->sanityCheckWorkspaces();
|
|
||||||
g_pAnimationManager->tick();
|
|
||||||
|
|
||||||
g_pConfigManager->dispatchExecOnce(); // We exec-once when at least one monitor starts refreshing, meaning stuff has init'd
|
if (max + *PRATSAFE > 1000.0 / PMONITOR->refreshRate)
|
||||||
|
return;
|
||||||
|
|
||||||
if (g_pConfigManager->m_bWantsMonitorReload)
|
const auto MSLEFT = 1000.0 / PMONITOR->refreshRate - PMONITOR->lastPresentationTimer.getMillis();
|
||||||
g_pConfigManager->performMonitorReload();
|
|
||||||
|
|
||||||
g_pHyprRenderer->ensureCursorRenderingMode(); // so that the cursor gets hidden/shown if the user requested timeouts
|
PMONITOR->RATScheduled = true;
|
||||||
}
|
|
||||||
// //
|
|
||||||
|
|
||||||
if (PMONITOR->scheduledRecalc) {
|
const auto ESTRENDERTIME = std::ceil(avg + *PRATSAFE);
|
||||||
PMONITOR->scheduledRecalc = false;
|
const auto TIMETOSLEEP = std::floor(MSLEFT - ESTRENDERTIME);
|
||||||
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PMONITOR->ID);
|
|
||||||
}
|
|
||||||
|
|
||||||
timespec now;
|
if (MSLEFT < 1 || MSLEFT < ESTRENDERTIME || TIMETOSLEEP < 1)
|
||||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
g_pHyprRenderer->renderMonitor(PMONITOR);
|
||||||
|
else
|
||||||
// check the damage
|
wl_event_source_timer_update(PMONITOR->renderTimer, TIMETOSLEEP);
|
||||||
pixman_region32_t damage;
|
|
||||||
bool hasChanged;
|
|
||||||
pixman_region32_init(&damage);
|
|
||||||
|
|
||||||
if (*PDAMAGETRACKINGMODE == -1) {
|
|
||||||
Debug::log(CRIT, "Damage tracking mode -1 ????");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_pHyprOpenGL->preRender(PMONITOR);
|
|
||||||
|
|
||||||
if (!wlr_output_damage_attach_render(PMONITOR->damage, &hasChanged, &damage)){
|
|
||||||
Debug::log(ERR, "Couldn't attach render to display %s ???", PMONITOR->szName.c_str());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// we need to cleanup fading out when rendering the appropriate context
|
|
||||||
g_pCompositor->cleanupFadingOut(PMONITOR->ID);
|
|
||||||
|
|
||||||
if (!hasChanged && *PDAMAGETRACKINGMODE != DAMAGE_TRACKING_NONE && PMONITOR->forceFullFrames == 0 && damageBlinkCleanup == 0) {
|
|
||||||
pixman_region32_fini(&damage);
|
|
||||||
wlr_output_rollback(PMONITOR->output);
|
|
||||||
|
|
||||||
if (*PDAMAGEBLINK || *PNOVFR)
|
|
||||||
g_pCompositor->scheduleFrameForMonitor(PMONITOR);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if we have no tracking or full tracking, invalidate the entire monitor
|
|
||||||
if (*PDAMAGETRACKINGMODE == DAMAGE_TRACKING_NONE || *PDAMAGETRACKINGMODE == DAMAGE_TRACKING_MONITOR || PMONITOR->forceFullFrames > 0 || damageBlinkCleanup > 0 || PMONITOR->isMirror() /* why??? */) {
|
|
||||||
pixman_region32_union_rect(&damage, &damage, 0, 0, (int)PMONITOR->vecTransformedSize.x * 10, (int)PMONITOR->vecTransformedSize.y * 10); // wot?
|
|
||||||
|
|
||||||
pixman_region32_copy(&g_pHyprOpenGL->m_rOriginalDamageRegion, &damage);
|
|
||||||
} else {
|
} else {
|
||||||
static auto *const PBLURENABLED = &g_pConfigManager->getConfigValuePtr("decoration:blur")->intValue;
|
g_pHyprRenderer->renderMonitor(PMONITOR);
|
||||||
|
|
||||||
// if we use blur we need to expand the damage for proper blurring
|
|
||||||
if (*PBLURENABLED == 1) {
|
|
||||||
// TODO: can this be optimized?
|
|
||||||
static auto *const PBLURSIZE = &g_pConfigManager->getConfigValuePtr("decoration:blur_size")->intValue;
|
|
||||||
static auto *const PBLURPASSES = &g_pConfigManager->getConfigValuePtr("decoration:blur_passes")->intValue;
|
|
||||||
const auto BLURRADIUS = *PBLURSIZE * pow(2, *PBLURPASSES); // is this 2^pass? I don't know but it works... I think.
|
|
||||||
|
|
||||||
pixman_region32_copy(&g_pHyprOpenGL->m_rOriginalDamageRegion, &damage);
|
|
||||||
|
|
||||||
// now, prep the damage, get the extended damage region
|
|
||||||
wlr_region_expand(&damage, &damage, BLURRADIUS); // expand for proper blurring
|
|
||||||
} else {
|
|
||||||
pixman_region32_copy(&g_pHyprOpenGL->m_rOriginalDamageRegion, &damage);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (PMONITOR->forceFullFrames > 0) {
|
|
||||||
PMONITOR->forceFullFrames -= 1;
|
|
||||||
if (PMONITOR->forceFullFrames > 10)
|
|
||||||
PMONITOR->forceFullFrames = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// TODO: this is getting called with extents being 0,0,0,0 should it be?
|
|
||||||
// potentially can save on resources.
|
|
||||||
|
|
||||||
g_pHyprOpenGL->begin(PMONITOR, &damage);
|
|
||||||
|
|
||||||
if (PMONITOR->isMirror()) {
|
|
||||||
g_pHyprOpenGL->renderMirrored();
|
|
||||||
} else {
|
|
||||||
g_pHyprOpenGL->clear(CColor(17, 17, 17, 255));
|
|
||||||
g_pHyprOpenGL->clearWithTex(); // will apply the hypr "wallpaper"
|
|
||||||
|
|
||||||
g_pHyprRenderer->renderAllClientsForMonitor(PMONITOR->ID, &now);
|
|
||||||
|
|
||||||
// if correct monitor draw hyprerror
|
|
||||||
if (PMONITOR->ID == 0)
|
|
||||||
g_pHyprError->draw();
|
|
||||||
|
|
||||||
// for drawing the debug overlay
|
|
||||||
if (PMONITOR->ID == 0 && *PDEBUGOVERLAY == 1) {
|
|
||||||
startRenderOverlay = std::chrono::high_resolution_clock::now();
|
|
||||||
g_pDebugOverlay->draw();
|
|
||||||
endRenderOverlay = std::chrono::high_resolution_clock::now();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (*PDAMAGEBLINK && damageBlinkCleanup == 0) {
|
|
||||||
wlr_box monrect = {0, 0, PMONITOR->vecTransformedSize.x, PMONITOR->vecTransformedSize.y};
|
|
||||||
g_pHyprOpenGL->renderRect(&monrect, CColor(255, 0, 255, 100), 0);
|
|
||||||
damageBlinkCleanup = 1;
|
|
||||||
} else if (*PDAMAGEBLINK) {
|
|
||||||
damageBlinkCleanup++;
|
|
||||||
if (damageBlinkCleanup > 3)
|
|
||||||
damageBlinkCleanup = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
wlr_renderer_begin(g_pCompositor->m_sWLRRenderer, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y);
|
|
||||||
|
|
||||||
wlr_output_render_software_cursors(PMONITOR->output, NULL);
|
|
||||||
|
|
||||||
wlr_renderer_end(g_pCompositor->m_sWLRRenderer);
|
|
||||||
}
|
|
||||||
|
|
||||||
g_pHyprOpenGL->end();
|
|
||||||
|
|
||||||
// calc frame damage
|
|
||||||
pixman_region32_t frameDamage;
|
|
||||||
pixman_region32_init(&frameDamage);
|
|
||||||
|
|
||||||
const auto TRANSFORM = wlr_output_transform_invert(PMONITOR->output->transform);
|
|
||||||
wlr_region_transform(&frameDamage, &PMONITOR->damage->current, TRANSFORM, (int)PMONITOR->vecTransformedSize.x, (int)PMONITOR->vecTransformedSize.y);
|
|
||||||
|
|
||||||
if (*PDAMAGETRACKINGMODE == DAMAGE_TRACKING_NONE || *PDAMAGETRACKINGMODE == DAMAGE_TRACKING_MONITOR)
|
|
||||||
pixman_region32_union_rect(&frameDamage, &frameDamage, 0, 0, (int)PMONITOR->vecTransformedSize.x, (int)PMONITOR->vecTransformedSize.y);
|
|
||||||
|
|
||||||
if (*PDAMAGEBLINK)
|
|
||||||
pixman_region32_union(&frameDamage, &frameDamage, &damage);
|
|
||||||
|
|
||||||
wlr_output_set_damage(PMONITOR->output, &frameDamage);
|
|
||||||
|
|
||||||
if (!PMONITOR->mirrors.empty())
|
|
||||||
g_pHyprRenderer->damageMirrorsWith(PMONITOR, &frameDamage);
|
|
||||||
|
|
||||||
pixman_region32_fini(&frameDamage);
|
|
||||||
pixman_region32_fini(&damage);
|
|
||||||
|
|
||||||
if (!wlr_output_commit(PMONITOR->output))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (*PDAMAGEBLINK || *PNOVFR)
|
|
||||||
g_pCompositor->scheduleFrameForMonitor(PMONITOR);
|
|
||||||
|
|
||||||
if (*PDEBUGOVERLAY == 1) {
|
|
||||||
const float µs = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::now() - startRender).count() / 1000.f;
|
|
||||||
g_pDebugOverlay->renderData(PMONITOR, µs);
|
|
||||||
if (PMONITOR->ID == 0) {
|
|
||||||
const float µsNoOverlay = µs - std::chrono::duration_cast<std::chrono::nanoseconds>(endRenderOverlay - startRenderOverlay).count() / 1000.f;
|
|
||||||
g_pDebugOverlay->renderDataNoOverlay(PMONITOR, µsNoOverlay);
|
|
||||||
} else {
|
|
||||||
g_pDebugOverlay->renderDataNoOverlay(PMONITOR, µs);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Events::listener_monitorDestroy(void* owner, void* data) {
|
void Events::listener_monitorDestroy(void* owner, void* data) {
|
||||||
const auto OUTPUT = (wlr_output*)data;
|
const auto OUTPUT = (wlr_output*)data;
|
||||||
|
|
||||||
CMonitor* pMonitor = nullptr;
|
CMonitor* pMonitor = nullptr;
|
||||||
|
|
||||||
for (auto& m : g_pCompositor->m_vMonitors) {
|
for (auto& m : g_pCompositor->m_vRealMonitors) {
|
||||||
if (m->szName == OUTPUT->name) {
|
if (m->output == OUTPUT) {
|
||||||
pMonitor = m.get();
|
pMonitor = m.get();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -315,25 +196,49 @@ void Events::listener_monitorDestroy(void* owner, void* data) {
|
|||||||
if (!pMonitor)
|
if (!pMonitor)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
pMonitor->onDisconnect();
|
Debug::log(LOG, "Destroy called for monitor {}", pMonitor->output->name);
|
||||||
|
|
||||||
// cleanup if not unsafe
|
pMonitor->onDisconnect(true);
|
||||||
|
|
||||||
if (!g_pCompositor->m_bUnsafeState) {
|
pMonitor->output = nullptr;
|
||||||
g_pCompositor->m_vRealMonitors.erase(std::remove_if(g_pCompositor->m_vRealMonitors.begin(), g_pCompositor->m_vRealMonitors.end(), [&](std::shared_ptr<CMonitor>& el) { return el.get() == pMonitor; }));
|
pMonitor->m_bRenderingInitPassed = false;
|
||||||
|
|
||||||
if (pMostHzMonitor == pMonitor) {
|
Debug::log(LOG, "Removing monitor {} from realMonitors", pMonitor->szName);
|
||||||
int mostHz = 0;
|
|
||||||
CMonitor* pMonitorMostHz = nullptr;
|
|
||||||
|
|
||||||
for (auto& m : g_pCompositor->m_vMonitors) {
|
std::erase_if(g_pCompositor->m_vRealMonitors, [&](std::shared_ptr<CMonitor>& el) { return el.get() == pMonitor; });
|
||||||
if (m->refreshRate > mostHz) {
|
}
|
||||||
pMonitorMostHz = m.get();
|
|
||||||
mostHz = m->refreshRate;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pMostHzMonitor = pMonitorMostHz;
|
void Events::listener_monitorStateRequest(void* owner, void* data) {
|
||||||
}
|
const auto PMONITOR = (CMonitor*)owner;
|
||||||
|
const auto E = (wlr_output_event_request_state*)data;
|
||||||
|
|
||||||
|
wlr_output_commit_state(PMONITOR->output, E->state);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Events::listener_monitorDamage(void* owner, void* data) {
|
||||||
|
const auto PMONITOR = (CMonitor*)owner;
|
||||||
|
const auto E = (wlr_output_event_damage*)data;
|
||||||
|
|
||||||
|
PMONITOR->addDamage(E->damage);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Events::listener_monitorNeedsFrame(void* owner, void* data) {
|
||||||
|
const auto PMONITOR = (CMonitor*)owner;
|
||||||
|
|
||||||
|
g_pCompositor->scheduleFrameForMonitor(PMONITOR);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Events::listener_monitorCommit(void* owner, void* data) {
|
||||||
|
const auto PMONITOR = (CMonitor*)owner;
|
||||||
|
|
||||||
|
const auto E = (wlr_output_event_commit*)data;
|
||||||
|
|
||||||
|
if (E->state->committed & WLR_OUTPUT_STATE_BUFFER) {
|
||||||
|
g_pProtocolManager->m_pScreencopyProtocolManager->onOutputCommit(PMONITOR, E);
|
||||||
|
g_pProtocolManager->m_pToplevelExportProtocolManager->onOutputCommit(PMONITOR, E);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Events::listener_monitorBind(void* owner, void* data) {
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|||||||
@@ -16,12 +16,12 @@
|
|||||||
// --------------------------------------------- //
|
// --------------------------------------------- //
|
||||||
|
|
||||||
void addPopupGlobalCoords(void* pPopup, int* x, int* y) {
|
void addPopupGlobalCoords(void* pPopup, int* x, int* y) {
|
||||||
SXDGPopup *const PPOPUP = (SXDGPopup*)pPopup;
|
SXDGPopup* const PPOPUP = (SXDGPopup*)pPopup;
|
||||||
|
|
||||||
auto curPopup = PPOPUP;
|
auto curPopup = PPOPUP;
|
||||||
|
|
||||||
int px = 0;
|
int px = 0;
|
||||||
int py = 0;
|
int py = 0;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
px += curPopup->popup->current.geometry.x;
|
px += curPopup->popup->current.geometry.x;
|
||||||
@@ -56,20 +56,21 @@ void createNewPopup(wlr_xdg_popup* popup, SXDGPopup* pHyprPopup) {
|
|||||||
pHyprPopup->popup = popup;
|
pHyprPopup->popup = popup;
|
||||||
|
|
||||||
pHyprPopup->hyprListener_destroyPopupXDG.initCallback(&popup->base->events.destroy, &Events::listener_destroyPopupXDG, pHyprPopup, "HyprPopup");
|
pHyprPopup->hyprListener_destroyPopupXDG.initCallback(&popup->base->events.destroy, &Events::listener_destroyPopupXDG, pHyprPopup, "HyprPopup");
|
||||||
pHyprPopup->hyprListener_mapPopupXDG.initCallback(&popup->base->events.map, &Events::listener_mapPopupXDG, pHyprPopup, "HyprPopup");
|
pHyprPopup->hyprListener_mapPopupXDG.initCallback(&popup->base->surface->events.map, &Events::listener_mapPopupXDG, pHyprPopup, "HyprPopup");
|
||||||
pHyprPopup->hyprListener_unmapPopupXDG.initCallback(&popup->base->events.unmap, &Events::listener_unmapPopupXDG, pHyprPopup, "HyprPopup");
|
pHyprPopup->hyprListener_unmapPopupXDG.initCallback(&popup->base->surface->events.unmap, &Events::listener_unmapPopupXDG, pHyprPopup, "HyprPopup");
|
||||||
pHyprPopup->hyprListener_newPopupFromPopupXDG.initCallback(&popup->base->events.new_popup, &Events::listener_newPopupFromPopupXDG, pHyprPopup, "HyprPopup");
|
pHyprPopup->hyprListener_newPopupFromPopupXDG.initCallback(&popup->base->events.new_popup, &Events::listener_newPopupFromPopupXDG, pHyprPopup, "HyprPopup");
|
||||||
pHyprPopup->hyprListener_commitPopupXDG.initCallback(&popup->base->surface->events.commit, &Events::listener_commitPopupXDG, pHyprPopup, "HyprPopup");
|
pHyprPopup->hyprListener_commitPopupXDG.initCallback(&popup->base->surface->events.commit, &Events::listener_commitPopupXDG, pHyprPopup, "HyprPopup");
|
||||||
|
pHyprPopup->hyprListener_repositionPopupXDG.initCallback(&popup->events.reposition, &Events::listener_repositionPopupXDG, pHyprPopup, "HyprPopup");
|
||||||
|
|
||||||
const auto PMONITOR = g_pCompositor->m_pLastMonitor;
|
const auto PMONITOR = g_pCompositor->m_pLastMonitor;
|
||||||
|
|
||||||
wlr_box box = {.x = PMONITOR->vecPosition.x - pHyprPopup->lx, .y = PMONITOR->vecPosition.y - pHyprPopup->ly, .width = PMONITOR->vecSize.x, .height = PMONITOR->vecSize.y};
|
CBox box = {PMONITOR->vecPosition.x - pHyprPopup->lx, PMONITOR->vecPosition.y - pHyprPopup->ly, PMONITOR->vecSize.x, PMONITOR->vecSize.y};
|
||||||
|
|
||||||
wlr_xdg_popup_unconstrain_from_box(popup, &box);
|
wlr_xdg_popup_unconstrain_from_box(popup, box.pWlr());
|
||||||
|
|
||||||
pHyprPopup->monitor = PMONITOR;
|
pHyprPopup->monitor = PMONITOR;
|
||||||
|
|
||||||
Debug::log(LOG, "Popup: Unconstrained from lx ly: %f %f, pHyprPopup lx ly: %f %f", (float)PMONITOR->vecPosition.x, (float)PMONITOR->vecPosition.y, (float)pHyprPopup->lx, (float)pHyprPopup->ly);
|
Debug::log(LOG, "Popup: Unconstrained from lx ly: {:j5}, pHyprPopup lx ly: {:.5f} {:.5f}", PMONITOR->vecPosition, (float)pHyprPopup->lx, (float)pHyprPopup->ly);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Events::listener_newPopup(void* owner, void* data) {
|
void Events::listener_newPopup(void* owner, void* data) {
|
||||||
@@ -77,7 +78,7 @@ void Events::listener_newPopup(void* owner, void* data) {
|
|||||||
|
|
||||||
ASSERT(layersurface);
|
ASSERT(layersurface);
|
||||||
|
|
||||||
Debug::log(LOG, "New layer popup created from surface %x", layersurface);
|
Debug::log(LOG, "New layer popup created from surface {:x}", (uintptr_t)layersurface);
|
||||||
|
|
||||||
const auto WLRPOPUP = (wlr_xdg_popup*)data;
|
const auto WLRPOPUP = (wlr_xdg_popup*)data;
|
||||||
|
|
||||||
@@ -85,10 +86,11 @@ void Events::listener_newPopup(void* owner, void* data) {
|
|||||||
|
|
||||||
const auto PMONITOR = g_pCompositor->getMonitorFromID(layersurface->monitorID);
|
const auto PMONITOR = g_pCompositor->getMonitorFromID(layersurface->monitorID);
|
||||||
|
|
||||||
PNEWPOPUP->popup = WLRPOPUP;
|
PNEWPOPUP->popup = WLRPOPUP;
|
||||||
PNEWPOPUP->lx = layersurface->position.x;
|
PNEWPOPUP->lx = layersurface->position.x;
|
||||||
PNEWPOPUP->ly = layersurface->position.y;
|
PNEWPOPUP->ly = layersurface->position.y;
|
||||||
PNEWPOPUP->monitor = PMONITOR;
|
PNEWPOPUP->monitor = PMONITOR;
|
||||||
|
PNEWPOPUP->parentLS = layersurface;
|
||||||
createNewPopup(WLRPOPUP, PNEWPOPUP);
|
createNewPopup(WLRPOPUP, PNEWPOPUP);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,7 +102,7 @@ void Events::listener_newPopupXDG(void* owner, void* data) {
|
|||||||
if (!PWINDOW->m_bIsMapped)
|
if (!PWINDOW->m_bIsMapped)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Debug::log(LOG, "New layer popup created from XDG window %x -> %s", PWINDOW, PWINDOW->m_szTitle.c_str());
|
Debug::log(LOG, "New layer popup created from XDG window {}", PWINDOW);
|
||||||
|
|
||||||
const auto WLRPOPUP = (wlr_xdg_popup*)data;
|
const auto WLRPOPUP = (wlr_xdg_popup*)data;
|
||||||
|
|
||||||
@@ -108,11 +110,11 @@ void Events::listener_newPopupXDG(void* owner, void* data) {
|
|||||||
|
|
||||||
const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID);
|
const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID);
|
||||||
|
|
||||||
PNEWPOPUP->popup = WLRPOPUP;
|
PNEWPOPUP->popup = WLRPOPUP;
|
||||||
PNEWPOPUP->lx = PWINDOW->m_vRealPosition.goalv().x;
|
PNEWPOPUP->lx = PWINDOW->m_vRealPosition.goalv().x;
|
||||||
PNEWPOPUP->ly = PWINDOW->m_vRealPosition.goalv().y;
|
PNEWPOPUP->ly = PWINDOW->m_vRealPosition.goalv().y;
|
||||||
PNEWPOPUP->parentWindow = PWINDOW;
|
PNEWPOPUP->parentWindow = PWINDOW;
|
||||||
PNEWPOPUP->monitor = PMONITOR;
|
PNEWPOPUP->monitor = PMONITOR;
|
||||||
createNewPopup(WLRPOPUP, PNEWPOPUP);
|
createNewPopup(WLRPOPUP, PNEWPOPUP);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,20 +124,20 @@ void Events::listener_newPopupFromPopupXDG(void* owner, void* data) {
|
|||||||
ASSERT(PPOPUP);
|
ASSERT(PPOPUP);
|
||||||
|
|
||||||
if (PPOPUP->parentWindow)
|
if (PPOPUP->parentWindow)
|
||||||
Debug::log(LOG, "New popup created from XDG Window popup %x -> %s", PPOPUP, PPOPUP->parentWindow->m_szTitle.c_str());
|
Debug::log(LOG, "New popup created from XDG Window popup {:x} -> {}", (uintptr_t)PPOPUP, PPOPUP->parentWindow);
|
||||||
else
|
else
|
||||||
Debug::log(LOG, "New popup created from Non-Window popup %x", PPOPUP);
|
Debug::log(LOG, "New popup created from Non-Window popup {:x}", (uintptr_t)PPOPUP);
|
||||||
|
|
||||||
const auto WLRPOPUP = (wlr_xdg_popup*)data;
|
const auto WLRPOPUP = (wlr_xdg_popup*)data;
|
||||||
|
|
||||||
const auto PNEWPOPUP = g_pCompositor->m_vXDGPopups.emplace_back(std::make_unique<SXDGPopup>()).get();
|
const auto PNEWPOPUP = g_pCompositor->m_vXDGPopups.emplace_back(std::make_unique<SXDGPopup>()).get();
|
||||||
|
|
||||||
PNEWPOPUP->popup = WLRPOPUP;
|
PNEWPOPUP->popup = WLRPOPUP;
|
||||||
PNEWPOPUP->parentPopup = PPOPUP;
|
PNEWPOPUP->parentPopup = PPOPUP;
|
||||||
PNEWPOPUP->lx = PPOPUP->lx;
|
PNEWPOPUP->lx = PPOPUP->lx;
|
||||||
PNEWPOPUP->ly = PPOPUP->ly;
|
PNEWPOPUP->ly = PPOPUP->ly;
|
||||||
PNEWPOPUP->parentWindow = PPOPUP->parentWindow;
|
PNEWPOPUP->parentWindow = PPOPUP->parentWindow;
|
||||||
PNEWPOPUP->monitor = PPOPUP->monitor;
|
PNEWPOPUP->monitor = PPOPUP->monitor;
|
||||||
|
|
||||||
createNewPopup(WLRPOPUP, PNEWPOPUP);
|
createNewPopup(WLRPOPUP, PNEWPOPUP);
|
||||||
}
|
}
|
||||||
@@ -145,19 +147,52 @@ void Events::listener_mapPopupXDG(void* owner, void* data) {
|
|||||||
|
|
||||||
ASSERT(PPOPUP);
|
ASSERT(PPOPUP);
|
||||||
|
|
||||||
Debug::log(LOG, "New XDG Popup mapped at %d %d", (int)PPOPUP->lx, (int)PPOPUP->ly);
|
Debug::log(LOG, "New XDG Popup mapped at {} {}", (int)PPOPUP->lx, (int)PPOPUP->ly);
|
||||||
|
|
||||||
|
if (PPOPUP->parentWindow)
|
||||||
|
PPOPUP->parentWindow->m_lPopupSurfaces.emplace_back(PPOPUP->popup->base->surface);
|
||||||
|
else if (PPOPUP->parentLS)
|
||||||
|
PPOPUP->parentLS->popupSurfaces.emplace_back(PPOPUP->popup->base->surface);
|
||||||
|
|
||||||
PPOPUP->pSurfaceTree = SubsurfaceTree::createTreeRoot(PPOPUP->popup->base->surface, addPopupGlobalCoords, PPOPUP, PPOPUP->parentWindow);
|
PPOPUP->pSurfaceTree = SubsurfaceTree::createTreeRoot(PPOPUP->popup->base->surface, addPopupGlobalCoords, PPOPUP, PPOPUP->parentWindow);
|
||||||
|
|
||||||
int lx = 0, ly = 0;
|
int lx = 0, ly = 0;
|
||||||
addPopupGlobalCoords(PPOPUP, &lx, &ly);
|
addPopupGlobalCoords(PPOPUP, &lx, &ly);
|
||||||
|
|
||||||
wlr_box extents;
|
CBox extents;
|
||||||
wlr_surface_get_extends(PPOPUP->popup->base->surface, &extents);
|
wlr_surface_get_extends(PPOPUP->popup->base->surface, extents.pWlr());
|
||||||
|
extents.applyFromWlr();
|
||||||
|
|
||||||
g_pHyprRenderer->damageBox(lx - extents.x, ly - extents.y, extents.width + 2, extents.height + 2);
|
g_pHyprRenderer->damageBox(lx - extents.x, ly - extents.y, extents.width + 2, extents.height + 2);
|
||||||
|
|
||||||
Debug::log(LOG, "XDG Popup got assigned a surfaceTreeNode %x", PPOPUP->pSurfaceTree);
|
if (PPOPUP->monitor) {
|
||||||
|
g_pCompositor->setPreferredScaleForSurface(PPOPUP->popup->base->surface, PPOPUP->monitor->scale);
|
||||||
|
g_pCompositor->setPreferredTransformForSurface(PPOPUP->popup->base->surface, PPOPUP->monitor->transform);
|
||||||
|
}
|
||||||
|
|
||||||
|
Debug::log(LOG, "XDG Popup got assigned a surfaceTreeNode {:x}", (uintptr_t)PPOPUP->pSurfaceTree);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Events::listener_repositionPopupXDG(void* owner, void* data) {
|
||||||
|
SXDGPopup* PPOPUP = (SXDGPopup*)owner;
|
||||||
|
|
||||||
|
Debug::log(LOG, "XDG Popup {:x} asks for a reposition", (uintptr_t)PPOPUP);
|
||||||
|
|
||||||
|
int lx = 0, ly = 0;
|
||||||
|
addPopupGlobalCoords(PPOPUP, &lx, &ly);
|
||||||
|
|
||||||
|
CBox extents;
|
||||||
|
wlr_surface_get_extends(PPOPUP->popup->base->surface, extents.pWlr());
|
||||||
|
extents.applyFromWlr();
|
||||||
|
|
||||||
|
PPOPUP->lastPos = {lx - extents.x, ly - extents.y};
|
||||||
|
PPOPUP->repositionRequested = true;
|
||||||
|
|
||||||
|
const auto PMONITOR = g_pCompositor->m_pLastMonitor;
|
||||||
|
|
||||||
|
CBox box = {PMONITOR->vecPosition.x - lx + PPOPUP->popup->current.geometry.x, PMONITOR->vecPosition.y - ly + PPOPUP->popup->current.geometry.y, PMONITOR->vecSize.x,
|
||||||
|
PMONITOR->vecSize.y};
|
||||||
|
wlr_xdg_popup_unconstrain_from_box(PPOPUP->popup, box.pWlr());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Events::listener_unmapPopupXDG(void* owner, void* data) {
|
void Events::listener_unmapPopupXDG(void* owner, void* data) {
|
||||||
@@ -166,25 +201,50 @@ void Events::listener_unmapPopupXDG(void* owner, void* data) {
|
|||||||
|
|
||||||
ASSERT(PPOPUP);
|
ASSERT(PPOPUP);
|
||||||
|
|
||||||
|
if (PPOPUP->popup->base->surface == g_pCompositor->m_pLastFocus)
|
||||||
|
g_pInputManager->releaseAllMouseButtons();
|
||||||
|
|
||||||
SubsurfaceTree::destroySurfaceTree(PPOPUP->pSurfaceTree);
|
SubsurfaceTree::destroySurfaceTree(PPOPUP->pSurfaceTree);
|
||||||
|
|
||||||
int lx = 0, ly = 0;
|
int lx = 0, ly = 0;
|
||||||
addPopupGlobalCoords(PPOPUP, &lx, &ly);
|
addPopupGlobalCoords(PPOPUP, &lx, &ly);
|
||||||
|
|
||||||
wlr_box extents;
|
CBox extents;
|
||||||
wlr_surface_get_extends(PPOPUP->popup->base->surface, &extents);
|
wlr_surface_get_extends(PPOPUP->popup->base->surface, extents.pWlr());
|
||||||
|
extents.applyFromWlr();
|
||||||
|
|
||||||
g_pHyprRenderer->damageBox(lx - extents.x, ly - extents.y, extents.width + 2, extents.height + 2);
|
g_pHyprRenderer->damageBox(lx - extents.x, ly - extents.y, extents.width + 2, extents.height + 2);
|
||||||
|
|
||||||
|
if (PPOPUP->parentWindow)
|
||||||
|
std::erase(PPOPUP->parentWindow->m_lPopupSurfaces, PPOPUP->popup->base->surface);
|
||||||
|
else if (PPOPUP->parentLS)
|
||||||
|
std::erase(PPOPUP->parentLS->popupSurfaces, PPOPUP->popup->base->surface);
|
||||||
|
|
||||||
PPOPUP->pSurfaceTree = nullptr;
|
PPOPUP->pSurfaceTree = nullptr;
|
||||||
|
|
||||||
|
g_pInputManager->simulateMouseMovement(); // to focus and return back to an appropriate surface
|
||||||
}
|
}
|
||||||
|
|
||||||
void Events::listener_commitPopupXDG(void* owner, void* data) {
|
void Events::listener_commitPopupXDG(void* owner, void* data) {
|
||||||
SXDGPopup* PPOPUP = (SXDGPopup*)owner;
|
SXDGPopup* PPOPUP = (SXDGPopup*)owner;
|
||||||
|
|
||||||
|
if (g_pCompositor->windowValidMapped(PPOPUP->parentWindow)) {
|
||||||
|
PPOPUP->lx = PPOPUP->parentWindow->m_vRealPosition.vec().x;
|
||||||
|
PPOPUP->ly = PPOPUP->parentWindow->m_vRealPosition.vec().y;
|
||||||
|
}
|
||||||
|
|
||||||
int lx = 0, ly = 0;
|
int lx = 0, ly = 0;
|
||||||
addPopupGlobalCoords(PPOPUP, &lx, &ly);
|
addPopupGlobalCoords(PPOPUP, &lx, &ly);
|
||||||
|
|
||||||
|
CBox extents;
|
||||||
|
wlr_surface_get_extends(PPOPUP->popup->base->surface, extents.pWlr());
|
||||||
|
extents.applyFromWlr();
|
||||||
|
|
||||||
|
if (PPOPUP->repositionRequested)
|
||||||
|
g_pHyprRenderer->damageBox(PPOPUP->lastPos.x, PPOPUP->lastPos.y, extents.width + 2, extents.height + 2);
|
||||||
|
|
||||||
|
PPOPUP->repositionRequested = false;
|
||||||
|
|
||||||
g_pHyprRenderer->damageSurface(PPOPUP->popup->base->surface, lx, ly);
|
g_pHyprRenderer->damageSurface(PPOPUP->popup->base->surface, lx, ly);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -193,12 +253,12 @@ void Events::listener_destroyPopupXDG(void* owner, void* data) {
|
|||||||
|
|
||||||
ASSERT(PPOPUP);
|
ASSERT(PPOPUP);
|
||||||
|
|
||||||
Debug::log(LOG, "Destroyed popup XDG %x", PPOPUP);
|
Debug::log(LOG, "Destroyed popup XDG {:x}", (uintptr_t)PPOPUP);
|
||||||
|
|
||||||
if (PPOPUP->pSurfaceTree) {
|
if (PPOPUP->pSurfaceTree) {
|
||||||
SubsurfaceTree::destroySurfaceTree(PPOPUP->pSurfaceTree);
|
SubsurfaceTree::destroySurfaceTree(PPOPUP->pSurfaceTree);
|
||||||
PPOPUP->pSurfaceTree = nullptr;
|
PPOPUP->pSurfaceTree = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
g_pCompositor->m_vXDGPopups.erase(std::remove_if(g_pCompositor->m_vXDGPopups.begin(), g_pCompositor->m_vXDGPopups.end(), [&](std::unique_ptr<SXDGPopup>& el) { return el.get() == PPOPUP; }));
|
std::erase_if(g_pCompositor->m_vXDGPopups, [&](std::unique_ptr<SXDGPopup>& el) { return el.get() == PPOPUP; });
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user