mirror of
https://github.com/hyprwm/Hyprland.git
synced 2025-08-01 04:31:57 -07:00
Compare commits
915 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
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 |
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.
|
4
.github/workflows/ci.yaml
vendored
4
.github/workflows/ci.yaml
vendored
@@ -39,7 +39,7 @@ jobs:
|
||||
mkdir hyprland/assets
|
||||
cp ./LICENSE hyprland/
|
||||
cp build/Hyprland hyprland/
|
||||
cp hyprctl/hyprctl hyprland/
|
||||
cp build/hyprctl/hyprctl hyprland/
|
||||
cp subprojects/wlroots/build/libwlroots.so.12032 hyprland/
|
||||
cp build/Hyprland hyprland/
|
||||
cp -r example/ hyprland/
|
||||
@@ -105,4 +105,4 @@ jobs:
|
||||
- name: Configure
|
||||
run: mkdir -p build && cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DNO_XWAYLAND:STRING=true -H./ -B./build -G Ninja
|
||||
- name: Compile
|
||||
run: make 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:
|
||||
- name: Install deps
|
||||
run: sudo apt install pandoc
|
||||
|
||||
- name: Clone repository
|
||||
uses: actions/checkout@v3
|
||||
# Not needed
|
||||
# with:
|
||||
# submodules: recursive
|
||||
with:
|
||||
token: ${{ secrets.PAT }}
|
||||
|
||||
- name: Build man pages
|
||||
run: make man
|
||||
|
||||
- uses: stefanzweifel/git-auto-commit-action@v4
|
||||
name: Commit
|
||||
with:
|
||||
|
26
.github/workflows/nix-build.yaml
vendored
26
.github/workflows/nix-build.yaml
vendored
@@ -1,26 +0,0 @@
|
||||
name: Build Hyprland (Nix)
|
||||
|
||||
on: [push, pull_request, workflow_dispatch]
|
||||
jobs:
|
||||
nix:
|
||||
name: "Build Hyprland (Nix)"
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Clone repository
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Install nix
|
||||
uses: cachix/install-nix-action@v20
|
||||
with:
|
||||
install_url: https://nixos.org/nix/install
|
||||
extra_nix_config: |
|
||||
auto-optimise-store = true
|
||||
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
||||
experimental-features = nix-command flakes
|
||||
- uses: cachix/cachix-action@v12
|
||||
with:
|
||||
name: hyprland
|
||||
authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'
|
||||
- name: Build packages
|
||||
run: nix flake check --print-build-logs --accept-flake-config
|
30
.github/workflows/nix-build.yml
vendored
Normal file
30
.github/workflows/nix-build.yml
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
on:
|
||||
workflow_call:
|
||||
secrets:
|
||||
CACHIX_AUTH_TOKEN:
|
||||
required: false
|
||||
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
matrix:
|
||||
package:
|
||||
- hyprland
|
||||
- hyprland-nvidia
|
||||
- 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
|
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"
|
29
.github/workflows/nix-update.yaml
vendored
29
.github/workflows/nix-update.yaml
vendored
@@ -1,29 +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@v20
|
||||
with:
|
||||
install_url: https://nixos.org/nix/install
|
||||
extra_nix_config: |
|
||||
auto-optimise-store = true
|
||||
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
||||
experimental-features = nix-command flakes
|
||||
- name: Update lockfile
|
||||
run: nix/update-inputs.sh
|
||||
- uses: cachix/cachix-action@v12
|
||||
with:
|
||||
name: hyprland
|
||||
authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'
|
||||
- name: Build Waybar-Hyprland
|
||||
run: nix build .#waybar-hyprland --print-build-logs
|
||||
- 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:
|
||||
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
|
||||
id: tar
|
||||
run: mkdir hyprland-source; mv ./* ./hyprland-source || 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
|
||||
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}}"
|
2
.gitignore
vendored
2
.gitignore
vendored
@@ -29,3 +29,5 @@ gmon.out
|
||||
*.tar.gz
|
||||
|
||||
PKGBUILD
|
||||
|
||||
src/version.h
|
||||
|
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -7,3 +7,6 @@
|
||||
[submodule "subprojects/udis86"]
|
||||
path = subprojects/udis86
|
||||
url = https://github.com/canihavesomecoffee/udis86
|
||||
[submodule "subprojects/tracy"]
|
||||
path = subprojects/tracy
|
||||
url = https://github.com/wolfpld/tracy
|
||||
|
207
CMakeLists.txt
Normal file → Executable file
207
CMakeLists.txt
Normal file → Executable file
@@ -10,6 +10,10 @@ project(Hyprland
|
||||
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")
|
||||
|
||||
message(STATUS "Gathering git info")
|
||||
@@ -17,31 +21,60 @@ message(STATUS "Gathering git info")
|
||||
# Get git info
|
||||
# hash and branch
|
||||
execute_process(
|
||||
COMMAND git rev-parse --abbrev-ref HEAD
|
||||
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 | sed -e 's/#//g' -e 's/\"//g'"
|
||||
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)
|
||||
COMMAND ./scripts/generateVersion.sh
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
|
||||
#
|
||||
#
|
||||
|
||||
# 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 = 12)([^032]|$$)/soversion = 12032/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.12032
|
||||
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")
|
||||
add_compile_definitions(HYPRLAND_DEBUG)
|
||||
@@ -52,9 +85,11 @@ endif()
|
||||
|
||||
include_directories(
|
||||
.
|
||||
"src/"
|
||||
"subprojects/wlroots/include/"
|
||||
"subprojects/wlroots/build/include/"
|
||||
"subprojects/udis86/")
|
||||
"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)
|
||||
@@ -66,25 +101,53 @@ message(STATUS "Checking deps...")
|
||||
find_package(Threads REQUIRED)
|
||||
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_check_modules(deps REQUIRED IMPORTED_TARGET wayland-server wayland-client wayland-cursor wayland-protocols cairo libdrm egl xkbcommon libinput pango pangocairo) # 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 CONFIGURE_DEPENDS "src/*.cpp")
|
||||
|
||||
add_executable(Hyprland ${SRCFILES})
|
||||
add_dependencies(Hyprland wlroots)
|
||||
|
||||
if(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG)
|
||||
message(STATUS "Setting debug flags")
|
||||
|
||||
target_link_libraries(Hyprland asan)
|
||||
if (WITH_ASAN)
|
||||
message(STATUS "Enabling ASan")
|
||||
|
||||
add_compile_options(-pg -no-pie -fno-builtin -fsanitize=address)
|
||||
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 PRIVATE execinfo)
|
||||
target_link_libraries(Hyprland execinfo)
|
||||
endif()
|
||||
|
||||
if(LEGACY_RENDERER)
|
||||
@@ -97,53 +160,85 @@ if(NO_XWAYLAND)
|
||||
add_compile_definitions(NO_XWAYLAND)
|
||||
else()
|
||||
message(STATUS "XWAYLAND Enabled (NO_XWAYLAND not defined) checking deps...")
|
||||
pkg_check_modules(xcbdep REQUIRED xcb)
|
||||
target_link_libraries(Hyprland xcb)
|
||||
pkg_check_modules(xcbdep REQUIRED IMPORTED_TARGET xcb)
|
||||
target_link_libraries(Hyprland PkgConfig::xcbdep)
|
||||
endif()
|
||||
|
||||
if(NO_SYSTEMD)
|
||||
message(STATUS "SYSTEMD support is disabled...")
|
||||
else()
|
||||
message(STATUS "SYSTEMD support is requested (NO_SYSTEMD not defined) checking deps...")
|
||||
pkg_check_modules(LIBSYSTEMD libsystemd)
|
||||
check_include_file("systemd/sd-daemon.h" SYSTEMDH)
|
||||
if(LIBSYSTEMD_FOUND AND SYSTEMDH)
|
||||
add_compile_definitions(USES_SYSTEMD)
|
||||
target_link_libraries(Hyprland "${LIBSYSTEMD_LIBRARIES}")
|
||||
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 libsystemd or systemd headers were not found")
|
||||
message(WARNING "Systemd support requested but systemd headers were not found")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
target_compile_definitions(Hyprland
|
||||
PRIVATE
|
||||
"GIT_COMMIT_HASH=\"${GIT_COMMIT_HASH}\""
|
||||
"GIT_BRANCH=\"${GIT_BRANCH}\""
|
||||
"GIT_COMMIT_MESSAGE=\"${GIT_COMMIT_MESSAGE}\""
|
||||
"GIT_DIRTY=\"${GIT_DIRTY}\"")
|
||||
|
||||
target_link_libraries(Hyprland rt)
|
||||
|
||||
set(CPACK_PROJECT_NAME ${PROJECT_NAME})
|
||||
set(CPACK_PROJECT_VERSION ${PROJECT_VERSION})
|
||||
include(CPack)
|
||||
|
||||
message(STATUS "Setting precompiled headers")
|
||||
|
||||
target_precompile_headers(Hyprland PRIVATE $<$<COMPILE_LANGUAGE:CXX>:src/pch/pch.hpp>)
|
||||
|
||||
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
|
||||
${CMAKE_SOURCE_DIR}/subprojects/wlroots/build/libwlroots.so.12032 # wlroots is provided by us
|
||||
pixman-1
|
||||
OpenGL
|
||||
GLESv2
|
||||
pthread
|
||||
${CMAKE_THREAD_LIBS_INIT}
|
||||
${CMAKE_SOURCE_DIR}/ext-workspace-unstable-v1-protocol.o
|
||||
${CMAKE_SOURCE_DIR}/wlr-foreign-toplevel-management-unstable-v1-protocol.o
|
||||
${CMAKE_SOURCE_DIR}/hyprland-toplevel-export-v1-protocol.o
|
||||
${CMAKE_SOURCE_DIR}/fractional-scale-v1-protocol.o
|
||||
${CMAKE_SOURCE_DIR}/text-input-unstable-v1-protocol.o
|
||||
${CMAKE_SOURCE_DIR}/wlr-screencopy-unstable-v1-protocol.o
|
||||
${CMAKE_SOURCE_DIR}/subprojects/udis86/build/libudis86/liblibudis86.a
|
||||
OpenGL::EGL
|
||||
OpenGL::GL
|
||||
Threads::Threads
|
||||
libudis86
|
||||
)
|
||||
|
||||
protocol("protocols/idle.xml" "idle" true)
|
||||
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)
|
||||
|
||||
# hyprctl
|
||||
add_subdirectory(hyprctl)
|
||||
|
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.
|
252
Makefile
252
Makefile
@@ -1,201 +1,58 @@
|
||||
include config.mk
|
||||
|
||||
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
|
||||
|
||||
hyprland-toplevel-export-v1-protocol.h:
|
||||
$(WAYLAND_SCANNER) server-header \
|
||||
subprojects/hyprland-protocols/protocols/hyprland-toplevel-export-v1.xml $@
|
||||
|
||||
hyprland-toplevel-export-v1-protocol.c:
|
||||
$(WAYLAND_SCANNER) private-code \
|
||||
subprojects/hyprland-protocols/protocols/hyprland-toplevel-export-v1.xml $@
|
||||
|
||||
hyprland-toplevel-export-v1-protocol.o: hyprland-toplevel-export-v1-protocol.h
|
||||
|
||||
linux-dmabuf-unstable-v1-protocol.h:
|
||||
$(WAYLAND_SCANNER) server-header \
|
||||
$(WAYLAND_PROTOCOLS)/unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml $@
|
||||
|
||||
linux-dmabuf-unstable-v1-protocol.c:
|
||||
$(WAYLAND_SCANNER) private-code \
|
||||
$(WAYLAND_PROTOCOLS)/unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml $@
|
||||
|
||||
linux-dmabuf-unstable-v1-protocol.o: linux-dmabuf-unstable-v1-protocol.h
|
||||
|
||||
wlr-foreign-toplevel-management-unstable-v1-protocol.h:
|
||||
$(WAYLAND_SCANNER) server-header \
|
||||
protocols/wlr-foreign-toplevel-management-unstable-v1.xml $@
|
||||
|
||||
wlr-foreign-toplevel-management-unstable-v1-protocol.c:
|
||||
$(WAYLAND_SCANNER) private-code \
|
||||
protocols/wlr-foreign-toplevel-management-unstable-v1.xml $@
|
||||
|
||||
wlr-foreign-toplevel-management-unstable-v1-protocol.o: wlr-foreign-toplevel-management-unstable-v1-protocol.h
|
||||
|
||||
fractional-scale-v1-protocol.h:
|
||||
$(WAYLAND_SCANNER) server-header \
|
||||
$(WAYLAND_PROTOCOLS)/staging/fractional-scale/fractional-scale-v1.xml $@
|
||||
|
||||
fractional-scale-v1-protocol.c:
|
||||
$(WAYLAND_SCANNER) private-code \
|
||||
$(WAYLAND_PROTOCOLS)/staging/fractional-scale/fractional-scale-v1.xml $@
|
||||
|
||||
fractional-scale-v1-protocol.o: fractional-scale-v1-protocol.h
|
||||
|
||||
text-input-unstable-v1-protocol.h:
|
||||
$(WAYLAND_SCANNER) server-header \
|
||||
$(WAYLAND_PROTOCOLS)/unstable/text-input/text-input-unstable-v1.xml $@
|
||||
|
||||
text-input-unstable-v1-protocol.c:
|
||||
$(WAYLAND_SCANNER) private-code \
|
||||
$(WAYLAND_PROTOCOLS)/unstable/text-input/text-input-unstable-v1.xml $@
|
||||
|
||||
text-input-unstable-v1-protocol.o: text-input-unstable-v1-protocol.h
|
||||
PREFIX = /usr/local
|
||||
|
||||
legacyrenderer:
|
||||
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:
|
||||
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:
|
||||
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:
|
||||
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:
|
||||
rm -rf build
|
||||
rm -f *.o *-protocol.h *-protocol.c
|
||||
rm -f ./hyprctl/hyprctl
|
||||
rm -f ./protocols/*-protocol.h ./protocols/*-protocol.c
|
||||
rm -rf ./subprojects/wlroots/build
|
||||
|
||||
all:
|
||||
make clear
|
||||
make fixwlr
|
||||
cd ./subprojects/wlroots && meson setup build/ --buildtype=release && ninja -C build/ && cp ./build/libwlroots.so.12032 ${PREFIX}/lib/ || echo "Could not install libwlroots to ${PREFIX}/lib/libwlroots.so.12032"
|
||||
cd subprojects/udis86 && 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)
|
||||
make protocols
|
||||
make release
|
||||
make -C hyprctl all
|
||||
@if [[ "$EUID" = 0 ]]; then echo -en "Avoid running $(MAKE) all as sudo.\n"; fi
|
||||
$(MAKE) clear
|
||||
$(MAKE) release
|
||||
|
||||
install:
|
||||
make clear
|
||||
make fixwlr
|
||||
cd ./subprojects/wlroots && meson setup build/ --buildtype=release && ninja -C build/ && cp ./build/libwlroots.so.12032 ${PREFIX}/lib/ || echo "Could not install libwlroots to ${PREFIX}/lib/libwlroots.so.12032"
|
||||
cd subprojects/udis86 && 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) && cd ../..
|
||||
make protocols
|
||||
make release
|
||||
make -C hyprctl all
|
||||
@if [ ! -f ./build/Hyprland ]; then echo -en "You need to run $(MAKE) all first.\n" && exit 1; fi
|
||||
@echo -en "!NOTE: Please note make install does not compile Hyprland and only installs the already built files."
|
||||
|
||||
mkdir -p ${PREFIX}/share/wayland-sessions
|
||||
mkdir -p ${PREFIX}/bin
|
||||
cp ./build/Hyprland ${PREFIX}/bin
|
||||
cp ./hyprctl/hyprctl ${PREFIX}/bin
|
||||
cp -f ./build/Hyprland ${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
|
||||
cp ./assets/wall_2K.png ${PREFIX}/share/hyprland
|
||||
cp ./assets/wall_4K.png ${PREFIX}/share/hyprland
|
||||
cp ./assets/wall_8K.png ${PREFIX}/share/hyprland
|
||||
cp ./assets/wall_* ${PREFIX}/share/hyprland
|
||||
mkdir -p ${PREFIX}/share/xdg-desktop-portal
|
||||
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:
|
||||
echo -en "make cleaninstall has been DEPRECATED, you should avoid using it in the future.\nRunning make install instead...\n"
|
||||
make install
|
||||
mkdir -p ${PREFIX}/lib/
|
||||
cp ./subprojects/wlroots/build/libwlroots.so.12032 ${PREFIX}/lib/
|
||||
|
||||
$(MAKE) installheaders
|
||||
|
||||
uninstall:
|
||||
rm -f ${PREFIX}/share/wayland-sessions/hyprland.desktop
|
||||
@@ -206,44 +63,27 @@ uninstall:
|
||||
rm -f ${PREFIX}/share/man/man1/Hyprland.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 linux-dmabuf-unstable-v1-protocol.o hyprland-toplevel-export-v1-protocol.o wlr-foreign-toplevel-management-unstable-v1-protocol.o fractional-scale-v1-protocol.o text-input-unstable-v1-protocol.o
|
||||
|
||||
fixwlr:
|
||||
sed -i -E 's/(soversion = 12)([^032]|$$)/soversion = 12032/g' subprojects/wlroots/meson.build
|
||||
|
||||
rm -rf ./subprojects/wlroots/build
|
||||
|
||||
config:
|
||||
make protocols
|
||||
|
||||
make fixwlr
|
||||
|
||||
meson setup subprojects/wlroots/build subprojects/wlroots --prefix=${PREFIX} --buildtype=release -Dwerror=false -Dexamples=false
|
||||
ninja -C subprojects/wlroots/build/
|
||||
|
||||
ninja -C subprojects/wlroots/build/ install
|
||||
|
||||
cd subprojects/udis86 && 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)
|
||||
|
||||
pluginenv:
|
||||
make protocols
|
||||
@echo -en "$(MAKE) pluginenv has been deprecated.\nPlease run $(MAKE) all && sudo $(MAKE) installheaders\n"
|
||||
@exit 1
|
||||
|
||||
installheaders:
|
||||
@if [ ! -f ./build/Hyprland ]; then echo -en "You need to run $(MAKE) all first.\n" && exit 1; fi
|
||||
|
||||
cd subprojects/udis86 && 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)
|
||||
mkdir -p ${PREFIX}/include/hyprland
|
||||
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
|
||||
|
||||
make fixwlr
|
||||
|
||||
meson setup subprojects/wlroots/build subprojects/wlroots --prefix=${PREFIX} --buildtype=release -Dwerror=false -Dexamples=false
|
||||
ninja -C subprojects/wlroots/build/
|
||||
|
||||
configdebug:
|
||||
make protocols
|
||||
|
||||
make fixwlr
|
||||
|
||||
meson setup subprojects/wlroots/build subprojects/wlroots --prefix=${PREFIX} --buildtype=debug -Dwerror=false -Dexamples=false -Db_sanitize=address
|
||||
ninja -C subprojects/wlroots/build/
|
||||
|
||||
ninja -C subprojects/wlroots/build/ install
|
||||
chmod -R 755 ${PREFIX}/include/hyprland
|
||||
chmod 755 ${PREFIX}/share/pkgconfig
|
||||
|
||||
man:
|
||||
pandoc ./docs/Hyprland.1.rst \
|
||||
|
53
README.md
53
README.md
@@ -16,7 +16,8 @@
|
||||
|
||||
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, a powerful plugin system 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>
|
||||
|
||||
@@ -32,40 +33,29 @@ It supports multiple layouts, fancy effects, has a very flexible IPC model allow
|
||||
<br>
|
||||
|
||||
</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.
|
||||
|
||||
# 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
|
||||
- Plugin support
|
||||
- Fast and active development
|
||||
- Not scared to provide bleeding-edge features
|
||||
- Config reloaded instantly upon saving
|
||||
- Custom bezier curve based animations
|
||||
- Dual Kawase blur
|
||||
- Drop shadows
|
||||
- Rounded corners
|
||||
- Gradient borders
|
||||
- Fully dynamic workspaces
|
||||
- Two built-in layouts and more available as plugins
|
||||
- Closely follows `wlroots-git`
|
||||
- Global keybinds passed to your apps of choice
|
||||
- A lot of customization
|
||||
- Bundled wlroots
|
||||
- Window/layer fade in/out
|
||||
- Tiling/pseudotiling/floating/fullscreen windows
|
||||
- Switching workspaces between window modes on the fly
|
||||
- Special workspaces (scratchpads)
|
||||
- Window/monitor rules
|
||||
- Window groups (tabbed mode)
|
||||
- Powerful window/monitor/layer rules
|
||||
- Socket-based IPC
|
||||
- `wlr_ext` workspaces protocol support
|
||||
- Event system for bash scripts
|
||||
- Full damage tracking
|
||||
- Docks support
|
||||
- Drawing tablet support
|
||||
- Native IME + Input panels support
|
||||
- Native IME and Input Panels Support
|
||||
- and much more...
|
||||
|
||||
<br>
|
||||
@@ -90,15 +80,6 @@ Although Hyprland is pretty stable, it may have some bugs.
|
||||
<br>
|
||||
<br>
|
||||
|
||||
# Stars Over Time
|
||||
|
||||
<br>
|
||||
|
||||
[![Stars Preview]][Stars]
|
||||
|
||||
<br>
|
||||
<br>
|
||||
|
||||
</div>
|
||||
|
||||
# Special Thanks
|
||||
@@ -147,9 +128,9 @@ Although Hyprland is pretty stable, it may have some bugs.
|
||||
<!----------------------------------{ Images }--------------------------------->
|
||||
|
||||
[Stars Preview]: https://starchart.cc/vaxerski/Hyprland.svg
|
||||
[Preview A]: https://i.ibb.co/SX7GbYR/winter-rice.png
|
||||
[Preview B]: https://i.ibb.co/B3GJg28/20221126-20h53m26s-grim.png
|
||||
[Preview C]: https://i.imgur.com/pC6YF1Y.png
|
||||
[Preview A]: https://cdn.discordapp.com/attachments/1091569872535814185/1107675866101723277/screenshot-summer.png
|
||||
[Preview B]: https://i.ibb.co/SX7GbYR/winter-rice.png
|
||||
[Preview C]: https://i.ibb.co/B3GJg28/20221126-20h53m26s-grim.png
|
||||
|
||||
|
||||
<!----------------------------------{ 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
|
||||
install_data(wallpapers, install_dir: join_paths(get_option('datadir'), 'hyprland'), install_tag: 'runtime')
|
||||
foreach type : wallpaper_types
|
||||
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
|
||||
|
||||
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,6 +1,6 @@
|
||||
.\" Automatically generated by Pandoc 2.9.2.1
|
||||
.\"
|
||||
.TH "Hyprland" "1" "03 Apr 2023" "" "Hyprland User Manual"
|
||||
.TH "Hyprland" "1" "" "" "Hyprland User Manual"
|
||||
.hy
|
||||
.SH NAME
|
||||
.PP
|
||||
|
@@ -2,7 +2,7 @@
|
||||
|
||||
First of all, please remember to:
|
||||
- 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://wiki.hyprland.org/Configuring/Configuring-Hyprland)
|
||||
|
||||
<br/>
|
||||
|
@@ -1,6 +1,6 @@
|
||||
.\" Automatically generated by Pandoc 2.9.2.1
|
||||
.\"
|
||||
.TH "hyprctl" "1" "03 Apr 2023" "" "hyprctl User Manual"
|
||||
.TH "hyprctl" "1" "" "" "hyprctl User Manual"
|
||||
.hy
|
||||
.SH NAME
|
||||
.PP
|
||||
|
@@ -3,6 +3,6 @@
|
||||
# and that you have ran `make protocols` in the hl dir.
|
||||
|
||||
all:
|
||||
g++ -shared -fPIC --no-gnu-unique main.cpp customLayout.cpp customDecoration.cpp -o examplePlugin.so -g -I "/usr/include/pixman-1" -I "/usr/include/libdrm" -I "${HYPRLAND_HEADERS}" -I "${HYPRLAND_HEADERS}/subprojects/wlroots/include" -I "${HYPRLAND_HEADERS}/subprojects/wlroots/include" -I "${HYPRLAND_HEADERS}/subprojects/wlroots/build/include" -std=c++23
|
||||
$(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
|
||||
|
@@ -1,6 +1,6 @@
|
||||
#include "customDecoration.hpp"
|
||||
#include "../../src/Window.hpp"
|
||||
#include "../../src/Compositor.hpp"
|
||||
#include <hyprland/src/Window.hpp>
|
||||
#include <hyprland/src/Compositor.hpp>
|
||||
#include "globals.hpp"
|
||||
|
||||
CCustomDecoration::CCustomDecoration(CWindow* pWindow) {
|
||||
@@ -33,8 +33,8 @@ void CCustomDecoration::draw(CMonitor* pMonitor, float a, const Vector2D& offset
|
||||
(m_pWindow->m_sAdditionalConfigData.rounding.toUnderlying() == -1 ? *PROUNDING : m_pWindow->m_sAdditionalConfigData.rounding.toUnderlying());
|
||||
|
||||
// draw the border
|
||||
wlr_box 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)};
|
||||
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;
|
||||
@@ -49,9 +49,9 @@ void CCustomDecoration::draw(CMonitor* pMonitor, float a, const Vector2D& offset
|
||||
if (fullBox.width < 1 || fullBox.height < 1)
|
||||
return; // don't draw invisible shadows
|
||||
|
||||
g_pHyprOpenGL->scissor((wlr_box*)nullptr);
|
||||
g_pHyprOpenGL->scissor((CBox*)nullptr);
|
||||
|
||||
scaleBox(&fullBox, pMonitor->scale);
|
||||
fullBox.scale(pMonitor->scale);
|
||||
g_pHyprOpenGL->renderBorder(&fullBox, CColor(*PCOLOR), *PROUNDING * pMonitor->scale + *PBORDERSIZE * 2, a);
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@ void CCustomDecoration::updateWindow(CWindow* pWindow) {
|
||||
}
|
||||
|
||||
void CCustomDecoration::damageEntire() {
|
||||
wlr_box 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};
|
||||
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);
|
||||
}
|
@@ -2,7 +2,7 @@
|
||||
|
||||
#define WLR_USE_UNSTABLE
|
||||
|
||||
#include "../../src/render/decorations/IHyprWindowDecoration.hpp"
|
||||
#include <hyprland/src/render/decorations/IHyprWindowDecoration.hpp>
|
||||
|
||||
class CCustomDecoration : public IHyprWindowDecoration {
|
||||
public:
|
||||
|
@@ -1,5 +1,5 @@
|
||||
#include "customLayout.hpp"
|
||||
#include "../../src/Compositor.hpp"
|
||||
#include <hyprland/src/Compositor.hpp>
|
||||
#include "globals.hpp"
|
||||
|
||||
void CHyprCustomLayout::onWindowCreatedTiling(CWindow* pWindow) {
|
||||
|
@@ -2,7 +2,7 @@
|
||||
|
||||
#define WLR_USE_UNSTABLE
|
||||
|
||||
#include "../../src/layout/IHyprLayout.hpp"
|
||||
#include <hyprland/src/layout/IHyprLayout.hpp>
|
||||
|
||||
struct SWindowData {
|
||||
CWindow* pWindow = nullptr;
|
||||
|
@@ -1,5 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <src/plugins/PluginAPI.hpp>
|
||||
#include <hyprland/src/plugins/PluginAPI.hpp>
|
||||
|
||||
inline HANDLE PHANDLE = nullptr;
|
@@ -2,8 +2,8 @@
|
||||
|
||||
#include "globals.hpp"
|
||||
|
||||
#include <src/Window.hpp>
|
||||
#include <src/Compositor.hpp>
|
||||
#include <hyprland/src/Window.hpp>
|
||||
#include <hyprland/src/Compositor.hpp>
|
||||
#include "customLayout.hpp"
|
||||
#include "customDecoration.hpp"
|
||||
|
||||
@@ -58,8 +58,8 @@ APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE 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, std::any data) { onActiveWindowChange(self, data); });
|
||||
HyprlandAPI::registerCallbackDynamic(PHANDLE, "openWindow", [&](void* self, std::any data) { onNewWindow(self, data); });
|
||||
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>();
|
||||
|
||||
@@ -77,8 +77,12 @@ APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) {
|
||||
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"}, {"time", (uint64_t)10000}, {"color", CColor(0.2, 0.2, 0.9, 1.0)}, {"icon", ICON_HINT}});
|
||||
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();
|
||||
|
@@ -49,16 +49,23 @@ general {
|
||||
col.inactive_border = rgba(595959aa)
|
||||
|
||||
layout = dwindle
|
||||
|
||||
# Please see https://wiki.hyprland.org/Configuring/Tearing/ before you turn this on
|
||||
allow_tearing = false
|
||||
}
|
||||
|
||||
decoration {
|
||||
# See https://wiki.hyprland.org/Configuring/Variables/ for more
|
||||
|
||||
rounding = 10
|
||||
blur = true
|
||||
blur_size = 3
|
||||
blur_passes = 1
|
||||
blur_new_optimizations = true
|
||||
|
||||
blur {
|
||||
enabled = true
|
||||
size = 3
|
||||
passes = 1
|
||||
|
||||
vibrancy = 0.1696
|
||||
}
|
||||
|
||||
drop_shadow = true
|
||||
shadow_range = 4
|
||||
@@ -97,8 +104,13 @@ gestures {
|
||||
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
|
||||
# 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 {
|
||||
sensitivity = -0.5
|
||||
}
|
||||
@@ -153,6 +165,10 @@ bind = $mainMod SHIFT, 8, movetoworkspace, 8
|
||||
bind = $mainMod SHIFT, 9, movetoworkspace, 9
|
||||
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
|
||||
bind = $mainMod, mouse_down, workspace, e+1
|
||||
bind = $mainMod, mouse_up, workspace, e-1
|
||||
|
47
flake.lock
generated
47
flake.lock
generated
@@ -4,14 +4,17 @@
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
],
|
||||
"systems": [
|
||||
"systems"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1671839510,
|
||||
"narHash": "sha256-+PY1qqJfmZzzROgcIY4I7AkCwpnC+qBIYk2eFoA9RWc=",
|
||||
"lastModified": 1691753796,
|
||||
"narHash": "sha256-zOEwiWoXk3j3+EoF3ySUJmberFewWlagvewDRuWYAso=",
|
||||
"owner": "hyprwm",
|
||||
"repo": "hyprland-protocols",
|
||||
"rev": "b8f55e02a328c47ed373133c52483bbfa20a1b75",
|
||||
"rev": "0c2ce70625cb30aef199cb388f99e19a61a6ce03",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -22,11 +25,11 @@
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1680669251,
|
||||
"narHash": "sha256-AVNE+0u4HlI3v96KCXE9risH7NKqj0QDLLfSckYXIbA=",
|
||||
"lastModified": 1698134075,
|
||||
"narHash": "sha256-foCD+nuKzfh49bIoiCBur4+Fx1nozo+4C/6k8BYk4sg=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "9c8ff8b426a8b07b9e0a131ac3218740dc85ba1e",
|
||||
"rev": "8efd5d1e283604f75a808a20e6cde0ef313d07d4",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -40,25 +43,42 @@
|
||||
"inputs": {
|
||||
"hyprland-protocols": "hyprland-protocols",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"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": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"host": "gitlab.freedesktop.org",
|
||||
"lastModified": 1680810405,
|
||||
"narHash": "sha256-LmI/4Yp/pOOoI4RxLRx9I90NBsiqdRLVOfbATKlgpkg=",
|
||||
"lastModified": 1699292815,
|
||||
"narHash": "sha256-HXu98PyBMKEWLqiTb8viuLDznud/SdkdJsx5A5CWx7I=",
|
||||
"owner": "wlroots",
|
||||
"repo": "wlroots",
|
||||
"rev": "7abda952d0000b72d240fe1d41457b9288f0b6e5",
|
||||
"rev": "5de9e1a99d6642c2d09d589aa37ff0a8945dcee1",
|
||||
"type": "gitlab"
|
||||
},
|
||||
"original": {
|
||||
"host": "gitlab.freedesktop.org",
|
||||
"owner": "wlroots",
|
||||
"repo": "wlroots",
|
||||
"rev": "5de9e1a99d6642c2d09d589aa37ff0a8945dcee1",
|
||||
"type": "gitlab"
|
||||
}
|
||||
},
|
||||
@@ -69,14 +89,17 @@
|
||||
],
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
],
|
||||
"systems": [
|
||||
"systems"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1673116118,
|
||||
"narHash": "sha256-eR0yDSkR2XYMesfdRWJs25kAdXET2mbNNHu5t+KUcKA=",
|
||||
"lastModified": 1697981233,
|
||||
"narHash": "sha256-y8q4XUwx+gVK7i2eLjfR32lVo7TYvEslyzrmzYEaPZU=",
|
||||
"owner": "hyprwm",
|
||||
"repo": "xdg-desktop-portal-hyprland",
|
||||
"rev": "d479c846531fd0e1d2357c9588b8310a2b859ef2",
|
||||
"rev": "22e7a65ff9633e1dedfa5317fdffc49f68de2ff2",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
141
flake.nix
141
flake.nix
@@ -3,19 +3,29 @@
|
||||
|
||||
inputs = {
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||
|
||||
# <https://github.com/nix-systems/nix-systems>
|
||||
systems.url = "github:nix-systems/default-linux";
|
||||
|
||||
wlroots = {
|
||||
url = "gitlab:wlroots/wlroots?host=gitlab.freedesktop.org";
|
||||
type = "gitlab";
|
||||
host = "gitlab.freedesktop.org";
|
||||
owner = "wlroots";
|
||||
repo = "wlroots";
|
||||
rev = "5de9e1a99d6642c2d09d589aa37ff0a8945dcee1";
|
||||
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";
|
||||
};
|
||||
};
|
||||
@@ -23,102 +33,55 @@
|
||||
outputs = inputs @ {
|
||||
self,
|
||||
nixpkgs,
|
||||
systems,
|
||||
...
|
||||
}: let
|
||||
inherit (nixpkgs) lib;
|
||||
genSystems = lib.genAttrs [
|
||||
# Add more systems if they are supported
|
||||
"aarch64-linux"
|
||||
"x86_64-linux"
|
||||
];
|
||||
|
||||
pkgsFor = nixpkgs.legacyPackages;
|
||||
|
||||
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)
|
||||
]);
|
||||
eachSystem = lib.genAttrs (import systems);
|
||||
pkgsFor = eachSystem (system:
|
||||
import nixpkgs {
|
||||
localSystem = system;
|
||||
overlays = with self.overlays; [
|
||||
hyprland-packages
|
||||
hyprland-extras
|
||||
];
|
||||
});
|
||||
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;
|
||||
libdisplay-info = prev.libdisplay-info.overrideAttrs (old: {
|
||||
version = "0.1.1+date=2023-03-02";
|
||||
src = prev.fetchFromGitLab {
|
||||
domain = "gitlab.freedesktop.org";
|
||||
owner = "emersion";
|
||||
repo = old.pname;
|
||||
rev = "147d6611a64a6ab04611b923e30efacaca6fc678";
|
||||
sha256 = "sha256-/q79o13Zvu7x02SBGu0W5yQznQ+p7ltZ9L6cMW5t/o4=";
|
||||
};
|
||||
});
|
||||
overlays = import ./nix/overlays.nix {inherit self lib inputs;};
|
||||
|
||||
libliftoff = prev.libliftoff.overrideAttrs (old: {
|
||||
version = "0.5.0-dev";
|
||||
src = prev.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"
|
||||
];
|
||||
});
|
||||
};
|
||||
hyprland = prev.callPackage ./nix/default.nix {
|
||||
stdenv = prev.gcc12Stdenv;
|
||||
version = props.version + "+date=" + (mkDate (self.lastModifiedDate or "19700101")) + "_" + (self.shortRev or "dirty");
|
||||
wlroots = wlroots-hyprland;
|
||||
commit = self.rev or "";
|
||||
inherit (inputs.hyprland-protocols.packages.${prev.stdenv.hostPlatform.system}) hyprland-protocols;
|
||||
inherit udis86;
|
||||
};
|
||||
hyprland-debug = hyprland.override {debug = true;};
|
||||
hyprland-hidpi = hyprland.override {hidpiXWayland = true;};
|
||||
hyprland-nvidia = hyprland.override {nvidiaPatches = true;};
|
||||
hyprland-no-hidpi = builtins.trace "hyprland-no-hidpi was removed. Please use the default package." hyprland;
|
||||
|
||||
udis86 = prev.callPackage ./nix/udis86.nix {};
|
||||
|
||||
waybar-hyprland = prev.waybar.overrideAttrs (oldAttrs: {
|
||||
postPatch = ''
|
||||
# use hyprctl to switch workspaces
|
||||
sed -i 's/zext_workspace_handle_v1_activate(workspace_handle_);/const std::string command = "hyprctl dispatch workspace " + name_;\n\tsystem(command.c_str());/g' src/modules/wlr/workspace_manager.cpp
|
||||
'';
|
||||
mesonFlags = oldAttrs.mesonFlags ++ ["-Dexperimental=true"];
|
||||
});
|
||||
|
||||
xdg-desktop-portal-hyprland = inputs.xdph.packages.${prev.stdenv.hostPlatform.system}.default.override {
|
||||
hyprland-share-picker = inputs.xdph.packages.${prev.stdenv.hostPlatform.system}.hyprland-share-picker.override {inherit hyprland;};
|
||||
};
|
||||
};
|
||||
|
||||
checks = genSystems (system:
|
||||
(lib.filterAttrs (n: _: (lib.hasPrefix "hyprland" n) && !(lib.hasSuffix "debug" n)) self.packages.${system})
|
||||
// {inherit (self.packages.${system}) xdg-desktop-portal-hyprland;});
|
||||
|
||||
packages = genSystems (system:
|
||||
(self.overlays.default null pkgsFor.${system})
|
||||
checks = eachSystem (system:
|
||||
(lib.filterAttrs
|
||||
(n: _: (lib.hasPrefix "hyprland" n) && !(lib.hasSuffix "debug" n))
|
||||
self.packages.${system})
|
||||
// {
|
||||
default = self.packages.${system}.hyprland;
|
||||
inherit (self.packages.${system}) xdg-desktop-portal-hyprland;
|
||||
});
|
||||
|
||||
devShells = genSystems (system: {
|
||||
default = pkgsFor.${system}.mkShell.override {stdenv = pkgsFor.${system}.gcc12Stdenv;} {
|
||||
packages = eachSystem (system: {
|
||||
default = self.packages.${system}.hyprland;
|
||||
inherit
|
||||
(pkgsFor.${system})
|
||||
# hyprland-packages
|
||||
hyprland
|
||||
hyprland-unwrapped
|
||||
hyprland-debug
|
||||
hyprland-nvidia
|
||||
# hyprland-extras
|
||||
xdg-desktop-portal-hyprland
|
||||
# dependencies
|
||||
hyprland-protocols
|
||||
wlroots-hyprland
|
||||
udis86
|
||||
;
|
||||
});
|
||||
|
||||
devShells = eachSystem (system: {
|
||||
default = pkgsFor.${system}.mkShell.override {
|
||||
stdenv = pkgsFor.${system}.gcc13Stdenv;
|
||||
} {
|
||||
name = "hyprland-shell";
|
||||
nativeBuildInputs = with pkgsFor.${system}; [
|
||||
cmake
|
||||
];
|
||||
buildInputs = [
|
||||
self.packages.${system}.wlroots-hyprland
|
||||
];
|
||||
nativeBuildInputs = with pkgsFor.${system}; [cmake python3];
|
||||
buildInputs = [self.packages.${system}.wlroots-hyprland];
|
||||
inputsFrom = [
|
||||
self.packages.${system}.wlroots-hyprland
|
||||
self.packages.${system}.hyprland
|
||||
@@ -126,7 +89,7 @@
|
||||
};
|
||||
});
|
||||
|
||||
formatter = genSystems (system: pkgsFor.${system}.alejandra);
|
||||
formatter = eachSystem (system: nixpkgs.legacyPackages.${system}.alejandra);
|
||||
|
||||
nixosModules.default = import ./nix/module.nix inputs;
|
||||
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:
|
||||
g++ -std=c++23 ./main.cpp -o ./hyprctl
|
||||
$(CXX) -std=c++2b ./main.cpp -o ./hyprctl
|
||||
clean:
|
||||
rm ./hyprctl
|
||||
|
261
hyprctl/main.cpp
261
hyprctl/main.cpp
@@ -11,18 +11,25 @@
|
||||
#include <unistd.h>
|
||||
#include <ranges>
|
||||
#include <algorithm>
|
||||
#include <signal.h>
|
||||
#include <format>
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <deque>
|
||||
#include <filesystem>
|
||||
#include <stdarg.h>
|
||||
|
||||
const std::string USAGE = R"#(usage: hyprctl [(opt)flags] [command] [(opt)args]
|
||||
|
||||
commands:
|
||||
monitors
|
||||
workspaces
|
||||
activeworkspace
|
||||
workspacerules
|
||||
clients
|
||||
activewindow
|
||||
layers
|
||||
@@ -43,13 +50,65 @@ commands:
|
||||
setprop
|
||||
plugin
|
||||
notify
|
||||
globalshortcuts
|
||||
instances
|
||||
|
||||
flags:
|
||||
-j -> output in JSON
|
||||
--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, int minArgs = 0) {
|
||||
#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 ARGS = std::count(arg.begin(), arg.end(), ' ');
|
||||
@@ -64,22 +123,17 @@ void request(std::string arg, int minArgs = 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// get the instance signature
|
||||
auto instanceSig = getenv("HYPRLAND_INSTANCE_SIGNATURE");
|
||||
|
||||
if (!instanceSig) {
|
||||
if (instanceSignature.empty()) {
|
||||
std::cout << "HYPRLAND_INSTANCE_SIGNATURE was not set! (Is Hyprland running?)";
|
||||
return;
|
||||
}
|
||||
|
||||
std::string instanceSigStr = std::string(instanceSig);
|
||||
|
||||
sockaddr_un serverAddress = {0};
|
||||
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) {
|
||||
std::cout << "Couldn't connect to " << socketPath << ". (3)";
|
||||
@@ -127,28 +181,26 @@ void requestHyprpaper(std::string arg) {
|
||||
return;
|
||||
}
|
||||
|
||||
// get the instance signature
|
||||
auto instanceSig = getenv("HYPRLAND_INSTANCE_SIGNATURE");
|
||||
|
||||
if (!instanceSig) {
|
||||
if (instanceSignature.empty()) {
|
||||
std::cout << "HYPRLAND_INSTANCE_SIGNATURE was not set! (Is Hyprland running?)";
|
||||
return;
|
||||
}
|
||||
|
||||
std::string instanceSigStr = std::string(instanceSig);
|
||||
|
||||
sockaddr_un serverAddress = {0};
|
||||
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) {
|
||||
std::cout << "Couldn't connect to " << socketPath << ". (3)";
|
||||
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());
|
||||
|
||||
if (sizeWritten < 0) {
|
||||
@@ -170,89 +222,42 @@ void requestHyprpaper(std::string arg) {
|
||||
std::cout << std::string(buffer);
|
||||
}
|
||||
|
||||
int dispatchRequest(int argc, char** argv) {
|
||||
|
||||
if (argc < 3) {
|
||||
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++) {
|
||||
if (!strcmp(argv[i], "--"))
|
||||
continue;
|
||||
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;
|
||||
}
|
||||
|
||||
int outputRequest(int argc, char** argv) {
|
||||
if (argc < 4) {
|
||||
std::cout << "Usage: hyprctl output <mode> <name>\n\
|
||||
creates / destroys a fake output\n\
|
||||
with create, name is the backend name to use (available: auto, x11, wayland, headless)\n\
|
||||
with destroy, name is the output name to destroy";
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::string rq = "output " + std::string(argv[2]) + " " + std::string(argv[3]);
|
||||
|
||||
request(rq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void batchRequest(std::string arg) {
|
||||
std::string rq = "[[BATCH]]" + arg.substr(arg.find_first_of(" ") + 1);
|
||||
|
||||
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> result;
|
||||
|
||||
@@ -269,7 +274,6 @@ bool isNumber(const std::string& str, bool allowfloat) {
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
int bflag = 0, sflag = 0, index, c;
|
||||
bool parseArgs = true;
|
||||
|
||||
if (argc < 2) {
|
||||
@@ -277,11 +281,13 @@ int main(int argc, char** argv) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::string fullRequest = "";
|
||||
std::string fullArgs = "";
|
||||
const auto ARGS = splitArgs(argc, argv);
|
||||
std::string fullRequest = "";
|
||||
std::string fullArgs = "";
|
||||
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] == "--") {
|
||||
// Stop parsing arguments after --
|
||||
parseArgs = false;
|
||||
@@ -291,8 +297,18 @@ int main(int argc, char** argv) {
|
||||
// parse
|
||||
if (ARGS[i] == "-j" && !fullArgs.contains("j")) {
|
||||
fullArgs += "j";
|
||||
json = true;
|
||||
} else if (ARGS[i] == "--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 {
|
||||
printf("%s\n", USAGE.c_str());
|
||||
return 1;
|
||||
@@ -313,6 +329,35 @@ int main(int argc, char** argv) {
|
||||
|
||||
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;
|
||||
|
||||
if (fullRequest.contains("/--batch"))
|
||||
@@ -323,6 +368,10 @@ int main(int argc, char** argv) {
|
||||
request(fullRequest);
|
||||
else if (fullRequest.contains("/workspaces"))
|
||||
request(fullRequest);
|
||||
else if (fullRequest.contains("/activeworkspace"))
|
||||
request(fullRequest);
|
||||
else if (fullRequest.contains("/workspacerules"))
|
||||
request(fullRequest);
|
||||
else if (fullRequest.contains("/activewindow"))
|
||||
request(fullRequest);
|
||||
else if (fullRequest.contains("/layers"))
|
||||
@@ -345,6 +394,10 @@ int main(int argc, char** argv) {
|
||||
request(fullRequest);
|
||||
else if (fullRequest.contains("/animations"))
|
||||
request(fullRequest);
|
||||
else if (fullRequest.contains("/globalshortcuts"))
|
||||
request(fullRequest);
|
||||
else if (fullRequest.contains("/instances"))
|
||||
instancesRequest(json);
|
||||
else if (fullRequest.contains("/switchxkblayout"))
|
||||
request(fullRequest, 2);
|
||||
else if (fullRequest.contains("/seterror"))
|
||||
@@ -356,15 +409,15 @@ int main(int argc, char** argv) {
|
||||
else if (fullRequest.contains("/notify"))
|
||||
request(fullRequest, 2);
|
||||
else if (fullRequest.contains("/output"))
|
||||
exitStatus = outputRequest(argc, argv);
|
||||
request(fullRequest, 2);
|
||||
else if (fullRequest.contains("/setcursor"))
|
||||
exitStatus = setcursorRequest(argc, argv);
|
||||
request(fullRequest, 1);
|
||||
else if (fullRequest.contains("/dispatch"))
|
||||
exitStatus = dispatchRequest(argc, argv);
|
||||
request(fullRequest, 1);
|
||||
else if (fullRequest.contains("/keyword"))
|
||||
exitStatus = keywordRequest(argc, argv);
|
||||
request(fullRequest, 2);
|
||||
else if (fullRequest.contains("/hyprpaper"))
|
||||
exitStatus = hyprpaperRequest(argc, argv);
|
||||
requestHyprpaper(fullRequest);
|
||||
else if (fullRequest.contains("/--help"))
|
||||
printf("%s", USAGE.c_str());
|
||||
else {
|
||||
|
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}"
|
35
meson.build
35
meson.build
@@ -20,26 +20,20 @@ else
|
||||
error('Could not configure current C++ compiler (' + cpp_compiler.get_id() + ' ' + cpp_compiler.version() + ') with required C++ standard (C++23)')
|
||||
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(
|
||||
[
|
||||
'-Wno-unused-parameter',
|
||||
'-Wno-unused-value',
|
||||
'-Wno-missing-field-initializers',
|
||||
'-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')
|
||||
|
||||
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')
|
||||
xcb_dep = dependency('xcb', required: get_option('xwayland'))
|
||||
|
||||
@@ -75,9 +69,28 @@ 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
|
||||
install_headers(file, subdir: 'hyprland', preserve_path: true)
|
||||
endforeach
|
||||
|
||||
subdir('protocols')
|
||||
subdir('src')
|
||||
subdir('hyprctl')
|
||||
subdir('assets')
|
||||
subdir('example')
|
||||
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'],
|
||||
)
|
||||
|
181
nix/default.nix
181
nix/default.nix
@@ -2,8 +2,10 @@
|
||||
lib,
|
||||
stdenv,
|
||||
pkg-config,
|
||||
makeWrapper,
|
||||
meson,
|
||||
ninja,
|
||||
binutils,
|
||||
cairo,
|
||||
git,
|
||||
hyprland-protocols,
|
||||
@@ -24,97 +26,116 @@
|
||||
xcbutilwm,
|
||||
xwayland,
|
||||
debug ? false,
|
||||
enableNvidiaPatches ? false,
|
||||
enableXWayland ? true,
|
||||
hidpiXWayland ? false,
|
||||
legacyRenderer ? false,
|
||||
nvidiaPatches ? false,
|
||||
withSystemd ? true,
|
||||
withSystemd ? lib.meta.availableOn stdenv.hostPlatform systemd,
|
||||
wrapRuntimeDeps ? true,
|
||||
version ? "git",
|
||||
commit,
|
||||
}: let
|
||||
assertXWayland = lib.assertMsg (hidpiXWayland -> enableXWayland) ''
|
||||
Hyprland: cannot have hidpiXWayland when enableXWayland is false.
|
||||
'';
|
||||
in
|
||||
assert assertXWayland;
|
||||
stdenv.mkDerivation {
|
||||
pname = "hyprland" + lib.optionalString debug "-debug";
|
||||
inherit version;
|
||||
# deprecated flags
|
||||
nvidiaPatches ? false,
|
||||
hidpiXWayland ? false,
|
||||
}:
|
||||
assert lib.assertMsg (!nvidiaPatches) "The option `nvidiaPatches` has been renamed `enableNvidiaPatches`";
|
||||
assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been removed. Please refer https://wiki.hyprland.org/Configuring/XWayland";
|
||||
stdenv.mkDerivation {
|
||||
pname = "hyprland${lib.optionalString enableNvidiaPatches "-nvidia"}${lib.optionalString debug "-debug"}";
|
||||
inherit version;
|
||||
|
||||
src = lib.cleanSourceWith {
|
||||
filter = name: type: let
|
||||
baseName = baseNameOf (toString name);
|
||||
in
|
||||
! (
|
||||
lib.hasSuffix ".nix" baseName
|
||||
);
|
||||
src = lib.cleanSource ../.;
|
||||
};
|
||||
src = lib.cleanSourceWith {
|
||||
filter = name: type: let
|
||||
baseName = baseNameOf (toString name);
|
||||
in
|
||||
! (lib.hasSuffix ".nix" baseName);
|
||||
src = lib.cleanSource ../.;
|
||||
};
|
||||
|
||||
nativeBuildInputs = [
|
||||
jq
|
||||
meson
|
||||
ninja
|
||||
pkg-config
|
||||
];
|
||||
nativeBuildInputs = [
|
||||
jq
|
||||
meson
|
||||
ninja
|
||||
pkg-config
|
||||
makeWrapper
|
||||
wayland-scanner
|
||||
];
|
||||
|
||||
outputs = [
|
||||
"out"
|
||||
"man"
|
||||
];
|
||||
outputs = [
|
||||
"out"
|
||||
"man"
|
||||
"dev"
|
||||
];
|
||||
|
||||
buildInputs =
|
||||
[
|
||||
git
|
||||
cairo
|
||||
hyprland-protocols
|
||||
libdrm
|
||||
libinput
|
||||
libxkbcommon
|
||||
mesa
|
||||
pango
|
||||
udis86
|
||||
wayland
|
||||
wayland-protocols
|
||||
wayland-scanner
|
||||
pciutils
|
||||
(wlroots.override {inherit enableXWayland hidpiXWayland nvidiaPatches;})
|
||||
]
|
||||
++ lib.optionals enableXWayland [libxcb xcbutilwm xwayland]
|
||||
++ lib.optionals withSystemd [systemd];
|
||||
buildInputs =
|
||||
[
|
||||
git
|
||||
cairo
|
||||
hyprland-protocols
|
||||
libdrm
|
||||
libinput
|
||||
libxkbcommon
|
||||
mesa
|
||||
pango
|
||||
udis86
|
||||
wayland
|
||||
wayland-protocols
|
||||
pciutils
|
||||
(wlroots.override {inherit enableNvidiaPatches;})
|
||||
]
|
||||
++ lib.optionals enableXWayland [libxcb xcbutilwm xwayland]
|
||||
++ lib.optionals withSystemd [systemd];
|
||||
|
||||
mesonBuildType =
|
||||
if debug
|
||||
then "debug"
|
||||
else "release";
|
||||
mesonBuildType =
|
||||
if debug
|
||||
then "debug"
|
||||
else "release";
|
||||
|
||||
mesonFlags = builtins.concatLists [
|
||||
["-Dauto_features=disabled"]
|
||||
(lib.optional enableXWayland "-Dxwayland=enabled")
|
||||
(lib.optional legacyRenderer "-Dlegacy_renderer=enabled")
|
||||
(lib.optional withSystemd "-Dsystemd=enabled")
|
||||
];
|
||||
mesonAutoFeatures = "disabled";
|
||||
|
||||
patches = [
|
||||
# make meson use the provided wlroots instead of the git submodule
|
||||
./meson-build.patch
|
||||
];
|
||||
mesonFlags = builtins.concatLists [
|
||||
(lib.optional enableXWayland "-Dxwayland=enabled")
|
||||
(lib.optional legacyRenderer "-Dlegacy_renderer=enabled")
|
||||
(lib.optional withSystemd "-Dsystemd=enabled")
|
||||
];
|
||||
|
||||
postPatch = ''
|
||||
# Fix hardcoded paths to /usr installation
|
||||
sed -i "s#/usr#$out#" src/render/OpenGL.cpp
|
||||
substituteInPlace meson.build \
|
||||
--replace "@GIT_COMMIT_HASH@" '${commit}' \
|
||||
--replace "@GIT_DIRTY@" '${if commit == "" then "dirty" else ""}'
|
||||
'';
|
||||
patches = [
|
||||
# make meson use the provided wlroots instead of the git submodule
|
||||
./patches/meson-build.patch
|
||||
];
|
||||
|
||||
passthru.providedSessions = ["hyprland"];
|
||||
postPatch = ''
|
||||
# Fix hardcoded paths to /usr installation
|
||||
sed -i "s#/usr#$out#" src/render/OpenGL.cpp
|
||||
|
||||
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";
|
||||
};
|
||||
}
|
||||
# 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 ""
|
||||
}'
|
||||
'';
|
||||
|
||||
postInstall = ''
|
||||
ln -s ${wlroots}/include/wlr $dev/include/hyprland/wlroots
|
||||
${lib.optionalString wrapRuntimeDeps ''
|
||||
wrapProgram $out/bin/Hyprland \
|
||||
--suffix PATH : ${lib.makeBinPath [binutils pciutils]}
|
||||
''}
|
||||
'';
|
||||
|
||||
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";
|
||||
};
|
||||
}
|
||||
|
@@ -7,21 +7,43 @@ self: {
|
||||
cfg = config.wayland.windowManager.hyprland;
|
||||
defaultHyprlandPackage = self.packages.${pkgs.stdenv.hostPlatform.system}.default.override {
|
||||
enableXWayland = cfg.xwayland.enable;
|
||||
hidpiXWayland = cfg.xwayland.hidpi;
|
||||
nvidiaPatches = cfg.nvidiaPatches;
|
||||
inherit (cfg) enableNvidiaPatches;
|
||||
};
|
||||
in {
|
||||
disabledModules = ["services/window-managers/hyprland.nix"];
|
||||
|
||||
meta.maintainers = [lib.maintainers.fufexan];
|
||||
|
||||
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 {
|
||||
type = with lib.types; nullOr package;
|
||||
default = defaultHyprlandPackage;
|
||||
description = ''
|
||||
Hyprland package to use. Will override the 'xwayland' option.
|
||||
defaultText = lib.literalExpression ''
|
||||
hyprland.packages.''${pkgs.stdenv.hostPlatform.system}.default.override {
|
||||
enableXWayland = config.wayland.windowManager.hyprland.xwayland.enable;
|
||||
inherit (config.wayland.windowManager.hyprland) enableNvidiaPatches;
|
||||
}
|
||||
'';
|
||||
description = lib.mdDoc ''
|
||||
Hyprland package to use. Will override the 'xwayland' and
|
||||
'enableNvidiaPatches' options.
|
||||
|
||||
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.
|
||||
|
||||
Set to null to not add any Hyprland package to your path. This should
|
||||
@@ -29,103 +51,96 @@ in {
|
||||
'';
|
||||
};
|
||||
|
||||
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 {
|
||||
type = lib.types.bool;
|
||||
default = pkgs.stdenv.isLinux;
|
||||
description = ''
|
||||
Whether to enable <filename>hyprland-session.target</filename> on
|
||||
hyprland startup. This links to <filename>graphical-session.target</filename>.
|
||||
description = lib.mdDoc ''
|
||||
Whether to enable {file}`hyprland-session.target` on
|
||||
Hyprland startup. This links to {file}`graphical-session.target`.
|
||||
Some important environment variables will be imported to systemd
|
||||
and dbus user environment before reaching the target, including
|
||||
<itemizedlist>
|
||||
<listitem><para><literal>DISPLAY</literal></para></listitem>
|
||||
<listitem><para><literal>WAYLAND_DISPLAY</literal></para></listitem>
|
||||
<listitem><para><literal>HYPRLAND_INSTANCE_SIGNATURE</literal></para></listitem>
|
||||
<listitem><para><literal>XDG_CURRENT_DESKTOP</literal></para></listitem>
|
||||
</itemizedlist>
|
||||
- {env}`DISPLAY`
|
||||
- {env}`HYPRLAND_INSTANCE_SIGNATURE`
|
||||
- {env}`WAYLAND_DISPLAY`
|
||||
- {env}`XDG_CURRENT_DESKTOP`
|
||||
'';
|
||||
};
|
||||
|
||||
disableAutoreload = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = false;
|
||||
defaultText = lib.literalExpression "false";
|
||||
example = lib.literalExpression "true";
|
||||
description = ''
|
||||
Whether to disable automatically reloading Hyprland's configuration when
|
||||
rebuilding the Home Manager profile.
|
||||
'';
|
||||
};
|
||||
|
||||
xwayland = {
|
||||
enable = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = true;
|
||||
description = ''
|
||||
Enable XWayland.
|
||||
disableAutoreload =
|
||||
lib.mkEnableOption null
|
||||
// {
|
||||
description = lib.mdDoc ''
|
||||
Whether to disable automatically reloading Hyprland's configuration when
|
||||
rebuilding the Home Manager profile.
|
||||
'';
|
||||
};
|
||||
hidpi = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Enable HiDPI XWayland.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
nvidiaPatches = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = false;
|
||||
defaultText = lib.literalExpression "false";
|
||||
example = lib.literalExpression "true";
|
||||
description = ''
|
||||
Patch wlroots for better Nvidia support.
|
||||
'';
|
||||
};
|
||||
xwayland.enable = lib.mkEnableOption (lib.mdDoc "XWayland") // {default = true;};
|
||||
|
||||
enableNvidiaPatches = lib.mkEnableOption (lib.mdDoc "patching wlroots for better Nvidia support.");
|
||||
|
||||
extraConfig = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.lines;
|
||||
default = "";
|
||||
description = ''
|
||||
Extra configuration lines to add to ~/.config/hypr/hyprland.conf.
|
||||
description = lib.mdDoc ''
|
||||
Extra configuration lines to add to {file}`~/.config/hypr/hyprland.conf`.
|
||||
'';
|
||||
};
|
||||
|
||||
recommendedEnvironment = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = true;
|
||||
defaultText = lib.literalExpression "true";
|
||||
example = lib.literalExpression "false";
|
||||
description = ''
|
||||
Whether to set the recommended environment variables.
|
||||
'';
|
||||
};
|
||||
|
||||
imports = [
|
||||
(
|
||||
lib.mkRenamedOptionModule
|
||||
["wayland" "windowManager" "hyprland" "xwayland"]
|
||||
["wayland" "windowManager" "hyprland" "xwayland" "enable"]
|
||||
)
|
||||
];
|
||||
recommendedEnvironment =
|
||||
lib.mkEnableOption null
|
||||
// {
|
||||
description = lib.mdDoc ''
|
||||
Whether to set the recommended environment variables.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
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 =
|
||||
lib.optional (cfg.package != null) cfg.package
|
||||
++ lib.optional cfg.xwayland.enable pkgs.xwayland;
|
||||
|
||||
home.sessionVariables = lib.mkIf cfg.recommendedEnvironment {
|
||||
NIXOS_OZONE_WL = "1";
|
||||
};
|
||||
home.sessionVariables =
|
||||
lib.mkIf cfg.recommendedEnvironment {NIXOS_OZONE_WL = "1";};
|
||||
|
||||
xdg.configFile."hypr/hyprland.conf" = lib.mkIf (cfg.extraConfig != null) {
|
||||
xdg.configFile."hypr/hyprland.conf" = lib.mkIf (cfg.systemdIntegration || cfg.extraConfig != null || cfg.plugins != []) {
|
||||
text =
|
||||
(lib.optionalString cfg.systemdIntegration ''
|
||||
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
|
||||
'')
|
||||
+ 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
|
||||
hyprlandPackage =
|
||||
@@ -133,30 +148,30 @@ in {
|
||||
then defaultHyprlandPackage
|
||||
else cfg.package;
|
||||
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
|
||||
)'';
|
||||
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 {
|
||||
Unit = {
|
||||
Description = "hyprland compositor session";
|
||||
Description = "Hyprland compositor session";
|
||||
Documentation = ["man:systemd.special(7)"];
|
||||
BindsTo = ["graphical-session.target"];
|
||||
Wants = ["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")
|
||||
];
|
||||
}
|
||||
|
134
nix/module.nix
134
nix/module.nix
@@ -1,105 +1,99 @@
|
||||
# Copied from https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/programs/sway.nix
|
||||
inputs: {
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
options,
|
||||
...
|
||||
}:
|
||||
with lib; let
|
||||
cfg = config.programs.hyprland;
|
||||
inherit (pkgs.stdenv.hostPlatform) system;
|
||||
|
||||
defaultHyprlandPackage = inputs.self.packages.${pkgs.stdenv.hostPlatform.system}.default.override {
|
||||
enableXWayland = cfg.xwayland.enable;
|
||||
hidpiXWayland = cfg.xwayland.hidpi;
|
||||
nvidiaPatches = cfg.nvidiaPatches;
|
||||
finalPortalPackage = cfg.portalPackage.override {
|
||||
hyprland = cfg.finalPackage;
|
||||
};
|
||||
in {
|
||||
imports = [
|
||||
(mkRemovedOptionModule ["programs" "hyprland" "extraPackages"] "extraPackages has been removed. Use environment.systemPackages instead.")
|
||||
];
|
||||
# disables Nixpkgs Hyprland module to avoid conflicts
|
||||
disabledModules = ["programs/hyprland.nix"];
|
||||
|
||||
options.programs.hyprland = {
|
||||
enable = mkEnableOption ''
|
||||
Hyprland, the dynamic tiling Wayland compositor that doesn't sacrifice on its looks.
|
||||
You can manually launch Hyprland by executing "exec Hyprland" on a TTY.
|
||||
A configuration file will be generated in ~/.config/hypr/hyprland.conf.
|
||||
See <link xlink:href="https://github.com/vaxerski/Hyprland/wiki" /> for
|
||||
more information.
|
||||
'';
|
||||
enable =
|
||||
mkEnableOption null
|
||||
// {
|
||||
description = mdDoc ''
|
||||
Hyprland, the dynamic tiling Wayland compositor that doesn't sacrifice on its looks.
|
||||
|
||||
package = mkOption {
|
||||
type = types.nullOr types.package;
|
||||
default = defaultHyprlandPackage;
|
||||
defaultText = literalExpression "<Hyprland flake>.packages.<system>.default";
|
||||
example = literalExpression "<Hyprland flake>.packages.<system>.default.override { }";
|
||||
description = ''
|
||||
Hyprland package to use.
|
||||
'';
|
||||
};
|
||||
You can manually launch Hyprland by executing {command}`Hyprland` on a TTY.
|
||||
|
||||
xwayland = {
|
||||
enable = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = ''
|
||||
Enable XWayland.
|
||||
A configuration file will be generated in {file}`~/.config/hypr/hyprland.conf`.
|
||||
See <https://wiki.hyprland.org> for more information.
|
||||
'';
|
||||
};
|
||||
hidpi = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Enable HiDPI XWayland.
|
||||
'';
|
||||
|
||||
package = mkPackageOptionMD inputs.self.packages.${system} "hyprland" { };
|
||||
|
||||
finalPackage = mkOption {
|
||||
type = types.package;
|
||||
readOnly = true;
|
||||
default = cfg.package.override {
|
||||
enableXWayland = cfg.xwayland.enable;
|
||||
enableNvidiaPatches = cfg.enableNvidiaPatches;
|
||||
};
|
||||
};
|
||||
|
||||
nvidiaPatches = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
example = literalExpression "true";
|
||||
description = ''
|
||||
Patch wlroots for better Nvidia support.
|
||||
defaultText =
|
||||
literalExpression
|
||||
"`programs.hyprland.package` with applied configuration";
|
||||
description = mdDoc ''
|
||||
The Hyprland package after applying configuration.
|
||||
'';
|
||||
};
|
||||
|
||||
recommendedEnvironment = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
defaultText = literalExpression "true";
|
||||
example = literalExpression "false";
|
||||
description = ''
|
||||
Whether to set the recommended environment variables.
|
||||
'';
|
||||
};
|
||||
portalPackage = mkPackageOptionMD inputs.xdph.packages.${system} "xdg-desktop-portal-hyprland" {};
|
||||
|
||||
xwayland.enable = mkEnableOption (mdDoc "support for XWayland") // {default = true;};
|
||||
|
||||
enableNvidiaPatches =
|
||||
mkEnableOption null
|
||||
// {
|
||||
description = mdDoc "Whether to apply patches to wlroots for better Nvidia support.";
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
environment = {
|
||||
systemPackages = lib.optional (cfg.package != null) cfg.package;
|
||||
environment.systemPackages = [cfg.finalPackage];
|
||||
|
||||
# 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 {
|
||||
NIXOS_OZONE_WL = "1";
|
||||
};
|
||||
};
|
||||
fonts.enableDefaultFonts = mkDefault true;
|
||||
hardware.opengl.enable = mkDefault true;
|
||||
|
||||
programs = {
|
||||
dconf.enable = mkDefault true;
|
||||
xwayland.enable = mkDefault true;
|
||||
xwayland.enable = mkDefault cfg.xwayland.enable;
|
||||
};
|
||||
|
||||
security.polkit.enable = true;
|
||||
services.xserver.displayManager.sessionPackages = lib.optional (cfg.package != null) cfg.package;
|
||||
|
||||
services.xserver.displayManager.sessionPackages = [cfg.finalPackage];
|
||||
|
||||
xdg.portal = {
|
||||
enable = mkDefault true;
|
||||
# xdg-desktop-portal-hyprland
|
||||
extraPortals = lib.mkIf (cfg.package != null) [
|
||||
(inputs.xdph.packages.${pkgs.stdenv.hostPlatform.system}.xdg-desktop-portal-hyprland.override {
|
||||
hyprland-share-picker = inputs.xdph.packages.${pkgs.stdenv.hostPlatform.system}.hyprland-share-picker.override {
|
||||
hyprland = cfg.package;
|
||||
};
|
||||
})
|
||||
];
|
||||
extraPortals = [finalPortalPackage];
|
||||
};
|
||||
};
|
||||
|
||||
imports = with lib; [
|
||||
(
|
||||
mkRemovedOptionModule
|
||||
["programs" "hyprland" "xwayland" "hidpi"]
|
||||
"XWayland patches are deprecated. Refer to https://wiki.hyprland.org/Configuring/XWayland"
|
||||
)
|
||||
(
|
||||
mkRenamedOptionModule
|
||||
["programs" "hyprland" "nvidiaPatches"]
|
||||
["programs" "hyprland" "enableNvidiaPatches"]
|
||||
)
|
||||
];
|
||||
}
|
||||
|
94
nix/overlays.nix
Normal file
94
nix/overlays.nix
Normal file
@@ -0,0 +1,94 @@
|
||||
{
|
||||
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 = final.hyprland.override {enableNvidiaPatches = true;};
|
||||
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"];
|
||||
});
|
||||
};
|
||||
};
|
||||
}
|
@@ -1,24 +1,12 @@
|
||||
diff --git a/meson.build b/meson.build
|
||||
index f3802553..6a924a79 100644
|
||||
index 1d2c7f9f..c5ef4e67 100644
|
||||
--- a/meson.build
|
||||
+++ b/meson.build
|
||||
@@ -21,9 +21,9 @@ else
|
||||
@@ -33,20 +33,7 @@ if cpp_compiler.check_header('execinfo.h')
|
||||
add_project_arguments('-DHAS_EXECINFO', language: 'cpp')
|
||||
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_HASH = '@GIT_COMMIT_HASH@'
|
||||
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()
|
||||
+GIT_DIRTY = '@GIT_DIRTY@'
|
||||
|
||||
add_project_arguments(
|
||||
[
|
||||
@@ -39,21 +39,8 @@ add_project_arguments(
|
||||
],
|
||||
language: 'cpp')
|
||||
|
||||
-wlroots = subproject('wlroots', default_options: ['examples=false'])
|
||||
-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'))
|
||||
-
|
||||
@@ -32,17 +20,24 @@ index f3802553..6a924a79 100644
|
||||
-have_xwayland = xcb_dep.found() and have_xwlr
|
||||
-
|
||||
-if not have_xwayland
|
||||
- add_project_arguments('-DNO_XWAYLAND', language: 'cpp')
|
||||
+if get_option('xwayland').disabled()
|
||||
+ add_project_arguments('-DNO_XWAYLAND', language: 'cpp')
|
||||
add_project_arguments('-DNO_XWAYLAND', language: 'cpp')
|
||||
endif
|
||||
|
||||
backtrace_dep = cpp_compiler.find_library('execinfo', required: false)
|
||||
@@ -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 7b658d31..60aa4057 100644
|
||||
index 0af864b9..38723b8c 100644
|
||||
--- a/src/meson.build
|
||||
+++ b/src/meson.build
|
||||
@@ -7,16 +7,16 @@ executable('Hyprland', src,
|
||||
@@ -9,16 +9,16 @@ executable('Hyprland', src,
|
||||
server_protos,
|
||||
dependency('wayland-server'),
|
||||
dependency('wayland-client'),
|
41
nix/patches/wlroots-nvidia.patch
Normal file
41
nix/patches/wlroots-nvidia.patch
Normal file
@@ -0,0 +1,41 @@
|
||||
diff --git a/render/gles2/renderer.c b/render/gles2/renderer.c
|
||||
index 9fe934f7..9662d4ee 100644
|
||||
--- a/render/gles2/renderer.c
|
||||
+++ b/render/gles2/renderer.c
|
||||
@@ -176,7 +176,7 @@ static bool gles2_bind_buffer(struct wlr_renderer *wlr_renderer,
|
||||
assert(wlr_egl_is_current(renderer->egl));
|
||||
|
||||
push_gles2_debug(renderer);
|
||||
- glFlush();
|
||||
+ glFinish();
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
pop_gles2_debug(renderer);
|
||||
|
||||
diff --git a/types/output/render.c b/types/output/render.c
|
||||
index 2e38919a..97f78608 100644
|
||||
--- a/types/output/render.c
|
||||
+++ b/types/output/render.c
|
||||
@@ -240,22 +240,7 @@ bool output_pick_format(struct wlr_output *output,
|
||||
}
|
||||
|
||||
uint32_t wlr_output_preferred_read_format(struct wlr_output *output) {
|
||||
- struct wlr_renderer *renderer = output->renderer;
|
||||
- assert(renderer != NULL);
|
||||
-
|
||||
- if (!renderer->impl->preferred_read_format || !renderer->impl->read_pixels) {
|
||||
- return DRM_FORMAT_INVALID;
|
||||
- }
|
||||
-
|
||||
- if (!wlr_output_attach_render(output, NULL)) {
|
||||
- return false;
|
||||
- }
|
||||
-
|
||||
- uint32_t fmt = renderer->impl->preferred_read_format(renderer);
|
||||
-
|
||||
- output_clear_back_buffer(output);
|
||||
-
|
||||
- return fmt;
|
||||
+ return DRM_FORMAT_XRGB8888;
|
||||
}
|
||||
|
||||
struct wlr_render_pass *wlr_output_begin_render_pass(struct wlr_output *output,
|
@@ -1,21 +1,19 @@
|
||||
#!/usr/bin/env -S nix shell nixpkgs#gawk nixpkgs#git nixpkgs#moreutils nixpkgs#jq nixpkgs#ripgrep -c bash
|
||||
#!/usr/bin/env -S nix shell nixpkgs#jq -c bash
|
||||
|
||||
set -ex
|
||||
# Update inputs when the Mesa version is outdated. We don't want
|
||||
# incompatibilities between the user's system and Hyprland.
|
||||
|
||||
# get wlroots revision from submodule
|
||||
SUB_REV=$(git submodule status | rg wlroots | awk '{ print substr($1,2)}')
|
||||
# and from lockfile
|
||||
CRT_REV=$(jq < flake.lock '.nodes.wlroots.locked.rev' -r)
|
||||
# get the current Nixpkgs revision
|
||||
REV=$(jq <flake.lock '.nodes.nixpkgs.locked.rev' -r)
|
||||
# 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)
|
||||
|
||||
if [ $SUB_REV != $CRT_REV ]; then
|
||||
# update nixpkgs to latest version
|
||||
nix flake lock --update-input nixpkgs
|
||||
if [ "$CRT_VER" != "$NEW_VER" ]; then
|
||||
echo "Updating Mesa $CRT_VER -> $NEW_VER and flake inputs"
|
||||
|
||||
# update wlroots to submodule revision
|
||||
nix flake lock --override-input wlroots "gitlab:wlroots/wlroots/$SUB_REV?host=gitlab.freedesktop.org"
|
||||
|
||||
# remove "dirty" mark from lockfile
|
||||
jq < flake.lock 'del(.nodes.wlroots.original.rev)' | sponge flake.lock
|
||||
# update inputs to latest versions
|
||||
nix flake update
|
||||
else
|
||||
echo "wlroots is up to date!"
|
||||
echo "nixpkgs is up to date!"
|
||||
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,164 +0,0 @@
|
||||
diff --git a/include/xwayland/xwm.h b/include/xwayland/xwm.h
|
||||
index 3d540522..1c5a2e37 100644
|
||||
--- a/include/xwayland/xwm.h
|
||||
+++ b/include/xwayland/xwm.h
|
||||
@@ -88,6 +88,7 @@ enum atom_name {
|
||||
DND_ACTION_PRIVATE,
|
||||
NET_CLIENT_LIST,
|
||||
NET_CLIENT_LIST_STACKING,
|
||||
+ XWAYLAND_GLOBAL_OUTPUT_SCALE,
|
||||
ATOM_LAST // keep last
|
||||
};
|
||||
|
||||
@@ -96,6 +97,7 @@ struct wlr_xwm {
|
||||
struct wl_event_source *event_source;
|
||||
struct wlr_seat *seat;
|
||||
uint32_t ping_timeout;
|
||||
+ uint32_t scale;
|
||||
|
||||
xcb_atom_t atoms[ATOM_LAST];
|
||||
xcb_connection_t *xcb_conn;
|
||||
diff --git a/xwayland/xwm.c b/xwayland/xwm.c
|
||||
index 5f857f24..21584ebd 100644
|
||||
--- a/xwayland/xwm.c
|
||||
+++ b/xwayland/xwm.c
|
||||
@@ -19,6 +19,14 @@
|
||||
#include <xcb/xfixes.h>
|
||||
#include "xwayland/xwm.h"
|
||||
|
||||
+static int32_t scale(struct wlr_xwm *xwm, uint32_t val) {
|
||||
+ return val * xwm->scale;
|
||||
+}
|
||||
+
|
||||
+static int32_t unscale(struct wlr_xwm *xwm, uint32_t val) {
|
||||
+ return (val + xwm->scale/2) / xwm->scale;
|
||||
+}
|
||||
+
|
||||
static const char *const atom_map[ATOM_LAST] = {
|
||||
[WL_SURFACE_ID] = "WL_SURFACE_ID",
|
||||
[WL_SURFACE_SERIAL] = "WL_SURFACE_SERIAL",
|
||||
@@ -90,6 +98,7 @@ static const char *const atom_map[ATOM_LAST] = {
|
||||
[DND_ACTION_PRIVATE] = "XdndActionPrivate",
|
||||
[NET_CLIENT_LIST] = "_NET_CLIENT_LIST",
|
||||
[NET_CLIENT_LIST_STACKING] = "_NET_CLIENT_LIST_STACKING",
|
||||
+ [XWAYLAND_GLOBAL_OUTPUT_SCALE] = "_XWAYLAND_GLOBAL_OUTPUT_SCALE",
|
||||
};
|
||||
|
||||
#define STARTUP_INFO_REMOVE_PREFIX "remove: ID="
|
||||
@@ -965,8 +974,8 @@ static void xwm_handle_create_notify(struct wlr_xwm *xwm,
|
||||
return;
|
||||
}
|
||||
|
||||
- xwayland_surface_create(xwm, ev->window, ev->x, ev->y,
|
||||
- ev->width, ev->height, ev->override_redirect);
|
||||
+ xwayland_surface_create(xwm, ev->window, unscale(xwm, ev->x), unscale(xwm, ev->y),
|
||||
+ unscale(xwm, ev->width), unscale(xwm, ev->height), ev->override_redirect);
|
||||
}
|
||||
|
||||
static void xwm_handle_destroy_notify(struct wlr_xwm *xwm,
|
||||
@@ -997,10 +1006,10 @@ static void xwm_handle_configure_request(struct wlr_xwm *xwm,
|
||||
|
||||
struct wlr_xwayland_surface_configure_event wlr_event = {
|
||||
.surface = surface,
|
||||
- .x = mask & XCB_CONFIG_WINDOW_X ? ev->x : surface->x,
|
||||
- .y = mask & XCB_CONFIG_WINDOW_Y ? ev->y : surface->y,
|
||||
- .width = mask & XCB_CONFIG_WINDOW_WIDTH ? ev->width : surface->width,
|
||||
- .height = mask & XCB_CONFIG_WINDOW_HEIGHT ? ev->height : surface->height,
|
||||
+ .x = mask & XCB_CONFIG_WINDOW_X ? unscale(xwm, ev->x) : surface->x,
|
||||
+ .y = mask & XCB_CONFIG_WINDOW_Y ? unscale(xwm, ev->y) : surface->y,
|
||||
+ .width = mask & XCB_CONFIG_WINDOW_WIDTH ? unscale(xwm, ev->width) : surface->width,
|
||||
+ .height = mask & XCB_CONFIG_WINDOW_HEIGHT ? unscale(xwm, ev->height) : surface->height,
|
||||
.mask = mask,
|
||||
};
|
||||
|
||||
@@ -1015,14 +1024,14 @@ static void xwm_handle_configure_notify(struct wlr_xwm *xwm,
|
||||
}
|
||||
|
||||
bool geometry_changed =
|
||||
- (xsurface->x != ev->x || xsurface->y != ev->y ||
|
||||
- xsurface->width != ev->width || xsurface->height != ev->height);
|
||||
+ (xsurface->x != unscale(xwm, ev->x) || xsurface->y != unscale(xwm, ev->y) ||
|
||||
+ xsurface->width != unscale(xwm, ev->width) || xsurface->height != unscale(xwm, ev->height));
|
||||
|
||||
if (geometry_changed) {
|
||||
- xsurface->x = ev->x;
|
||||
- xsurface->y = ev->y;
|
||||
- xsurface->width = ev->width;
|
||||
- xsurface->height = ev->height;
|
||||
+ xsurface->x = unscale(xwm, ev->x);
|
||||
+ xsurface->y = unscale(xwm, ev->y);
|
||||
+ xsurface->width = unscale(xwm, ev->width);
|
||||
+ xsurface->height = unscale(xwm, ev->height);
|
||||
}
|
||||
|
||||
if (xsurface->override_redirect != ev->override_redirect) {
|
||||
@@ -1133,6 +1142,20 @@ static void xwm_handle_property_notify(struct wlr_xwm *xwm,
|
||||
xcb_property_notify_event_t *ev) {
|
||||
struct wlr_xwayland_surface *xsurface = lookup_surface(xwm, ev->window);
|
||||
if (xsurface == NULL) {
|
||||
+ if (ev->atom == xwm->atoms[XWAYLAND_GLOBAL_OUTPUT_SCALE]) {
|
||||
+ xcb_get_property_cookie_t cookie = xcb_get_property(xwm->xcb_conn, 0,
|
||||
+ ev->window, ev->atom, XCB_ATOM_ANY, 0, 2048);
|
||||
+ xcb_get_property_reply_t *reply = xcb_get_property_reply(xwm->xcb_conn,
|
||||
+ cookie, NULL);
|
||||
+ if (reply == NULL) {
|
||||
+ return;
|
||||
+ }
|
||||
+ if (reply->type == XCB_ATOM_CARDINAL) {
|
||||
+ xwm->scale = *(uint32_t*)xcb_get_property_value(reply);
|
||||
+ }
|
||||
+ free(reply);
|
||||
+ }
|
||||
+
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1760,16 +1783,17 @@ void wlr_xwayland_surface_configure(struct wlr_xwayland_surface *xsurface,
|
||||
int old_w = xsurface->width;
|
||||
int old_h = xsurface->height;
|
||||
|
||||
+ struct wlr_xwm *xwm = xsurface->xwm;
|
||||
+
|
||||
xsurface->x = x;
|
||||
xsurface->y = y;
|
||||
xsurface->width = width;
|
||||
xsurface->height = height;
|
||||
|
||||
- struct wlr_xwm *xwm = xsurface->xwm;
|
||||
uint32_t mask = XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y |
|
||||
XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT |
|
||||
XCB_CONFIG_WINDOW_BORDER_WIDTH;
|
||||
- uint32_t values[] = {x, y, width, height, 0};
|
||||
+ uint32_t values[] = {scale(xwm, x), scale(xwm, y), scale(xwm, width), scale(xwm, height), 0};
|
||||
xcb_configure_window(xwm->xcb_conn, xsurface->window_id, mask, values);
|
||||
|
||||
// If the window size did not change, then we cannot rely on
|
||||
@@ -1777,15 +1801,15 @@ void wlr_xwayland_surface_configure(struct wlr_xwayland_surface *xsurface,
|
||||
// we are supposed to send a synthetic event. See ICCCM part
|
||||
// 4.1.5. But we ignore override-redirect windows as ICCCM does
|
||||
// not apply to them.
|
||||
- if (width == old_w && height == old_h && !xsurface->override_redirect) {
|
||||
+ if (scale(xwm, width) == scale(xwm, old_w) && scale(xwm, height) == scale(xwm, old_h) && !xsurface->override_redirect) {
|
||||
xcb_configure_notify_event_t configure_notify = {
|
||||
.response_type = XCB_CONFIGURE_NOTIFY,
|
||||
.event = xsurface->window_id,
|
||||
.window = xsurface->window_id,
|
||||
- .x = x,
|
||||
- .y = y,
|
||||
- .width = width,
|
||||
- .height = height,
|
||||
+ .x = scale(xwm, x),
|
||||
+ .y = scale(xwm, y),
|
||||
+ .width = scale(xwm, width),
|
||||
+ .height = scale(xwm, height),
|
||||
};
|
||||
|
||||
xcb_send_event(xwm->xcb_conn, 0, xsurface->window_id,
|
||||
@@ -2122,6 +2146,7 @@ struct wlr_xwm *xwm_create(struct wlr_xwayland *xwayland, int wm_fd) {
|
||||
wl_list_init(&xwm->pending_startup_ids);
|
||||
xwm->ping_timeout = 10000;
|
||||
|
||||
+ xwm->scale = 1;
|
||||
xwm->xcb_conn = xcb_connect_to_fd(wm_fd, NULL);
|
||||
|
||||
int rc = xcb_connection_has_error(xwm->xcb_conn);
|
@@ -1,76 +1,28 @@
|
||||
{
|
||||
lib,
|
||||
version,
|
||||
src,
|
||||
#
|
||||
wlroots,
|
||||
xwayland,
|
||||
fetchpatch,
|
||||
lib,
|
||||
hwdata,
|
||||
libliftoff,
|
||||
libdisplay-info,
|
||||
hidpiXWayland ? true,
|
||||
libliftoff,
|
||||
enableXWayland ? true,
|
||||
nvidiaPatches ? false,
|
||||
enableNvidiaPatches ? false,
|
||||
}:
|
||||
assert (lib.assertMsg (hidpiXWayland -> enableXWayland) ''
|
||||
wlroots-hyprland: cannot have hidpiXWayland when enableXWayland is false.
|
||||
'');
|
||||
(wlroots.overrideAttrs
|
||||
(old: {
|
||||
inherit version src;
|
||||
pname =
|
||||
old.pname
|
||||
+ "-hyprland"
|
||||
+ (
|
||||
if hidpiXWayland
|
||||
then "-hidpi"
|
||||
else ""
|
||||
)
|
||||
+ (
|
||||
if nvidiaPatches
|
||||
then "-nvidia"
|
||||
else ""
|
||||
);
|
||||
patches =
|
||||
(old.patches or [])
|
||||
++ (lib.optionals (enableXWayland && hidpiXWayland) [
|
||||
# adapted from https://gitlab.freedesktop.org/lilydjwg/wlroots/-/commit/6c5ffcd1fee9e44780a6a8792f74ecfbe24a1ca7
|
||||
./wlroots-hidpi.patch
|
||||
(fetchpatch {
|
||||
url = "https://gitlab.freedesktop.org/wlroots/wlroots/-/commit/18595000f3a21502fd60bf213122859cc348f9af.diff";
|
||||
sha256 = "sha256-jvfkAMh3gzkfuoRhB4E9T5X1Hu62wgUjj4tZkJm0mrI=";
|
||||
revert = true;
|
||||
})
|
||||
])
|
||||
++ (lib.optionals nvidiaPatches [
|
||||
(fetchpatch {
|
||||
url = "https://aur.archlinux.org/cgit/aur.git/plain/0001-nvidia-format-workaround.patch?h=hyprland-nvidia-screenshare-git";
|
||||
sha256 = "A9f1p5EW++mGCaNq8w7ZJfeWmvTfUm4iO+1KDcnqYX8=";
|
||||
})
|
||||
]);
|
||||
postPatch =
|
||||
(old.postPatch or "")
|
||||
+ (
|
||||
if nvidiaPatches
|
||||
then ''
|
||||
substituteInPlace render/gles2/renderer.c --replace "glFlush();" "glFinish();"
|
||||
''
|
||||
else ""
|
||||
);
|
||||
buildInputs = old.buildInputs ++ [hwdata libliftoff libdisplay-info];
|
||||
wlroots.overrideAttrs (old: {
|
||||
inherit version src enableXWayland;
|
||||
|
||||
NIX_CFLAGS_COMPILE = toString [
|
||||
"-Wno-error=maybe-uninitialized"
|
||||
];
|
||||
}))
|
||||
.override {
|
||||
xwayland = xwayland.overrideAttrs (old: {
|
||||
patches =
|
||||
(old.patches or [])
|
||||
++ (lib.optionals hidpiXWayland [
|
||||
./xwayland-vsync.patch
|
||||
./xwayland-hidpi.patch
|
||||
]);
|
||||
});
|
||||
}
|
||||
pname = "${old.pname}-hyprland${lib.optionalString enableNvidiaPatches "-nvidia"}";
|
||||
|
||||
patches =
|
||||
(old.patches or [])
|
||||
++ (lib.optionals enableNvidiaPatches [
|
||||
./patches/wlroots-nvidia.patch
|
||||
]);
|
||||
|
||||
buildInputs = old.buildInputs ++ [hwdata libliftoff libdisplay-info];
|
||||
|
||||
NIX_CFLAGS_COMPILE = toString [
|
||||
"-Wno-error=maybe-uninitialized"
|
||||
];
|
||||
})
|
||||
|
@@ -1,493 +0,0 @@
|
||||
diff --git a/hw/xwayland/xwayland-cursor.c b/hw/xwayland/xwayland-cursor.c
|
||||
index e3c1aaa50..eba29b5ba 100644
|
||||
--- a/hw/xwayland/xwayland-cursor.c
|
||||
+++ b/hw/xwayland/xwayland-cursor.c
|
||||
@@ -164,6 +164,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);
|
||||
@@ -195,6 +197,7 @@ xwl_cursor_clear_frame_cb(struct xwl_cursor *xwl_cursor)
|
||||
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;
|
||||
@@ -225,8 +228,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);
|
||||
}
|
||||
@@ -235,6 +238,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;
|
||||
@@ -263,8 +267,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 6e0600e4e..4a22ebff0 100644
|
||||
--- a/hw/xwayland/xwayland-input.c
|
||||
+++ b/hw/xwayland/xwayland-input.c
|
||||
@@ -507,8 +507,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;
|
||||
@@ -731,13 +731,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);
|
||||
@@ -887,12 +888,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;
|
||||
@@ -1382,8 +1384,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);
|
||||
@@ -1419,8 +1421,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);
|
||||
}
|
||||
|
||||
@@ -2110,8 +2112,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;
|
||||
@@ -3152,6 +3154,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;
|
||||
@@ -3163,6 +3166,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 ||
|
||||
@@ -3171,8 +3175,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 661e1828d..6c60aba34 100644
|
||||
--- a/hw/xwayland/xwayland-output.c
|
||||
+++ b/hw/xwayland/xwayland-output.c
|
||||
@@ -186,6 +186,9 @@ update_backing_pixmaps(struct xwl_screen *xwl_screen, int width, int height)
|
||||
static void
|
||||
update_screen_size(struct xwl_screen *xwl_screen, int width, int height)
|
||||
{
|
||||
+ width *= xwl_screen->global_output_scale;
|
||||
+ height *= xwl_screen->global_output_scale;
|
||||
+
|
||||
xwl_screen->width = width;
|
||||
xwl_screen->height = height;
|
||||
|
||||
@@ -597,14 +600,15 @@ xwl_output_set_emulated_mode(struct xwl_output *xwl_output, ClientPtr client,
|
||||
new_emulated_height);
|
||||
}
|
||||
|
||||
-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;
|
||||
@@ -623,10 +627,10 @@ apply_output_change(struct xwl_output *xwl_output)
|
||||
}
|
||||
if (xwl_output->randr_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.
|
||||
@@ -686,7 +690,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
|
||||
@@ -746,7 +750,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
|
||||
@@ -857,6 +861,8 @@ xwl_output_create(struct xwl_screen *xwl_screen, uint32_t id,
|
||||
RRCrtcGammaSetSize(xwl_output->randr_crtc, 256);
|
||||
RROutputSetCrtcs(xwl_output->randr_output, &xwl_output->randr_crtc, 1);
|
||||
RROutputSetConnection(xwl_output->randr_output, RR_Connected);
|
||||
+
|
||||
+ 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 a95288e4f..46d1ead2a 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;
|
||||
@@ -102,6 +102,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 189e7cfd6..555434031 100644
|
||||
--- a/hw/xwayland/xwayland-present.c
|
||||
+++ b/hw/xwayland/xwayland-present.c
|
||||
@@ -764,6 +764,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 (xorg_list_is_empty(&xwl_present_window->frame_callback_list)) {
|
||||
xorg_list_add(&xwl_present_window->frame_callback_list,
|
||||
diff --git a/hw/xwayland/xwayland-screen.c b/hw/xwayland/xwayland-screen.c
|
||||
index 46ab4fed7..b2d7022e6 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"
|
||||
@@ -111,6 +112,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)
|
||||
@@ -128,6 +135,38 @@ 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;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+
|
||||
struct xwl_output *
|
||||
xwl_screen_get_fixed_or_first_output(struct xwl_screen *xwl_screen)
|
||||
{
|
||||
@@ -144,19 +183,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)
|
||||
- xwl_window_update_property(xwl_window, rec);
|
||||
+ 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);
|
||||
+ }
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -638,8 +682,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
|
||||
@@ -655,6 +705,30 @@ 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);
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+
|
||||
static int
|
||||
xwl_server_grab(ClientPtr client)
|
||||
{
|
||||
@@ -712,6 +786,7 @@ 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;
|
||||
@@ -746,6 +821,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) {
|
||||
@@ -988,6 +1064,13 @@ 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);
|
||||
AddCallback(&RootWindowFinalizeCallback, xwl_root_window_finalized_callback, pScreen);
|
||||
|
||||
diff --git a/hw/xwayland/xwayland-screen.h b/hw/xwayland/xwayland-screen.h
|
||||
index fadd0526e..2ce6ce5ab 100644
|
||||
--- a/hw/xwayland/xwayland-screen.h
|
||||
+++ b/hw/xwayland/xwayland-screen.h
|
||||
@@ -87,6 +87,7 @@ 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;
|
||||
@@ -134,6 +135,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;
|
||||
@@ -166,6 +168,8 @@ 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);
|
||||
int xwl_screen_get_next_output_serial(struct xwl_screen * xwl_screen);
|
||||
|
||||
#endif /* XWAYLAND_SCREEN_H */
|
||||
diff --git a/hw/xwayland/xwayland-window.c b/hw/xwayland/xwayland-window.c
|
||||
index 6b7f38605..2f1e0dee1 100644
|
||||
--- a/hw/xwayland/xwayland-window.c
|
||||
+++ b/hw/xwayland/xwayland-window.c
|
||||
@@ -788,7 +788,8 @@ xwl_create_root_surface(struct xwl_window *xwl_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);
|
||||
|
||||
@@ -1322,6 +1323,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;
|
@@ -1,3 +1,3 @@
|
||||
{
|
||||
"version": "0.24.0"
|
||||
"version": "0.32.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>
|
@@ -5,7 +5,7 @@ wayland_protos = dependency('wayland-protocols',
|
||||
)
|
||||
|
||||
hyprland_protos = dependency('hyprland-protocols',
|
||||
version: '>=0.1',
|
||||
version: '>=0.2',
|
||||
fallback: 'hyprland-protocols',
|
||||
)
|
||||
|
||||
@@ -22,16 +22,19 @@ protocols = [
|
||||
[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-output-power-management-unstable-v1.xml'],
|
||||
['wlr-screencopy-unstable-v1.xml'],
|
||||
['ext-workspace-unstable-v1.xml'],
|
||||
['pointer-constraints-unstable-v1.xml'],
|
||||
['tablet-unstable-v2.xml'],
|
||||
['idle.xml'],
|
||||
[hl_protocol_dir, 'protocols/hyprland-toplevel-export-v1.xml']
|
||||
[hl_protocol_dir, 'protocols/hyprland-toplevel-export-v1.xml'],
|
||||
[hl_protocol_dir, 'protocols/hyprland-global-shortcuts-v1.xml']
|
||||
]
|
||||
wl_protos_src = []
|
||||
wl_protos_headers = []
|
||||
@@ -46,6 +49,8 @@ foreach p : protocols
|
||||
wl_protos_headers += custom_target(
|
||||
xml.underscorify() + '_server_h',
|
||||
input: xml,
|
||||
install: true,
|
||||
install_dir: join_paths(get_option('includedir'), 'hyprland/protocols'),
|
||||
output: '@BASENAME@-protocol.h',
|
||||
command: [wayland_scanner, 'server-header', '@INPUT@', '@OUTPUT@'],
|
||||
)
|
||||
|
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
|
1120
src/Compositor.cpp
1120
src/Compositor.cpp
File diff suppressed because it is too large
Load Diff
@@ -27,8 +27,10 @@
|
||||
#include "render/OpenGL.hpp"
|
||||
#include "hyprerror/HyprError.hpp"
|
||||
#include "plugins/PluginSystem.hpp"
|
||||
#include "helpers/Watchdog.hpp"
|
||||
|
||||
enum eManagersInitStage {
|
||||
enum eManagersInitStage
|
||||
{
|
||||
STAGE_PRIORITY = 0,
|
||||
STAGE_LATE
|
||||
};
|
||||
@@ -52,7 +54,7 @@ class CCompositor {
|
||||
wlr_drm_lease_v1_manager* m_sWRLDRMLeaseMgr;
|
||||
wlr_xdg_activation_v1* m_sWLRXDGActivation;
|
||||
wlr_output_layout* m_sWLROutputLayout;
|
||||
wlr_idle* m_sWLRIdle;
|
||||
wlr_idle_notifier_v1* m_sWLRIdleNotifier;
|
||||
wlr_layer_shell_v1* m_sWLRLayerShell;
|
||||
wlr_xdg_shell* m_sWLRXDGShell;
|
||||
wlr_cursor* m_sWLRCursor;
|
||||
@@ -60,12 +62,10 @@ class CCompositor {
|
||||
wlr_virtual_keyboard_manager_v1* m_sWLRVKeyboardMgr;
|
||||
wlr_output_manager_v1* m_sWLROutputMgr;
|
||||
wlr_presentation* m_sWLRPresentation;
|
||||
wlr_scene* m_sWLRScene;
|
||||
wlr_input_inhibit_manager* m_sWLRInhibitMgr;
|
||||
wlr_keyboard_shortcuts_inhibit_manager_v1* m_sWLRKbShInhibitMgr;
|
||||
wlr_egl* m_sWLREGL;
|
||||
int m_iDRMFD;
|
||||
wlr_ext_workspace_manager_v1* m_sWLREXTWorkspaceMgr;
|
||||
wlr_pointer_constraints_v1* m_sWLRPointerConstraints;
|
||||
wlr_relative_pointer_manager_v1* m_sWLRRelPointerMgr;
|
||||
wlr_server_decoration_manager* m_sWLRServerDecoMgr;
|
||||
@@ -83,6 +83,9 @@ class CCompositor {
|
||||
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 = "";
|
||||
@@ -98,9 +101,13 @@ class CCompositor {
|
||||
std::vector<CWindow*> m_vWindowsFadingOut;
|
||||
std::vector<SLayerSurface*> m_vSurfacesFadingOut;
|
||||
|
||||
std::unordered_map<std::string, uint64_t> m_mMonitorIDMap;
|
||||
|
||||
void initServer();
|
||||
void startCompositor();
|
||||
void cleanup();
|
||||
void createLockFile();
|
||||
void removeLockFile();
|
||||
|
||||
wlr_surface* m_pLastFocus = nullptr;
|
||||
CWindow* m_pLastWindow = nullptr;
|
||||
@@ -113,13 +120,16 @@ class CCompositor {
|
||||
bool m_bReadyToProcess = false;
|
||||
bool m_bSessionActive = true;
|
||||
bool m_bDPMSStateON = true;
|
||||
bool m_bUnsafeState = false; // unsafe state is when there is no monitors.
|
||||
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* getMonitorFromName(const std::string&);
|
||||
CMonitor* getMonitorFromDesc(const std::string&);
|
||||
CMonitor* getMonitorFromCursor();
|
||||
CMonitor* getMonitorFromVector(const Vector2D&);
|
||||
void removeWindowFromVectorSafe(CWindow*);
|
||||
@@ -132,6 +142,7 @@ class CCompositor {
|
||||
CWindow* vectorToWindowTiled(const Vector2D&);
|
||||
wlr_surface* vectorToLayerSurface(const Vector2D&, std::vector<std::unique_ptr<SLayerSurface>>*, Vector2D*, SLayerSurface**);
|
||||
wlr_surface* vectorWindowToSurface(const Vector2D&, CWindow*, Vector2D& sl);
|
||||
Vector2D vectorToSurfaceLocal(const Vector2D&, CWindow*, wlr_surface*);
|
||||
CWindow* windowFromCursor();
|
||||
CWindow* windowFloatingFromCursor();
|
||||
CMonitor* getMonitorFromOutput(wlr_output*);
|
||||
@@ -149,13 +160,13 @@ class CCompositor {
|
||||
CWindow* getUrgentWindow();
|
||||
bool hasUrgentWindowOnWorkspace(const int&);
|
||||
CWindow* getFirstWindowOnWorkspace(const int&);
|
||||
CWindow* getTopLeftWindowOnWorkspace(const int&);
|
||||
CWindow* getFullscreenWindowOnWorkspace(const int&);
|
||||
bool doesSeatAcceptInput(wlr_surface*);
|
||||
bool isWindowActive(CWindow*);
|
||||
void moveWindowToTop(CWindow*);
|
||||
void changeWindowZOrder(CWindow*, bool);
|
||||
void cleanupFadingOut(const int& monid);
|
||||
CWindow* getWindowInDirection(CWindow*, char);
|
||||
void deactivateAllWLRWorkspaces(wlr_ext_workspace_handle_v1* exclude = nullptr);
|
||||
CWindow* getNextWindowOnWorkspace(CWindow*, bool focusableOnly = false);
|
||||
CWindow* getPrevWindowOnWorkspace(CWindow*, bool focusableOnly = false);
|
||||
int getNextAvailableNamedWorkspace();
|
||||
@@ -164,12 +175,13 @@ class CCompositor {
|
||||
CMonitor* getMonitorInDirection(const char&);
|
||||
void updateAllWindowsAnimatedDecorationValues();
|
||||
void updateWindowAnimatedDecorationValues(CWindow*);
|
||||
int getNextAvailableMonitorID();
|
||||
int getNextAvailableMonitorID(std::string const& name);
|
||||
void moveWorkspaceToMonitor(CWorkspace*, CMonitor*);
|
||||
void swapActiveWorkspaces(CMonitor*, CMonitor*);
|
||||
CMonitor* getMonitorFromString(const std::string&);
|
||||
bool workspaceIDOutOfBounds(const int&);
|
||||
bool workspaceIDOutOfBounds(const int64_t&);
|
||||
void setWindowFullscreen(CWindow*, bool, eFullscreenMode);
|
||||
void updateFullscreenFadeOnWorkspace(CWorkspace*);
|
||||
CWindow* getX11Parent(CWindow*);
|
||||
void scheduleFrameForMonitor(CMonitor*);
|
||||
void addToFadingOutSafe(SLayerSurface*);
|
||||
@@ -188,6 +200,15 @@ class CCompositor {
|
||||
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;
|
||||
|
||||
@@ -195,6 +216,7 @@ class CCompositor {
|
||||
void initAllSignals();
|
||||
void setRandomSplash();
|
||||
void initManagers(eManagersInitStage stage);
|
||||
void prepareFallbackOutput();
|
||||
|
||||
uint64_t m_iHyprlandPID = 0;
|
||||
};
|
||||
@@ -213,4 +235,5 @@ inline std::map<std::string, xcb_atom_t> HYPRATOMS = {HYPRATOM("_NET_WM_WINDOW_T
|
||||
HYPRATOM("_NET_WM_WINDOW_TYPE_DROPDOWN_MENU"),
|
||||
HYPRATOM("_NET_WM_WINDOW_TYPE_POPUP_MENU"),
|
||||
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")};
|
||||
|
@@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "helpers/Vector2D.hpp"
|
||||
|
||||
enum eIcons
|
||||
{
|
||||
ICON_WARNING = 0,
|
||||
@@ -9,4 +11,39 @@ enum eIcons
|
||||
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;
|
||||
}
|
||||
};
|
575
src/Window.cpp
575
src/Window.cpp
@@ -1,6 +1,7 @@
|
||||
#include "Window.hpp"
|
||||
#include "Compositor.hpp"
|
||||
#include "render/decorations/CHyprDropShadowDecoration.hpp"
|
||||
#include "render/decorations/CHyprGroupBarDecoration.hpp"
|
||||
|
||||
CWindow::CWindow() {
|
||||
m_vRealPosition.create(AVARTYPE_VECTOR, g_pConfigManager->getAnimationPropertyConfig("windowsIn"), (void*)this, AVARDAMAGE_ENTIRE);
|
||||
@@ -12,7 +13,7 @@ CWindow::CWindow() {
|
||||
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_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() {
|
||||
@@ -22,41 +23,83 @@ CWindow::~CWindow() {
|
||||
}
|
||||
}
|
||||
|
||||
wlr_box CWindow::getFullWindowBoundingBox() {
|
||||
static auto* const PBORDERSIZE = &g_pConfigManager->getConfigValuePtr("general:border_size")->intValue;
|
||||
SWindowDecorationExtents CWindow::getFullWindowExtents() {
|
||||
if (m_bFadingOut)
|
||||
return m_eOriginalClosedExtents;
|
||||
|
||||
const int BORDERSIZE = getRealBorderSize();
|
||||
|
||||
if (m_sAdditionalConfigData.dimAround) {
|
||||
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
|
||||
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)}};
|
||||
}
|
||||
|
||||
SWindowDecorationExtents maxExtents = {{BORDERSIZE + 2, BORDERSIZE + 2}, {BORDERSIZE + 2, BORDERSIZE + 2}};
|
||||
|
||||
const auto EXTENTS = g_pDecorationPositioner->getWindowDecorationExtents(this);
|
||||
|
||||
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};
|
||||
}
|
||||
|
||||
SWindowDecorationExtents maxExtents = {{*PBORDERSIZE + 2, *PBORDERSIZE + 2}, {*PBORDERSIZE + 2, *PBORDERSIZE + 2}};
|
||||
auto maxExtents = getFullWindowExtents();
|
||||
|
||||
for (auto& wd : m_dWindowDecorations) {
|
||||
|
||||
const auto EXTENTS = wd->getWindowDecorationExtents();
|
||||
|
||||
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
|
||||
wlr_box 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};
|
||||
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;
|
||||
}
|
||||
|
||||
wlr_box CWindow::getWindowIdealBoundingBoxIgnoreReserved() {
|
||||
CBox CWindow::getWindowIdealBoundingBoxIgnoreReserved() {
|
||||
|
||||
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
|
||||
|
||||
@@ -67,7 +110,7 @@ wlr_box CWindow::getWindowIdealBoundingBoxIgnoreReserved() {
|
||||
POS = PMONITOR->vecPosition;
|
||||
SIZE = PMONITOR->vecSize;
|
||||
|
||||
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};
|
||||
}
|
||||
|
||||
if (DELTALESSTHAN(POS.y - PMONITOR->vecPosition.y, PMONITOR->vecReservedTopLeft.y, 1)) {
|
||||
@@ -85,77 +128,86 @@ wlr_box CWindow::getWindowIdealBoundingBoxIgnoreReserved() {
|
||||
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};
|
||||
}
|
||||
|
||||
wlr_box CWindow::getWindowInputBox() {
|
||||
static auto* const PBORDERSIZE = &g_pConfigManager->getConfigValuePtr("general:border_size")->intValue;
|
||||
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 = {{*PBORDERSIZE + 2, *PBORDERSIZE + 2}, {*PBORDERSIZE + 2, *PBORDERSIZE + 2}};
|
||||
SWindowDecorationExtents maxExtents = {{BORDERSIZE + 2, BORDERSIZE + 2}, {BORDERSIZE + 2, BORDERSIZE + 2}};
|
||||
|
||||
for (auto& wd : m_dWindowDecorations) {
|
||||
const auto EXTENTS = g_pDecorationPositioner->getWindowDecorationExtents(this, true);
|
||||
|
||||
if (!wd->allowsInput())
|
||||
continue;
|
||||
if (EXTENTS.topLeft.x > maxExtents.topLeft.x)
|
||||
maxExtents.topLeft.x = EXTENTS.topLeft.x;
|
||||
|
||||
const auto EXTENTS = wd->getWindowDecorationExtents();
|
||||
if (EXTENTS.topLeft.y > maxExtents.topLeft.y)
|
||||
maxExtents.topLeft.y = EXTENTS.topLeft.y;
|
||||
|
||||
if (EXTENTS.topLeft.x > maxExtents.topLeft.x)
|
||||
maxExtents.topLeft.x = EXTENTS.topLeft.x;
|
||||
if (EXTENTS.bottomRight.x > maxExtents.bottomRight.x)
|
||||
maxExtents.bottomRight.x = EXTENTS.bottomRight.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 (EXTENTS.bottomRight.y > maxExtents.bottomRight.y)
|
||||
maxExtents.bottomRight.y = EXTENTS.bottomRight.y;
|
||||
|
||||
// Add extents to the real base BB and return
|
||||
wlr_box 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};
|
||||
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() {
|
||||
SWindowDecorationExtents extents;
|
||||
|
||||
for (auto& wd : m_dWindowDecorations) {
|
||||
const auto RESERVED = wd->getWindowDecorationReservedArea();
|
||||
|
||||
if (RESERVED.bottomRight == Vector2D{} && RESERVED.topLeft == Vector2D{})
|
||||
continue;
|
||||
|
||||
extents.topLeft = extents.topLeft + RESERVED.topLeft;
|
||||
extents.bottomRight = extents.bottomRight + RESERVED.bottomRight;
|
||||
}
|
||||
|
||||
return extents;
|
||||
return g_pDecorationPositioner->getWindowDecorationReserved(this);
|
||||
}
|
||||
|
||||
void CWindow::updateWindowDecos() {
|
||||
for (auto& wd : m_dWindowDecorations)
|
||||
wd->updateWindow(this);
|
||||
bool recalc = false;
|
||||
|
||||
if (!m_bIsMapped || isHidden())
|
||||
return;
|
||||
|
||||
for (auto& wd : m_vDecosToRemove) {
|
||||
for (auto it = m_dWindowDecorations.begin(); it != m_dWindowDecorations.end(); it++) {
|
||||
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())
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
g_pDecorationPositioner->onWindowUpdate(this);
|
||||
|
||||
if (recalc)
|
||||
g_pLayoutManager->getCurrentLayout()->recalculateWindow(this);
|
||||
|
||||
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));
|
||||
updateWindowDecos();
|
||||
}
|
||||
|
||||
void CWindow::removeWindowDeco(IHyprWindowDecoration* deco) {
|
||||
m_vDecosToRemove.push_back(deco);
|
||||
updateWindowDecos();
|
||||
}
|
||||
|
||||
pid_t CWindow::getPID() {
|
||||
@@ -167,6 +219,9 @@ pid_t CWindow::getPID() {
|
||||
|
||||
wl_client_get_credentials(wl_resource_get_client(m_uSurface.xdg->resource), &PID, nullptr, nullptr);
|
||||
} else {
|
||||
if (!m_bIsMapped || !m_bMappedX11)
|
||||
return -1;
|
||||
|
||||
PID = m_uSurface.xwayland->pid;
|
||||
}
|
||||
|
||||
@@ -197,7 +252,7 @@ void CWindow::createToplevelHandle() {
|
||||
|
||||
// handle events
|
||||
hyprListener_toplevelActivate.initCallback(
|
||||
&m_phForeignToplevel->events.request_activate, [&](void* owner, void* data) { g_pCompositor->focusWindow(this); }, this, "Toplevel");
|
||||
&m_phForeignToplevel->events.request_activate, [&](void* owner, void* data) { g_pLayoutManager->getCurrentLayout()->requestFocusForWindow(this); }, this, "Toplevel");
|
||||
|
||||
hyprListener_toplevelFullscreen.initCallback(
|
||||
&m_phForeignToplevel->events.request_fullscreen,
|
||||
@@ -268,19 +323,33 @@ void CWindow::updateSurfaceOutputs() {
|
||||
wlr_surface_for_each_surface(m_pWLSurface.wlr(), sendLeaveIter, PLASTMONITOR->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) {
|
||||
if (m_iWorkspaceID == workspaceID)
|
||||
return;
|
||||
|
||||
static auto* const PCLOSEONLASTSPECIAL = &g_pConfigManager->getConfigValuePtr("misc:close_special_on_empty")->intValue;
|
||||
|
||||
const int OLDWORKSPACE = m_iWorkspaceID;
|
||||
|
||||
m_iWorkspaceID = workspaceID;
|
||||
|
||||
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
|
||||
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(m_iWorkspaceID);
|
||||
|
||||
updateSpecialRenderData();
|
||||
|
||||
if (PWORKSPACE) {
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{"movewindow", getFormat("%x,%s", this, PWORKSPACE->m_szName.c_str())});
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{"movewindow", std::format("{:x},{}", (uintptr_t)this, PWORKSPACE->m_szName)});
|
||||
EMIT_HOOK_EVENT("moveWindow", (std::vector<void*>{this, PWORKSPACE}));
|
||||
}
|
||||
|
||||
@@ -289,8 +358,17 @@ void CWindow::moveToWorkspace(int workspaceID) {
|
||||
m_pSwallowed->m_iMonitorID = m_iMonitorID;
|
||||
}
|
||||
|
||||
if (PMONITOR)
|
||||
g_pProtocolManager->m_pFractionalScaleProtocolManager->setPreferredScaleForSurface(m_pWLSurface.wlr(), PMONITOR->scale);
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CWindow* CWindow::X11TransientFor() {
|
||||
@@ -326,6 +404,8 @@ void unregisterVar(void* ptr) {
|
||||
}
|
||||
|
||||
void CWindow::onUnmap() {
|
||||
static auto* const PCLOSEONLASTSPECIAL = &g_pConfigManager->getConfigValuePtr("misc:close_special_on_empty")->intValue;
|
||||
|
||||
if (g_pCompositor->m_pLastWindow == this)
|
||||
g_pCompositor->m_pLastWindow = nullptr;
|
||||
|
||||
@@ -345,11 +425,23 @@ void CWindow::onUnmap() {
|
||||
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();
|
||||
@@ -377,7 +469,10 @@ void CWindow::onMap() {
|
||||
|
||||
g_pCompositor->m_vWindowFocusHistory.push_back(this);
|
||||
|
||||
hyprListener_unmapWindow.initCallback(m_bIsX11 ? &m_uSurface.xwayland->events.unmap : &m_uSurface.xdg->events.unmap, &Events::listener_unmapWindow, this, "CWindow");
|
||||
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) {
|
||||
@@ -415,42 +510,62 @@ void CWindow::applyDynamicRule(const SWindowRule& r) {
|
||||
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.find("rounding") == 0) {
|
||||
} 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 \"%s\" failed with: %s", r.szRule.c_str(), e.what()); }
|
||||
} else if (r.szRule.find("opacity") == 0) {
|
||||
} 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, ' ');
|
||||
|
||||
for (size_t i = 1 /* first item is "opacity" */; i < vars.size(); ++i) {
|
||||
if (i == 1) {
|
||||
// first arg, alpha
|
||||
m_sSpecialRenderData.alpha = std::stof(vars[i]);
|
||||
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 (vars[i] == "override") {
|
||||
if (i == 2) {
|
||||
m_sSpecialRenderData.alphaOverride = true;
|
||||
} else {
|
||||
m_sSpecialRenderData.alphaInactiveOverride = true;
|
||||
}
|
||||
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 {
|
||||
m_sSpecialRenderData.alphaInactive = std::stof(vars[i]);
|
||||
throw std::runtime_error("more than 2 alpha values");
|
||||
}
|
||||
|
||||
opacityIDX++;
|
||||
}
|
||||
}
|
||||
} catch (std::exception& e) { Debug::log(ERR, "Opacity rule \"%s\" failed with: %s", r.szRule.c_str(), e.what()); }
|
||||
} 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.find("animation") == 0) {
|
||||
} 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.find("bordercolor") == 0) {
|
||||
} else if (r.szRule.starts_with("bordercolor")) {
|
||||
try {
|
||||
std::string colorPart = removeBeginEndSpacesTabs(r.szRule.substr(r.szRule.find_first_of(' ') + 1));
|
||||
|
||||
@@ -461,9 +576,17 @@ void CWindow::applyDynamicRule(const SWindowRule& r) {
|
||||
} else {
|
||||
m_sSpecialRenderData.activeBorderColor = configStringToInt(colorPart);
|
||||
}
|
||||
} catch (std::exception& e) { Debug::log(ERR, "BorderColor rule \"%s\" failed with: %s", r.szRule.c_str(), e.what()); }
|
||||
} 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 (...) {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -475,47 +598,53 @@ void CWindow::updateDynamicRules() {
|
||||
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.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;
|
||||
|
||||
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) {
|
||||
static auto* const ROUNDING = &g_pConfigManager->getConfigValuePtr("decoration:rounding")->intValue;
|
||||
static auto* const BORDERSIZE = &g_pConfigManager->getConfigValuePtr("general:border_size")->intValue;
|
||||
|
||||
if (BORDERSIZE >= ROUNDING || ROUNDING == 0)
|
||||
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;
|
||||
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;
|
||||
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;
|
||||
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;
|
||||
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 Vector2D{x1, y1}.distance(Vector2D{x, y}) > (double)ROUNDING;
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -524,9 +653,9 @@ bool CWindow::isInCurvedCorner(double x, double y) {
|
||||
void findExtensionForVector2D(wlr_surface* surface, int x, int y, void* data) {
|
||||
const auto DATA = (SExtensionFindingData*)data;
|
||||
|
||||
wlr_box box = {DATA->origin.x + x, DATA->origin.y + y, surface->current.width, surface->current.height};
|
||||
CBox box = {DATA->origin.x + x, DATA->origin.y + y, surface->current.width, surface->current.height};
|
||||
|
||||
if (wlr_box_contains_point(&box, DATA->vec.x, DATA->vec.y))
|
||||
if (box.containsPoint(DATA->vec))
|
||||
*DATA->found = surface;
|
||||
}
|
||||
|
||||
@@ -543,6 +672,69 @@ bool CWindow::hasPopupAt(const Vector2D& pos) {
|
||||
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)
|
||||
@@ -564,6 +756,36 @@ CWindow* CWindow::getGroupCurrent() {
|
||||
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;
|
||||
@@ -591,7 +813,7 @@ void CWindow::setGroupCurrent(CWindow* pWindow) {
|
||||
g_pCompositor->setWindowFullscreen(PCURRENT, false, WORKSPACE->m_efFullscreenMode);
|
||||
|
||||
PCURRENT->setHidden(true);
|
||||
pWindow->setHidden(false);
|
||||
pWindow->setHidden(false); // can remove m_pLastWindow
|
||||
|
||||
g_pLayoutManager->getCurrentLayout()->replaceWindowDataWith(PCURRENT, pWindow);
|
||||
|
||||
@@ -607,34 +829,64 @@ void CWindow::setGroupCurrent(CWindow* pWindow) {
|
||||
|
||||
if (FULLSCREEN)
|
||||
g_pCompositor->setWindowFullscreen(pWindow, true, WORKSPACE->m_efFullscreenMode);
|
||||
|
||||
g_pHyprRenderer->damageWindow(pWindow);
|
||||
|
||||
pWindow->updateWindowDecos();
|
||||
}
|
||||
|
||||
void CWindow::insertWindowToGroup(CWindow* pWindow) {
|
||||
const auto PHEAD = getGroupHead();
|
||||
const auto PTAIL = getGroupTail();
|
||||
const auto BEGINAT = this;
|
||||
const auto ENDAT = m_sGroupData.pNextWindow;
|
||||
|
||||
if (pWindow->m_sGroupData.pNextWindow) {
|
||||
std::vector<CWindow*> members;
|
||||
CWindow* curr = pWindow;
|
||||
do {
|
||||
const auto PLAST = curr;
|
||||
members.push_back(curr);
|
||||
curr = curr->m_sGroupData.pNextWindow;
|
||||
PLAST->m_sGroupData.pNextWindow = nullptr;
|
||||
PLAST->m_sGroupData.head = false;
|
||||
} while (curr != pWindow);
|
||||
|
||||
for (auto& w : members) {
|
||||
insertWindowToGroup(w);
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
PTAIL->m_sGroupData.pNextWindow = pWindow;
|
||||
pWindow->m_sGroupData.pNextWindow = PHEAD;
|
||||
const auto SHEAD = pWindow->getGroupHead();
|
||||
const auto STAIL = pWindow->getGroupTail();
|
||||
|
||||
setGroupCurrent(pWindow);
|
||||
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() {
|
||||
@@ -652,4 +904,73 @@ void CWindow::updateGroupOutputs() {
|
||||
|
||||
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;
|
||||
}
|
||||
|
137
src/Window.hpp
137
src/Window.hpp
@@ -1,7 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "defines.hpp"
|
||||
#include "events/Events.hpp"
|
||||
#include "helpers/SubsurfaceTree.hpp"
|
||||
#include "helpers/AnimatedVariable.hpp"
|
||||
#include "render/decorations/IHyprWindowDecoration.hpp"
|
||||
@@ -9,6 +8,8 @@
|
||||
#include "config/ConfigDataValues.hpp"
|
||||
#include "helpers/Vector2D.hpp"
|
||||
#include "helpers/WLSurface.hpp"
|
||||
#include "macros.hpp"
|
||||
#include "managers/XWaylandManager.hpp"
|
||||
|
||||
enum eIdleInhibitMode
|
||||
{
|
||||
@@ -18,6 +19,21 @@ enum eIdleInhibitMode
|
||||
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:
|
||||
@@ -101,9 +117,11 @@ struct SWindowSpecialRenderData {
|
||||
CWindowOverridableVar<int64_t> inactiveBorderColor = -1; // -1 means unset
|
||||
|
||||
// set by the layout
|
||||
bool rounding = true;
|
||||
bool border = true;
|
||||
bool decorate = true;
|
||||
CWindowOverridableVar<int> borderSize = -1; // -1 means unset
|
||||
bool rounding = true;
|
||||
bool border = true;
|
||||
bool decorate = true;
|
||||
bool shadow = true;
|
||||
};
|
||||
|
||||
struct SWindowAdditionalConfigData {
|
||||
@@ -116,10 +134,16 @@ struct SWindowAdditionalConfigData {
|
||||
CWindowOverridableVar<bool> forceNoAnims = false;
|
||||
CWindowOverridableVar<bool> forceNoBorder = 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 {
|
||||
@@ -133,6 +157,7 @@ struct SWindowRule {
|
||||
int bFloating = -1;
|
||||
int bFullscreen = -1;
|
||||
int bPinned = -1;
|
||||
std::string szWorkspace = ""; // empty means any
|
||||
};
|
||||
|
||||
class CWindow {
|
||||
@@ -158,6 +183,9 @@ class CWindow {
|
||||
DYNLISTENER(toplevelActivate);
|
||||
DYNLISTENER(toplevelFullscreen);
|
||||
DYNLISTENER(setOverrideRedirect);
|
||||
DYNLISTENER(associateX11);
|
||||
DYNLISTENER(dissociateX11);
|
||||
DYNLISTENER(ackConfigure);
|
||||
// DYNLISTENER(newSubsurfaceWindow);
|
||||
|
||||
CWLSurface m_pWLSurface;
|
||||
@@ -177,8 +205,11 @@ class CWindow {
|
||||
CAnimatedVariable m_vRealSize;
|
||||
|
||||
// for not spamming the protocols
|
||||
Vector2D m_vReportedPosition;
|
||||
Vector2D m_vReportedSize;
|
||||
Vector2D m_vReportedPosition;
|
||||
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
|
||||
Vector2D m_vLastFloatingSize;
|
||||
@@ -188,7 +219,7 @@ class CWindow {
|
||||
bool m_bIsPseudotiled = false;
|
||||
Vector2D m_vPseudoSize = Vector2D(0, 0);
|
||||
|
||||
uint64_t m_iTags = 0;
|
||||
bool m_bFirstMap = false; // for layouts
|
||||
bool m_bIsFloating = false;
|
||||
bool m_bDraggingTiled = false; // for dragging around tiled windows
|
||||
bool m_bIsFullscreen = false;
|
||||
@@ -214,15 +245,17 @@ class CWindow {
|
||||
bool m_bIsModal = false;
|
||||
bool m_bX11DoesntWantBorders = false;
|
||||
bool m_bX11ShouldntFocus = false;
|
||||
float m_fX11SurfaceScaledBy = 1.f;
|
||||
//
|
||||
|
||||
// For nofocus
|
||||
bool m_bNoFocus = false;
|
||||
bool m_bNoInitialFocus = false;
|
||||
|
||||
// initial fullscreen and fullscreen disabled
|
||||
// Fullscreen and Maximize
|
||||
bool m_bWantsInitialFullscreen = false;
|
||||
bool m_bNoFullscreenRequest = false;
|
||||
bool m_bNoMaximizeRequest = false;
|
||||
|
||||
SSurfaceTreeNode* m_pSurfaceTree = nullptr;
|
||||
|
||||
@@ -233,11 +266,12 @@ class CWindow {
|
||||
CAnimatedVariable m_fBorderAngleAnimationProgress;
|
||||
|
||||
// Fade in-out
|
||||
CAnimatedVariable m_fAlpha;
|
||||
bool m_bFadingOut = false;
|
||||
bool m_bReadyToDelete = false;
|
||||
Vector2D m_vOriginalClosedPos; // these will be used for calculations later on in
|
||||
Vector2D m_vOriginalClosedSize; // drawing the closing animations
|
||||
CAnimatedVariable m_fAlpha;
|
||||
bool m_bFadingOut = false;
|
||||
bool m_bReadyToDelete = false;
|
||||
Vector2D m_vOriginalClosedPos; // these will be used for calculations later on in
|
||||
Vector2D m_vOriginalClosedSize; // drawing the closing animations
|
||||
SWindowDecorationExtents m_eOriginalClosedExtents;
|
||||
|
||||
// For pinned (sticky) windows
|
||||
bool m_bPinned = false;
|
||||
@@ -262,6 +296,9 @@ class CWindow {
|
||||
SWindowSpecialRenderData m_sSpecialRenderData;
|
||||
SWindowAdditionalConfigData m_sAdditionalConfigData;
|
||||
|
||||
// Transformers
|
||||
std::vector<std::unique_ptr<IWindowTransformer>> m_vTransformers;
|
||||
|
||||
// for alpha
|
||||
CAnimatedVariable m_fActiveInactiveAlpha;
|
||||
|
||||
@@ -274,6 +311,9 @@ class CWindow {
|
||||
// swallowing
|
||||
CWindow* m_pSwallowed = nullptr;
|
||||
|
||||
// focus stuff
|
||||
bool m_bStayFocused = false;
|
||||
|
||||
// for toplevel monitor events
|
||||
uint64_t m_iLastToplevelMonitorID = -1;
|
||||
uint64_t m_iLastSurfaceMonitorID = -1;
|
||||
@@ -285,7 +325,12 @@ class CWindow {
|
||||
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
|
||||
bool operator==(const CWindow& rhs) {
|
||||
@@ -294,10 +339,14 @@ class CWindow {
|
||||
}
|
||||
|
||||
// methods
|
||||
wlr_box getFullWindowBoundingBox();
|
||||
wlr_box getWindowInputBox();
|
||||
wlr_box getWindowIdealBoundingBoxIgnoreReserved();
|
||||
CBox getFullWindowBoundingBox();
|
||||
SWindowDecorationExtents getFullWindowExtents();
|
||||
CBox getWindowInputBox();
|
||||
CBox getWindowMainSurfaceBox();
|
||||
CBox getWindowIdealBoundingBoxIgnoreReserved();
|
||||
void addWindowDeco(std::unique_ptr<IHyprWindowDecoration> deco);
|
||||
void updateWindowDecos();
|
||||
void removeWindowDeco(IHyprWindowDecoration* deco);
|
||||
pid_t getPID();
|
||||
IHyprWindowDecoration* getDecorationByType(eDecorationType);
|
||||
void removeDecorationByType(eDecorationType);
|
||||
@@ -314,19 +363,75 @@ class CWindow {
|
||||
void applyDynamicRule(const SWindowRule& r);
|
||||
void updateDynamicRules();
|
||||
SWindowDecorationExtents getFullWindowReservedArea();
|
||||
Vector2D middle();
|
||||
bool opaque();
|
||||
float rounding();
|
||||
bool canBeTorn();
|
||||
|
||||
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
|
||||
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, "]");
|
||||
}
|
||||
};
|
||||
|
@@ -2,13 +2,12 @@
|
||||
#include "../defines.hpp"
|
||||
#include <vector>
|
||||
|
||||
enum eConfigValueDataTypes
|
||||
{
|
||||
enum eConfigValueDataTypes {
|
||||
CVD_TYPE_INVALID = -1,
|
||||
CVD_TYPE_GRADIENT = 0
|
||||
};
|
||||
|
||||
interface ICustomConfigValueData {
|
||||
class ICustomConfigValueData {
|
||||
public:
|
||||
virtual ~ICustomConfigValueData() = 0;
|
||||
|
||||
@@ -38,7 +37,8 @@ class CGradientValueData : public ICustomConfigValueData {
|
||||
/* Float corresponding to the angle (rad) */
|
||||
float m_fAngle = 0;
|
||||
|
||||
bool operator==(const CGradientValueData& other) {
|
||||
//
|
||||
bool operator==(const CGradientValueData& other) const {
|
||||
if (other.m_vColors.size() != m_vColors.size() || m_fAngle != other.m_fAngle)
|
||||
return false;
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -10,14 +10,17 @@
|
||||
#include <deque>
|
||||
#include <algorithm>
|
||||
#include <regex>
|
||||
#include <optional>
|
||||
#include <functional>
|
||||
#include <xf86drmMode.h>
|
||||
#include "../Window.hpp"
|
||||
#include "../helpers/WLClasses.hpp"
|
||||
#include "../helpers/Monitor.hpp"
|
||||
#include "../helpers/VarList.hpp"
|
||||
|
||||
#include "defaultConfig.hpp"
|
||||
#include "ConfigDataValues.hpp"
|
||||
|
||||
#define STRVAL_EMPTY "[[EMPTY]]"
|
||||
|
||||
#define INITANIMCFG(name) animationConfig[name] = {}
|
||||
#define CREATEANIMCFG(name, parent) animationConfig[name] = {false, "", "", 0.f, -1, &animationConfig["global"], &animationConfig[parent]}
|
||||
|
||||
@@ -33,16 +36,21 @@ struct SConfigValue {
|
||||
bool set = false; // used for device configs
|
||||
};
|
||||
|
||||
struct SMonitorRule {
|
||||
std::string name = "";
|
||||
Vector2D resolution = Vector2D(1280, 720);
|
||||
Vector2D offset = Vector2D(0, 0);
|
||||
float scale = 1;
|
||||
float refreshRate = 60;
|
||||
bool disabled = false;
|
||||
wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL;
|
||||
std::string mirrorOf = "";
|
||||
bool enable10bit = false;
|
||||
struct SWorkspaceRule {
|
||||
std::string monitor = "";
|
||||
std::string workspaceString = "";
|
||||
std::string workspaceName = "";
|
||||
int workspaceId = -1;
|
||||
bool isDefault = false;
|
||||
bool isPersistent = false;
|
||||
std::optional<int64_t> gapsIn;
|
||||
std::optional<int64_t> gapsOut;
|
||||
std::optional<int64_t> borderSize;
|
||||
std::optional<int> border;
|
||||
std::optional<int> rounding;
|
||||
std::optional<int> decorate;
|
||||
std::optional<int> shadow;
|
||||
std::optional<std::string> onCreatedEmptyRunCmd;
|
||||
};
|
||||
|
||||
struct SMonitorAdditionalReservedArea {
|
||||
@@ -64,67 +72,17 @@ struct SAnimationPropertyConfig {
|
||||
SAnimationPropertyConfig* pParentAnimation = nullptr;
|
||||
};
|
||||
|
||||
struct SPluginKeyword {
|
||||
HANDLE handle = 0;
|
||||
std::string name = "";
|
||||
std::function<void(const std::string&, const std::string&)> fn;
|
||||
};
|
||||
|
||||
struct SExecRequestedRule {
|
||||
std::string szRule = "";
|
||||
uint64_t iPid = 0;
|
||||
};
|
||||
|
||||
class CVarList {
|
||||
public:
|
||||
CVarList(const std::string& in, long unsigned int lastArgNo = 0, const char separator = ',') {
|
||||
std::string curitem = "";
|
||||
std::string argZ = in;
|
||||
|
||||
auto nextItem = [&]() {
|
||||
auto idx = lastArgNo != 0 && m_vArgs.size() >= lastArgNo - 1 ? std::string::npos : argZ.find_first_of(separator);
|
||||
|
||||
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;
|
||||
|
||||
size_t 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];
|
||||
}
|
||||
|
||||
// for range-based loops
|
||||
std::vector<std::string>::iterator begin() {
|
||||
return m_vArgs.begin();
|
||||
}
|
||||
std::vector<std::string>::const_iterator begin() const {
|
||||
return m_vArgs.begin();
|
||||
}
|
||||
std::vector<std::string>::iterator end() {
|
||||
return m_vArgs.end();
|
||||
}
|
||||
std::vector<std::string>::const_iterator end() const {
|
||||
return m_vArgs.end();
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<std::string> m_vArgs;
|
||||
};
|
||||
|
||||
class CConfigManager {
|
||||
public:
|
||||
CConfigManager();
|
||||
@@ -134,25 +92,32 @@ class CConfigManager {
|
||||
|
||||
int getInt(const std::string&);
|
||||
float getFloat(const std::string&);
|
||||
Vector2D getVec(const std::string&);
|
||||
std::string getString(const std::string&);
|
||||
void setFloat(const std::string&, float);
|
||||
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&);
|
||||
float getDeviceFloat(const std::string&, const std::string&);
|
||||
std::string getDeviceString(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&, const std::string& fallback = "");
|
||||
Vector2D getDeviceVec(const std::string&, const std::string&, const std::string& fallback = "");
|
||||
std::string getDeviceString(const std::string&, const std::string&, const std::string& fallback = "");
|
||||
bool deviceConfigExists(const std::string&);
|
||||
bool shouldBlurLS(const std::string&);
|
||||
|
||||
SConfigValue* getConfigValuePtr(const std::string&);
|
||||
SConfigValue* getConfigValuePtrSafe(const std::string&);
|
||||
static std::string getConfigDir();
|
||||
static std::string getMainConfigPath();
|
||||
|
||||
SMonitorRule getMonitorRuleFor(const std::string&, const std::string& displayName = "");
|
||||
SWorkspaceRule getWorkspaceRuleFor(CWorkspace*);
|
||||
std::string getDefaultWorkspaceFor(const 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<SLayerRule> getMatchingRules(SLayerSurface*);
|
||||
@@ -162,7 +127,8 @@ class CConfigManager {
|
||||
std::unordered_map<std::string, SAnimationPropertyConfig> getAnimationConfig();
|
||||
|
||||
void addPluginConfigVar(HANDLE handle, const std::string& name, const SConfigValue& value);
|
||||
void removePluginConfig(HANDLE handle);
|
||||
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.
|
||||
void dispatchExecOnce();
|
||||
@@ -182,6 +148,8 @@ class CConfigManager {
|
||||
|
||||
void addExecRule(const SExecRequestedRule&);
|
||||
|
||||
void handlePluginLoads();
|
||||
|
||||
std::string configCurrentPath;
|
||||
|
||||
private:
|
||||
@@ -199,16 +167,16 @@ class CConfigManager {
|
||||
|
||||
std::string m_szCurrentSubmap = ""; // For storing the current keybind submap
|
||||
|
||||
std::vector<std::pair<std::string, std::string>> boundWorkspaces;
|
||||
|
||||
std::vector<SExecRequestedRule> execRequestedRules; // rules requested with exec, e.g. [workspace 2] kitty
|
||||
|
||||
std::vector<std::string> m_vDeclaredPlugins;
|
||||
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::unordered_map<std::string, std::string> m_mDefaultWorkspaces;
|
||||
std::deque<SWorkspaceRule> m_dWorkspaceRules;
|
||||
std::deque<SWindowRule> m_dWindowRules;
|
||||
std::deque<SLayerRule> m_dLayerRules;
|
||||
std::deque<std::string> m_dBlurLSNamespaces;
|
||||
@@ -219,6 +187,8 @@ class CConfigManager {
|
||||
|
||||
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
|
||||
void setDefaultVars();
|
||||
void setDefaultAnimationVars();
|
||||
@@ -231,7 +201,7 @@ class CConfigManager {
|
||||
void applyUserDefinedVars(std::string&, const size_t);
|
||||
void loadConfigLoadVars();
|
||||
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 configSetValueSafe(const std::string&, const std::string&);
|
||||
void handleDeviceConfig(const std::string&, const std::string&);
|
||||
@@ -242,7 +212,7 @@ class CConfigManager {
|
||||
void handleWindowRule(const std::string&, const std::string&);
|
||||
void handleLayerRule(const std::string&, const std::string&);
|
||||
void handleWindowRuleV2(const std::string&, const std::string&);
|
||||
void handleDefaultWorkspace(const std::string&, const std::string&);
|
||||
void handleWorkspaceRules(const std::string&, const std::string&);
|
||||
void handleBezier(const std::string&, const std::string&);
|
||||
void handleAnimation(const std::string&, const std::string&);
|
||||
void handleSource(const std::string&, const std::string&);
|
||||
@@ -250,6 +220,7 @@ class CConfigManager {
|
||||
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;
|
||||
|
@@ -58,16 +58,21 @@ general {
|
||||
col.inactive_border = rgba(595959aa)
|
||||
|
||||
layout = dwindle
|
||||
|
||||
# Please see https://wiki.hyprland.org/Configuring/Tearing/ before you turn this on
|
||||
allow_tearing = false
|
||||
}
|
||||
|
||||
decoration {
|
||||
# See https://wiki.hyprland.org/Configuring/Variables/ for more
|
||||
|
||||
rounding = 10
|
||||
blur = yes
|
||||
blur_size = 3
|
||||
blur_passes = 1
|
||||
blur_new_optimizations = on
|
||||
|
||||
blur {
|
||||
enabled = true
|
||||
size = 3
|
||||
passes = 1
|
||||
}
|
||||
|
||||
drop_shadow = yes
|
||||
shadow_range = 4
|
||||
@@ -106,6 +111,11 @@ gestures {
|
||||
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
|
||||
# See https://wiki.hyprland.org/Configuring/Keywords/#executing for more
|
||||
device:epic-mouse-v1 {
|
||||
@@ -162,6 +172,10 @@ bind = $mainMod SHIFT, 8, movetoworkspace, 8
|
||||
bind = $mainMod SHIFT, 9, movetoworkspace, 9
|
||||
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
|
||||
bind = $mainMod, mouse_down, workspace, e+1
|
||||
bind = $mainMod, mouse_up, workspace, e-1
|
||||
|
@@ -1,7 +1,6 @@
|
||||
#include "CrashReporter.hpp"
|
||||
#include <random>
|
||||
#include <sys/utsname.h>
|
||||
#include <execinfo.h>
|
||||
#include <fstream>
|
||||
#include <signal.h>
|
||||
|
||||
@@ -25,7 +24,8 @@ std::string getRandomMessage() {
|
||||
"*thud*",
|
||||
"Well this is awkward.",
|
||||
"\"stable\"",
|
||||
"I hope you didn't have any unsaved progress."};
|
||||
"I hope you didn't have any unsaved progress.",
|
||||
"All these computers..."};
|
||||
|
||||
std::random_device dev;
|
||||
std::mt19937 engine(dev());
|
||||
@@ -44,15 +44,15 @@ void CrashReporter::createAndSaveCrash(int sig) {
|
||||
finalCrashReport += "--------------------------------------------\n Hyprland Crash Report\n--------------------------------------------\n";
|
||||
finalCrashReport += getRandomMessage() + "\n\n";
|
||||
|
||||
finalCrashReport += getFormat("Hyprland received signal %d (%s)\n\n", sig, strsignal(sig));
|
||||
finalCrashReport += std::format("Hyprland received signal {} ({})\n\n", sig, (const char*)strsignal(sig));
|
||||
|
||||
finalCrashReport += getFormat("Version: %s\n\n", GIT_COMMIT_HASH);
|
||||
finalCrashReport += std::format("Version: {}\nTag: {}\n\n", GIT_COMMIT_HASH, GIT_TAG);
|
||||
|
||||
if (!g_pPluginSystem->getAllPlugins().empty()) {
|
||||
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 += getFormat("\t%s (%s) %s\n", p->name.c_str(), p->author.c_str(), p->version.c_str());
|
||||
finalCrashReport += std::format("\t{} ({}) {}\n", p->name, p->author, p->version);
|
||||
}
|
||||
|
||||
finalCrashReport += "\n\n";
|
||||
@@ -64,7 +64,7 @@ void CrashReporter::createAndSaveCrash(int sig) {
|
||||
uname(&unameInfo);
|
||||
|
||||
finalCrashReport +=
|
||||
getFormat("\tSystem name: %s\n\tNode name: %s\n\tRelease: %s\n\tVersion: %s\n\n", unameInfo.sysname, unameInfo.nodename, unameInfo.release, unameInfo.version);
|
||||
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");
|
||||
@@ -74,16 +74,11 @@ void CrashReporter::createAndSaveCrash(int sig) {
|
||||
|
||||
finalCrashReport += "GPU:\n\t" + GPUINFO;
|
||||
|
||||
finalCrashReport += getFormat("\n\nos-release:\n\t%s\n\n\n", replaceInString(execAndGet("cat /etc/os-release"), "\n", "\n\t").c_str());
|
||||
finalCrashReport += std::format("\n\nos-release:\n\t{}\n\n\n", replaceInString(execAndGet("cat /etc/os-release"), "\n", "\n\t"));
|
||||
|
||||
finalCrashReport += "Backtrace:\n";
|
||||
|
||||
void* bt[1024];
|
||||
size_t btSize;
|
||||
char** btSymbols;
|
||||
|
||||
btSize = backtrace(bt, 1024);
|
||||
btSymbols = backtrace_symbols(bt, btSize);
|
||||
const auto CALLSTACK = getBacktrace();
|
||||
|
||||
#if defined(KERN_PROC_PATHNAME)
|
||||
int mib[] = {
|
||||
@@ -110,51 +105,53 @@ void CrashReporter::createAndSaveCrash(int sig) {
|
||||
const auto FPATH = std::filesystem::canonical("/proc/self/exe");
|
||||
#endif
|
||||
|
||||
for (size_t i = 0; i < btSize; ++i) {
|
||||
finalCrashReport += getFormat("\t#%i | %s\n", i, btSymbols[i]);
|
||||
for (size_t i = 0; i < CALLSTACK.size(); ++i) {
|
||||
finalCrashReport += std::format("\t#{} | {}\n", i, CALLSTACK[i].desc);
|
||||
|
||||
#ifdef __clang__
|
||||
const auto CMD = getFormat("llvm-addr2line -e %s -f 0x%lx", FPATH.c_str(), (uint64_t)bt[i]);
|
||||
const auto CMD = std::format("llvm-addr2line -e {} -f 0x{:x}", FPATH.c_str(), (uint64_t)CALLSTACK[i].adr);
|
||||
#else
|
||||
const auto CMD = getFormat("addr2line -e %s -f 0x%lx", FPATH.c_str(), (uint64_t)bt[i]);
|
||||
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);
|
||||
}
|
||||
|
||||
free(btSymbols);
|
||||
|
||||
finalCrashReport += "\n\nLog tail:\n";
|
||||
|
||||
finalCrashReport += execAndGet(("cat \"" + Debug::logFile + "\" | tail -n 50").c_str());
|
||||
|
||||
const auto HOME = getenv("HOME");
|
||||
const auto HOME = getenv("HOME");
|
||||
const auto CACHE_HOME = getenv("XDG_CACHE_HOME");
|
||||
|
||||
if (!HOME)
|
||||
return;
|
||||
|
||||
std::ofstream ofs;
|
||||
if (!CACHE_HOME) {
|
||||
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);
|
||||
}
|
||||
|
||||
ofs.open(std::string(HOME) + "/.hyprland/hyprlandCrashReport" + std::to_string(PID) + ".txt", std::ios::trunc);
|
||||
path = std::string(HOME) + "/.hyprland/hyprlandCrashReport" + std::to_string(PID) + ".txt";
|
||||
ofs.open(path, std::ios::trunc);
|
||||
|
||||
} else if (CACHE_HOME) {
|
||||
} 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);
|
||||
}
|
||||
|
||||
ofs.open(std::string(CACHE_HOME) + "/hyprland/hyprlandCrashReport" + std::to_string(PID) + ".txt", std::ios::trunc);
|
||||
} else {
|
||||
return;
|
||||
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);
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -132,7 +132,7 @@ int CHyprMonitorDebugOverlay::draw(int offset) {
|
||||
|
||||
yOffset += 17;
|
||||
cairo_move_to(g_pDebugOverlay->m_pCairo, 0, yOffset);
|
||||
text = std::string(getFormat("%i FPS", (int)FPS));
|
||||
text = std::format("{} FPS", (int)FPS);
|
||||
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)
|
||||
@@ -143,7 +143,7 @@ int CHyprMonitorDebugOverlay::draw(int offset) {
|
||||
|
||||
yOffset += 11;
|
||||
cairo_move_to(g_pDebugOverlay->m_pCairo, 0, yOffset);
|
||||
text = std::string(getFormat("Avg Frametime: %.2fms (var %.2fms)", avgFrametime, varFrametime));
|
||||
text = std::format("Avg Frametime: {:.2f}ms (var {:.2f}ms)", avgFrametime, varFrametime);
|
||||
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)
|
||||
@@ -151,7 +151,7 @@ int CHyprMonitorDebugOverlay::draw(int offset) {
|
||||
|
||||
yOffset += 11;
|
||||
cairo_move_to(g_pDebugOverlay->m_pCairo, 0, yOffset);
|
||||
text = std::string(getFormat("Avg Rendertime: %.2fms (var %.2fms)", avgRenderTime, varRenderTime));
|
||||
text = std::format("Avg Rendertime: {:.2f}ms (var {:.2f}ms)", avgRenderTime, varRenderTime);
|
||||
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)
|
||||
@@ -159,7 +159,7 @@ int CHyprMonitorDebugOverlay::draw(int offset) {
|
||||
|
||||
yOffset += 11;
|
||||
cairo_move_to(g_pDebugOverlay->m_pCairo, 0, yOffset);
|
||||
text = std::string(getFormat("Avg Rendertime (No Overlay): %.2fms (var %.2fms)", avgRenderTimeNoOverlay, varRenderTimeNoOverlay));
|
||||
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_text_extents(g_pDebugOverlay->m_pCairo, text.c_str(), &cairoExtents);
|
||||
if (cairoExtents.width > maxX)
|
||||
@@ -167,7 +167,7 @@ int CHyprMonitorDebugOverlay::draw(int offset) {
|
||||
|
||||
yOffset += 11;
|
||||
cairo_move_to(g_pDebugOverlay->m_pCairo, 0, yOffset);
|
||||
text = std::string(getFormat("Avg Anim Tick: %.2fms (var %.2fms) (%.2f TPS)", avgAnimMgrTick, varAnimMgrTick, 1.0 / (avgAnimMgrTick / 1000.0)));
|
||||
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)
|
||||
@@ -233,6 +233,6 @@ void CHyprDebugOverlay::draw() {
|
||||
|
||||
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, 1.f);
|
||||
}
|
||||
|
@@ -24,7 +24,7 @@ class CHyprMonitorDebugOverlay {
|
||||
std::deque<float> m_dLastAnimationTicks;
|
||||
std::chrono::high_resolution_clock::time_point m_tpLastFrame;
|
||||
CMonitor* m_pMonitor = nullptr;
|
||||
wlr_box m_wbLastDrawnBox;
|
||||
CBox m_wbLastDrawnBox;
|
||||
|
||||
friend class CHyprRenderer;
|
||||
};
|
||||
|
@@ -3,7 +3,7 @@
|
||||
#include <pango/pangocairo.h>
|
||||
|
||||
CHyprNotificationOverlay::CHyprNotificationOverlay() {
|
||||
g_pHookSystem->hookDynamic("focusedMon", [&](void* self, std::any param) {
|
||||
g_pHookSystem->hookDynamic("focusedMon", [&](void* self, SCallbackInfo& info, std::any param) {
|
||||
if (m_dNotifications.size() == 0)
|
||||
return;
|
||||
|
||||
@@ -44,9 +44,13 @@ void CHyprNotificationOverlay::addNotification(const std::string& text, const CC
|
||||
PNOTIF->started.reset();
|
||||
PNOTIF->timeMs = timeMs;
|
||||
PNOTIF->icon = icon;
|
||||
|
||||
for (auto& m : g_pCompositor->m_vMonitors) {
|
||||
g_pCompositor->scheduleFrameForMonitor(m.get());
|
||||
}
|
||||
}
|
||||
|
||||
wlr_box CHyprNotificationOverlay::drawNotifications(CMonitor* pMonitor) {
|
||||
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;
|
||||
@@ -166,7 +170,7 @@ wlr_box CHyprNotificationOverlay::drawNotifications(CMonitor* pMonitor) {
|
||||
// cleanup notifs
|
||||
std::erase_if(m_dNotifications, [](const auto& notif) { return notif->started.getMillis() > notif->timeMs; });
|
||||
|
||||
return wlr_box{(int)(pMonitor->vecPosition.x + pMonitor->vecSize.x - maxWidth - 20), (int)pMonitor->vecPosition.y, (int)maxWidth + 20, (int)offsetY + 10};
|
||||
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) {
|
||||
@@ -197,7 +201,7 @@ void CHyprNotificationOverlay::draw(CMonitor* pMonitor) {
|
||||
|
||||
cairo_surface_flush(m_pCairoSurface);
|
||||
|
||||
wlr_box damage = drawNotifications(pMonitor);
|
||||
CBox damage = drawNotifications(pMonitor);
|
||||
|
||||
g_pHyprRenderer->damageBox(&damage);
|
||||
g_pHyprRenderer->damageBox(&m_bLastDamage);
|
||||
@@ -220,6 +224,6 @@ void CHyprNotificationOverlay::draw(CMonitor* pMonitor) {
|
||||
|
||||
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, 1.f);
|
||||
}
|
@@ -44,8 +44,8 @@ class CHyprNotificationOverlay {
|
||||
void addNotification(const std::string& text, const CColor& color, const float timeMs, const eIcons icon = ICON_NONE);
|
||||
|
||||
private:
|
||||
wlr_box drawNotifications(CMonitor* pMonitor);
|
||||
wlr_box m_bLastDamage;
|
||||
CBox drawNotifications(CMonitor* pMonitor);
|
||||
CBox m_bLastDamage;
|
||||
|
||||
std::deque<std::unique_ptr<SNotification>> m_dNotifications;
|
||||
|
||||
|
@@ -10,6 +10,12 @@ void Debug::init(const std::string& IS) {
|
||||
}
|
||||
|
||||
void Debug::wlrLog(wlr_log_importance level, const char* fmt, va_list args) {
|
||||
if (disableLogs && *disableLogs)
|
||||
return;
|
||||
|
||||
if (level > wlr_log_get_verbosity())
|
||||
return;
|
||||
|
||||
char* outputStr = nullptr;
|
||||
|
||||
std::ofstream ofs;
|
||||
@@ -27,57 +33,3 @@ void Debug::wlrLog(wlr_log_importance level, const char* fmt, va_list args) {
|
||||
if (!disableStdout)
|
||||
std::cout << output << "\n";
|
||||
}
|
||||
|
||||
void Debug::log(LogLevel level, const char* fmt, ...) {
|
||||
|
||||
if (disableLogs && *disableLogs)
|
||||
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;
|
||||
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
vasprintf(&outputStr, fmt, args);
|
||||
va_end(args);
|
||||
|
||||
std::string output = std::string(outputStr);
|
||||
free(outputStr);
|
||||
|
||||
ofs << output << "\n";
|
||||
|
||||
ofs.close();
|
||||
|
||||
// log it to the stdout too.
|
||||
if (!disableStdout)
|
||||
std::cout << output << "\n";
|
||||
}
|
||||
|
@@ -1,26 +1,82 @@
|
||||
#pragma once
|
||||
#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
|
||||
|
||||
enum LogLevel
|
||||
{
|
||||
enum LogLevel {
|
||||
NONE = -1,
|
||||
LOG = 0,
|
||||
WARN,
|
||||
ERR,
|
||||
CRIT,
|
||||
INFO
|
||||
INFO,
|
||||
TRACE
|
||||
};
|
||||
|
||||
namespace Debug {
|
||||
void init(const 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 int64_t* disableLogs = nullptr;
|
||||
inline int64_t* disableTime = nullptr;
|
||||
inline bool disableStdout = false;
|
||||
};
|
||||
inline bool trace = false;
|
||||
|
||||
void init(const std::string& IS);
|
||||
template <typename... Args>
|
||||
void log(LogLevel level, std::format_string<Args...> fmt, Args&&... args) {
|
||||
if (disableLogs && *disableLogs)
|
||||
return;
|
||||
|
||||
if (level == TRACE && !trace)
|
||||
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;
|
||||
}
|
||||
|
||||
// log to a file
|
||||
std::ofstream ofs;
|
||||
ofs.open(logFile, std::ios::out | std::ios::app);
|
||||
|
||||
// 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...));
|
||||
|
||||
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);
|
||||
};
|
||||
|
35
src/debug/TracyDefines.hpp
Normal file
35
src/debug/TracyDefines.hpp
Normal file
@@ -0,0 +1,35 @@
|
||||
#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"
|
||||
|
||||
inline void loadGLProc(void* pProc, const char* name) {
|
||||
void* proc = (void*)eglGetProcAddress(name);
|
||||
if (proc == NULL) {
|
||||
Debug::log(CRIT, "[Tracy GPU Profiling] eglGetProcAddress({}) failed", name);
|
||||
abort();
|
||||
}
|
||||
*(void**)pProc = proc;
|
||||
}
|
||||
|
||||
#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,92 +1,5 @@
|
||||
#include "includes.hpp"
|
||||
#include "debug/Log.hpp"
|
||||
#include "helpers/MiscFunctions.hpp"
|
||||
#include "helpers/WLListener.hpp"
|
||||
#include "helpers/Color.hpp"
|
||||
|
||||
#include "wlrunstable/wlr_ext_workspace_v1.hpp"
|
||||
|
||||
#include <utility>
|
||||
|
||||
#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 PIXMAN_REGION_FOREACH(region) PIXMAN_DAMAGE_FOREACH(region)
|
||||
|
||||
#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_START (-99)
|
||||
|
||||
#define PI 3.14159265358979
|
||||
#include "macros.hpp"
|
||||
|
@@ -19,7 +19,7 @@ void Events::listener_keyboardDestroy(void* owner, void* data) {
|
||||
SKeyboard* PKEYBOARD = (SKeyboard*)owner;
|
||||
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) {
|
||||
@@ -63,30 +63,30 @@ void Events::listener_newInput(wl_listener* listener, void* data) {
|
||||
|
||||
switch (DEVICE->type) {
|
||||
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);
|
||||
break;
|
||||
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);
|
||||
break;
|
||||
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);
|
||||
break;
|
||||
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);
|
||||
break;
|
||||
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);
|
||||
break;
|
||||
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);
|
||||
break;
|
||||
default: Debug::log(WARN, "Unrecognized input device plugged in: %s", DEVICE->name); break;
|
||||
default: Debug::log(WARN, "Unrecognized input device plugged in: {}", DEVICE->name); break;
|
||||
}
|
||||
|
||||
g_pInputManager->updateCapabilities();
|
||||
@@ -95,7 +95,7 @@ void Events::listener_newInput(wl_listener* listener, void* data) {
|
||||
void Events::listener_newConstraint(wl_listener* listener, void* 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();
|
||||
const auto CONSTRAINT = &g_pInputManager->m_lConstraints.back();
|
||||
@@ -122,24 +122,13 @@ void Events::listener_destroyConstraint(void* owner, void* data) {
|
||||
|
||||
const auto PWINDOW = g_pCompositor->getConstraintWindow(g_pCompositor->m_sSeat.mouse);
|
||||
|
||||
if (PWINDOW && PCONSTRAINT->positionHint != Vector2D{-1, -1}) {
|
||||
if (PWINDOW->m_bIsX11) {
|
||||
wlr_cursor_warp(g_pCompositor->m_sWLRCursor, nullptr, PCONSTRAINT->positionHint.x + PWINDOW->m_uSurface.xwayland->x,
|
||||
PWINDOW->m_uSurface.xwayland->y + PCONSTRAINT->positionHint.y);
|
||||
|
||||
wlr_seat_pointer_warp(PCONSTRAINT->constraint->seat, PCONSTRAINT->positionHint.x, PCONSTRAINT->positionHint.y);
|
||||
} else {
|
||||
wlr_cursor_warp(g_pCompositor->m_sWLRCursor, nullptr, PCONSTRAINT->positionHint.x + PWINDOW->m_vRealPosition.vec().x,
|
||||
PCONSTRAINT->positionHint.y + PWINDOW->m_vRealPosition.vec().y);
|
||||
|
||||
wlr_seat_pointer_warp(PCONSTRAINT->constraint->seat, PCONSTRAINT->positionHint.x, PCONSTRAINT->positionHint.y);
|
||||
}
|
||||
}
|
||||
if (PWINDOW && PCONSTRAINT->active && PCONSTRAINT->constraint->type == WLR_POINTER_CONSTRAINT_V1_LOCKED)
|
||||
g_pInputManager->warpMouseToConstraintMiddle(PCONSTRAINT);
|
||||
|
||||
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);
|
||||
}
|
||||
|
@@ -39,6 +39,7 @@ namespace Events {
|
||||
DYNLISTENFUNC(destroyPopupXDG);
|
||||
DYNLISTENFUNC(commitPopupXDG);
|
||||
DYNLISTENFUNC(newPopupFromPopupXDG);
|
||||
DYNLISTENFUNC(repositionPopupXDG);
|
||||
|
||||
// Surface XDG (window)
|
||||
LISTENER(newXDGSurface);
|
||||
@@ -59,6 +60,9 @@ namespace Events {
|
||||
DYNLISTENFUNC(requestMinimize);
|
||||
DYNLISTENFUNC(requestMaximize);
|
||||
DYNLISTENFUNC(setOverrideRedirect);
|
||||
DYNLISTENFUNC(associateX11);
|
||||
DYNLISTENFUNC(dissociateX11);
|
||||
DYNLISTENFUNC(ackConfigure);
|
||||
|
||||
// Window subsurfaces
|
||||
// LISTENER(newSubsurfaceWindow);
|
||||
@@ -100,6 +104,8 @@ namespace Events {
|
||||
DYNLISTENFUNC(monitorStateRequest);
|
||||
DYNLISTENFUNC(monitorDamage);
|
||||
DYNLISTENFUNC(monitorNeedsFrame);
|
||||
DYNLISTENFUNC(monitorCommit);
|
||||
DYNLISTENFUNC(monitorBind);
|
||||
|
||||
// XWayland
|
||||
LISTENER(readyXWayland);
|
||||
@@ -163,4 +169,13 @@ namespace Events {
|
||||
|
||||
// Session Lock
|
||||
LISTENER(newSessionLock);
|
||||
|
||||
// Gamma control
|
||||
LISTENER(setGamma);
|
||||
|
||||
// Cursor shape
|
||||
LISTENER(setCursorShape);
|
||||
|
||||
// Tearing hints
|
||||
LISTENER(newTearingHint);
|
||||
};
|
||||
|
@@ -26,7 +26,7 @@ void Events::listener_newLayerSurface(wl_listener* listener, void* data) {
|
||||
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;
|
||||
}
|
||||
@@ -44,8 +44,8 @@ void Events::listener_newLayerSurface(wl_listener* listener, void* data) {
|
||||
|
||||
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_mapLayerSurface.initCallback(&WLRLAYERSURFACE->events.map, &Events::listener_mapLayerSurface, layerSurface, "layerSurface");
|
||||
layerSurface->hyprListener_unmapLayerSurface.initCallback(&WLRLAYERSURFACE->events.unmap, &Events::listener_unmapLayerSurface, layerSurface, "layerSurface");
|
||||
layerSurface->hyprListener_mapLayerSurface.initCallback(&WLRLAYERSURFACE->surface->events.map, &Events::listener_mapLayerSurface, 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->layerSurface = WLRLAYERSURFACE;
|
||||
@@ -55,14 +55,14 @@ void Events::listener_newLayerSurface(wl_listener* listener, void* data) {
|
||||
|
||||
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) {
|
||||
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);
|
||||
|
||||
@@ -95,8 +95,8 @@ void Events::listener_destroyLayerSurface(void* owner, void* data) {
|
||||
PMONITOR->scheduledRecalc = true;
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
@@ -107,12 +107,11 @@ void Events::listener_destroyLayerSurface(void* owner, void* data) {
|
||||
void Events::listener_mapLayerSurface(void* owner, void* data) {
|
||||
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->surface = layersurface->layerSurface->surface;
|
||||
layersurface->mapped = true;
|
||||
layersurface->keyboardExclusive = layersurface->layerSurface->current.keyboard_interactive;
|
||||
layersurface->surface = layersurface->layerSurface->surface;
|
||||
|
||||
// anim
|
||||
layersurface->alpha.setConfig(g_pConfigManager->getAnimationPropertyConfig("fadeIn"));
|
||||
@@ -143,8 +142,11 @@ void Events::listener_mapLayerSurface(void* owner, void* data) {
|
||||
|
||||
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);
|
||||
|
||||
const auto LOCAL =
|
||||
@@ -155,25 +157,28 @@ void Events::listener_mapLayerSurface(void* owner, void* data) {
|
||||
|
||||
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);
|
||||
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 = 1.f;
|
||||
layersurface->alpha = ((layersurface->layer == ZWLR_LAYER_SHELL_V1_LAYER_TOP && FULLSCREEN && !GRABSFOCUS) ? 0.f : 1.f);
|
||||
layersurface->readyToDelete = false;
|
||||
layersurface->fadingOut = false;
|
||||
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{"openlayer", std::string(layersurface->layerSurface->_namespace ? layersurface->layerSurface->_namespace : "")});
|
||||
EMIT_HOOK_EVENT("openLayer", layersurface);
|
||||
|
||||
g_pProtocolManager->m_pFractionalScaleProtocolManager->setPreferredScaleForSurface(layersurface->layerSurface->surface, PMONITOR->scale);
|
||||
g_pCompositor->setPreferredScaleForSurface(layersurface->layerSurface->surface, PMONITOR->scale);
|
||||
g_pCompositor->setPreferredTransformForSurface(layersurface->layerSurface->surface, PMONITOR->transform);
|
||||
}
|
||||
|
||||
void Events::listener_unmapLayerSurface(void* owner, void* data) {
|
||||
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 : "")});
|
||||
EMIT_HOOK_EVENT("closeLayer", layersurface);
|
||||
@@ -204,9 +209,6 @@ void Events::listener_unmapLayerSurface(void* owner, void* data) {
|
||||
|
||||
g_pCompositor->addToFadingOutSafe(layersurface);
|
||||
|
||||
if (layersurface->layerSurface->mapped)
|
||||
layersurface->layerSurface->mapped = false;
|
||||
|
||||
const auto PMONITOR = g_pCompositor->getMonitorFromOutput(layersurface->layerSurface->output);
|
||||
|
||||
const bool WASLASTFOCUS = g_pCompositor->m_pLastFocus == layersurface->layerSurface->surface;
|
||||
@@ -245,8 +247,8 @@ 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);
|
||||
|
||||
geomFixed = {layersurface->geometry.x + (int)PMONITOR->vecPosition.x, layersurface->geometry.y + (int)PMONITOR->vecPosition.y,
|
||||
@@ -268,7 +270,7 @@ void Events::listener_commitLayerSurface(void* owner, void* data) {
|
||||
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
|
||||
|
||||
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);
|
||||
|
||||
// fix if it changed its mon
|
||||
@@ -323,7 +325,24 @@ void Events::listener_commitLayerSurface(void* owner, void* data) {
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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_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_pProtocolManager->m_pFractionalScaleProtocolManager->setPreferredScaleForSurface(layersurface->layerSurface->surface, PMONITOR->scale);
|
||||
g_pCompositor->setPreferredScaleForSurface(layersurface->layerSurface->surface, PMONITOR->scale);
|
||||
g_pCompositor->setPreferredTransformForSurface(layersurface->layerSurface->surface, PMONITOR->transform);
|
||||
}
|
||||
|
@@ -49,7 +49,7 @@ void Events::listener_readyXWayland(wl_listener* listener, void* data) {
|
||||
const auto XCBCONNECTION = xcb_connect(g_pXWaylandManager->m_sWLRXWayland->display_name, NULL);
|
||||
const auto ERR = xcb_connection_has_error(XCBCONNECTION);
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ void Events::listener_readyXWayland(wl_listener* listener, void* data) {
|
||||
xcb_intern_atom_reply_t* reply = xcb_intern_atom_reply(XCBCONNECTION, cookie, NULL);
|
||||
|
||||
if (!reply) {
|
||||
Debug::log(LogLevel::ERR, "XWayland -> Atom failed: %s", ATOM.first.c_str());
|
||||
Debug::log(LogLevel::ERR, "XWayland -> Atom failed: {}", ATOM.first);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -98,20 +98,20 @@ void Events::listener_startDrag(wl_listener* listener, void* 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;
|
||||
|
||||
g_pInputManager->m_sDrag.hyprListener_destroy.initCallback(&wlrDrag->events.destroy, &Events::listener_destroyDrag, &g_pInputManager->m_sDrag, "Drag");
|
||||
|
||||
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;
|
||||
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_unmapIcon.initCallback(&wlrDrag->icon->events.unmap, &Events::listener_unmapDragIcon, &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->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_commitIcon.initCallback(&wlrDrag->icon->surface->events.commit, &Events::listener_commitDragIcon, &g_pInputManager->m_sDrag,
|
||||
"DragIcon");
|
||||
@@ -157,7 +157,7 @@ void Events::listener_commitDragIcon(void* owner, void* data) {
|
||||
}
|
||||
|
||||
void Events::listener_InhibitActivate(wl_listener* listener, void* data) {
|
||||
Debug::log(LOG, "Activated exclusive for %x.", g_pCompositor->m_sSeat.exclusiveClient);
|
||||
Debug::log(LOG, "Activated exclusive for {:x}.", (uintptr_t)g_pCompositor->m_sSeat.exclusiveClient);
|
||||
|
||||
g_pInputManager->refocus();
|
||||
g_pCompositor->m_sSeat.exclusiveClient = g_pCompositor->m_sWLRInhibitMgr->active_client;
|
||||
@@ -214,3 +214,66 @@ void Events::listener_newSessionLock(wl_listener* listener, void* data) {
|
||||
|
||||
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");
|
||||
}
|
||||
|
@@ -19,15 +19,18 @@ void Events::listener_change(wl_listener* listener, void* data) {
|
||||
// layout got changed, let's update monitors.
|
||||
const auto CONFIG = wlr_output_configuration_v1_create();
|
||||
|
||||
if (!CONFIG)
|
||||
return;
|
||||
|
||||
for (auto& m : g_pCompositor->m_vMonitors) {
|
||||
if (!m->output)
|
||||
continue;
|
||||
|
||||
const auto CONFIGHEAD = wlr_output_configuration_head_v1_create(CONFIG, m->output);
|
||||
|
||||
// TODO: clients off of disabled
|
||||
wlr_box BOX;
|
||||
wlr_output_layout_get_box(g_pCompositor->m_sWLROutputLayout, m->output, &BOX);
|
||||
CBox BOX;
|
||||
wlr_output_layout_get_box(g_pCompositor->m_sWLROutputLayout, m->output, BOX.pWlr());
|
||||
BOX.applyFromWlr();
|
||||
|
||||
//m->vecSize.x = BOX.width;
|
||||
// m->vecSize.y = BOX.height;
|
||||
@@ -36,8 +39,18 @@ void Events::listener_change(wl_listener* listener, void* data) {
|
||||
|
||||
CONFIGHEAD->state.enabled = m->output->enabled;
|
||||
CONFIGHEAD->state.mode = m->output->current_mode;
|
||||
CONFIGHEAD->state.x = m->vecPosition.x;
|
||||
CONFIGHEAD->state.y = m->vecPosition.y;
|
||||
if (!m->output->current_mode) {
|
||||
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);
|
||||
@@ -55,50 +68,38 @@ void Events::listener_newOutput(wl_listener* listener, void* data) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (g_pCompositor->m_bUnsafeState) {
|
||||
Debug::log(WARN, "Recovering from an unsafe state. May you be lucky.");
|
||||
}
|
||||
|
||||
// add it to real
|
||||
std::shared_ptr<CMonitor>* PNEWMONITORWRAP = nullptr;
|
||||
|
||||
for (auto& rm : g_pCompositor->m_vRealMonitors) {
|
||||
if (rm->szName == OUTPUT->name) {
|
||||
PNEWMONITORWRAP = &rm;
|
||||
Debug::log(LOG, "Recovering a removed monitor.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
PNEWMONITORWRAP = &g_pCompositor->m_vRealMonitors.emplace_back(std::make_shared<CMonitor>());
|
||||
if (std::string("HEADLESS-1") == OUTPUT->name)
|
||||
g_pCompositor->m_pUnsafeOutput = PNEWMONITORWRAP->get();
|
||||
|
||||
if (!PNEWMONITORWRAP) {
|
||||
Debug::log(LOG, "Adding completely new monitor.");
|
||||
PNEWMONITORWRAP = &g_pCompositor->m_vRealMonitors.emplace_back(std::make_shared<CMonitor>());
|
||||
(*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;
|
||||
|
||||
(*PNEWMONITORWRAP)->ID = g_pCompositor->getNextAvailableMonitorID();
|
||||
}
|
||||
if (!FALLBACK)
|
||||
PNEWMONITOR->onConnect(false);
|
||||
|
||||
const auto PNEWMONITOR = PNEWMONITORWRAP->get();
|
||||
if (!PNEWMONITOR->m_bEnabled || FALLBACK)
|
||||
return;
|
||||
|
||||
PNEWMONITOR->output = OUTPUT;
|
||||
PNEWMONITOR->m_pThisWrap = PNEWMONITORWRAP;
|
||||
|
||||
PNEWMONITOR->onConnect(false);
|
||||
// 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;
|
||||
|
||||
// ready to process cuz we have a monitor
|
||||
if (PNEWMONITOR->m_bEnabled) {
|
||||
g_pCompositor->m_bReadyToProcess = true;
|
||||
g_pCompositor->m_bUnsafeState = false;
|
||||
}
|
||||
g_pCompositor->m_bReadyToProcess = true;
|
||||
|
||||
g_pConfigManager->m_bWantsMonitorReload = true;
|
||||
g_pCompositor->scheduleFrameForMonitor(PNEWMONITOR);
|
||||
|
||||
if (firstLaunch) {
|
||||
firstLaunch = false;
|
||||
const auto POS = PNEWMONITOR->vecPosition + PNEWMONITOR->vecSize / 2.f;
|
||||
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 {
|
||||
@@ -117,8 +118,12 @@ 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) {
|
||||
Debug::log(WARN, "Attempted to render frame on inactive session!");
|
||||
|
||||
if (g_pCompositor->m_bUnsafeState)
|
||||
g_pConfigManager->performMonitorReload();
|
||||
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)
|
||||
}
|
||||
@@ -126,12 +131,25 @@ void Events::listener_monitorFrame(void* owner, void* data) {
|
||||
if (!PMONITOR->m_bEnabled)
|
||||
return;
|
||||
|
||||
g_pHyprRenderer->recheckSolitaryForMonitor(PMONITOR);
|
||||
|
||||
PMONITOR->tearingState.busy = false;
|
||||
|
||||
if (PMONITOR->tearingState.activelyTearing && PMONITOR->solitaryClient /* can be invalidated by a recheck */) {
|
||||
|
||||
if (!PMONITOR->tearingState.frameScheduledWhileBusy)
|
||||
return; // we did not schedule a frame yet to be displayed, but we are tearing. Why render?
|
||||
|
||||
PMONITOR->tearingState.nextRenderTorn = true;
|
||||
PMONITOR->tearingState.frameScheduledWhileBusy = false;
|
||||
}
|
||||
|
||||
static auto* const PENABLERAT = &g_pConfigManager->getConfigValuePtr("misc:render_ahead_of_time")->intValue;
|
||||
static auto* const PRATSAFE = &g_pConfigManager->getConfigValuePtr("misc:render_ahead_safezone")->intValue;
|
||||
|
||||
PMONITOR->lastPresentationTimer.reset();
|
||||
|
||||
if (*PENABLERAT) {
|
||||
if (*PENABLERAT && !PMONITOR->tearingState.nextRenderTorn) {
|
||||
if (!PMONITOR->RATScheduled) {
|
||||
// render
|
||||
g_pHyprRenderer->renderMonitor(PMONITOR);
|
||||
@@ -175,19 +193,16 @@ void Events::listener_monitorDestroy(void* owner, void* data) {
|
||||
if (!pMonitor)
|
||||
return;
|
||||
|
||||
Debug::log(LOG, "Destroy called for monitor %s", pMonitor->output->name);
|
||||
Debug::log(LOG, "Destroy called for monitor {}", pMonitor->output->name);
|
||||
|
||||
pMonitor->onDisconnect();
|
||||
|
||||
pMonitor->output = nullptr;
|
||||
pMonitor->m_bRenderingInitPassed = false;
|
||||
|
||||
// cleanup if not unsafe
|
||||
if (!g_pCompositor->m_bUnsafeState) {
|
||||
Debug::log(LOG, "Removing monitor %s from realMonitors", pMonitor->szName.c_str());
|
||||
Debug::log(LOG, "Removing monitor {} from realMonitors", pMonitor->szName);
|
||||
|
||||
std::erase_if(g_pCompositor->m_vRealMonitors, [&](std::shared_ptr<CMonitor>& el) { return el.get() == pMonitor; });
|
||||
}
|
||||
std::erase_if(g_pCompositor->m_vRealMonitors, [&](std::shared_ptr<CMonitor>& el) { return el.get() == pMonitor; });
|
||||
}
|
||||
|
||||
void Events::listener_monitorStateRequest(void* owner, void* data) {
|
||||
@@ -209,3 +224,18 @@ void Events::listener_monitorNeedsFrame(void* owner, void* data) {
|
||||
|
||||
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) {
|
||||
;
|
||||
}
|
||||
|
@@ -56,21 +56,21 @@ void createNewPopup(wlr_xdg_popup* popup, SXDGPopup* pHyprPopup) {
|
||||
pHyprPopup->popup = popup;
|
||||
|
||||
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_unmapPopupXDG.initCallback(&popup->base->events.unmap, &Events::listener_unmapPopupXDG, pHyprPopup, "HyprPopup");
|
||||
pHyprPopup->hyprListener_mapPopupXDG.initCallback(&popup->base->surface->events.map, &Events::listener_mapPopupXDG, 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_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;
|
||||
|
||||
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;
|
||||
|
||||
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) {
|
||||
@@ -78,7 +78,7 @@ void Events::listener_newPopup(void* owner, void* data) {
|
||||
|
||||
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;
|
||||
|
||||
@@ -102,7 +102,7 @@ void Events::listener_newPopupXDG(void* owner, void* data) {
|
||||
if (!PWINDOW->m_bIsMapped)
|
||||
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;
|
||||
|
||||
@@ -124,9 +124,9 @@ void Events::listener_newPopupFromPopupXDG(void* owner, void* data) {
|
||||
ASSERT(PPOPUP);
|
||||
|
||||
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
|
||||
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;
|
||||
|
||||
@@ -147,7 +147,7 @@ void Events::listener_mapPopupXDG(void* owner, void* data) {
|
||||
|
||||
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);
|
||||
@@ -159,12 +159,40 @@ void Events::listener_mapPopupXDG(void* owner, void* data) {
|
||||
int lx = 0, ly = 0;
|
||||
addPopupGlobalCoords(PPOPUP, &lx, &ly);
|
||||
|
||||
wlr_box extents;
|
||||
wlr_surface_get_extends(PPOPUP->popup->base->surface, &extents);
|
||||
CBox 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);
|
||||
|
||||
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) {
|
||||
@@ -181,8 +209,9 @@ void Events::listener_unmapPopupXDG(void* owner, void* data) {
|
||||
int lx = 0, ly = 0;
|
||||
addPopupGlobalCoords(PPOPUP, &lx, &ly);
|
||||
|
||||
wlr_box extents;
|
||||
wlr_surface_get_extends(PPOPUP->popup->base->surface, &extents);
|
||||
CBox 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);
|
||||
|
||||
@@ -199,9 +228,23 @@ void Events::listener_unmapPopupXDG(void* owner, void* data) {
|
||||
void Events::listener_commitPopupXDG(void* owner, void* data) {
|
||||
SXDGPopup* PPOPUP = (SXDGPopup*)owner;
|
||||
|
||||
int lx = 0, ly = 0;
|
||||
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;
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -210,7 +253,7 @@ void Events::listener_destroyPopupXDG(void* owner, void* data) {
|
||||
|
||||
ASSERT(PPOPUP);
|
||||
|
||||
Debug::log(LOG, "Destroyed popup XDG %x", PPOPUP);
|
||||
Debug::log(LOG, "Destroyed popup XDG {:x}", (uintptr_t)PPOPUP);
|
||||
|
||||
if (PPOPUP->pSurfaceTree) {
|
||||
SubsurfaceTree::destroySurfaceTree(PPOPUP->pSurfaceTree);
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -41,8 +41,8 @@ void CAnimatedVariable::create(ANIMATEDVARTYPE type, std::any val, SAnimationPro
|
||||
default: ASSERT(false); break;
|
||||
}
|
||||
} catch (std::exception& e) {
|
||||
Debug::log(ERR, "CAnimatedVariable create error: %s", e.what());
|
||||
RASSERT(false, "CAnimatedVariable create error: %s", e.what());
|
||||
Debug::log(ERR, "CAnimatedVariable create error: {}", e.what());
|
||||
RASSERT(false, "CAnimatedVariable create error: {}", e.what());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,13 +51,16 @@ CAnimatedVariable::~CAnimatedVariable() {
|
||||
}
|
||||
|
||||
void CAnimatedVariable::unregister() {
|
||||
g_pAnimationManager->m_lAnimatedVariables.remove(this);
|
||||
if (!g_pAnimationManager)
|
||||
return;
|
||||
std::erase_if(g_pAnimationManager->m_vAnimatedVariables, [&](const auto& other) { return other == this; });
|
||||
m_bIsRegistered = false;
|
||||
disconnectFromActive();
|
||||
}
|
||||
|
||||
void CAnimatedVariable::registerVar() {
|
||||
if (!m_bIsRegistered)
|
||||
g_pAnimationManager->m_lAnimatedVariables.push_back(this);
|
||||
g_pAnimationManager->m_vAnimatedVariables.push_back(this);
|
||||
m_bIsRegistered = true;
|
||||
}
|
||||
|
||||
@@ -78,4 +81,18 @@ float CAnimatedVariable::getCurveValue() {
|
||||
return 1.f;
|
||||
|
||||
return g_pAnimationManager->getBezier(m_pConfig->pValues->internalBezier)->getYForPoint(SPENT);
|
||||
}
|
||||
|
||||
void CAnimatedVariable::connectToActive() {
|
||||
g_pAnimationManager->scheduleTick(); // otherwise the animation manager will never pick this up
|
||||
|
||||
if (!m_bIsConnectedToActive)
|
||||
g_pAnimationManager->m_vActiveAnimatedVariables.push_back(this);
|
||||
|
||||
m_bIsConnectedToActive = true;
|
||||
}
|
||||
|
||||
void CAnimatedVariable::disconnectFromActive() {
|
||||
std::erase_if(g_pAnimationManager->m_vActiveAnimatedVariables, [&](const auto& other) { return other == this; });
|
||||
m_bIsConnectedToActive = false;
|
||||
}
|
@@ -1,16 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
#include "../defines.hpp"
|
||||
#include <functional>
|
||||
#include <any>
|
||||
#include <chrono>
|
||||
#include "Vector2D.hpp"
|
||||
#include "Color.hpp"
|
||||
#include "../macros.hpp"
|
||||
#include "../debug/Log.hpp"
|
||||
|
||||
enum ANIMATEDVARTYPE {
|
||||
enum ANIMATEDVARTYPE
|
||||
{
|
||||
AVARTYPE_INVALID = -1,
|
||||
AVARTYPE_FLOAT,
|
||||
AVARTYPE_VECTOR,
|
||||
AVARTYPE_COLOR
|
||||
};
|
||||
|
||||
enum AVARDAMAGEPOLICY {
|
||||
enum AVARDAMAGEPOLICY
|
||||
{
|
||||
AVARDAMAGE_NONE = -1,
|
||||
AVARDAMAGE_ENTIRE = 0,
|
||||
AVARDAMAGE_BORDER,
|
||||
@@ -30,6 +37,11 @@ class CAnimatedVariable {
|
||||
void create(ANIMATEDVARTYPE, SAnimationPropertyConfig*, void* pWindow, AVARDAMAGEPOLICY);
|
||||
void create(ANIMATEDVARTYPE, std::any val, SAnimationPropertyConfig*, void* pWindow, AVARDAMAGEPOLICY);
|
||||
|
||||
CAnimatedVariable(const CAnimatedVariable&) = delete;
|
||||
CAnimatedVariable(CAnimatedVariable&&) = delete;
|
||||
CAnimatedVariable& operator=(const CAnimatedVariable&) = delete;
|
||||
CAnimatedVariable& operator=(CAnimatedVariable&&) = delete;
|
||||
|
||||
~CAnimatedVariable();
|
||||
|
||||
void unregister();
|
||||
@@ -66,6 +78,9 @@ class CAnimatedVariable {
|
||||
}
|
||||
|
||||
CAnimatedVariable& operator=(const Vector2D& v) {
|
||||
if (v == m_vGoal)
|
||||
return *this;
|
||||
|
||||
m_vGoal = v;
|
||||
animationBegin = std::chrono::system_clock::now();
|
||||
m_vBegun = m_vValue;
|
||||
@@ -76,6 +91,9 @@ class CAnimatedVariable {
|
||||
}
|
||||
|
||||
CAnimatedVariable& operator=(const float& v) {
|
||||
if (v == m_fGoal)
|
||||
return *this;
|
||||
|
||||
m_fGoal = v;
|
||||
animationBegin = std::chrono::system_clock::now();
|
||||
m_fBegun = m_fValue;
|
||||
@@ -86,6 +104,9 @@ class CAnimatedVariable {
|
||||
}
|
||||
|
||||
CAnimatedVariable& operator=(const CColor& v) {
|
||||
if (v == m_cGoal)
|
||||
return *this;
|
||||
|
||||
m_cGoal = v;
|
||||
animationBegin = std::chrono::system_clock::now();
|
||||
m_cBegun = m_cValue;
|
||||
@@ -97,6 +118,9 @@ class CAnimatedVariable {
|
||||
|
||||
// Sets the actual stored value, without affecting the goal, but resets the timer
|
||||
void setValue(const Vector2D& v) {
|
||||
if (v == m_vValue)
|
||||
return;
|
||||
|
||||
m_vValue = v;
|
||||
animationBegin = std::chrono::system_clock::now();
|
||||
m_vBegun = m_vValue;
|
||||
@@ -106,6 +130,9 @@ class CAnimatedVariable {
|
||||
|
||||
// Sets the actual stored value, without affecting the goal, but resets the timer
|
||||
void setValue(const float& v) {
|
||||
if (v == m_fValue)
|
||||
return;
|
||||
|
||||
m_fValue = v;
|
||||
animationBegin = std::chrono::system_clock::now();
|
||||
m_vBegun = m_vValue;
|
||||
@@ -115,6 +142,9 @@ class CAnimatedVariable {
|
||||
|
||||
// Sets the actual stored value, without affecting the goal, but resets the timer
|
||||
void setValue(const CColor& v) {
|
||||
if (v == m_cValue)
|
||||
return;
|
||||
|
||||
m_cValue = v;
|
||||
animationBegin = std::chrono::system_clock::now();
|
||||
m_vBegun = m_vValue;
|
||||
@@ -141,17 +171,8 @@ class CAnimatedVariable {
|
||||
}
|
||||
|
||||
// checks if an animation is in progress
|
||||
bool isBeingAnimated() {
|
||||
switch (m_eVarType) {
|
||||
case AVARTYPE_FLOAT: return m_fValue != m_fGoal;
|
||||
case AVARTYPE_VECTOR: return m_vValue != m_vGoal;
|
||||
case AVARTYPE_COLOR: return m_cValue != m_cGoal;
|
||||
default: UNREACHABLE();
|
||||
}
|
||||
|
||||
UNREACHABLE();
|
||||
|
||||
return false; // just so that the warning is suppressed
|
||||
inline bool isBeingAnimated() {
|
||||
return m_bIsBeingAnimated;
|
||||
}
|
||||
|
||||
void warp(bool endCallback = true) {
|
||||
@@ -171,6 +192,8 @@ class CAnimatedVariable {
|
||||
default: UNREACHABLE();
|
||||
}
|
||||
|
||||
m_bIsBeingAnimated = false;
|
||||
|
||||
if (endCallback)
|
||||
onAnimationEnd();
|
||||
}
|
||||
@@ -209,10 +232,17 @@ class CAnimatedVariable {
|
||||
m_bRemoveBeginAfterRan = remove;
|
||||
}
|
||||
|
||||
/* Sets the update callback, called every time the value is animated and a step is done
|
||||
Warning: calling unregisterVar/registerVar in this handler will cause UB */
|
||||
void setUpdateCallback(std::function<void(void* thisptr)> func) {
|
||||
m_fUpdateCallback = func;
|
||||
}
|
||||
|
||||
/* resets all callbacks. Does not call any. */
|
||||
void resetAllCallbacks() {
|
||||
m_fBeginCallback = nullptr;
|
||||
m_fEndCallback = nullptr;
|
||||
m_fUpdateCallback = nullptr;
|
||||
m_bRemoveBeginAfterRan = false;
|
||||
m_bRemoveEndAfterRan = false;
|
||||
}
|
||||
@@ -237,8 +267,9 @@ class CAnimatedVariable {
|
||||
|
||||
SAnimationPropertyConfig* m_pConfig = nullptr;
|
||||
|
||||
bool m_bDummy = true;
|
||||
bool m_bIsRegistered = false;
|
||||
bool m_bDummy = true;
|
||||
bool m_bIsRegistered = false;
|
||||
bool m_bIsBeingAnimated = false;
|
||||
|
||||
std::chrono::system_clock::time_point animationBegin;
|
||||
|
||||
@@ -249,17 +280,30 @@ class CAnimatedVariable {
|
||||
bool m_bRemoveBeginAfterRan = true;
|
||||
std::function<void(void* thisptr)> m_fEndCallback;
|
||||
std::function<void(void* thisptr)> m_fBeginCallback;
|
||||
std::function<void(void* thisptr)> m_fUpdateCallback;
|
||||
|
||||
bool m_bIsConnectedToActive = false;
|
||||
void connectToActive();
|
||||
void disconnectFromActive();
|
||||
|
||||
// methods
|
||||
void onAnimationEnd() {
|
||||
m_bIsBeingAnimated = false;
|
||||
disconnectFromActive();
|
||||
|
||||
if (m_fEndCallback) {
|
||||
// loading m_bRemoveEndAfterRan before calling the callback allows the callback to delete this animation safely if it is false.
|
||||
auto removeEndCallback = m_bRemoveEndAfterRan;
|
||||
m_fEndCallback(this);
|
||||
if (m_bRemoveEndAfterRan)
|
||||
if (removeEndCallback)
|
||||
m_fEndCallback = nullptr; // reset
|
||||
}
|
||||
}
|
||||
|
||||
void onAnimationBegin() {
|
||||
m_bIsBeingAnimated = true;
|
||||
connectToActive();
|
||||
|
||||
if (m_fBeginCallback) {
|
||||
m_fBeginCallback(this);
|
||||
if (m_bRemoveBeginAfterRan)
|
||||
|
@@ -1,5 +1,8 @@
|
||||
#include "BezierCurve.hpp"
|
||||
#include "../debug/Log.hpp"
|
||||
#include "../macros.hpp"
|
||||
|
||||
#include <chrono>
|
||||
#include <algorithm>
|
||||
|
||||
void CBezierCurve::setup(std::vector<Vector2D>* pVec) {
|
||||
@@ -15,7 +18,7 @@ void CBezierCurve::setup(std::vector<Vector2D>* pVec) {
|
||||
|
||||
m_dPoints.emplace_back(Vector2D(1, 1));
|
||||
|
||||
RASSERT(m_dPoints.size() == 4, "CBezierCurve only supports cubic beziers! (points num: %i)", m_dPoints.size());
|
||||
RASSERT(m_dPoints.size() == 4, "CBezierCurve only supports cubic beziers! (points num: {})", m_dPoints.size());
|
||||
|
||||
// bake BAKEDPOINTS points for faster lookups
|
||||
// T -> X ( / BAKEDPOINTS )
|
||||
@@ -31,8 +34,8 @@ void CBezierCurve::setup(std::vector<Vector2D>* pVec) {
|
||||
getYForPoint(i);
|
||||
const auto ELAPSEDCALCAVG = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::now() - BEGINCALC).count() / 1000.f / 10.f;
|
||||
|
||||
Debug::log(LOG, "Created a bezier curve, baked %i points, mem usage: %.2fkB, time to bake: %.2fµs. Estimated average calc time: %.2fµs.", BAKEDPOINTS, POINTSSIZE, ELAPSEDUS,
|
||||
ELAPSEDCALCAVG);
|
||||
Debug::log(LOG, "Created a bezier curve, baked {} points, mem usage: {:.2f}kB, time to bake: {:.2f}µs. Estimated average calc time: {:.2f}µs.", BAKEDPOINTS, POINTSSIZE,
|
||||
ELAPSEDUS, ELAPSEDCALCAVG);
|
||||
}
|
||||
|
||||
float CBezierCurve::getYForT(float t) {
|
||||
@@ -45,27 +48,25 @@ float CBezierCurve::getXForT(float t) {
|
||||
|
||||
// Todo: this probably can be done better and faster
|
||||
float CBezierCurve::getYForPoint(float x) {
|
||||
if (x >= 1.0)
|
||||
return 1.0;
|
||||
if (x >= 1.f)
|
||||
return 1.f;
|
||||
|
||||
// binary search for the range UPDOWN X
|
||||
int upperT = BAKEDPOINTS - 1;
|
||||
int lowerT = 0;
|
||||
int mid = upperT / 2;
|
||||
int index = 0;
|
||||
bool below = true;
|
||||
for (int step = (BAKEDPOINTS + 1) / 2; step > 0; step /= 2) {
|
||||
if (below)
|
||||
index += step;
|
||||
else
|
||||
index -= step;
|
||||
|
||||
while (std::abs(upperT - lowerT) > 1) {
|
||||
if (m_aPointsBaked[mid].x > x) {
|
||||
upperT = mid;
|
||||
} else {
|
||||
lowerT = mid;
|
||||
}
|
||||
|
||||
mid = (upperT + lowerT) / 2;
|
||||
below = m_aPointsBaked[index].x < x;
|
||||
}
|
||||
|
||||
int lowerIndex = index - (!below || index == BAKEDPOINTS - 1);
|
||||
|
||||
// in the name of performance i shall make a hack
|
||||
const auto LOWERPOINT = &m_aPointsBaked[std::clamp(lowerT, 0, BAKEDPOINTS - 1)];
|
||||
const auto UPPERPOINT = &m_aPointsBaked[std::clamp(upperT, 0, BAKEDPOINTS - 1)];
|
||||
const auto LOWERPOINT = &m_aPointsBaked[lowerIndex];
|
||||
const auto UPPERPOINT = &m_aPointsBaked[lowerIndex + 1];
|
||||
|
||||
const auto PERCINDELTA = (x - LOWERPOINT->x) / (UPPERPOINT->x - LOWERPOINT->x);
|
||||
|
||||
@@ -73,4 +74,4 @@ float CBezierCurve::getYForPoint(float x) {
|
||||
return 0.f;
|
||||
|
||||
return LOWERPOINT->y + (UPPERPOINT->y - LOWERPOINT->y) * PERCINDELTA;
|
||||
}
|
||||
}
|
||||
|
@@ -1,14 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include "../defines.hpp"
|
||||
#include <deque>
|
||||
#include <array>
|
||||
#include <vector>
|
||||
#include "Vector2D.hpp"
|
||||
|
||||
constexpr int BAKEDPOINTS = 255;
|
||||
constexpr float INVBAKEDPOINTS = 1.f / BAKEDPOINTS;
|
||||
|
||||
// an implementation of a cubic bezier curve
|
||||
// might do better later
|
||||
// TODO: n-point curves
|
||||
class CBezierCurve {
|
||||
public:
|
||||
// sets up the bezier curve.
|
||||
@@ -24,4 +25,4 @@ class CBezierCurve {
|
||||
std::deque<Vector2D> m_dPoints;
|
||||
|
||||
std::array<Vector2D, BAKEDPOINTS> m_aPointsBaked;
|
||||
};
|
||||
};
|
||||
|
125
src/helpers/Box.cpp
Normal file
125
src/helpers/Box.cpp
Normal file
@@ -0,0 +1,125 @@
|
||||
#include "Box.hpp"
|
||||
wlr_box CBox::wlr() {
|
||||
CBox rounded = roundInternal();
|
||||
m_bWlrBox = wlr_box{(int)rounded.x, (int)rounded.y, (int)rounded.w, (int)rounded.h};
|
||||
return m_bWlrBox;
|
||||
}
|
||||
|
||||
wlr_box* CBox::pWlr() {
|
||||
CBox rounded = roundInternal();
|
||||
m_bWlrBox = wlr_box{(int)rounded.x, (int)rounded.y, (int)rounded.w, (int)rounded.h};
|
||||
return &m_bWlrBox;
|
||||
}
|
||||
|
||||
CBox& CBox::scale(double scale) {
|
||||
x *= scale;
|
||||
y *= scale;
|
||||
w *= scale;
|
||||
h *= scale;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
CBox& CBox::scale(const Vector2D& scale) {
|
||||
x *= scale.x;
|
||||
y *= scale.y;
|
||||
w *= scale.x;
|
||||
h *= scale.y;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
CBox& CBox::translate(const Vector2D& vec) {
|
||||
x += vec.x;
|
||||
y += vec.y;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Vector2D CBox::middle() const {
|
||||
return Vector2D{x + w / 2.0, y + h / 2.0};
|
||||
}
|
||||
|
||||
bool CBox::containsPoint(const Vector2D& vec) const {
|
||||
return VECINRECT(vec, x, y, x + w, y + h);
|
||||
}
|
||||
|
||||
bool CBox::empty() const {
|
||||
return w == 0 || h == 0;
|
||||
}
|
||||
|
||||
CBox& CBox::applyFromWlr() {
|
||||
x = m_bWlrBox.x;
|
||||
y = m_bWlrBox.y;
|
||||
w = m_bWlrBox.width;
|
||||
h = m_bWlrBox.height;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
CBox& CBox::round() {
|
||||
float newW = x + w - std::round(x);
|
||||
float newH = y + h - std::round(y);
|
||||
x = std::round(x);
|
||||
y = std::round(y);
|
||||
w = std::round(newW);
|
||||
h = std::round(newH);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
CBox& CBox::transform(const wl_output_transform t, double w, double h) {
|
||||
wlr_box_transform(&m_bWlrBox, pWlr(), t, w, h);
|
||||
applyFromWlr();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
CBox& CBox::addExtents(const SWindowDecorationExtents& e) {
|
||||
x -= e.topLeft.x;
|
||||
y -= e.topLeft.y;
|
||||
w += e.topLeft.x + e.bottomRight.x;
|
||||
h += e.topLeft.y + e.bottomRight.y;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
CBox& CBox::scaleFromCenter(double scale) {
|
||||
double oldW = w, oldH = h;
|
||||
|
||||
w *= scale;
|
||||
h *= scale;
|
||||
|
||||
x -= (w - oldW) / 2.0;
|
||||
y -= (h - oldH) / 2.0;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
CBox& CBox::expand(const double& value) {
|
||||
x -= value;
|
||||
y -= value;
|
||||
w += value * 2.0;
|
||||
h += value * 2.0;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
CBox CBox::roundInternal() {
|
||||
float newW = x + w - std::floor(x);
|
||||
float newH = y + h - std::floor(y);
|
||||
|
||||
return CBox{std::floor(x), std::floor(y), std::floor(newW), std::floor(newH)};
|
||||
}
|
||||
|
||||
Vector2D CBox::pos() const {
|
||||
return {x, y};
|
||||
}
|
||||
|
||||
Vector2D CBox::size() const {
|
||||
return {w, h};
|
||||
}
|
||||
|
||||
SWindowDecorationExtents CBox::extentsFrom(const CBox& small) {
|
||||
return {{small.x - x, small.y - y}, {w - small.w - (small.x - x), h - small.h - (small.y - y)}};
|
||||
}
|
83
src/helpers/Box.hpp
Normal file
83
src/helpers/Box.hpp
Normal file
@@ -0,0 +1,83 @@
|
||||
#pragma once
|
||||
|
||||
#include "Vector2D.hpp"
|
||||
#include "../SharedDefs.hpp"
|
||||
#include "../includes.hpp"
|
||||
|
||||
class CBox {
|
||||
public:
|
||||
CBox(double x_, double y_, double w_, double h_) {
|
||||
x = x_;
|
||||
y = y_;
|
||||
w = w_;
|
||||
h = h_;
|
||||
}
|
||||
|
||||
CBox() {
|
||||
w = 0;
|
||||
h = 0;
|
||||
}
|
||||
|
||||
CBox(const wlr_box& box) {
|
||||
x = box.x;
|
||||
y = box.y;
|
||||
w = box.width;
|
||||
h = box.height;
|
||||
}
|
||||
|
||||
CBox(const double d) {
|
||||
x = d;
|
||||
y = d;
|
||||
w = d;
|
||||
h = d;
|
||||
}
|
||||
|
||||
CBox(const Vector2D& pos, const Vector2D& size) {
|
||||
x = pos.x;
|
||||
y = pos.y;
|
||||
w = size.x;
|
||||
h = size.y;
|
||||
}
|
||||
|
||||
wlr_box wlr();
|
||||
wlr_box* pWlr();
|
||||
|
||||
CBox& applyFromWlr();
|
||||
CBox& scale(double scale);
|
||||
CBox& scaleFromCenter(double scale);
|
||||
CBox& scale(const Vector2D& scale);
|
||||
CBox& translate(const Vector2D& vec);
|
||||
CBox& round();
|
||||
CBox& transform(const wl_output_transform t, double w, double h);
|
||||
CBox& addExtents(const SWindowDecorationExtents& e);
|
||||
CBox& expand(const double& value);
|
||||
|
||||
SWindowDecorationExtents extentsFrom(const CBox&); // this is the big box
|
||||
|
||||
Vector2D middle() const;
|
||||
Vector2D pos() const;
|
||||
Vector2D size() const;
|
||||
|
||||
bool containsPoint(const Vector2D& vec) const;
|
||||
bool empty() const;
|
||||
|
||||
double x = 0, y = 0;
|
||||
union {
|
||||
double w;
|
||||
double width;
|
||||
};
|
||||
union {
|
||||
double h;
|
||||
double height;
|
||||
};
|
||||
|
||||
//
|
||||
bool operator==(const CBox& rhs) const {
|
||||
return x == rhs.x && y == rhs.y && w == rhs.w && h == rhs.h;
|
||||
}
|
||||
|
||||
private:
|
||||
CBox roundInternal();
|
||||
|
||||
wlr_box m_bWlrBox;
|
||||
};
|
@@ -1,5 +1,9 @@
|
||||
#include "Color.hpp"
|
||||
#include "../defines.hpp"
|
||||
|
||||
#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)
|
||||
|
||||
CColor::CColor() {}
|
||||
|
||||
|
@@ -5,7 +5,7 @@
|
||||
class CColor {
|
||||
public:
|
||||
CColor();
|
||||
CColor(float, float, float, float);
|
||||
CColor(float r, float g, float b, float a);
|
||||
CColor(uint64_t);
|
||||
|
||||
float r = 0, g = 0, b = 0, a = 1.f;
|
||||
@@ -27,4 +27,8 @@ class CColor {
|
||||
bool operator==(const CColor& c2) const {
|
||||
return r == c2.r && g == c2.g && b == c2.b && a == c2.a;
|
||||
}
|
||||
|
||||
CColor stripA() const {
|
||||
return {r, g, b, 1};
|
||||
}
|
||||
};
|
||||
|
@@ -2,9 +2,14 @@
|
||||
#include "../defines.hpp"
|
||||
#include <algorithm>
|
||||
#include "../Compositor.hpp"
|
||||
#include <optional>
|
||||
#include <set>
|
||||
#include <sys/utsname.h>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
#ifdef HAS_EXECINFO
|
||||
#include <execinfo.h>
|
||||
#endif
|
||||
|
||||
#if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
|
||||
#include <sys/sysctl.h>
|
||||
@@ -124,20 +129,22 @@ static const float transforms[][9] = {
|
||||
std::string absolutePath(const std::string& rawpath, const std::string& currentPath) {
|
||||
auto value = rawpath;
|
||||
|
||||
if (value[0] == '.') {
|
||||
auto currentDir = currentPath.substr(0, currentPath.find_last_of('/'));
|
||||
|
||||
if (value[1] == '.') {
|
||||
auto parentDir = currentDir.substr(0, currentDir.find_last_of('/'));
|
||||
value.replace(0, 2, parentDir);
|
||||
} else {
|
||||
value.replace(0, 1, currentDir);
|
||||
}
|
||||
}
|
||||
|
||||
if (value[0] == '~') {
|
||||
static const char* const ENVHOME = getenv("HOME");
|
||||
value.replace(0, 1, std::string(ENVHOME));
|
||||
} else if (value[0] != '/') {
|
||||
auto currentDir = currentPath.substr(0, currentPath.find_last_of('/'));
|
||||
|
||||
if (value[0] == '.') {
|
||||
if (value[1] == '.' && value[2] == '/') {
|
||||
auto parentDir = currentDir.substr(0, currentDir.find_last_of('/'));
|
||||
value.replace(0, 2 + currentPath.empty(), parentDir);
|
||||
} else if (value[1] == '/')
|
||||
value.replace(0, 1 + currentPath.empty(), currentDir);
|
||||
else
|
||||
value = currentDir + '/' + value;
|
||||
} else
|
||||
value = currentDir + '/' + value;
|
||||
}
|
||||
|
||||
return value;
|
||||
@@ -149,27 +156,13 @@ void addWLSignal(wl_signal* pSignal, wl_listener* pListener, void* pOwner, const
|
||||
|
||||
wl_signal_add(pSignal, pListener);
|
||||
|
||||
Debug::log(LOG, "Registered signal for owner %x: %x -> %x (owner: %s)", pOwner, pSignal, pListener, ownerString.c_str());
|
||||
Debug::log(LOG, "Registered signal for owner {:x}: {:x} -> {:x} (owner: {})", (uintptr_t)pOwner, (uintptr_t)pSignal, (uintptr_t)pListener, ownerString);
|
||||
}
|
||||
|
||||
void handleNoop(struct wl_listener* listener, void* data) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
std::string getFormat(const char* fmt, ...) {
|
||||
char* outputStr = nullptr;
|
||||
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
vasprintf(&outputStr, fmt, args);
|
||||
va_end(args);
|
||||
|
||||
std::string output = std::string(outputStr);
|
||||
free(outputStr);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
std::string escapeJSONStrings(const std::string& str) {
|
||||
std::ostringstream oss;
|
||||
for (auto& c : str) {
|
||||
@@ -192,13 +185,6 @@ std::string escapeJSONStrings(const std::string& str) {
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
void scaleBox(wlr_box* box, float scale) {
|
||||
box->width = std::round(box->width * scale);
|
||||
box->height = std::round(box->height * scale);
|
||||
box->x = std::round(box->x * scale);
|
||||
box->y = std::round(box->y * scale);
|
||||
}
|
||||
|
||||
std::string removeBeginEndSpacesTabs(std::string str) {
|
||||
if (str.empty())
|
||||
return str;
|
||||
@@ -222,7 +208,7 @@ float getPlusMinusKeywordResult(std::string source, float relative) {
|
||||
try {
|
||||
return relative + stof(source);
|
||||
} catch (...) {
|
||||
Debug::log(ERR, "Invalid arg \"%s\" in getPlusMinusKeywordResult!", source.c_str());
|
||||
Debug::log(ERR, "Invalid arg \"{}\" in getPlusMinusKeywordResult!", source);
|
||||
return INT_MAX;
|
||||
}
|
||||
}
|
||||
@@ -242,7 +228,7 @@ bool isNumber(const std::string& str, bool allowfloat) {
|
||||
if (point)
|
||||
return false;
|
||||
point = true;
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!std::isdigit(c))
|
||||
@@ -256,9 +242,13 @@ bool isDirection(const std::string& arg) {
|
||||
return arg == "l" || arg == "r" || arg == "u" || arg == "d" || arg == "t" || arg == "b";
|
||||
}
|
||||
|
||||
bool isDirection(const char& arg) {
|
||||
return arg == 'l' || arg == 'r' || arg == 'u' || arg == 'd' || arg == 't' || arg == 'b';
|
||||
}
|
||||
|
||||
int getWorkspaceIDFromString(const std::string& in, std::string& outName) {
|
||||
int result = INT_MAX;
|
||||
if (in.find("special") == 0) {
|
||||
if (in.starts_with("special")) {
|
||||
outName = "special";
|
||||
|
||||
if (in.length() > 8) {
|
||||
@@ -272,7 +262,7 @@ int getWorkspaceIDFromString(const std::string& in, std::string& outName) {
|
||||
}
|
||||
|
||||
return SPECIAL_WORKSPACE_START;
|
||||
} else if (in.find("name:") == 0) {
|
||||
} else if (in.starts_with("name:")) {
|
||||
const auto WORKSPACENAME = in.substr(in.find_first_of(':') + 1);
|
||||
const auto WORKSPACE = g_pCompositor->getWorkspaceByName(WORKSPACENAME);
|
||||
if (!WORKSPACE) {
|
||||
@@ -281,14 +271,14 @@ int getWorkspaceIDFromString(const std::string& in, std::string& outName) {
|
||||
result = WORKSPACE->m_iID;
|
||||
}
|
||||
outName = WORKSPACENAME;
|
||||
} else if (in.find("empty") == 0) {
|
||||
} else if (in.starts_with("empty")) {
|
||||
int id = 0;
|
||||
while (++id < INT_MAX) {
|
||||
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(id);
|
||||
if (!PWORKSPACE || (g_pCompositor->getWindowsOnWorkspace(id) == 0))
|
||||
return id;
|
||||
}
|
||||
} else if (in.find("prev") == 0) {
|
||||
} else if (in.starts_with("prev")) {
|
||||
if (!g_pCompositor->m_pLastMonitor)
|
||||
return INT_MAX;
|
||||
|
||||
@@ -305,7 +295,140 @@ int getWorkspaceIDFromString(const std::string& in, std::string& outName) {
|
||||
outName = PLASTWORKSPACE->m_szName;
|
||||
return PLASTWORKSPACE->m_iID;
|
||||
} else {
|
||||
if ((in[0] == 'm' || in[0] == 'e') && (in[1] == '-' || in[1] == '+') && isNumber(in.substr(2))) {
|
||||
if (in[0] == 'r' && (in[1] == '-' || in[1] == '+') && isNumber(in.substr(2))) {
|
||||
if (!g_pCompositor->m_pLastMonitor) {
|
||||
Debug::log(ERR, "Relative monitor workspace on monitor null!");
|
||||
result = INT_MAX;
|
||||
return result;
|
||||
}
|
||||
result = (int)getPlusMinusKeywordResult(in.substr(1), 0);
|
||||
|
||||
int remains = (int)result;
|
||||
|
||||
std::set<int> invalidWSes;
|
||||
|
||||
// Collect all the workspaces we can't jump to.
|
||||
for (auto& ws : g_pCompositor->m_vWorkspaces) {
|
||||
if (ws->m_bIsSpecialWorkspace || (ws->m_iMonitorID != g_pCompositor->m_pLastMonitor->ID)) {
|
||||
// Can't jump to this workspace
|
||||
invalidWSes.insert(ws->m_iID);
|
||||
}
|
||||
}
|
||||
for (auto& rule : g_pConfigManager->getAllWorkspaceRules()) {
|
||||
const auto PMONITOR = g_pCompositor->getMonitorFromName(rule.monitor);
|
||||
if (!PMONITOR || PMONITOR->ID == g_pCompositor->m_pLastMonitor->ID) {
|
||||
// Can't be invalid
|
||||
continue;
|
||||
}
|
||||
// WS is bound to another monitor, can't jump to this
|
||||
invalidWSes.insert(rule.workspaceId);
|
||||
}
|
||||
|
||||
// Prepare all named workspaces in case when we need them
|
||||
std::vector<int> namedWSes;
|
||||
for (auto& ws : g_pCompositor->m_vWorkspaces) {
|
||||
if (ws->m_bIsSpecialWorkspace || (ws->m_iMonitorID != g_pCompositor->m_pLastMonitor->ID) || ws->m_iID >= 0)
|
||||
continue;
|
||||
|
||||
namedWSes.push_back(ws->m_iID);
|
||||
}
|
||||
std::sort(namedWSes.begin(), namedWSes.end());
|
||||
|
||||
// Just take a blind guess at where we'll probably end up
|
||||
int predictedWSID = g_pCompositor->m_pLastMonitor->activeWorkspace + remains;
|
||||
int remainingWSes = 0;
|
||||
char walkDir = in[1];
|
||||
|
||||
// sanitize. 0 means invalid oob in -
|
||||
predictedWSID = std::max(predictedWSID, 0);
|
||||
|
||||
// Count how many invalidWSes are in between (how bad the prediction was)
|
||||
int beginID = in[1] == '+' ? g_pCompositor->m_pLastMonitor->activeWorkspace + 1 : predictedWSID;
|
||||
int endID = in[1] == '+' ? predictedWSID : g_pCompositor->m_pLastMonitor->activeWorkspace;
|
||||
auto begin = invalidWSes.upper_bound(beginID - 1); // upper_bound is >, we want >=
|
||||
for (auto it = begin; *it <= endID && it != invalidWSes.end(); it++) {
|
||||
remainingWSes++;
|
||||
}
|
||||
|
||||
// Handle named workspaces. They are treated like always before other workspaces
|
||||
if (g_pCompositor->m_pLastMonitor->activeWorkspace < 0) {
|
||||
// Behaviour similar to 'm'
|
||||
// Find current
|
||||
int currentItem = -1;
|
||||
for (size_t i = 0; i < namedWSes.size(); i++) {
|
||||
if (namedWSes[i] == g_pCompositor->m_pLastMonitor->activeWorkspace) {
|
||||
currentItem = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
currentItem += remains;
|
||||
currentItem = std::max(currentItem, 0);
|
||||
if (currentItem >= (int)namedWSes.size()) {
|
||||
// At the seam between namedWSes and normal WSes. Behave like r+[diff] at imaginary ws 0
|
||||
int diff = currentItem - (namedWSes.size() - 1);
|
||||
predictedWSID = diff;
|
||||
int beginID = 1;
|
||||
int endID = predictedWSID;
|
||||
auto begin = invalidWSes.upper_bound(beginID - 1); // upper_bound is >, we want >=
|
||||
for (auto it = begin; *it <= endID && it != invalidWSes.end(); it++) {
|
||||
remainingWSes++;
|
||||
}
|
||||
walkDir = '+';
|
||||
} else {
|
||||
// We found our final ws.
|
||||
remainingWSes = 0;
|
||||
predictedWSID = namedWSes[currentItem];
|
||||
}
|
||||
}
|
||||
|
||||
// Go in the search direction for remainingWSes
|
||||
// The performance impact is directly proportional to the number of open and bound workspaces
|
||||
int finalWSID = predictedWSID;
|
||||
if (walkDir == '-') {
|
||||
int beginID = finalWSID;
|
||||
int curID = finalWSID;
|
||||
while (--curID > 0 && remainingWSes > 0) {
|
||||
if (!invalidWSes.contains(curID)) {
|
||||
remainingWSes--;
|
||||
}
|
||||
finalWSID = curID;
|
||||
}
|
||||
if (finalWSID <= 0 || invalidWSes.contains(finalWSID)) {
|
||||
if (namedWSes.size()) {
|
||||
// Go to the named workspaces
|
||||
// Need remainingWSes more
|
||||
int namedWSIdx = namedWSes.size() - remainingWSes;
|
||||
// Sanitze
|
||||
namedWSIdx = std::clamp(namedWSIdx, 0, (int)namedWSes.size() - 1);
|
||||
finalWSID = namedWSes[namedWSIdx];
|
||||
} else {
|
||||
// Couldn't find valid workspace in negative direction, search last first one back up positive direction
|
||||
walkDir = '+';
|
||||
// We know, that everything less than beginID is invalid, so don't bother with that
|
||||
finalWSID = beginID;
|
||||
remainingWSes = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (walkDir == '+') {
|
||||
int curID = finalWSID;
|
||||
while (++curID < INT32_MAX && remainingWSes > 0) {
|
||||
if (!invalidWSes.contains(curID)) {
|
||||
remainingWSes--;
|
||||
}
|
||||
finalWSID = curID;
|
||||
}
|
||||
}
|
||||
|
||||
result = finalWSID;
|
||||
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(result);
|
||||
if (PWORKSPACE)
|
||||
outName = g_pCompositor->getWorkspaceByID(result)->m_szName;
|
||||
else
|
||||
outName = std::to_string(finalWSID);
|
||||
|
||||
} else if ((in[0] == 'm' || in[0] == 'e') && (in[1] == '-' || in[1] == '+') && isNumber(in.substr(2))) {
|
||||
bool onAllMonitors = in[0] == 'e';
|
||||
|
||||
if (!g_pCompositor->m_pLastMonitor) {
|
||||
@@ -354,7 +477,6 @@ int getWorkspaceIDFromString(const std::string& in, std::string& outName) {
|
||||
|
||||
result = validWSes[currentItem];
|
||||
outName = g_pCompositor->getWorkspaceByID(validWSes[currentItem])->m_szName;
|
||||
|
||||
} else {
|
||||
if (in[0] == '+' || in[0] == '-') {
|
||||
if (g_pCompositor->m_pLastMonitor)
|
||||
@@ -379,6 +501,43 @@ int getWorkspaceIDFromString(const std::string& in, std::string& outName) {
|
||||
return result;
|
||||
}
|
||||
|
||||
std::optional<std::string> cleanCmdForWorkspace(const std::string& inWorkspaceName, std::string dirtyCmd) {
|
||||
|
||||
std::string cmd = removeBeginEndSpacesTabs(dirtyCmd);
|
||||
|
||||
if (!cmd.empty()) {
|
||||
std::string rules;
|
||||
const std::string workspaceRule = "workspace " + inWorkspaceName;
|
||||
|
||||
if (cmd[0] == '[') {
|
||||
const int closingBracketIdx = cmd.find_last_of(']');
|
||||
auto tmpRules = cmd.substr(1, closingBracketIdx - 1);
|
||||
cmd = cmd.substr(closingBracketIdx + 1);
|
||||
|
||||
auto rulesList = CVarList(tmpRules, 0, ';');
|
||||
|
||||
bool hadWorkspaceRule = false;
|
||||
rulesList.map([&](std::string& rule) {
|
||||
if (rule.find("workspace") == 0) {
|
||||
rule = workspaceRule;
|
||||
hadWorkspaceRule = true;
|
||||
}
|
||||
});
|
||||
|
||||
if (!hadWorkspaceRule)
|
||||
rulesList.append(workspaceRule);
|
||||
|
||||
rules = "[" + rulesList.join(";") + "]";
|
||||
} else {
|
||||
rules = "[" + workspaceRule + "]";
|
||||
}
|
||||
|
||||
return std::optional<std::string>(rules + " " + cmd);
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
float vecToRectDistanceSquared(const Vector2D& vec, const Vector2D& p1, const Vector2D& p2) {
|
||||
const float DX = std::max({0.0, p1.x - vec.x, vec.x - p2.x});
|
||||
const float DY = std::max({0.0, p1.y - vec.y, vec.y - p2.y});
|
||||
@@ -405,10 +564,10 @@ void logSystemInfo() {
|
||||
|
||||
uname(&unameInfo);
|
||||
|
||||
Debug::log(LOG, "System name: %s", unameInfo.sysname);
|
||||
Debug::log(LOG, "Node name: %s", unameInfo.nodename);
|
||||
Debug::log(LOG, "Release: %s", unameInfo.release);
|
||||
Debug::log(LOG, "Version: %s", unameInfo.version);
|
||||
Debug::log(LOG, "System name: {}", unameInfo.sysname);
|
||||
Debug::log(LOG, "Node name: {}", unameInfo.nodename);
|
||||
Debug::log(LOG, "Release: {}", unameInfo.release);
|
||||
Debug::log(LOG, "Version: {}", unameInfo.version);
|
||||
|
||||
Debug::log(NONE, "\n");
|
||||
|
||||
@@ -417,7 +576,7 @@ void logSystemInfo() {
|
||||
#else
|
||||
const std::string GPUINFO = execAndGet("lspci -vnn | grep VGA");
|
||||
#endif
|
||||
Debug::log(LOG, "GPU information:\n%s\n", GPUINFO.c_str());
|
||||
Debug::log(LOG, "GPU information:\n{}\n", GPUINFO);
|
||||
|
||||
if (GPUINFO.contains("NVIDIA")) {
|
||||
Debug::log(WARN, "Warning: you're using an NVIDIA GPU. Make sure you follow the instructions on the wiki if anything is amiss.\n");
|
||||
@@ -426,7 +585,7 @@ void logSystemInfo() {
|
||||
// log etc
|
||||
Debug::log(LOG, "os-release:");
|
||||
|
||||
Debug::log(NONE, "%s", execAndGet("cat /etc/os-release").c_str());
|
||||
Debug::log(NONE, "{}", execAndGet("cat /etc/os-release"));
|
||||
}
|
||||
|
||||
void matrixProjection(float mat[9], int w, int h, wl_output_transform tr) {
|
||||
@@ -504,15 +663,15 @@ int64_t getPPIDof(int64_t pid) {
|
||||
}
|
||||
|
||||
int64_t configStringToInt(const std::string& VALUE) {
|
||||
if (VALUE.find("0x") == 0) {
|
||||
if (VALUE.starts_with("0x")) {
|
||||
// Values with 0x are hex
|
||||
const auto VALUEWITHOUTHEX = VALUE.substr(2);
|
||||
return stol(VALUEWITHOUTHEX, nullptr, 16);
|
||||
} else if (VALUE.find("rgba(") == 0 && VALUE.find(')') == VALUE.length() - 1) {
|
||||
} else if (VALUE.starts_with("rgba(") && VALUE.ends_with(')')) {
|
||||
const auto VALUEWITHOUTFUNC = VALUE.substr(5, VALUE.length() - 6);
|
||||
|
||||
if (removeBeginEndSpacesTabs(VALUEWITHOUTFUNC).length() != 8) {
|
||||
Debug::log(WARN, "invalid length %i for rgba", VALUEWITHOUTFUNC.length());
|
||||
Debug::log(WARN, "invalid length {} for rgba", VALUEWITHOUTFUNC.length());
|
||||
throw std::invalid_argument("rgba() expects length of 8 characters (4 bytes)");
|
||||
}
|
||||
|
||||
@@ -520,20 +679,20 @@ int64_t configStringToInt(const std::string& VALUE) {
|
||||
|
||||
// now we need to RGBA -> ARGB. The config holds ARGB only.
|
||||
return (RGBA >> 8) + 0x1000000 * (RGBA & 0xFF);
|
||||
} else if (VALUE.find("rgb(") == 0 && VALUE.find(')') == VALUE.length() - 1) {
|
||||
} else if (VALUE.starts_with("rgb(") && VALUE.ends_with(')')) {
|
||||
const auto VALUEWITHOUTFUNC = VALUE.substr(4, VALUE.length() - 5);
|
||||
|
||||
if (removeBeginEndSpacesTabs(VALUEWITHOUTFUNC).length() != 6) {
|
||||
Debug::log(WARN, "invalid length %i for rgb", VALUEWITHOUTFUNC.length());
|
||||
Debug::log(WARN, "invalid length {} for rgb", VALUEWITHOUTFUNC.length());
|
||||
throw std::invalid_argument("rgb() expects length of 6 characters (3 bytes)");
|
||||
}
|
||||
|
||||
const auto RGB = std::stol(VALUEWITHOUTFUNC, nullptr, 16);
|
||||
|
||||
return RGB + 0xFF000000; // 0xFF for opaque
|
||||
} else if (VALUE.find("true") == 0 || VALUE.find("on") == 0 || VALUE.find("yes") == 0) {
|
||||
} else if (VALUE.starts_with("true") || VALUE.starts_with("on") || VALUE.starts_with("yes")) {
|
||||
return 1;
|
||||
} else if (VALUE.find("false") == 0 || VALUE.find("off") == 0 || VALUE.find("no") == 0) {
|
||||
} else if (VALUE.starts_with("false") || VALUE.starts_with("off") || VALUE.starts_with("no")) {
|
||||
return 0;
|
||||
}
|
||||
return std::stoll(VALUE);
|
||||
@@ -563,3 +722,46 @@ std::string replaceInString(std::string subject, const std::string& search, cons
|
||||
}
|
||||
return subject;
|
||||
}
|
||||
|
||||
std::vector<SCallstackFrameInfo> getBacktrace() {
|
||||
std::vector<SCallstackFrameInfo> callstack;
|
||||
|
||||
#ifdef HAS_EXECINFO
|
||||
void* bt[1024];
|
||||
size_t btSize;
|
||||
char** btSymbols;
|
||||
|
||||
btSize = backtrace(bt, 1024);
|
||||
btSymbols = backtrace_symbols(bt, btSize);
|
||||
|
||||
for (size_t i = 0; i < btSize; ++i) {
|
||||
callstack.emplace_back(SCallstackFrameInfo{bt[i], std::string{btSymbols[i]}});
|
||||
}
|
||||
#else
|
||||
callstack.emplace_back(SCallstackFrameInfo{nullptr, "configuration does not support execinfo.h"});
|
||||
#endif
|
||||
|
||||
return callstack;
|
||||
}
|
||||
|
||||
void throwError(const std::string& err) {
|
||||
Debug::log(CRIT, "Critical error thrown: {}", err);
|
||||
throw std::runtime_error(err);
|
||||
}
|
||||
|
||||
uint32_t drmFormatToGL(uint32_t drm) {
|
||||
switch (drm) {
|
||||
case DRM_FORMAT_XRGB8888:
|
||||
case DRM_FORMAT_XBGR8888: return GL_RGBA; // doesn't matter, opengl is gucci in this case.
|
||||
case DRM_FORMAT_XRGB2101010:
|
||||
case DRM_FORMAT_XBGR2101010:
|
||||
#ifdef GLES2
|
||||
return GL_RGB10_A2_EXT;
|
||||
#else
|
||||
return GL_RGB10_A2;
|
||||
#endif
|
||||
default: return GL_RGBA;
|
||||
}
|
||||
UNREACHABLE();
|
||||
return GL_RGBA;
|
||||
}
|
@@ -1,22 +1,44 @@
|
||||
#pragma once
|
||||
|
||||
#include "../includes.hpp"
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <wayland-server.h>
|
||||
#include <wlr/util/box.h>
|
||||
#include "Vector2D.hpp"
|
||||
#include <vector>
|
||||
#include <format>
|
||||
|
||||
std::string absolutePath(const std::string&, const std::string&);
|
||||
void addWLSignal(wl_signal*, wl_listener*, void* pOwner, const std::string& ownerString);
|
||||
std::string getFormat(const char* fmt, ...); // Basically Debug::log to a string
|
||||
std::string escapeJSONStrings(const std::string& str);
|
||||
void scaleBox(wlr_box*, float);
|
||||
std::string removeBeginEndSpacesTabs(std::string);
|
||||
bool isNumber(const std::string&, bool allowfloat = false);
|
||||
bool isDirection(const std::string&);
|
||||
int getWorkspaceIDFromString(const std::string&, std::string&);
|
||||
float vecToRectDistanceSquared(const Vector2D& vec, const Vector2D& p1, const Vector2D& p2);
|
||||
void logSystemInfo();
|
||||
std::string execAndGet(const char*);
|
||||
int64_t getPPIDof(int64_t pid);
|
||||
int64_t configStringToInt(const std::string&);
|
||||
float getPlusMinusKeywordResult(std::string in, float relative);
|
||||
void matrixProjection(float mat[9], int w, int h, wl_output_transform tr);
|
||||
double normalizeAngleRad(double ang);
|
||||
std::string replaceInString(std::string subject, const std::string& search, const std::string& replace);
|
||||
struct SCallstackFrameInfo {
|
||||
void* adr = nullptr;
|
||||
std::string desc;
|
||||
};
|
||||
|
||||
std::string absolutePath(const std::string&, const std::string&);
|
||||
void addWLSignal(wl_signal*, wl_listener*, void* pOwner, const std::string& ownerString);
|
||||
std::string escapeJSONStrings(const std::string& str);
|
||||
std::string removeBeginEndSpacesTabs(std::string);
|
||||
bool isNumber(const std::string&, bool allowfloat = false);
|
||||
bool isDirection(const std::string&);
|
||||
bool isDirection(const char&);
|
||||
int getWorkspaceIDFromString(const std::string&, std::string&);
|
||||
std::optional<std::string> cleanCmdForWorkspace(const std::string&, std::string);
|
||||
float vecToRectDistanceSquared(const Vector2D& vec, const Vector2D& p1, const Vector2D& p2);
|
||||
void logSystemInfo();
|
||||
std::string execAndGet(const char*);
|
||||
int64_t getPPIDof(int64_t pid);
|
||||
int64_t configStringToInt(const std::string&);
|
||||
float getPlusMinusKeywordResult(std::string in, float relative);
|
||||
void matrixProjection(float mat[9], int w, int h, wl_output_transform tr);
|
||||
double normalizeAngleRad(double ang);
|
||||
std::string replaceInString(std::string subject, const std::string& search, const std::string& replace);
|
||||
std::vector<SCallstackFrameInfo> getBacktrace();
|
||||
void throwError(const std::string& err);
|
||||
uint32_t drmFormatToGL(uint32_t drm);
|
||||
|
||||
template <typename... Args>
|
||||
[[deprecated("use std::format instead")]] std::string getFormat(std::format_string<Args...> fmt, Args&&... args) {
|
||||
// no need for try {} catch {} because std::format_string<Args...> ensures that vformat never throw std::format_error
|
||||
// because any suck format specifier will cause a compilation error
|
||||
// this is actually what std::format in stdlib does
|
||||
return std::vformat(fmt.get(), std::make_format_args(args...));
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user