mirror of
https://github.com/hyprwm/Hyprland.git
synced 2025-09-03 05:23:48 -07:00
Compare commits
743 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
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 |
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
|
||||
|
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"
|
7
.github/workflows/release.yaml
vendored
7
.github/workflows/release.yaml
vendored
@@ -15,10 +15,15 @@ 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: |
|
||||
sed -i "1s/^/#define GIT_COMMIT_HASH $(git rev-parse HEAD)\n#define GIT_TAG \"$(git describe --tags)\"\n/" ./src/defines.hpp
|
||||
mkdir hyprland-source; mv ./* ./hyprland-source || tar -czv --owner=0 --group=0 --no-same-owner --no-same-permissions -f source.tar.gz *
|
||||
|
||||
- id: whatrelease
|
||||
|
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
|
||||
|
140
CMakeLists.txt
Normal file → Executable file
140
CMakeLists.txt
Normal file → Executable file
@@ -21,37 +21,51 @@ 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)
|
||||
|
||||
execute_process(
|
||||
COMMAND sh -c "git describe --tags"
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||
OUTPUT_VARIABLE GIT_TAG
|
||||
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(
|
||||
@@ -71,6 +85,7 @@ endif()
|
||||
|
||||
include_directories(
|
||||
.
|
||||
"src/"
|
||||
"subprojects/wlroots/include/"
|
||||
"subprojects/wlroots/build/include/"
|
||||
"subprojects/udis86/"
|
||||
@@ -92,16 +107,43 @@ pkg_check_modules(deps REQUIRED IMPORTED_TARGET wayland-server wayland-client wa
|
||||
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)
|
||||
@@ -126,32 +168,33 @@ 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)
|
||||
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 libsystemd or systemd headers were not found")
|
||||
message(WARNING "Systemd support requested but systemd libraries were not found")
|
||||
endif()
|
||||
else()
|
||||
message(WARNING "Systemd support requested but systemd headers were not found")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
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}\""
|
||||
"GIT_TAG=\"${GIT_TAG}\"")
|
||||
|
||||
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 rt PkgConfig::deps)
|
||||
|
||||
function(protocol protoPath protoName external)
|
||||
if (external)
|
||||
execute_process(
|
||||
@@ -172,17 +215,14 @@ function(protocol protoPath protoName external)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
target_link_libraries(Hyprland PkgConfig::deps)
|
||||
|
||||
target_link_libraries(Hyprland
|
||||
${CMAKE_SOURCE_DIR}/subprojects/wlroots/build/libwlroots.so.12032 # wlroots is provided by us
|
||||
OpenGL::EGL
|
||||
OpenGL::GL
|
||||
Threads::Threads
|
||||
${CMAKE_SOURCE_DIR}/subprojects/udis86/build/libudis86/liblibudis86.a
|
||||
libudis86
|
||||
)
|
||||
|
||||
protocol("protocols/ext-workspace-unstable-v1.xml" "ext-workspace-unstable-v1" true)
|
||||
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)
|
||||
@@ -194,5 +234,11 @@ protocol("subprojects/hyprland-protocols/protocols/hyprland-global-shortcuts-v1.
|
||||
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.
|
80
Makefile
80
Makefile
@@ -3,68 +3,56 @@ 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`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`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`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`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
|
||||
chmod -R 777 ./build
|
||||
|
||||
clear:
|
||||
rm -rf build
|
||||
rm -f ./protocols/*-protocol.h ./protocols/*-protocol.c
|
||||
rm -f ./hyprctl/hyprctl
|
||||
rm -rf ./subprojects/wlroots/build
|
||||
|
||||
all:
|
||||
@if [[ "$EUID" = 0 ]]; then echo -en "Avoid running $(MAKE) all as sudo.\n"; fi
|
||||
$(MAKE) clear
|
||||
$(MAKE) fixwlr
|
||||
cd ./subprojects/wlroots && meson setup build/ --buildtype=release && ninja -C build/ && mkdir -p ${PREFIX}/lib/ && 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`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
|
||||
$(MAKE) release
|
||||
$(MAKE) -C hyprctl all
|
||||
|
||||
install:
|
||||
$(MAKE) clear
|
||||
$(MAKE) fixwlr
|
||||
cd ./subprojects/wlroots && meson setup build/ --buildtype=release && ninja -C build/ && mkdir -p ${PREFIX}/lib/ && 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`nproc 2>/dev/null || getconf NPROCESSORS_CONF` && cd ../..
|
||||
$(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 -f ./build/Hyprland ${PREFIX}/bin
|
||||
cp -f ./hyprctl/hyprctl ${PREFIX}/bin
|
||||
cp -f ./build/hyprctl/hyprctl ${PREFIX}/bin
|
||||
chmod 755 ${PREFIX}/bin/Hyprland
|
||||
chmod 755 ${PREFIX}/bin/hyprctl
|
||||
if [ ! -f ${PREFIX}/share/wayland-sessions/hyprland.desktop ]; then cp ./example/hyprland.desktop ${PREFIX}/share/wayland-sessions; fi
|
||||
mkdir -p ${PREFIX}/share/hyprland
|
||||
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
|
||||
|
||||
mkdir -p ${PREFIX}/share/man/man1
|
||||
install -m644 ./docs/*.1 ${PREFIX}/share/man/man1
|
||||
|
||||
mkdir -p ${PREFIX}/include/hyprland
|
||||
mkdir -p ${PREFIX}/include/hyprland/protocols
|
||||
mkdir -p ${PREFIX}/include/hyprland/wlroots
|
||||
mkdir -p ${PREFIX}/share/pkgconfig
|
||||
mkdir -p ${PREFIX}/lib/
|
||||
cp ./subprojects/wlroots/build/libwlroots.so.12032 ${PREFIX}/lib/
|
||||
|
||||
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 ../../..
|
||||
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
|
||||
|
||||
cleaninstall:
|
||||
echo -en "$(MAKE) cleaninstall has been DEPRECATED, you should avoid using it in the future.\nRunning $(MAKE) install instead...\n"
|
||||
$(MAKE) install
|
||||
$(MAKE) installheaders
|
||||
|
||||
uninstall:
|
||||
rm -f ${PREFIX}/share/wayland-sessions/hyprland.desktop
|
||||
@@ -75,30 +63,12 @@ uninstall:
|
||||
rm -f ${PREFIX}/share/man/man1/Hyprland.1
|
||||
rm -f ${PREFIX}/share/man/man1/hyprctl.1
|
||||
|
||||
fixwlr:
|
||||
sed -E -i -e 's/(soversion = 12)([^032]|$$)/soversion = 12032/g' subprojects/wlroots/meson.build
|
||||
|
||||
rm -rf ./subprojects/wlroots/build
|
||||
|
||||
config:
|
||||
$(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`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
|
||||
|
||||
pluginenv:
|
||||
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`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
|
||||
@echo -en "$(MAKE) pluginenv has been deprecated.\nPlease run $(MAKE) all && sudo $(MAKE) installheaders\n"
|
||||
@exit 1
|
||||
|
||||
$(MAKE) fixwlr
|
||||
|
||||
meson setup subprojects/wlroots/build subprojects/wlroots --prefix=${PREFIX} --buildtype=release -Dwerror=false -Dexamples=false
|
||||
ninja -C subprojects/wlroots/build/
|
||||
|
||||
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -S . -B ./build -G Ninja
|
||||
installheaders:
|
||||
@if [ ! -f ./build/Hyprland ]; then echo -en "You need to run $(MAKE) all first.\n" && exit 1; fi
|
||||
|
||||
mkdir -p ${PREFIX}/include/hyprland
|
||||
mkdir -p ${PREFIX}/include/hyprland/protocols
|
||||
@@ -107,17 +77,13 @@ pluginenv:
|
||||
|
||||
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
|
||||
|
||||
configdebug:
|
||||
$(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>
|
||||
|
||||
@@ -33,39 +34,28 @@ It supports multiple layouts, fancy effects, has a very flexible IPC model allow
|
||||
|
||||
</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,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,7 +33,7 @@ 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),
|
||||
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;
|
||||
@@ -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),
|
||||
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": 1681065697,
|
||||
"narHash": "sha256-QPzwwlGKX95tl6ZEshboZbEwwAXww6lNLdVYd6T9Mrc=",
|
||||
"lastModified": 1691753796,
|
||||
"narHash": "sha256-zOEwiWoXk3j3+EoF3ySUJmberFewWlagvewDRuWYAso=",
|
||||
"owner": "hyprwm",
|
||||
"repo": "hyprland-protocols",
|
||||
"rev": "4d29e48433270a2af06b8bc711ca1fe5109746cd",
|
||||
"rev": "0c2ce70625cb30aef199cb388f99e19a61a6ce03",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -22,11 +25,11 @@
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1683014792,
|
||||
"narHash": "sha256-6Va9iVtmmsw4raBc3QKvQT2KT/NGRWlvUlJj46zN8B8=",
|
||||
"lastModified": 1698134075,
|
||||
"narHash": "sha256-foCD+nuKzfh49bIoiCBur4+Fx1nozo+4C/6k8BYk4sg=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "1a411f23ba299db155a5b45d5e145b85a7aafc42",
|
||||
"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": 1682436395,
|
||||
"narHash": "sha256-GGEjkQO9m7YLYIXIXM76HWdhjg4Ye+oafOtyaFAYKI4=",
|
||||
"lastModified": 1697909146,
|
||||
"narHash": "sha256-jU0I6FoCKnj4zIBL4daosFWh81U1fM719Z6cae8PxSY=",
|
||||
"owner": "wlroots",
|
||||
"repo": "wlroots",
|
||||
"rev": "6830bfc17fd94709e2cdd4da0af989f102a26e59",
|
||||
"rev": "47bf87ade2bd32395615a385ebde1fefbcdf79a2",
|
||||
"type": "gitlab"
|
||||
},
|
||||
"original": {
|
||||
"host": "gitlab.freedesktop.org",
|
||||
"owner": "wlroots",
|
||||
"repo": "wlroots",
|
||||
"rev": "47bf87ade2bd32395615a385ebde1fefbcdf79a2",
|
||||
"type": "gitlab"
|
||||
}
|
||||
},
|
||||
@@ -69,14 +89,17 @@
|
||||
],
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
],
|
||||
"systems": [
|
||||
"systems"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1682439384,
|
||||
"narHash": "sha256-zHDa8LCZs05TZHQSIZ3ucwyMPglBGHcqTBzfkLjYXTM=",
|
||||
"lastModified": 1697981233,
|
||||
"narHash": "sha256-y8q4XUwx+gVK7i2eLjfR32lVo7TYvEslyzrmzYEaPZU=",
|
||||
"owner": "hyprwm",
|
||||
"repo": "xdg-desktop-portal-hyprland",
|
||||
"rev": "c0e233955568fbea4e859336f6d3d14d51294d7c",
|
||||
"rev": "22e7a65ff9633e1dedfa5317fdffc49f68de2ff2",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
74
flake.nix
74
flake.nix
@@ -4,19 +4,28 @@
|
||||
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 = "47bf87ade2bd32395615a385ebde1fefbcdf79a2";
|
||||
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";
|
||||
};
|
||||
};
|
||||
@@ -24,38 +33,23 @@
|
||||
outputs = inputs @ {
|
||||
self,
|
||||
nixpkgs,
|
||||
systems,
|
||||
...
|
||||
}: let
|
||||
lib = nixpkgs.lib.extend (import ./nix/lib.nix);
|
||||
genSystems = lib.genAttrs [
|
||||
# Add more systems if they are supported
|
||||
"aarch64-linux"
|
||||
"x86_64-linux"
|
||||
];
|
||||
|
||||
pkgsFor = genSystems (system:
|
||||
inherit (nixpkgs) lib;
|
||||
eachSystem = lib.genAttrs (import systems);
|
||||
pkgsFor = eachSystem (system:
|
||||
import nixpkgs {
|
||||
inherit system;
|
||||
overlays = [
|
||||
self.overlays.hyprland-packages
|
||||
self.overlays.wlroots-hyprland
|
||||
inputs.hyprland-protocols.overlays.default
|
||||
localSystem = system;
|
||||
overlays = with self.overlays; [
|
||||
hyprland-packages
|
||||
hyprland-extras
|
||||
];
|
||||
});
|
||||
in {
|
||||
overlays =
|
||||
(import ./nix/overlays.nix {inherit self lib inputs;})
|
||||
// {
|
||||
default =
|
||||
lib.mkJoinedOverlays
|
||||
(with self.overlays; [
|
||||
hyprland-packages
|
||||
hyprland-extras
|
||||
wlroots-hyprland
|
||||
]);
|
||||
};
|
||||
overlays = import ./nix/overlays.nix {inherit self lib inputs;};
|
||||
|
||||
checks = genSystems (system:
|
||||
checks = eachSystem (system:
|
||||
(lib.filterAttrs
|
||||
(n: _: (lib.hasPrefix "hyprland" n) && !(lib.hasSuffix "debug" n))
|
||||
self.packages.${system})
|
||||
@@ -63,16 +57,30 @@
|
||||
inherit (self.packages.${system}) xdg-desktop-portal-hyprland;
|
||||
});
|
||||
|
||||
packages = genSystems (system:
|
||||
(self.overlays.default pkgsFor.${system} pkgsFor.${system})
|
||||
// {
|
||||
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 = genSystems (system: {
|
||||
default = pkgsFor.${system}.mkShell {
|
||||
devShells = eachSystem (system: {
|
||||
default = pkgsFor.${system}.mkShell.override {
|
||||
stdenv = pkgsFor.${system}.gcc13Stdenv;
|
||||
} {
|
||||
name = "hyprland-shell";
|
||||
nativeBuildInputs = with pkgsFor.${system}; [cmake];
|
||||
nativeBuildInputs = with pkgsFor.${system}; [cmake python3];
|
||||
buildInputs = [self.packages.${system}.wlroots-hyprland];
|
||||
inputsFrom = [
|
||||
self.packages.${system}.wlroots-hyprland
|
||||
@@ -81,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")
|
241
hyprctl/main.cpp
241
hyprctl/main.cpp
@@ -11,12 +11,17 @@
|
||||
#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]
|
||||
|
||||
@@ -24,6 +29,7 @@ commands:
|
||||
monitors
|
||||
workspaces
|
||||
activeworkspace
|
||||
workspacerules
|
||||
clients
|
||||
activewindow
|
||||
layers
|
||||
@@ -45,14 +51,63 @@ commands:
|
||||
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)
|
||||
)#";
|
||||
|
||||
#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);
|
||||
|
||||
@@ -68,20 +123,15 @@ 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";
|
||||
|
||||
strncpy(serverAddress.sun_path, socketPath.c_str(), sizeof(serverAddress.sun_path) - 1);
|
||||
|
||||
@@ -131,20 +181,15 @@ 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";
|
||||
|
||||
strncpy(serverAddress.sun_path, socketPath.c_str(), sizeof(serverAddress.sun_path) - 1);
|
||||
|
||||
@@ -153,6 +198,9 @@ void requestHyprpaper(std::string arg) {
|
||||
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) {
|
||||
@@ -174,92 +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 ";
|
||||
for (size_t i = 2; i < argc; ++i)
|
||||
rq += std::string(argv[i]) + " ";
|
||||
rq.pop_back();
|
||||
|
||||
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;
|
||||
|
||||
@@ -287,6 +285,8 @@ int main(int argc, char** 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) {
|
||||
if (ARGS[i] == "--") {
|
||||
@@ -298,8 +298,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;
|
||||
@@ -320,6 +330,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 || 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"))
|
||||
@@ -332,6 +371,8 @@ int main(int argc, char** argv) {
|
||||
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"))
|
||||
@@ -356,6 +397,8 @@ int main(int argc, char** argv) {
|
||||
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"))
|
||||
@@ -367,15 +410,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 {
|
||||
|
20
meson.build
20
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,6 +69,8 @@ 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
|
||||
@@ -96,5 +92,5 @@ import('pkgconfig').generate(
|
||||
url: 'https://github.com/hyprwm/Hyprland',
|
||||
description: 'Hyprland header files',
|
||||
install_dir: pkg_install_dir,
|
||||
subdirs: ['', 'hyprland/protocols'],
|
||||
subdirs: ['', 'hyprland/protocols', 'hyprland/wlroots'],
|
||||
)
|
||||
|
@@ -2,8 +2,10 @@
|
||||
lib,
|
||||
stdenv,
|
||||
pkg-config,
|
||||
makeWrapper,
|
||||
meson,
|
||||
ninja,
|
||||
binutils,
|
||||
cairo,
|
||||
git,
|
||||
hyprland-protocols,
|
||||
@@ -24,30 +26,28 @@
|
||||
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;
|
||||
# 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 debug "-debug";
|
||||
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
|
||||
);
|
||||
! (lib.hasSuffix ".nix" baseName);
|
||||
src = lib.cleanSource ../.;
|
||||
};
|
||||
|
||||
@@ -56,6 +56,8 @@ in
|
||||
meson
|
||||
ninja
|
||||
pkg-config
|
||||
makeWrapper
|
||||
wayland-scanner
|
||||
];
|
||||
|
||||
outputs = [
|
||||
@@ -77,9 +79,8 @@ in
|
||||
udis86
|
||||
wayland
|
||||
wayland-protocols
|
||||
wayland-scanner
|
||||
pciutils
|
||||
(wlroots.override {inherit enableXWayland hidpiXWayland nvidiaPatches;})
|
||||
(wlroots.override {inherit enableNvidiaPatches;})
|
||||
]
|
||||
++ lib.optionals enableXWayland [libxcb xcbutilwm xwayland]
|
||||
++ lib.optionals withSystemd [systemd];
|
||||
@@ -89,8 +90,9 @@ in
|
||||
then "debug"
|
||||
else "release";
|
||||
|
||||
mesonAutoFeatures = "disabled";
|
||||
|
||||
mesonFlags = builtins.concatLists [
|
||||
["-Dauto_features=disabled"]
|
||||
(lib.optional enableXWayland "-Dxwayland=enabled")
|
||||
(lib.optional legacyRenderer "-Dlegacy_renderer=enabled")
|
||||
(lib.optional withSystemd "-Dsystemd=enabled")
|
||||
@@ -98,21 +100,35 @@ in
|
||||
|
||||
patches = [
|
||||
# make meson use the provided wlroots instead of the git submodule
|
||||
./meson-build.patch
|
||||
./patches/meson-build.patch
|
||||
];
|
||||
|
||||
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@" '${
|
||||
|
||||
# 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; {
|
||||
|
@@ -7,10 +7,11 @@ self: {
|
||||
cfg = config.wayland.windowManager.hyprland;
|
||||
defaultHyprlandPackage = self.packages.${pkgs.stdenv.hostPlatform.system}.default.override {
|
||||
enableXWayland = cfg.xwayland.enable;
|
||||
hidpiXWayland = cfg.xwayland.hidpi;
|
||||
inherit (cfg) nvidiaPatches;
|
||||
inherit (cfg) enableNvidiaPatches;
|
||||
};
|
||||
in {
|
||||
disabledModules = ["services/window-managers/hyprland.nix"];
|
||||
|
||||
meta.maintainers = [lib.maintainers.fufexan];
|
||||
|
||||
options.wayland.windowManager.hyprland = {
|
||||
@@ -34,13 +35,12 @@ in {
|
||||
defaultText = lib.literalExpression ''
|
||||
hyprland.packages.''${pkgs.stdenv.hostPlatform.system}.default.override {
|
||||
enableXWayland = config.wayland.windowManager.hyprland.xwayland.enable;
|
||||
hidpiXWayland = config.wayland.windowManager.hyprland.xwayland.hidpi;
|
||||
inherit (config.wayland.windowManager.hyprland) nvidiaPatches;
|
||||
inherit (config.wayland.windowManager.hyprland) enableNvidiaPatches;
|
||||
}
|
||||
'';
|
||||
description = lib.mdDoc ''
|
||||
Hyprland package to use. Will override the 'xwayland' and
|
||||
'nvidiaPatches' options.
|
||||
'enableNvidiaPatches' options.
|
||||
|
||||
Defaults to the one provided by the flake. Set it to
|
||||
{package}`pkgs.hyprland` to use the one provided by nixpkgs or
|
||||
@@ -55,7 +55,7 @@ in {
|
||||
type = with lib.types; listOf (either package path);
|
||||
default = [];
|
||||
description = lib.mdDoc ''
|
||||
List of hyprlad plugins to use. Can either be packages or
|
||||
List of Hyprland plugins to use. Can either be packages or
|
||||
absolute plugin paths.
|
||||
'';
|
||||
};
|
||||
@@ -65,7 +65,7 @@ in {
|
||||
default = pkgs.stdenv.isLinux;
|
||||
description = lib.mdDoc ''
|
||||
Whether to enable {file}`hyprland-session.target` on
|
||||
hyprland startup. This links to {file}`graphical-session.target`.
|
||||
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
|
||||
- {env}`DISPLAY`
|
||||
@@ -84,19 +84,9 @@ in {
|
||||
'';
|
||||
};
|
||||
|
||||
xwayland = {
|
||||
enable = lib.mkEnableOption (lib.mdDoc "XWayland") // {default = true;};
|
||||
hidpi =
|
||||
lib.mkEnableOption null
|
||||
// {
|
||||
description = lib.mdDoc ''
|
||||
Enable HiDPI XWayland, based on [XWayland MR 733](https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/733).
|
||||
See <https://wiki.hyprland.org/Nix/Options-Overrides/#xwayland-hidpi> for more info.
|
||||
'';
|
||||
};
|
||||
};
|
||||
xwayland.enable = lib.mkEnableOption (lib.mdDoc "XWayland") // {default = true;};
|
||||
|
||||
nvidiaPatches = lib.mkEnableOption (lib.mdDoc "patching wlroots for better Nvidia support.");
|
||||
enableNvidiaPatches = lib.mkEnableOption (lib.mdDoc "patching wlroots for better Nvidia support.");
|
||||
|
||||
extraConfig = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.lines;
|
||||
@@ -117,10 +107,14 @@ in {
|
||||
|
||||
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.'' ]
|
||||
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 =
|
||||
@@ -136,9 +130,17 @@ in {
|
||||
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
|
||||
'')
|
||||
+ 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 "");
|
||||
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 =
|
||||
@@ -159,7 +161,7 @@ in {
|
||||
|
||||
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"];
|
||||
@@ -167,4 +169,9 @@ in {
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
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")
|
||||
];
|
||||
}
|
||||
|
@@ -1,8 +0,0 @@
|
||||
final: prev: let
|
||||
lib = final;
|
||||
|
||||
mkJoinedOverlays = overlays: final: prev:
|
||||
lib.foldl' (attrs: overlay: attrs // (overlay final prev)) {} overlays;
|
||||
in prev // {
|
||||
inherit mkJoinedOverlays;
|
||||
}
|
@@ -2,15 +2,15 @@ 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;
|
||||
inherit (cfg) nvidiaPatches;
|
||||
finalPortalPackage = cfg.portalPackage.override {
|
||||
hyprland = cfg.finalPackage;
|
||||
};
|
||||
in {
|
||||
# disables Nixpkgs Hyprland module to avoid conflicts
|
||||
@@ -30,69 +30,70 @@ in {
|
||||
'';
|
||||
};
|
||||
|
||||
package = mkOption {
|
||||
type = types.path;
|
||||
default = defaultHyprlandPackage;
|
||||
defaultText = literalExpression ''
|
||||
hyprland.packages.''${pkgs.stdenv.hostPlatform.system}.default.override {
|
||||
enableXWayland = config.programs.hyprland.xwayland.enable;
|
||||
hidpiXWayland = config.programs.hyprland.xwayland.hidpi;
|
||||
inherit (config.programs.hyprland) nvidiaPatches;
|
||||
}
|
||||
'';
|
||||
example = literalExpression "pkgs.hyprland";
|
||||
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;
|
||||
};
|
||||
defaultText =
|
||||
literalExpression
|
||||
"`programs.hyprland.package` with applied configuration";
|
||||
description = mdDoc ''
|
||||
The Hyprland package to use.
|
||||
Setting this option will make {option}`programs.hyprland.xwayland` and
|
||||
{option}`programs.hyprland.nvidiaPatches` not work.
|
||||
The Hyprland package after applying configuration.
|
||||
'';
|
||||
};
|
||||
|
||||
xwayland = {
|
||||
enable = mkEnableOption (mdDoc "XWayland") // {default = true;};
|
||||
hidpi =
|
||||
portalPackage = mkPackageOptionMD inputs.xdph.packages.${system} "xdg-desktop-portal-hyprland" {};
|
||||
|
||||
xwayland.enable = mkEnableOption (mdDoc "support for XWayland") // {default = true;};
|
||||
|
||||
enableNvidiaPatches =
|
||||
mkEnableOption null
|
||||
// {
|
||||
description = mdDoc ''
|
||||
Enable HiDPI XWayland, based on [XWayland MR 733](https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/733).
|
||||
See <https://wiki.hyprland.org/Nix/Options-Overrides/#xwayland-hidpi> for more info.
|
||||
'';
|
||||
description = mdDoc "Whether to apply patches to wlroots for better Nvidia support.";
|
||||
};
|
||||
};
|
||||
|
||||
nvidiaPatches = mkEnableOption (mdDoc "patching wlroots for better Nvidia support");
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
environment = {
|
||||
systemPackages = [cfg.package];
|
||||
environment.systemPackages = [cfg.finalPackage];
|
||||
|
||||
sessionVariables = {
|
||||
NIXOS_OZONE_WL = mkDefault "1";
|
||||
};
|
||||
};
|
||||
# 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;};
|
||||
|
||||
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 = [cfg.package];
|
||||
services.xserver.displayManager.sessionPackages = [cfg.finalPackage];
|
||||
|
||||
xdg.portal = {
|
||||
enable = mkDefault true;
|
||||
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"]
|
||||
)
|
||||
];
|
||||
};
|
||||
};
|
||||
}
|
||||
|
@@ -10,66 +10,62 @@
|
||||
(builtins.substring 4 2 longDate)
|
||||
(builtins.substring 6 2 longDate)
|
||||
]);
|
||||
|
||||
mkJoinedOverlays = overlays: final: prev:
|
||||
lib.foldl' (attrs: overlay: attrs // (overlay final prev)) {} overlays;
|
||||
in {
|
||||
# Packages for variations of Hyprland, and its dependencies.
|
||||
hyprland-packages = final: prev: {
|
||||
# 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 {
|
||||
version =
|
||||
props.version
|
||||
+ "+date="
|
||||
+ (mkDate (self.lastModifiedDate or "19700101"))
|
||||
+ "_"
|
||||
+ (self.shortRev or "dirty");
|
||||
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-hidpi = final.hyprland.override {hidpiXWayland = true;};
|
||||
hyprland-nvidia = final.hyprland.override {nvidiaPatches = true;};
|
||||
hyprland-no-hidpi =
|
||||
builtins.trace
|
||||
"hyprland-no-hidpi was removed. Please use the default package."
|
||||
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;
|
||||
|
||||
udis86 = final.callPackage ./udis86.nix {};
|
||||
};
|
||||
})
|
||||
];
|
||||
|
||||
# Packages for extra software recommended for usage with Hyprland,
|
||||
# including forked or patched packages for compatibility.
|
||||
hyprland-extras = lib.mkJoinedOverlays [
|
||||
# Include any inputs' specific overlays whose attributes should
|
||||
# be re-exported by the Hyprland flake.
|
||||
#
|
||||
inputs.xdph.overlays.default
|
||||
# Provides:
|
||||
# - xdg-desktop-portal-hyprland
|
||||
# - hyprland-share-picker
|
||||
#
|
||||
# Attributes for `hyprland-extras` defined by this flake can
|
||||
# go in the oberlay below.
|
||||
(final: prev: {
|
||||
waybar-hyprland = prev.waybar.overrideAttrs (old: {
|
||||
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 = old.mesonFlags ++ ["-Dexperimental=true"];
|
||||
});
|
||||
})
|
||||
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");
|
||||
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 {
|
||||
@@ -80,6 +76,7 @@ in {
|
||||
sha256 = "sha256-/q79o13Zvu7x02SBGu0W5yQznQ+p7ltZ9L6cMW5t/o4=";
|
||||
};
|
||||
});
|
||||
|
||||
libliftoff = prev.libliftoff.overrideAttrs (old: {
|
||||
version = "0.5.0-dev";
|
||||
src = final.fetchFromGitLab {
|
||||
|
@@ -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 [ "$CRT_VER" != "$NEW_VER" ]; then
|
||||
echo "Updating Mesa $CRT_VER -> $NEW_VER and flake inputs"
|
||||
|
||||
if [ "$SUB_REV" != "$CRT_REV" ]; then
|
||||
# update inputs to latest versions
|
||||
nix flake update
|
||||
|
||||
# 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
|
||||
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 ""
|
||||
);
|
||||
wlroots.overrideAttrs (old: {
|
||||
inherit version src enableXWayland;
|
||||
|
||||
pname = "${old.pname}-hyprland${lib.optionalString enableNvidiaPatches "-nvidia"}";
|
||||
|
||||
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=";
|
||||
})
|
||||
++ (lib.optionals enableNvidiaPatches [
|
||||
./patches/wlroots-nvidia.patch
|
||||
]);
|
||||
postPatch =
|
||||
(old.postPatch or "")
|
||||
+ (
|
||||
if nvidiaPatches
|
||||
then ''
|
||||
substituteInPlace render/gles2/renderer.c --replace "glFlush();" "glFinish();"
|
||||
''
|
||||
else ""
|
||||
);
|
||||
|
||||
buildInputs = old.buildInputs ++ [hwdata libliftoff libdisplay-info];
|
||||
|
||||
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
|
||||
]);
|
||||
});
|
||||
}
|
||||
})
|
||||
|
@@ -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.25.0"
|
||||
"version": "0.32.0"
|
||||
}
|
@@ -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>
|
@@ -22,12 +22,14 @@ 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'],
|
||||
|
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
|
File diff suppressed because it is too large
Load Diff
@@ -27,6 +27,7 @@
|
||||
#include "render/OpenGL.hpp"
|
||||
#include "hyprerror/HyprError.hpp"
|
||||
#include "plugins/PluginSystem.hpp"
|
||||
#include "helpers/Watchdog.hpp"
|
||||
|
||||
enum eManagersInitStage
|
||||
{
|
||||
@@ -53,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;
|
||||
@@ -61,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;
|
||||
@@ -84,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 = "";
|
||||
@@ -99,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;
|
||||
@@ -115,12 +121,15 @@ class CCompositor {
|
||||
bool m_bSessionActive = true;
|
||||
bool m_bDPMSStateON = true;
|
||||
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*);
|
||||
@@ -133,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*);
|
||||
@@ -150,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();
|
||||
@@ -165,11 +175,11 @@ 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*);
|
||||
@@ -191,6 +201,14 @@ class CCompositor {
|
||||
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;
|
||||
|
||||
@@ -198,6 +216,7 @@ class CCompositor {
|
||||
void initAllSignals();
|
||||
void setRandomSplash();
|
||||
void initManagers(eManagersInitStage stage);
|
||||
void prepareFallbackOutput();
|
||||
|
||||
uint64_t m_iHyprlandPID = 0;
|
||||
};
|
||||
|
@@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "helpers/Vector2D.hpp"
|
||||
|
||||
enum eIcons
|
||||
{
|
||||
ICON_WARNING = 0,
|
||||
@@ -20,4 +22,24 @@ enum eRenderStage
|
||||
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 floor() {
|
||||
return {topLeft.floor(), bottomRight.floor()};
|
||||
}
|
||||
};
|
459
src/Window.cpp
459
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);
|
||||
@@ -22,15 +23,19 @@ 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 {PMONITOR->vecPosition.x, PMONITOR->vecPosition.y, PMONITOR->vecSize.x, PMONITOR->vecSize.y};
|
||||
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 = {{*PBORDERSIZE + 2, *PBORDERSIZE + 2}, {*PBORDERSIZE + 2, *PBORDERSIZE + 2}};
|
||||
SWindowDecorationExtents maxExtents = {{BORDERSIZE + 2, BORDERSIZE + 2}, {BORDERSIZE + 2, BORDERSIZE + 2}};
|
||||
|
||||
for (auto& wd : m_dWindowDecorations) {
|
||||
|
||||
@@ -49,14 +54,55 @@ wlr_box CWindow::getFullWindowBoundingBox() {
|
||||
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,
|
||||
if (m_pWLSurface.exists() && !m_bIsX11) {
|
||||
CBox surfaceExtents = {0, 0, 0, 0};
|
||||
// TODO: this could be better, perhaps make a getFullWindowRegion?
|
||||
wlr_xdg_surface_for_each_popup_surface(
|
||||
m_uSurface.xdg,
|
||||
[](wlr_surface* surf, int sx, int sy, void* data) {
|
||||
CBox* pSurfaceExtents = (CBox*)data;
|
||||
if (sx < pSurfaceExtents->x)
|
||||
pSurfaceExtents->x = sx;
|
||||
if (sy < pSurfaceExtents->y)
|
||||
pSurfaceExtents->y = sy;
|
||||
if (sx + surf->current.width > pSurfaceExtents->width)
|
||||
pSurfaceExtents->width = sx + surf->current.width - pSurfaceExtents->x;
|
||||
if (sy + surf->current.height > pSurfaceExtents->height)
|
||||
pSurfaceExtents->height = sy + surf->current.height - pSurfaceExtents->y;
|
||||
},
|
||||
&surfaceExtents);
|
||||
|
||||
if (-surfaceExtents.x > maxExtents.topLeft.x)
|
||||
maxExtents.topLeft.x = -surfaceExtents.x;
|
||||
|
||||
if (-surfaceExtents.y > maxExtents.topLeft.y)
|
||||
maxExtents.topLeft.y = -surfaceExtents.y;
|
||||
|
||||
if (surfaceExtents.x + surfaceExtents.width > m_pWLSurface.wlr()->current.width + maxExtents.bottomRight.x)
|
||||
maxExtents.bottomRight.x = surfaceExtents.x + surfaceExtents.width - m_pWLSurface.wlr()->current.width;
|
||||
|
||||
if (surfaceExtents.y + surfaceExtents.height > m_pWLSurface.wlr()->current.height + maxExtents.bottomRight.y)
|
||||
maxExtents.bottomRight.y = surfaceExtents.y + surfaceExtents.height - m_pWLSurface.wlr()->current.height;
|
||||
}
|
||||
|
||||
return maxExtents;
|
||||
}
|
||||
|
||||
CBox CWindow::getFullWindowBoundingBox() {
|
||||
if (m_sAdditionalConfigData.dimAround) {
|
||||
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
|
||||
return {PMONITOR->vecPosition.x, PMONITOR->vecPosition.y, PMONITOR->vecSize.x, PMONITOR->vecSize.y};
|
||||
}
|
||||
|
||||
auto maxExtents = getFullWindowExtents();
|
||||
|
||||
CBox finalBox = {m_vRealPosition.vec().x - maxExtents.topLeft.x, m_vRealPosition.vec().y - maxExtents.topLeft.y,
|
||||
m_vRealSize.vec().x + maxExtents.topLeft.x + maxExtents.bottomRight.x, m_vRealSize.vec().y + maxExtents.topLeft.y + maxExtents.bottomRight.y};
|
||||
|
||||
return finalBox;
|
||||
}
|
||||
|
||||
wlr_box CWindow::getWindowIdealBoundingBoxIgnoreReserved() {
|
||||
CBox CWindow::getWindowIdealBoundingBoxIgnoreReserved() {
|
||||
|
||||
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
|
||||
|
||||
@@ -67,7 +113,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,22 +131,22 @@ 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) {
|
||||
|
||||
if (!wd->allowsInput())
|
||||
if (!(wd->getDecorationFlags() & DECORATION_ALLOWS_MOUSE_INPUT))
|
||||
continue;
|
||||
|
||||
const auto EXTENTS = wd->getWindowDecorationExtents();
|
||||
@@ -119,12 +165,16 @@ wlr_box CWindow::getWindowInputBox() {
|
||||
}
|
||||
|
||||
// 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,
|
||||
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;
|
||||
|
||||
@@ -145,16 +195,22 @@ void CWindow::updateWindowDecos() {
|
||||
for (auto& wd : m_dWindowDecorations)
|
||||
wd->updateWindow(this);
|
||||
|
||||
bool recalc = false;
|
||||
|
||||
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);
|
||||
recalc = true;
|
||||
if (it == m_dWindowDecorations.end())
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (recalc)
|
||||
g_pLayoutManager->getCurrentLayout()->recalculateWindow(this);
|
||||
|
||||
m_vDecosToRemove.clear();
|
||||
}
|
||||
|
||||
@@ -167,6 +223,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 +256,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 +327,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("%lx,%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,19 +362,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 (!m_bIsMapped)
|
||||
return;
|
||||
if (g_pCompositor->isWorkspaceSpecial(OLDWORKSPACE) && g_pCompositor->getWindowsOnWorkspace(OLDWORKSPACE) == 0 && *PCLOSEONLASTSPECIAL) {
|
||||
const auto PWS = g_pCompositor->getWorkspaceByID(OLDWORKSPACE);
|
||||
|
||||
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_pProtocolManager->m_pFractionalScaleProtocolManager->setPreferredScaleForSurface(surf, PMONITOR ? PMONITOR->scale : 1.f);
|
||||
},
|
||||
this);
|
||||
if (PWS) {
|
||||
if (const auto PMONITOR = g_pCompositor->getMonitorFromID(PWS->m_iMonitorID); PMONITOR)
|
||||
PMONITOR->setSpecialWorkspace(nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CWindow* CWindow::X11TransientFor() {
|
||||
@@ -337,6 +408,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;
|
||||
|
||||
@@ -356,11 +429,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();
|
||||
@@ -388,7 +473,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) {
|
||||
@@ -426,42 +514,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]);
|
||||
} else {
|
||||
if (vars[i] == "override") {
|
||||
if (i == 2) {
|
||||
int opacityIDX = 0;
|
||||
|
||||
for (auto& r : vars) {
|
||||
if (r == "opacity")
|
||||
continue;
|
||||
|
||||
if (r == "override") {
|
||||
if (opacityIDX == 1) {
|
||||
m_sSpecialRenderData.alphaOverride = true;
|
||||
} else {
|
||||
m_sSpecialRenderData.alphaInactiveOverride = true;
|
||||
}
|
||||
} else if (opacityIDX == 2)
|
||||
m_sSpecialRenderData.alphaInactiveOverride = true;
|
||||
} else {
|
||||
m_sSpecialRenderData.alphaInactive = std::stof(vars[i]);
|
||||
if (opacityIDX == 0) {
|
||||
m_sSpecialRenderData.alpha = std::stof(r);
|
||||
m_sSpecialRenderData.alphaInactive = std::stof(r);
|
||||
} else if (opacityIDX == 1) {
|
||||
m_sSpecialRenderData.alphaInactive = std::stof(r);
|
||||
m_sSpecialRenderData.alphaInactiveOverride = false;
|
||||
} else {
|
||||
throw std::runtime_error("more than 2 alpha values");
|
||||
}
|
||||
|
||||
opacityIDX++;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (std::exception& e) { Debug::log(ERR, "Opacity rule \"%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));
|
||||
|
||||
@@ -472,9 +580,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 (...) {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -486,6 +602,7 @@ 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;
|
||||
@@ -493,40 +610,45 @@ void CWindow::updateDynamicRules() {
|
||||
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;
|
||||
@@ -535,9 +657,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;
|
||||
}
|
||||
|
||||
@@ -554,6 +676,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;
|
||||
|
||||
m_dWindowDecorations.emplace_back(std::make_unique<CHyprGroupBarDecoration>(this));
|
||||
updateWindowDecos();
|
||||
|
||||
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)
|
||||
@@ -575,6 +760,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;
|
||||
@@ -602,7 +817,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);
|
||||
|
||||
@@ -618,34 +833,62 @@ void CWindow::setGroupCurrent(CWindow* pWindow) {
|
||||
|
||||
if (FULLSCREEN)
|
||||
g_pCompositor->setWindowFullscreen(pWindow, true, WORKSPACE->m_efFullscreenMode);
|
||||
|
||||
g_pHyprRenderer->damageWindow(pWindow);
|
||||
}
|
||||
|
||||
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->m_dWindowDecorations.emplace_back(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() {
|
||||
@@ -670,6 +913,17 @@ Vector2D CWindow::middle() {
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
@@ -677,9 +931,48 @@ bool CWindow::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)
|
||||
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;
|
||||
}
|
||||
|
114
src/Window.hpp
114
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,14 +8,32 @@
|
||||
#include "config/ConfigDataValues.hpp"
|
||||
#include "helpers/Vector2D.hpp"
|
||||
#include "helpers/WLSurface.hpp"
|
||||
#include "macros.hpp"
|
||||
#include "managers/XWaylandManager.hpp"
|
||||
|
||||
enum eIdleInhibitMode {
|
||||
enum eIdleInhibitMode
|
||||
{
|
||||
IDLEINHIBIT_NONE = 0,
|
||||
IDLEINHIBIT_ALWAYS,
|
||||
IDLEINHIBIT_FULLSCREEN,
|
||||
IDLEINHIBIT_FOCUS
|
||||
};
|
||||
|
||||
enum eGroupRules
|
||||
{
|
||||
// effective only during first map, except for _ALWAYS variant
|
||||
GROUP_NONE = 0,
|
||||
GROUP_SET = 1 << 0, // Open as new group or add to focused group
|
||||
GROUP_SET_ALWAYS = 1 << 1,
|
||||
GROUP_BARRED = 1 << 2, // Don't insert to focused group.
|
||||
GROUP_LOCK = 1 << 3, // Lock m_sGroupData.lock
|
||||
GROUP_LOCK_ALWAYS = 1 << 4,
|
||||
GROUP_INVADE = 1 << 5, // Force enter a group, event if lock is engaged
|
||||
GROUP_OVERRIDE = 1 << 6, // Override other rules
|
||||
};
|
||||
|
||||
class IWindowTransformer;
|
||||
|
||||
template <typename T>
|
||||
class CWindowOverridableVar {
|
||||
public:
|
||||
@@ -100,10 +117,11 @@ struct SWindowSpecialRenderData {
|
||||
CWindowOverridableVar<int64_t> inactiveBorderColor = -1; // -1 means unset
|
||||
|
||||
// set by the layout
|
||||
int borderSize = -1;
|
||||
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,8 @@ class CWindow {
|
||||
DYNLISTENER(toplevelActivate);
|
||||
DYNLISTENER(toplevelFullscreen);
|
||||
DYNLISTENER(setOverrideRedirect);
|
||||
DYNLISTENER(associateX11);
|
||||
DYNLISTENER(dissociateX11);
|
||||
// DYNLISTENER(newSubsurfaceWindow);
|
||||
|
||||
CWLSurface m_pWLSurface;
|
||||
@@ -179,6 +206,7 @@ class CWindow {
|
||||
// for not spamming the protocols
|
||||
Vector2D m_vReportedPosition;
|
||||
Vector2D m_vReportedSize;
|
||||
Vector2D m_vPendingReportedSize;
|
||||
|
||||
// for restoring floating statuses
|
||||
Vector2D m_vLastFloatingSize;
|
||||
@@ -188,7 +216,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 +242,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;
|
||||
|
||||
@@ -238,6 +268,7 @@ class CWindow {
|
||||
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 +293,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 +308,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 +322,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,9 +336,11 @@ class CWindow {
|
||||
}
|
||||
|
||||
// methods
|
||||
wlr_box getFullWindowBoundingBox();
|
||||
wlr_box getWindowInputBox();
|
||||
wlr_box getWindowIdealBoundingBoxIgnoreReserved();
|
||||
CBox getFullWindowBoundingBox();
|
||||
SWindowDecorationExtents getFullWindowExtents();
|
||||
CBox getWindowInputBox();
|
||||
CBox getWindowMainSurfaceBox();
|
||||
CBox getWindowIdealBoundingBoxIgnoreReserved();
|
||||
void updateWindowDecos();
|
||||
pid_t getPID();
|
||||
IHyprWindowDecoration* getDecorationByType(eDecorationType);
|
||||
@@ -316,19 +360,73 @@ class CWindow {
|
||||
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
@@ -11,14 +11,16 @@
|
||||
#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]}
|
||||
|
||||
@@ -34,29 +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 {
|
||||
@@ -78,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();
|
||||
@@ -148,19 +92,24 @@ 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*);
|
||||
@@ -168,6 +117,7 @@ class CConfigManager {
|
||||
|
||||
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*);
|
||||
@@ -177,6 +127,7 @@ class CConfigManager {
|
||||
std::unordered_map<std::string, SAnimationPropertyConfig> getAnimationConfig();
|
||||
|
||||
void addPluginConfigVar(HANDLE handle, const std::string& name, const SConfigValue& value);
|
||||
void addPluginKeyword(HANDLE handle, const std::string& name, std::function<void(const std::string& cmd, const std::string& val)> fun);
|
||||
void removePluginConfig(HANDLE handle);
|
||||
|
||||
// no-op when done.
|
||||
@@ -216,17 +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<int, SWorkspaceRule> m_mWorkspaceRules;
|
||||
std::deque<SWorkspaceRule> m_dWorkspaceRules;
|
||||
std::deque<SWindowRule> m_dWindowRules;
|
||||
std::deque<SLayerRule> m_dLayerRules;
|
||||
std::deque<std::string> m_dBlurLSNamespaces;
|
||||
@@ -237,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();
|
||||
@@ -249,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&);
|
||||
|
@@ -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 && !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,20 +105,18 @@ 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#%lu | %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());
|
||||
@@ -136,7 +129,7 @@ void CrashReporter::createAndSaveCrash(int sig) {
|
||||
|
||||
std::ofstream ofs;
|
||||
std::string path;
|
||||
if (!CACHE_HOME) {
|
||||
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);
|
||||
@@ -145,7 +138,7 @@ void CrashReporter::createAndSaveCrash(int sig) {
|
||||
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);
|
||||
@@ -153,8 +146,6 @@ void CrashReporter::createAndSaveCrash(int sig) {
|
||||
|
||||
path = std::string(CACHE_HOME) + "/hyprland/hyprlandCrashReport" + std::to_string(PID) + ".txt";
|
||||
ofs.open(path, std::ios::trunc);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
ofs << finalCrashReport;
|
||||
@@ -162,5 +153,5 @@ void CrashReporter::createAndSaveCrash(int sig) {
|
||||
ofs.close();
|
||||
|
||||
Debug::disableStdout = false;
|
||||
Debug::log(CRIT, "Hyprland has crashed :( Consult the crash report at %s for more information.", path.c_str());
|
||||
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,95 +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
|
||||
#ifndef GIT_TAG
|
||||
#define GIT_TAG "?"
|
||||
#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 %lx", 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 %lx", 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 %lx", 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,8 @@ namespace Events {
|
||||
DYNLISTENFUNC(requestMinimize);
|
||||
DYNLISTENFUNC(requestMaximize);
|
||||
DYNLISTENFUNC(setOverrideRedirect);
|
||||
DYNLISTENFUNC(associateX11);
|
||||
DYNLISTENFUNC(dissociateX11);
|
||||
|
||||
// Window subsurfaces
|
||||
// LISTENER(newSubsurfaceWindow);
|
||||
@@ -101,6 +104,7 @@ namespace Events {
|
||||
DYNLISTENFUNC(monitorDamage);
|
||||
DYNLISTENFUNC(monitorNeedsFrame);
|
||||
DYNLISTENFUNC(monitorCommit);
|
||||
DYNLISTENFUNC(monitorBind);
|
||||
|
||||
// XWayland
|
||||
LISTENER(readyXWayland);
|
||||
@@ -164,4 +168,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 %lx (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 %lx destroyed", layersurface->layerSurface);
|
||||
Debug::log(LOG, "LayerSurface {:x} destroyed", (uintptr_t)layersurface->layerSurface);
|
||||
|
||||
const auto PMONITOR = g_pCompositor->getMonitorFromID(layersurface->monitorID);
|
||||
|
||||
@@ -95,7 +95,7 @@ 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,
|
||||
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,11 +107,10 @@ void Events::listener_destroyLayerSurface(void* owner, void* data) {
|
||||
void Events::listener_mapLayerSurface(void* owner, void* data) {
|
||||
SLayerSurface* layersurface = (SLayerSurface*)owner;
|
||||
|
||||
Debug::log(LOG, "LayerSurface %lx mapped", layersurface->layerSurface);
|
||||
Debug::log(LOG, "LayerSurface {:x} mapped", (uintptr_t)layersurface->layerSurface);
|
||||
|
||||
layersurface->layerSurface->mapped = true;
|
||||
layersurface->mapped = true;
|
||||
|
||||
layersurface->keyboardExclusive = layersurface->layerSurface->current.keyboard_interactive;
|
||||
layersurface->surface = layersurface->layerSurface->surface;
|
||||
|
||||
// anim
|
||||
@@ -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,
|
||||
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 %lx 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,7 +247,7 @@ 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,
|
||||
CBox geomFixed = {layersurface->geometry.x + PMONITOR->vecPosition.x, layersurface->geometry.y + PMONITOR->vecPosition.y, layersurface->geometry.width,
|
||||
layersurface->geometry.height};
|
||||
g_pHyprRenderer->damageBox(&geomFixed);
|
||||
|
||||
@@ -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 %lx", 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 %lx", 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 %lx.", 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");
|
||||
}
|
||||
|
@@ -28,9 +28,9 @@ void Events::listener_change(wl_listener* listener, void* data) {
|
||||
|
||||
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;
|
||||
@@ -39,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;
|
||||
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);
|
||||
@@ -58,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;
|
||||
}
|
||||
}
|
||||
|
||||
if (!PNEWMONITORWRAP) {
|
||||
Debug::log(LOG, "Adding completely new monitor.");
|
||||
PNEWMONITORWRAP = &g_pCompositor->m_vRealMonitors.emplace_back(std::make_shared<CMonitor>());
|
||||
if (std::string("HEADLESS-1") == OUTPUT->name)
|
||||
g_pCompositor->m_pUnsafeOutput = PNEWMONITORWRAP->get();
|
||||
|
||||
(*PNEWMONITORWRAP)->ID = g_pCompositor->getNextAvailableMonitorID();
|
||||
}
|
||||
|
||||
(*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;
|
||||
|
||||
PNEWMONITOR->output = OUTPUT;
|
||||
PNEWMONITOR->m_pThisWrap = PNEWMONITORWRAP;
|
||||
|
||||
if (!FALLBACK)
|
||||
PNEWMONITOR->onConnect(false);
|
||||
|
||||
if (!PNEWMONITOR->m_bEnabled || FALLBACK)
|
||||
return;
|
||||
|
||||
// ready to process if we have a real monitor
|
||||
|
||||
if ((!g_pHyprRenderer->m_pMostHzMonitor || PNEWMONITOR->refreshRate > g_pHyprRenderer->m_pMostHzMonitor->refreshRate) && PNEWMONITOR->m_bEnabled)
|
||||
g_pHyprRenderer->m_pMostHzMonitor = PNEWMONITOR;
|
||||
|
||||
// ready to process cuz we have a monitor
|
||||
if (PNEWMONITOR->m_bEnabled) {
|
||||
g_pCompositor->m_bReadyToProcess = true;
|
||||
g_pCompositor->m_bUnsafeState = false;
|
||||
}
|
||||
|
||||
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 {
|
||||
@@ -120,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)
|
||||
}
|
||||
@@ -129,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);
|
||||
@@ -178,20 +193,17 @@ 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; });
|
||||
}
|
||||
}
|
||||
|
||||
void Events::listener_monitorStateRequest(void* owner, void* data) {
|
||||
const auto PMONITOR = (CMonitor*)owner;
|
||||
@@ -218,5 +230,12 @@ void Events::listener_monitorCommit(void* owner, void* data) {
|
||||
|
||||
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 %lx", 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 %lx -> %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 %lx -> %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 %lx", 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,15 +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);
|
||||
|
||||
if (PPOPUP->monitor)
|
||||
g_pProtocolManager->m_pFractionalScaleProtocolManager->setPreferredScaleForSurface(PPOPUP->popup->base->surface, PPOPUP->monitor->scale);
|
||||
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 %lx", PPOPUP->pSurfaceTree);
|
||||
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) {
|
||||
@@ -184,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);
|
||||
|
||||
@@ -202,9 +228,23 @@ void Events::listener_unmapPopupXDG(void* owner, void* data) {
|
||||
void Events::listener_commitPopupXDG(void* owner, void* data) {
|
||||
SXDGPopup* PPOPUP = (SXDGPopup*)owner;
|
||||
|
||||
if (g_pCompositor->windowValidMapped(PPOPUP->parentWindow)) {
|
||||
PPOPUP->lx = PPOPUP->parentWindow->m_vRealPosition.vec().x;
|
||||
PPOPUP->ly = PPOPUP->parentWindow->m_vRealPosition.vec().y;
|
||||
}
|
||||
|
||||
int lx = 0, ly = 0;
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -213,7 +253,7 @@ void Events::listener_destroyPopupXDG(void* owner, void* data) {
|
||||
|
||||
ASSERT(PPOPUP);
|
||||
|
||||
Debug::log(LOG, "Destroyed popup XDG %lx", PPOPUP);
|
||||
Debug::log(LOG, "Destroyed popup XDG {:x}", (uintptr_t)PPOPUP);
|
||||
|
||||
if (PPOPUP->pSurfaceTree) {
|
||||
SubsurfaceTree::destroySurfaceTree(PPOPUP->pSurfaceTree);
|
||||
|
@@ -46,6 +46,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
static auto* const PSWALLOW = &g_pConfigManager->getConfigValuePtr("misc:enable_swallow")->intValue;
|
||||
static auto* const PSWALLOWREGEX = &g_pConfigManager->getConfigValuePtr("misc:swallow_regex")->strValue;
|
||||
static auto* const PSWALLOWEXREGEX = &g_pConfigManager->getConfigValuePtr("misc:swallow_exception_regex")->strValue;
|
||||
static auto* const PNEWTAKESOVERFS = &g_pConfigManager->getConfigValuePtr("misc:new_window_takes_over_fullscreen")->intValue;
|
||||
|
||||
auto PMONITOR = g_pCompositor->m_pLastMonitor;
|
||||
const auto PWORKSPACE =
|
||||
@@ -58,6 +59,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
PWINDOW->m_bFadingOut = false;
|
||||
PWINDOW->m_szTitle = g_pXWaylandManager->getTitle(PWINDOW);
|
||||
PWINDOW->m_iX11Type = PWINDOW->m_bIsX11 ? (PWINDOW->m_uSurface.xwayland->override_redirect ? 2 : 1) : 1;
|
||||
PWINDOW->m_bFirstMap = true;
|
||||
|
||||
if (g_pInputManager->m_bLastFocusOnLS) // waybar fix
|
||||
g_pInputManager->releaseAllMouseButtons();
|
||||
@@ -94,7 +96,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
|
||||
if (PWORKSPACE->m_bDefaultPseudo) {
|
||||
PWINDOW->m_bIsPseudotiled = true;
|
||||
wlr_box desiredGeometry = {0};
|
||||
CBox desiredGeometry = {0};
|
||||
g_pXWaylandManager->getGeometryForWindow(PWINDOW, &desiredGeometry);
|
||||
PWINDOW->m_vPseudoSize = Vector2D(desiredGeometry.width, desiredGeometry.height);
|
||||
}
|
||||
@@ -108,14 +110,14 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
(PWINDOW->m_bIsX11 && PWINDOW->m_uSurface.xwayland->fullscreen);
|
||||
bool requestsFakeFullscreen = false;
|
||||
bool requestsMaximize = false;
|
||||
bool shouldFocus = true;
|
||||
bool workspaceSpecial = false;
|
||||
bool overridingNoFullscreen = false;
|
||||
bool overridingNoMaximize = false;
|
||||
|
||||
PWINDOW->m_szInitialTitle = g_pXWaylandManager->getTitle(PWINDOW);
|
||||
PWINDOW->m_szInitialClass = g_pXWaylandManager->getAppIDClass(PWINDOW);
|
||||
|
||||
for (auto& r : WINDOWRULES) {
|
||||
if (r.szRule.find("monitor") == 0) {
|
||||
if (r.szRule.starts_with("monitor")) {
|
||||
try {
|
||||
const auto MONITORSTR = removeBeginEndSpacesTabs(r.szRule.substr(r.szRule.find(' ')));
|
||||
|
||||
@@ -133,21 +135,23 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
if (PMONITOR)
|
||||
PWINDOW->m_iMonitorID = PMONITOR->ID;
|
||||
else {
|
||||
Debug::log(ERR, "No monitor in monitor %s rule", MONITORSTR.c_str());
|
||||
Debug::log(ERR, "No monitor in monitor {} rule", MONITORSTR);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PWINDOW->m_iWorkspaceID = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID)->activeWorkspace;
|
||||
const auto PMONITORFROMID = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID);
|
||||
|
||||
if (PWINDOW->m_iMonitorID != PMONITOR->ID) {
|
||||
g_pKeybindManager->m_mDispatchers["focusmonitor"](std::to_string(PWINDOW->m_iMonitorID));
|
||||
PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID);
|
||||
PMONITOR = PMONITORFROMID;
|
||||
}
|
||||
PWINDOW->m_iWorkspaceID = PMONITOR->specialWorkspaceID ? PMONITOR->specialWorkspaceID : PMONITOR->activeWorkspace;
|
||||
|
||||
Debug::log(ERR, "Rule monitor, applying to window %lx -> mon: %i, workspace: %i", PWINDOW, PWINDOW->m_iMonitorID, PWINDOW->m_iWorkspaceID);
|
||||
} catch (std::exception& e) { Debug::log(ERR, "Rule monitor failed, rule: %s -> %s | err: %s", r.szRule.c_str(), r.szValue.c_str(), e.what()); }
|
||||
} else if (r.szRule.find("workspace") == 0) {
|
||||
Debug::log(LOG, "Rule monitor, applying to {:mw}", PWINDOW);
|
||||
} catch (std::exception& e) { Debug::log(ERR, "Rule monitor failed, rule: {} -> {} | err: {}", r.szRule, r.szValue, e.what()); }
|
||||
} else if (r.szRule.starts_with("workspace")) {
|
||||
// check if it isnt unset
|
||||
const auto WORKSPACERQ = r.szRule.substr(r.szRule.find_first_of(' ') + 1);
|
||||
|
||||
@@ -162,21 +166,24 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
if (JUSTWORKSPACE == PWORKSPACE->m_szName || JUSTWORKSPACE == "name:" + PWORKSPACE->m_szName)
|
||||
requestedWorkspace = "";
|
||||
|
||||
Debug::log(LOG, "Rule workspace matched by window %lx, %s applied.", PWINDOW, r.szValue.c_str());
|
||||
} else if (r.szRule.find("float") == 0) {
|
||||
Debug::log(LOG, "Rule workspace matched by {}, {} applied.", PWINDOW, r.szValue);
|
||||
} else if (r.szRule.starts_with("float")) {
|
||||
PWINDOW->m_bIsFloating = true;
|
||||
} else if (r.szRule.find("tile") == 0) {
|
||||
} else if (r.szRule.starts_with("tile")) {
|
||||
PWINDOW->m_bIsFloating = false;
|
||||
} else if (r.szRule.find("pseudo") == 0) {
|
||||
} else if (r.szRule.starts_with("pseudo")) {
|
||||
PWINDOW->m_bIsPseudotiled = true;
|
||||
} else if (r.szRule.find("nofocus") == 0) {
|
||||
} else if (r.szRule.starts_with("nofocus")) {
|
||||
PWINDOW->m_bNoFocus = true;
|
||||
} else if (r.szRule.find("noinitialfocus") == 0) {
|
||||
} else if (r.szRule.starts_with("noinitialfocus")) {
|
||||
PWINDOW->m_bNoInitialFocus = true;
|
||||
} else if (r.szRule.find("nofullscreenrequest") == 0) {
|
||||
} else if (r.szRule.starts_with("nofullscreenrequest")) {
|
||||
PWINDOW->m_bNoFullscreenRequest = true;
|
||||
} else if (r.szRule.starts_with("nomaximizerequest")) {
|
||||
PWINDOW->m_bNoMaximizeRequest = true;
|
||||
} else if (r.szRule == "fullscreen") {
|
||||
requestsFullscreen = true;
|
||||
overridingNoFullscreen = true;
|
||||
} else if (r.szRule == "fakefullscreen") {
|
||||
requestsFakeFullscreen = true;
|
||||
} else if (r.szRule == "windowdance") {
|
||||
@@ -189,7 +196,57 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
PWINDOW->m_bPinned = true;
|
||||
} else if (r.szRule == "maximize") {
|
||||
requestsMaximize = true;
|
||||
} else if (r.szRule.find("idleinhibit") == 0) {
|
||||
overridingNoMaximize = true;
|
||||
} else if (r.szRule == "stayfocused") {
|
||||
PWINDOW->m_bStayFocused = true;
|
||||
} else if (r.szRule.starts_with("group")) {
|
||||
if (PWINDOW->m_eGroupRules & GROUP_OVERRIDE)
|
||||
continue;
|
||||
|
||||
// `group` is a shorthand of `group set`
|
||||
if (removeBeginEndSpacesTabs(r.szRule) == "group") {
|
||||
PWINDOW->m_eGroupRules |= GROUP_SET;
|
||||
continue;
|
||||
}
|
||||
|
||||
CVarList vars(r.szRule, 0, 's');
|
||||
std::string vPrev = "";
|
||||
|
||||
for (auto const& v : vars) {
|
||||
if (v == "group")
|
||||
continue;
|
||||
|
||||
if (v == "set") {
|
||||
PWINDOW->m_eGroupRules |= GROUP_SET;
|
||||
} else if (v == "new") {
|
||||
// shorthand for `group barred set`
|
||||
PWINDOW->m_eGroupRules |= (GROUP_SET | GROUP_BARRED);
|
||||
} else if (v == "lock") {
|
||||
PWINDOW->m_eGroupRules |= GROUP_LOCK;
|
||||
} else if (v == "invade") {
|
||||
PWINDOW->m_eGroupRules |= GROUP_INVADE;
|
||||
} else if (v == "barred") {
|
||||
PWINDOW->m_eGroupRules |= GROUP_BARRED;
|
||||
} else if (v == "deny") {
|
||||
PWINDOW->m_sGroupData.deny = true;
|
||||
} else if (v == "override") {
|
||||
// Clear existing rules
|
||||
PWINDOW->m_eGroupRules = GROUP_OVERRIDE;
|
||||
} else if (v == "unset") {
|
||||
// Clear existing rules and stop processing
|
||||
PWINDOW->m_eGroupRules = GROUP_OVERRIDE;
|
||||
break;
|
||||
} else if (v == "always") {
|
||||
if (vPrev == "set" || vPrev == "group")
|
||||
PWINDOW->m_eGroupRules |= GROUP_SET_ALWAYS;
|
||||
else if (vPrev == "lock")
|
||||
PWINDOW->m_eGroupRules |= GROUP_LOCK_ALWAYS;
|
||||
else
|
||||
Debug::log(ERR, "windowrule `group` does not support `{} always`", vPrev);
|
||||
}
|
||||
vPrev = v;
|
||||
}
|
||||
} else if (r.szRule.starts_with("idleinhibit")) {
|
||||
auto IDLERULE = r.szRule.substr(r.szRule.find_first_of(' ') + 1);
|
||||
|
||||
if (IDLERULE == "none") {
|
||||
@@ -201,89 +258,49 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
} else if (IDLERULE == "fullscreen") {
|
||||
PWINDOW->m_eIdleInhibitMode = IDLEINHIBIT_FULLSCREEN;
|
||||
} else {
|
||||
Debug::log(ERR, "Rule idleinhibit: unknown mode %s", IDLERULE.c_str());
|
||||
Debug::log(ERR, "Rule idleinhibit: unknown mode {}", IDLERULE);
|
||||
}
|
||||
}
|
||||
PWINDOW->applyDynamicRule(r);
|
||||
}
|
||||
|
||||
CWindow* pFullscreenWindow = nullptr;
|
||||
if (PWORKSPACE->m_bHasFullscreenWindow && !PWINDOW->m_bIsFloating) {
|
||||
const auto PFULLWINDOW = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID);
|
||||
pFullscreenWindow = PFULLWINDOW;
|
||||
g_pCompositor->setWindowFullscreen(PFULLWINDOW, false, PWORKSPACE->m_efFullscreenMode);
|
||||
}
|
||||
PWINDOW->updateSpecialRenderData();
|
||||
|
||||
// disallow tiled pinned
|
||||
if (PWINDOW->m_bPinned && !PWINDOW->m_bIsFloating)
|
||||
PWINDOW->m_bPinned = false;
|
||||
|
||||
if (requestedWorkspace != "") {
|
||||
// process requested workspace
|
||||
if (requestedWorkspace.contains(' ')) {
|
||||
// check for silent
|
||||
if (requestedWorkspace.contains("silent")) {
|
||||
const CVarList WORKSPACEARGS = CVarList(requestedWorkspace, 0, ' ');
|
||||
|
||||
if (!WORKSPACEARGS[0].empty()) {
|
||||
if (WORKSPACEARGS[WORKSPACEARGS.size() - 1].starts_with("silent"))
|
||||
workspaceSilent = true;
|
||||
shouldFocus = false;
|
||||
|
||||
requestedWorkspace = requestedWorkspace.substr(0, requestedWorkspace.find_first_of(' '));
|
||||
}
|
||||
std::string requestedWorkspaceName;
|
||||
const int REQUESTEDWORKSPACEID = getWorkspaceIDFromString(WORKSPACEARGS.join(" ", 0, workspaceSilent ? WORKSPACEARGS.size() - 1 : 0), requestedWorkspaceName);
|
||||
|
||||
if (!shouldFocus && requestedWorkspace == std::to_string(PMONITOR->activeWorkspace))
|
||||
shouldFocus = true;
|
||||
}
|
||||
if (REQUESTEDWORKSPACEID != INT_MAX) {
|
||||
auto pWorkspace = g_pCompositor->getWorkspaceByID(REQUESTEDWORKSPACEID);
|
||||
|
||||
if (requestedWorkspace.find("special") == 0) {
|
||||
workspaceSpecial = true;
|
||||
if (!pWorkspace)
|
||||
pWorkspace = g_pCompositor->createNewWorkspace(REQUESTEDWORKSPACEID, PWINDOW->m_iMonitorID, requestedWorkspaceName);
|
||||
|
||||
PWINDOW->m_iWorkspaceID = pWorkspace->m_iID;
|
||||
PWINDOW->m_iMonitorID = pWorkspace->m_iMonitorID;
|
||||
|
||||
if (g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID)->specialWorkspaceID && !pWorkspace->m_bIsSpecialWorkspace)
|
||||
workspaceSilent = true;
|
||||
}
|
||||
|
||||
if (!workspaceSilent) {
|
||||
g_pKeybindManager->m_mDispatchers["workspace"](requestedWorkspace);
|
||||
|
||||
PWINDOW->m_iMonitorID = g_pCompositor->m_pLastMonitor->ID;
|
||||
PWINDOW->m_iWorkspaceID = g_pCompositor->m_pLastMonitor->activeWorkspace;
|
||||
if (pWorkspace->m_bIsSpecialWorkspace)
|
||||
g_pCompositor->getMonitorFromID(pWorkspace->m_iMonitorID)->setSpecialWorkspace(pWorkspace);
|
||||
else
|
||||
g_pKeybindManager->m_mDispatchers["workspace"](requestedWorkspaceName);
|
||||
|
||||
PMONITOR = g_pCompositor->m_pLastMonitor;
|
||||
}
|
||||
}
|
||||
|
||||
if (workspaceSilent) {
|
||||
// get the workspace
|
||||
|
||||
auto PWORKSPACE = g_pCompositor->getWorkspaceByString(requestedWorkspace);
|
||||
|
||||
if (!PWORKSPACE) {
|
||||
std::string workspaceName = "";
|
||||
int workspaceID = 0;
|
||||
|
||||
if (requestedWorkspace.find("name:") == 0) {
|
||||
workspaceName = requestedWorkspace.substr(5);
|
||||
workspaceID = g_pCompositor->getNextAvailableNamedWorkspace();
|
||||
} else if (workspaceSpecial) {
|
||||
workspaceName = "";
|
||||
workspaceID = getWorkspaceIDFromString(requestedWorkspace, workspaceName);
|
||||
} else {
|
||||
try {
|
||||
workspaceID = std::stoi(requestedWorkspace);
|
||||
} catch (...) {
|
||||
workspaceID = -1;
|
||||
Debug::log(ERR, "Invalid workspace requested in workspace silent rule!");
|
||||
}
|
||||
|
||||
if (workspaceID < 1) {
|
||||
workspaceID = -1; // means invalid
|
||||
}
|
||||
}
|
||||
|
||||
if (workspaceID != -1)
|
||||
PWORKSPACE = g_pCompositor->createNewWorkspace(workspaceID, PWINDOW->m_iMonitorID, workspaceName);
|
||||
}
|
||||
|
||||
if (PWORKSPACE) {
|
||||
PWINDOW->m_iWorkspaceID = PWORKSPACE->m_iID;
|
||||
PWINDOW->m_iMonitorID = PWORKSPACE->m_iMonitorID;
|
||||
}
|
||||
} else
|
||||
workspaceSilent = false;
|
||||
}
|
||||
|
||||
if (PWINDOW->m_bIsFloating) {
|
||||
@@ -292,7 +309,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
|
||||
// size and move rules
|
||||
for (auto& r : WINDOWRULES) {
|
||||
if (r.szRule.find("size") == 0) {
|
||||
if (r.szRule.starts_with("size")) {
|
||||
try {
|
||||
const auto VALUE = r.szRule.substr(r.szRule.find(' ') + 1);
|
||||
const auto SIZEXSTR = VALUE.substr(0, VALUE.find(' '));
|
||||
@@ -307,14 +324,14 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
std::clamp(MAXSIZE.y, 20.0, PMONITOR->vecSize.y) :
|
||||
(!SIZEYSTR.contains('%') ? std::stoi(SIZEYSTR) : std::stof(SIZEYSTR.substr(0, SIZEYSTR.length() - 1)) * 0.01 * PMONITOR->vecSize.y);
|
||||
|
||||
Debug::log(LOG, "Rule size, applying to window %lx", PWINDOW);
|
||||
Debug::log(LOG, "Rule size, applying to {}", PWINDOW);
|
||||
|
||||
PWINDOW->m_vRealSize = Vector2D(SIZEX, SIZEY);
|
||||
g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goalv());
|
||||
|
||||
PWINDOW->setHidden(false);
|
||||
} catch (...) { Debug::log(LOG, "Rule size failed, rule: %s -> %s", r.szRule.c_str(), r.szValue.c_str()); }
|
||||
} else if (r.szRule.find("minsize") == 0) {
|
||||
} catch (...) { Debug::log(LOG, "Rule size failed, rule: {} -> {}", r.szRule, r.szValue); }
|
||||
} else if (r.szRule.starts_with("minsize")) {
|
||||
try {
|
||||
const auto VALUE = r.szRule.substr(r.szRule.find(' ') + 1);
|
||||
const auto SIZEXSTR = VALUE.substr(0, VALUE.find(' '));
|
||||
@@ -327,8 +344,8 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goalv());
|
||||
|
||||
PWINDOW->setHidden(false);
|
||||
} catch (...) { Debug::log(LOG, "Rule minsize failed, rule: %s -> %s", r.szRule.c_str(), r.szValue.c_str()); }
|
||||
} else if (r.szRule.find("maxsize") == 0) {
|
||||
} catch (...) { Debug::log(LOG, "Rule minsize failed, rule: {} -> {}", r.szRule, r.szValue); }
|
||||
} else if (r.szRule.starts_with("maxsize")) {
|
||||
try {
|
||||
const auto VALUE = r.szRule.substr(r.szRule.find(' ') + 1);
|
||||
const auto SIZEXSTR = VALUE.substr(0, VALUE.find(' '));
|
||||
@@ -341,12 +358,17 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goalv());
|
||||
|
||||
PWINDOW->setHidden(false);
|
||||
} catch (...) { Debug::log(LOG, "Rule maxsize failed, rule: %s -> %s", r.szRule.c_str(), r.szValue.c_str()); }
|
||||
} else if (r.szRule.find("move") == 0) {
|
||||
} catch (...) { Debug::log(LOG, "Rule maxsize failed, rule: {} -> {}", r.szRule, r.szValue); }
|
||||
} else if (r.szRule.starts_with("move")) {
|
||||
try {
|
||||
auto value = r.szRule.substr(r.szRule.find(' ') + 1);
|
||||
|
||||
const bool CURSOR = value.find("cursor") == 0;
|
||||
const bool ONSCREEN = value.starts_with("onscreen");
|
||||
|
||||
if (ONSCREEN)
|
||||
value = value.substr(value.find_first_of(' ') + 1);
|
||||
|
||||
const bool CURSOR = value.starts_with("cursor");
|
||||
|
||||
if (CURSOR)
|
||||
value = value.substr(value.find_first_of(' ') + 1);
|
||||
@@ -357,8 +379,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
int posX = 0;
|
||||
int posY = 0;
|
||||
|
||||
if (POSXSTR.find("100%-") == 0) {
|
||||
const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID);
|
||||
if (POSXSTR.starts_with("100%-")) {
|
||||
const auto POSXRAW = POSXSTR.substr(5);
|
||||
posX =
|
||||
PMONITOR->vecSize.x - (!POSXRAW.contains('%') ? std::stoi(POSXRAW) : std::stof(POSXRAW.substr(0, POSXRAW.length() - 1)) * 0.01 * PMONITOR->vecSize.x);
|
||||
@@ -377,8 +398,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
}
|
||||
}
|
||||
|
||||
if (POSYSTR.find("100%-") == 0) {
|
||||
const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID);
|
||||
if (POSYSTR.starts_with("100%-")) {
|
||||
const auto POSYRAW = POSYSTR.substr(5);
|
||||
posY =
|
||||
PMONITOR->vecSize.y - (!POSYRAW.contains('%') ? std::stoi(POSYRAW) : std::stof(POSYRAW.substr(0, POSYRAW.length() - 1)) * 0.01 * PMONITOR->vecSize.y);
|
||||
@@ -397,14 +417,29 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
}
|
||||
}
|
||||
|
||||
Debug::log(LOG, "Rule move, applying to window %lx", PWINDOW);
|
||||
if (ONSCREEN) {
|
||||
int borderSize = PWINDOW->getRealBorderSize();
|
||||
|
||||
posX = std::clamp(posX, (int)(PMONITOR->vecReservedTopLeft.x + borderSize),
|
||||
(int)(PMONITOR->vecSize.x - PMONITOR->vecReservedBottomRight.x - PWINDOW->m_vRealSize.goalv().x - borderSize));
|
||||
|
||||
posY = std::clamp(posY, (int)(PMONITOR->vecReservedTopLeft.y + borderSize),
|
||||
(int)(PMONITOR->vecSize.y - PMONITOR->vecReservedBottomRight.y - PWINDOW->m_vRealSize.goalv().y - borderSize));
|
||||
}
|
||||
|
||||
Debug::log(LOG, "Rule move, applying to {}", PWINDOW);
|
||||
|
||||
PWINDOW->m_vRealPosition = Vector2D(posX, posY) + PMONITOR->vecPosition;
|
||||
|
||||
PWINDOW->setHidden(false);
|
||||
} catch (...) { Debug::log(LOG, "Rule move failed, rule: %s -> %s", r.szRule.c_str(), r.szValue.c_str()); }
|
||||
} else if (r.szRule == "center") {
|
||||
PWINDOW->m_vRealPosition = PMONITOR->vecPosition + PMONITOR->vecSize / 2.f - PWINDOW->m_vRealSize.goalv() / 2.f;
|
||||
} catch (...) { Debug::log(LOG, "Rule move failed, rule: {} -> {}", r.szRule, r.szValue); }
|
||||
} else if (r.szRule.starts_with("center")) {
|
||||
auto RESERVEDOFFSET = Vector2D();
|
||||
const auto ARGS = CVarList(r.szRule, 2, ' ');
|
||||
if (ARGS[1] == "1")
|
||||
RESERVEDOFFSET = (PMONITOR->vecReservedTopLeft - PMONITOR->vecReservedBottomRight) / 2.f;
|
||||
|
||||
PWINDOW->m_vRealPosition = PMONITOR->middle() - PWINDOW->m_vRealSize.goalv() / 2.f + RESERVEDOFFSET;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -412,7 +447,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
// because the windows are animated on RealSize
|
||||
PWINDOW->m_vPseudoSize = PWINDOW->m_vRealSize.goalv();
|
||||
|
||||
g_pCompositor->moveWindowToTop(PWINDOW);
|
||||
g_pCompositor->changeWindowZOrder(PWINDOW, true);
|
||||
} else {
|
||||
g_pLayoutManager->getCurrentLayout()->onWindowCreated(PWINDOW);
|
||||
|
||||
@@ -429,21 +464,33 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
}
|
||||
|
||||
// check LS focus grab
|
||||
const auto PFORCEFOCUS = g_pCompositor->getForceFocus();
|
||||
const auto PLSFROMFOCUS = g_pCompositor->getLayerSurfaceFromSurface(g_pCompositor->m_pLastFocus);
|
||||
if (PLSFROMFOCUS && PLSFROMFOCUS->layerSurface->current.keyboard_interactive)
|
||||
PWINDOW->m_bNoInitialFocus = true;
|
||||
if (PWORKSPACE->m_bHasFullscreenWindow && !requestsFullscreen && !PWINDOW->m_bIsFloating) {
|
||||
if (*PNEWTAKESOVERFS == 0)
|
||||
PWINDOW->m_bNoInitialFocus = true;
|
||||
else if (*PNEWTAKESOVERFS == 2)
|
||||
g_pCompositor->setWindowFullscreen(g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID), false, FULLSCREEN_INVALID);
|
||||
else if (PWORKSPACE->m_efFullscreenMode == FULLSCREEN_MAXIMIZED)
|
||||
requestsMaximize = true;
|
||||
else
|
||||
requestsFullscreen = true;
|
||||
}
|
||||
|
||||
if (!PWINDOW->m_bNoFocus && !PWINDOW->m_bNoInitialFocus &&
|
||||
(PWINDOW->m_iX11Type != 2 || (PWINDOW->m_bIsX11 && wlr_xwayland_or_surface_wants_focus(PWINDOW->m_uSurface.xwayland))) && !workspaceSilent) {
|
||||
(PWINDOW->m_iX11Type != 2 || (PWINDOW->m_bIsX11 && wlr_xwayland_or_surface_wants_focus(PWINDOW->m_uSurface.xwayland))) && !workspaceSilent &&
|
||||
(!PFORCEFOCUS || PFORCEFOCUS == PWINDOW)) {
|
||||
g_pCompositor->focusWindow(PWINDOW);
|
||||
PWINDOW->m_fActiveInactiveAlpha.setValueAndWarp(*PACTIVEALPHA);
|
||||
PWINDOW->m_fDimPercent.setValueAndWarp(*PDIMSTRENGTH);
|
||||
PWINDOW->m_fDimPercent.setValueAndWarp(PWINDOW->m_sAdditionalConfigData.forceNoDim ? 0.f : *PDIMSTRENGTH);
|
||||
} else {
|
||||
PWINDOW->m_fActiveInactiveAlpha.setValueAndWarp(*PINACTIVEALPHA);
|
||||
PWINDOW->m_fDimPercent.setValueAndWarp(0);
|
||||
}
|
||||
|
||||
Debug::log(LOG, "Window got assigned a surfaceTreeNode %lx", PWINDOW->m_pSurfaceTree);
|
||||
Debug::log(LOG, "Window got assigned a surfaceTreeNode {:x}", (uintptr_t)PWINDOW->m_pSurfaceTree);
|
||||
|
||||
if (!PWINDOW->m_bIsX11) {
|
||||
PWINDOW->hyprListener_commitWindow.initCallback(&PWINDOW->m_uSurface.xdg->surface->events.commit, &Events::listener_commitWindow, PWINDOW, "XDG Window Late");
|
||||
@@ -464,7 +511,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
PWINDOW->hyprListener_setTitleWindow.initCallback(&PWINDOW->m_uSurface.xwayland->events.set_title, &Events::listener_setTitleWindow, PWINDOW, "XWayland Window Late");
|
||||
PWINDOW->hyprListener_requestMinimize.initCallback(&PWINDOW->m_uSurface.xwayland->events.request_minimize, &Events::listener_requestMinimize, PWINDOW,
|
||||
"Xwayland Window Late");
|
||||
PWINDOW->hyprListener_requestMinimize.initCallback(&PWINDOW->m_uSurface.xwayland->events.request_maximize, &Events::listener_requestMaximize, PWINDOW,
|
||||
PWINDOW->hyprListener_requestMaximize.initCallback(&PWINDOW->m_uSurface.xwayland->events.request_maximize, &Events::listener_requestMaximize, PWINDOW,
|
||||
"Xwayland Window Late");
|
||||
|
||||
if (PWINDOW->m_iX11Type == 2)
|
||||
@@ -480,7 +527,8 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
PWINDOW->m_vRealPosition.setCallbackOnEnd(setAnimToMove);
|
||||
PWINDOW->m_vRealSize.setCallbackOnEnd(setAnimToMove);
|
||||
|
||||
if ((requestsFullscreen || requestsMaximize || requestsFakeFullscreen) && !PWINDOW->m_bNoFullscreenRequest) {
|
||||
if ((requestsFullscreen && (!PWINDOW->m_bNoFullscreenRequest || overridingNoFullscreen)) || (requestsMaximize && (!PWINDOW->m_bNoMaximizeRequest || overridingNoMaximize)) ||
|
||||
requestsFakeFullscreen) {
|
||||
// fix fullscreen on requested (basically do a switcheroo)
|
||||
if (PWORKSPACE->m_bHasFullscreenWindow) {
|
||||
const auto PFULLWINDOW = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID);
|
||||
@@ -491,16 +539,14 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
PWINDOW->m_bFakeFullscreenState = !PWINDOW->m_bFakeFullscreenState;
|
||||
g_pXWaylandManager->setWindowFullscreen(PWINDOW, true);
|
||||
} else {
|
||||
overridingNoFullscreen = false;
|
||||
overridingNoMaximize = false;
|
||||
PWINDOW->m_vRealPosition.warp();
|
||||
PWINDOW->m_vRealSize.warp();
|
||||
g_pCompositor->setWindowFullscreen(PWINDOW, true, requestsFullscreen ? FULLSCREEN_FULL : FULLSCREEN_MAXIMIZED);
|
||||
}
|
||||
}
|
||||
|
||||
if (pFullscreenWindow && workspaceSilent) {
|
||||
g_pCompositor->setWindowFullscreen(pFullscreenWindow, true, PWORKSPACE->m_efFullscreenMode);
|
||||
}
|
||||
|
||||
// recheck idle inhibitors
|
||||
g_pInputManager->recheckIdleInhibitorStatus();
|
||||
|
||||
@@ -508,7 +554,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
|
||||
PWINDOW->updateToplevel();
|
||||
|
||||
if (!shouldFocus) {
|
||||
if (workspaceSilent) {
|
||||
if (g_pCompositor->windowValidMapped(PFOCUSEDWINDOWPREV)) {
|
||||
g_pCompositor->focusWindow(PFOCUSEDWINDOWPREV);
|
||||
PFOCUSEDWINDOWPREV->updateWindowDecos(); // need to for some reason i cba to find out why
|
||||
@@ -578,38 +624,50 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
g_pLayoutManager->getCurrentLayout()->onWindowRemoved(finalFound);
|
||||
|
||||
finalFound->setHidden(true);
|
||||
|
||||
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PWINDOW->m_iMonitorID);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Debug::log(LOG, "Map request dispatched, monitor %s, xywh: %f %f %f %f", PMONITOR->szName.c_str(), PWINDOW->m_vRealPosition.goalv().x, PWINDOW->m_vRealPosition.goalv().y,
|
||||
PWINDOW->m_vRealSize.goalv().x, PWINDOW->m_vRealSize.goalv().y);
|
||||
PWINDOW->m_bFirstMap = false;
|
||||
|
||||
Debug::log(LOG, "Map request dispatched, monitor {}, window pos: {:5j}, window size: {:5j}", PMONITOR->szName, PWINDOW->m_vRealPosition.goalv(), PWINDOW->m_vRealSize.goalv());
|
||||
|
||||
auto workspaceID = requestedWorkspace != "" ? requestedWorkspace : PWORKSPACE->m_szName;
|
||||
g_pEventManager->postEvent(
|
||||
SHyprIPCEvent{"openwindow", getFormat("%lx,%s,%s,%s", PWINDOW, workspaceID.c_str(), g_pXWaylandManager->getAppIDClass(PWINDOW).c_str(), PWINDOW->m_szTitle.c_str())});
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{"openwindow", std::format("{:x},{},{},{}", PWINDOW, workspaceID, g_pXWaylandManager->getAppIDClass(PWINDOW), PWINDOW->m_szTitle)});
|
||||
EMIT_HOOK_EVENT("openWindow", PWINDOW);
|
||||
|
||||
// recalc the values for this window
|
||||
g_pCompositor->updateWindowAnimatedDecorationValues(PWINDOW);
|
||||
// avoid this window being visible
|
||||
if (PWORKSPACE->m_bHasFullscreenWindow && !PWINDOW->m_bIsFullscreen && !PWINDOW->m_bIsFloating)
|
||||
PWINDOW->m_fAlpha.setValueAndWarp(0.f);
|
||||
|
||||
g_pProtocolManager->m_pFractionalScaleProtocolManager->setPreferredScaleForSurface(PWINDOW->m_pWLSurface.wlr(), PMONITOR->scale);
|
||||
g_pCompositor->setPreferredScaleForSurface(PWINDOW->m_pWLSurface.wlr(), PMONITOR->scale);
|
||||
g_pCompositor->setPreferredTransformForSurface(PWINDOW->m_pWLSurface.wlr(), PMONITOR->transform);
|
||||
|
||||
if (g_pCompositor->vectorToWindowIdeal(g_pInputManager->getMouseCoordsInternal()) == g_pCompositor->m_pLastWindow)
|
||||
g_pInputManager->simulateMouseMovement();
|
||||
|
||||
// fix some xwayland apps that don't behave nicely
|
||||
PWINDOW->m_vReportedSize = PWINDOW->m_vPendingReportedSize;
|
||||
}
|
||||
|
||||
void Events::listener_unmapWindow(void* owner, void* data) {
|
||||
CWindow* PWINDOW = (CWindow*)owner;
|
||||
|
||||
Debug::log(LOG, "Window %lx unmapped (class %s)", PWINDOW, g_pXWaylandManager->getAppIDClass(PWINDOW).c_str());
|
||||
Debug::log(LOG, "{:c} unmapped", PWINDOW);
|
||||
|
||||
if (!PWINDOW->m_pWLSurface.exists() || !PWINDOW->m_bIsMapped) {
|
||||
Debug::log(WARN, "Window %lx unmapped without being mapped??", PWINDOW);
|
||||
Debug::log(WARN, "{} unmapped without being mapped??", PWINDOW);
|
||||
PWINDOW->m_bFadingOut = false;
|
||||
return;
|
||||
}
|
||||
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{"closewindow", getFormat("%lx", PWINDOW)});
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{"closewindow", std::format("{:x}", PWINDOW)});
|
||||
EMIT_HOOK_EVENT("closeWindow", PWINDOW);
|
||||
|
||||
g_pProtocolManager->m_pToplevelExportProtocolManager->onWindowUnmap(PWINDOW);
|
||||
@@ -634,8 +692,14 @@ void Events::listener_unmapWindow(void* owner, void* data) {
|
||||
PWINDOW->hyprListener_requestMinimize.removeCallback();
|
||||
}
|
||||
|
||||
if (PWINDOW->m_bIsFullscreen) {
|
||||
if (PWINDOW->m_bIsFullscreen)
|
||||
g_pCompositor->setWindowFullscreen(PWINDOW, false, FULLSCREEN_FULL);
|
||||
|
||||
const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID);
|
||||
if (PMONITOR) {
|
||||
PWINDOW->m_vOriginalClosedPos = PWINDOW->m_vRealPosition.vec() - PMONITOR->vecPosition;
|
||||
PWINDOW->m_vOriginalClosedSize = PWINDOW->m_vRealSize.vec();
|
||||
PWINDOW->m_eOriginalClosedExtents = PWINDOW->getFullWindowExtents();
|
||||
}
|
||||
|
||||
// Allow the renderer to catch the last frame.
|
||||
@@ -675,21 +739,25 @@ void Events::listener_unmapWindow(void* owner, void* data) {
|
||||
if (wasLastWindow) {
|
||||
const auto PWINDOWCANDIDATE = g_pLayoutManager->getCurrentLayout()->getNextWindowCandidate(PWINDOW);
|
||||
|
||||
Debug::log(LOG, "On closed window, new focused candidate is %lx", PWINDOWCANDIDATE);
|
||||
Debug::log(LOG, "On closed window, new focused candidate is {}", PWINDOWCANDIDATE);
|
||||
|
||||
if (PWINDOWCANDIDATE != g_pCompositor->m_pLastWindow) {
|
||||
if (!PWINDOWCANDIDATE)
|
||||
g_pInputManager->refocus();
|
||||
else
|
||||
if (PWINDOWCANDIDATE != g_pCompositor->m_pLastWindow && PWINDOWCANDIDATE)
|
||||
g_pCompositor->focusWindow(PWINDOWCANDIDATE);
|
||||
} else {
|
||||
g_pInputManager->refocus();
|
||||
|
||||
if (g_pCompositor->vectorToWindowIdeal(g_pInputManager->getMouseCoordsInternal()) == PWINDOWCANDIDATE)
|
||||
g_pInputManager->simulateMouseMovement();
|
||||
|
||||
// CWindow::onUnmap will remove this window's active status, but we can't really do it above.
|
||||
if (PWINDOW == g_pCompositor->m_pLastWindow || !g_pCompositor->m_pLastWindow) {
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{"activewindow", ","});
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{"activewindowv2", ","});
|
||||
EMIT_HOOK_EVENT("activeWindow", (CWindow*)nullptr);
|
||||
}
|
||||
} else {
|
||||
Debug::log(LOG, "Unmapped was not focused, ignoring a refocus.");
|
||||
}
|
||||
|
||||
Debug::log(LOG, "Destroying the SubSurface tree of unmapped window %lx", PWINDOW);
|
||||
Debug::log(LOG, "Destroying the SubSurface tree of unmapped window {}", PWINDOW);
|
||||
SubsurfaceTree::destroySurfaceTree(PWINDOW->m_pSurfaceTree);
|
||||
|
||||
PWINDOW->m_pSurfaceTree = nullptr;
|
||||
@@ -700,14 +768,6 @@ void Events::listener_unmapWindow(void* owner, void* data) {
|
||||
|
||||
g_pHyprRenderer->damageMonitor(g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID));
|
||||
|
||||
const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID);
|
||||
|
||||
// do the animation thing
|
||||
if (PMONITOR) {
|
||||
PWINDOW->m_vOriginalClosedPos = PWINDOW->m_vRealPosition.vec() - PMONITOR->vecPosition;
|
||||
PWINDOW->m_vOriginalClosedSize = PWINDOW->m_vRealSize.vec();
|
||||
}
|
||||
|
||||
if (!PWINDOW->m_bX11DoesntWantBorders) // don't animate out if they weren't animated in.
|
||||
PWINDOW->m_vRealPosition = PWINDOW->m_vRealPosition.vec() + Vector2D(0.01f, 0.01f); // it has to be animated, otherwise onWindowPostCreateClose will ignore it
|
||||
|
||||
@@ -734,20 +794,42 @@ void Events::listener_commitWindow(void* owner, void* data) {
|
||||
if (!PWINDOW->m_bMappedX11 || PWINDOW->isHidden() || (PWINDOW->m_bIsX11 && !PWINDOW->m_bMappedX11))
|
||||
return;
|
||||
|
||||
PWINDOW->m_vReportedSize = PWINDOW->m_vPendingReportedSize; // apply pending size. We pinged, the window ponged.
|
||||
|
||||
PWINDOW->updateSurfaceOutputs();
|
||||
|
||||
g_pHyprRenderer->damageSurface(PWINDOW->m_pWLSurface.wlr(), PWINDOW->m_vRealPosition.goalv().x, PWINDOW->m_vRealPosition.goalv().y);
|
||||
g_pHyprRenderer->damageSurface(PWINDOW->m_pWLSurface.wlr(), PWINDOW->m_vRealPosition.goalv().x, PWINDOW->m_vRealPosition.goalv().y,
|
||||
PWINDOW->m_bIsX11 ? 1.0 / PWINDOW->m_fX11SurfaceScaledBy : 1.0);
|
||||
|
||||
// Debug::log(LOG, "Window %lx committed", PWINDOW); // SPAM!
|
||||
if (PWINDOW->m_bIsX11 || !PWINDOW->m_bIsFloating || PWINDOW->m_bIsFullscreen)
|
||||
return;
|
||||
|
||||
const auto ISRIGID = PWINDOW->m_uSurface.xdg->toplevel->current.max_height == PWINDOW->m_uSurface.xdg->toplevel->current.min_height &&
|
||||
PWINDOW->m_uSurface.xdg->toplevel->current.max_width == PWINDOW->m_uSurface.xdg->toplevel->current.min_width;
|
||||
|
||||
if (!ISRIGID)
|
||||
return;
|
||||
|
||||
const Vector2D REQUESTEDSIZE = {PWINDOW->m_uSurface.xdg->toplevel->current.max_width, PWINDOW->m_uSurface.xdg->toplevel->current.max_height};
|
||||
|
||||
if (REQUESTEDSIZE == PWINDOW->m_vReportedSize || REQUESTEDSIZE.x < 5 || REQUESTEDSIZE.y < 5)
|
||||
return;
|
||||
|
||||
const Vector2D DELTA = PWINDOW->m_vReportedSize - REQUESTEDSIZE;
|
||||
|
||||
PWINDOW->m_vRealPosition = PWINDOW->m_vRealPosition.goalv() + DELTA / 2.0;
|
||||
PWINDOW->m_vRealSize = REQUESTEDSIZE;
|
||||
g_pXWaylandManager->setWindowSize(PWINDOW, REQUESTEDSIZE, true);
|
||||
g_pHyprRenderer->damageWindow(PWINDOW);
|
||||
}
|
||||
|
||||
void Events::listener_destroyWindow(void* owner, void* data) {
|
||||
CWindow* PWINDOW = (CWindow*)owner;
|
||||
|
||||
Debug::log(LOG, "Window %lx destroyed, queueing. (class %s)", PWINDOW, g_pXWaylandManager->getAppIDClass(PWINDOW).c_str());
|
||||
Debug::log(LOG, "{:c} destroyed, queueing.", PWINDOW);
|
||||
|
||||
if (PWINDOW->m_bIsX11)
|
||||
Debug::log(LOG, "XWayland class raw: %s", PWINDOW->m_uSurface.xwayland->_class);
|
||||
Debug::log(LOG, "XWayland class raw: {}", PWINDOW->m_uSurface.xwayland->_class ? PWINDOW->m_uSurface.xwayland->_class : "null");
|
||||
|
||||
if (PWINDOW == g_pCompositor->m_pLastWindow) {
|
||||
g_pCompositor->m_pLastWindow = nullptr;
|
||||
@@ -759,11 +841,13 @@ void Events::listener_destroyWindow(void* owner, void* data) {
|
||||
PWINDOW->hyprListener_destroyWindow.removeCallback();
|
||||
PWINDOW->hyprListener_configureX11.removeCallback();
|
||||
PWINDOW->hyprListener_setOverrideRedirect.removeCallback();
|
||||
PWINDOW->hyprListener_associateX11.removeCallback();
|
||||
PWINDOW->hyprListener_dissociateX11.removeCallback();
|
||||
|
||||
g_pLayoutManager->getCurrentLayout()->onWindowRemoved(PWINDOW);
|
||||
|
||||
if (PWINDOW->m_pSurfaceTree) {
|
||||
Debug::log(LOG, "Destroying Subsurface tree of %lx in destroyWindow", PWINDOW);
|
||||
Debug::log(LOG, "Destroying Subsurface tree of {} in destroyWindow", PWINDOW);
|
||||
SubsurfaceTree::destroySurfaceTree(PWINDOW->m_pSurfaceTree);
|
||||
PWINDOW->m_pSurfaceTree = nullptr;
|
||||
}
|
||||
@@ -771,8 +855,8 @@ void Events::listener_destroyWindow(void* owner, void* data) {
|
||||
PWINDOW->m_bReadyToDelete = true;
|
||||
|
||||
if (!PWINDOW->m_bFadingOut) {
|
||||
Debug::log(LOG, "Unmapped {} removed instantly", PWINDOW);
|
||||
g_pCompositor->removeWindowFromVectorSafe(PWINDOW); // most likely X11 unmanaged or sumn
|
||||
Debug::log(LOG, "Unmapped window %lx removed instantly", PWINDOW);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -783,10 +867,12 @@ void Events::listener_setTitleWindow(void* owner, void* data) {
|
||||
return;
|
||||
|
||||
PWINDOW->m_szTitle = g_pXWaylandManager->getTitle(PWINDOW);
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{"windowtitle", std::format("{:x}", (uintptr_t)PWINDOW)});
|
||||
EMIT_HOOK_EVENT("windowTitle", PWINDOW);
|
||||
|
||||
if (PWINDOW == g_pCompositor->m_pLastWindow) { // if it's the active, let's post an event to update others
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{"activewindow", g_pXWaylandManager->getAppIDClass(PWINDOW) + "," + PWINDOW->m_szTitle});
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{"activewindowv2", getFormat("%lx", PWINDOW)});
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{"activewindowv2", std::format("{:x}", (uintptr_t)PWINDOW)});
|
||||
EMIT_HOOK_EVENT("activeWindow", PWINDOW);
|
||||
}
|
||||
|
||||
@@ -794,7 +880,7 @@ void Events::listener_setTitleWindow(void* owner, void* data) {
|
||||
g_pCompositor->updateWindowAnimatedDecorationValues(PWINDOW);
|
||||
PWINDOW->updateToplevel();
|
||||
|
||||
Debug::log(LOG, "Window %lx set title to %s", PWINDOW, PWINDOW->m_szTitle.c_str());
|
||||
Debug::log(LOG, "Window {:x} set title to {}", PWINDOW, PWINDOW->m_szTitle);
|
||||
}
|
||||
|
||||
void Events::listener_fullscreenWindow(void* owner, void* data) {
|
||||
@@ -837,7 +923,7 @@ void Events::listener_fullscreenWindow(void* owner, void* data) {
|
||||
|
||||
wlr_xdg_surface_schedule_configure(PWINDOW->m_uSurface.xdg);
|
||||
} else {
|
||||
if (!PWINDOW->m_uSurface.xwayland->mapped)
|
||||
if (!PWINDOW->m_uSurface.xwayland->surface->mapped)
|
||||
return;
|
||||
|
||||
if (!PWINDOW->m_bFakeFullscreenState)
|
||||
@@ -853,7 +939,7 @@ void Events::listener_fullscreenWindow(void* owner, void* data) {
|
||||
|
||||
PWINDOW->updateToplevel();
|
||||
|
||||
Debug::log(LOG, "Window %lx fullscreen to %i", PWINDOW, PWINDOW->m_bIsFullscreen);
|
||||
Debug::log(LOG, "{} fullscreen to {}", PWINDOW, PWINDOW->m_bIsFullscreen);
|
||||
}
|
||||
|
||||
void Events::listener_activateXDG(wl_listener* listener, void* data) {
|
||||
@@ -861,7 +947,7 @@ void Events::listener_activateXDG(wl_listener* listener, void* data) {
|
||||
|
||||
static auto* const PFOCUSONACTIVATE = &g_pConfigManager->getConfigValuePtr("misc:focus_on_activate")->intValue;
|
||||
|
||||
Debug::log(LOG, "Activate request for surface at %lx", E->surface);
|
||||
Debug::log(LOG, "Activate request for surface at {:x}", (uintptr_t)E->surface);
|
||||
|
||||
if (!wlr_xdg_surface_try_from_wlr_surface(E->surface))
|
||||
return;
|
||||
@@ -871,25 +957,19 @@ void Events::listener_activateXDG(wl_listener* listener, void* data) {
|
||||
if (!PWINDOW || PWINDOW == g_pCompositor->m_pLastWindow)
|
||||
return;
|
||||
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{"urgent", getFormat("%lx", PWINDOW)});
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{"urgent", std::format("{:x}", (uintptr_t)PWINDOW)});
|
||||
EMIT_HOOK_EVENT("urgent", PWINDOW);
|
||||
|
||||
PWINDOW->m_bIsUrgent = true;
|
||||
|
||||
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(PWINDOW->m_iWorkspaceID);
|
||||
if (PWORKSPACE->m_pWlrHandle) {
|
||||
wlr_ext_workspace_handle_v1_set_urgent(PWORKSPACE->m_pWlrHandle, 1);
|
||||
}
|
||||
|
||||
if (!*PFOCUSONACTIVATE)
|
||||
return;
|
||||
|
||||
if (PWINDOW->m_bIsFloating)
|
||||
g_pCompositor->moveWindowToTop(PWINDOW);
|
||||
g_pCompositor->changeWindowZOrder(PWINDOW, true);
|
||||
|
||||
g_pCompositor->focusWindow(PWINDOW);
|
||||
Vector2D middle = PWINDOW->m_vRealPosition.goalv() + PWINDOW->m_vRealSize.goalv() / 2.f;
|
||||
g_pCompositor->warpCursorTo(middle);
|
||||
g_pCompositor->warpCursorTo(PWINDOW->middle());
|
||||
}
|
||||
|
||||
void Events::listener_activateX11(void* owner, void* data) {
|
||||
@@ -897,11 +977,11 @@ void Events::listener_activateX11(void* owner, void* data) {
|
||||
|
||||
static auto* const PFOCUSONACTIVATE = &g_pConfigManager->getConfigValuePtr("misc:focus_on_activate")->intValue;
|
||||
|
||||
Debug::log(LOG, "X11 Activate request for window %lx", PWINDOW);
|
||||
Debug::log(LOG, "X11 Activate request for window {}", PWINDOW);
|
||||
|
||||
if (PWINDOW->m_iX11Type == 2) {
|
||||
|
||||
Debug::log(LOG, "Unmanaged X11 %lx requests activate", PWINDOW);
|
||||
Debug::log(LOG, "Unmanaged X11 {} requests activate", PWINDOW);
|
||||
|
||||
if (g_pCompositor->m_pLastWindow && g_pCompositor->m_pLastWindow->getPID() != PWINDOW->getPID())
|
||||
return;
|
||||
@@ -913,18 +993,17 @@ void Events::listener_activateX11(void* owner, void* data) {
|
||||
if (PWINDOW == g_pCompositor->m_pLastWindow)
|
||||
return;
|
||||
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{"urgent", getFormat("%lx", PWINDOW)});
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{"urgent", std::format("{:x}", (uintptr_t)PWINDOW)});
|
||||
EMIT_HOOK_EVENT("urgent", PWINDOW);
|
||||
|
||||
if (!*PFOCUSONACTIVATE)
|
||||
return;
|
||||
|
||||
if (PWINDOW->m_bIsFloating)
|
||||
g_pCompositor->moveWindowToTop(PWINDOW);
|
||||
g_pCompositor->changeWindowZOrder(PWINDOW, true);
|
||||
|
||||
g_pCompositor->focusWindow(PWINDOW);
|
||||
Vector2D middle = PWINDOW->m_vRealPosition.goalv() + PWINDOW->m_vRealSize.goalv() / 2.f;
|
||||
g_pCompositor->warpCursorTo(middle);
|
||||
g_pCompositor->warpCursorTo(PWINDOW->middle());
|
||||
}
|
||||
|
||||
void Events::listener_configureX11(void* owner, void* data) {
|
||||
@@ -932,8 +1011,9 @@ void Events::listener_configureX11(void* owner, void* data) {
|
||||
|
||||
const auto E = (wlr_xwayland_surface_configure_event*)data;
|
||||
|
||||
if (!PWINDOW->m_uSurface.xwayland->mapped || !PWINDOW->m_bMappedX11) {
|
||||
if (!PWINDOW->m_uSurface.xwayland->surface || !PWINDOW->m_uSurface.xwayland->surface->mapped || !PWINDOW->m_bMappedX11) {
|
||||
wlr_xwayland_surface_configure(PWINDOW->m_uSurface.xwayland, E->x, E->y, E->width, E->height);
|
||||
PWINDOW->m_vReportedSize = {E->width, E->height};
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -951,8 +1031,17 @@ void Events::listener_configureX11(void* owner, void* data) {
|
||||
else
|
||||
PWINDOW->setHidden(true);
|
||||
|
||||
PWINDOW->m_vRealPosition.setValueAndWarp(Vector2D(E->x, E->y));
|
||||
const auto LOGICALPOS = g_pXWaylandManager->xwaylandToWaylandCoords({E->x, E->y});
|
||||
|
||||
PWINDOW->m_vRealPosition.setValueAndWarp(LOGICALPOS);
|
||||
PWINDOW->m_vRealSize.setValueAndWarp(Vector2D(E->width, E->height));
|
||||
|
||||
static auto* const PXWLFORCESCALEZERO = &g_pConfigManager->getConfigValuePtr("xwayland:force_zero_scaling")->intValue;
|
||||
if (*PXWLFORCESCALEZERO) {
|
||||
if (const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID); PMONITOR)
|
||||
PWINDOW->m_vRealSize.setValueAndWarp(PWINDOW->m_vRealSize.goalv() / PMONITOR->scale);
|
||||
}
|
||||
|
||||
PWINDOW->m_vPosition = PWINDOW->m_vRealPosition.vec();
|
||||
PWINDOW->m_vSize = PWINDOW->m_vRealSize.vec();
|
||||
|
||||
@@ -960,7 +1049,7 @@ void Events::listener_configureX11(void* owner, void* data) {
|
||||
|
||||
PWINDOW->m_iWorkspaceID = g_pCompositor->getMonitorFromVector(PWINDOW->m_vRealPosition.vec() + PWINDOW->m_vRealSize.vec() / 2.f)->activeWorkspace;
|
||||
|
||||
g_pCompositor->moveWindowToTop(PWINDOW);
|
||||
g_pCompositor->changeWindowZOrder(PWINDOW, true);
|
||||
|
||||
PWINDOW->m_bCreatedOverFullscreen = true;
|
||||
|
||||
@@ -970,6 +1059,8 @@ void Events::listener_configureX11(void* owner, void* data) {
|
||||
g_pHyprRenderer->damageWindow(PWINDOW);
|
||||
|
||||
PWINDOW->updateWindowDecos();
|
||||
|
||||
PWINDOW->m_vReportedSize = {E->width, E->height};
|
||||
}
|
||||
|
||||
void Events::listener_unmanagedSetGeometry(void* owner, void* data) {
|
||||
@@ -992,20 +1083,32 @@ void Events::listener_unmanagedSetGeometry(void* owner, void* data) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (abs(std::floor(POS.x) - PWINDOW->m_uSurface.xwayland->x) > 2 || abs(std::floor(POS.y) - PWINDOW->m_uSurface.xwayland->y) > 2 ||
|
||||
abs(std::floor(SIZ.x) - PWINDOW->m_uSurface.xwayland->width) > 2 || abs(std::floor(SIZ.y) - PWINDOW->m_uSurface.xwayland->height) > 2) {
|
||||
Debug::log(LOG, "Unmanaged window %lx requests geometry update to %i %i %i %i", PWINDOW, (int)PWINDOW->m_uSurface.xwayland->x, (int)PWINDOW->m_uSurface.xwayland->y,
|
||||
(int)PWINDOW->m_uSurface.xwayland->width, (int)PWINDOW->m_uSurface.xwayland->height);
|
||||
static auto* const PXWLFORCESCALEZERO = &g_pConfigManager->getConfigValuePtr("xwayland:force_zero_scaling")->intValue;
|
||||
|
||||
const auto LOGICALPOS = g_pXWaylandManager->xwaylandToWaylandCoords({PWINDOW->m_uSurface.xwayland->x, PWINDOW->m_uSurface.xwayland->y});
|
||||
|
||||
if (abs(std::floor(POS.x) - LOGICALPOS.x) > 2 || abs(std::floor(POS.y) - LOGICALPOS.y) > 2 || abs(std::floor(SIZ.x) - PWINDOW->m_uSurface.xwayland->width) > 2 ||
|
||||
abs(std::floor(SIZ.y) - PWINDOW->m_uSurface.xwayland->height) > 2) {
|
||||
Debug::log(LOG, "Unmanaged window {} requests geometry update to {:j} {} {}", PWINDOW, LOGICALPOS, (int)PWINDOW->m_uSurface.xwayland->width,
|
||||
(int)PWINDOW->m_uSurface.xwayland->height);
|
||||
|
||||
g_pHyprRenderer->damageWindow(PWINDOW);
|
||||
PWINDOW->m_vRealPosition.setValueAndWarp(Vector2D(PWINDOW->m_uSurface.xwayland->x, PWINDOW->m_uSurface.xwayland->y));
|
||||
PWINDOW->m_vRealPosition.setValueAndWarp(Vector2D(LOGICALPOS.x, LOGICALPOS.y));
|
||||
|
||||
if (abs(std::floor(SIZ.x) - PWINDOW->m_uSurface.xwayland->width) > 2 || abs(std::floor(SIZ.y) - PWINDOW->m_uSurface.xwayland->height) > 2)
|
||||
PWINDOW->m_vRealSize.setValueAndWarp(Vector2D(PWINDOW->m_uSurface.xwayland->width, PWINDOW->m_uSurface.xwayland->height));
|
||||
|
||||
if (*PXWLFORCESCALEZERO) {
|
||||
if (const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID); PMONITOR)
|
||||
PWINDOW->m_vRealSize.setValueAndWarp(PWINDOW->m_vRealSize.goalv() / PMONITOR->scale);
|
||||
}
|
||||
|
||||
PWINDOW->m_vPosition = PWINDOW->m_vRealPosition.goalv();
|
||||
PWINDOW->m_vSize = PWINDOW->m_vRealSize.goalv();
|
||||
|
||||
PWINDOW->m_iWorkspaceID = g_pCompositor->getMonitorFromVector(PWINDOW->m_vRealPosition.vec() + PWINDOW->m_vRealSize.vec() / 2.f)->activeWorkspace;
|
||||
|
||||
g_pCompositor->moveWindowToTop(PWINDOW);
|
||||
g_pCompositor->changeWindowZOrder(PWINDOW, true);
|
||||
PWINDOW->updateWindowDecos();
|
||||
g_pHyprRenderer->damageWindow(PWINDOW);
|
||||
}
|
||||
@@ -1019,12 +1122,24 @@ void Events::listener_setOverrideRedirect(void* owner, void* data) {
|
||||
//}
|
||||
}
|
||||
|
||||
void Events::listener_associateX11(void* owner, void* data) {
|
||||
const auto PWINDOW = (CWindow*)owner;
|
||||
|
||||
PWINDOW->hyprListener_mapWindow.initCallback(&PWINDOW->m_uSurface.xwayland->surface->events.map, &Events::listener_mapWindow, PWINDOW, "XWayland Window");
|
||||
}
|
||||
|
||||
void Events::listener_dissociateX11(void* owner, void* data) {
|
||||
const auto PWINDOW = (CWindow*)owner;
|
||||
|
||||
PWINDOW->hyprListener_mapWindow.removeCallback();
|
||||
}
|
||||
|
||||
void Events::listener_surfaceXWayland(wl_listener* listener, void* data) {
|
||||
const auto XWSURFACE = (wlr_xwayland_surface*)data;
|
||||
|
||||
Debug::log(LOG, "New XWayland Surface created (class %s).", XWSURFACE->_class);
|
||||
Debug::log(LOG, "New XWayland Surface created (class {}).", XWSURFACE->_class ? XWSURFACE->_class : "null");
|
||||
if (XWSURFACE->parent)
|
||||
Debug::log(LOG, "Window parent data: %s at %lx", XWSURFACE->parent->_class, XWSURFACE->parent);
|
||||
Debug::log(LOG, "Window parent data: {} at {:x}", XWSURFACE->parent->_class ? XWSURFACE->parent->_class : "null", (uintptr_t)XWSURFACE->parent);
|
||||
|
||||
const auto PNEWWINDOW = (CWindow*)g_pCompositor->m_vWindows.emplace_back(std::make_unique<CWindow>()).get();
|
||||
|
||||
@@ -1034,7 +1149,8 @@ void Events::listener_surfaceXWayland(wl_listener* listener, void* data) {
|
||||
|
||||
PNEWWINDOW->m_pX11Parent = g_pCompositor->getX11Parent(PNEWWINDOW);
|
||||
|
||||
PNEWWINDOW->hyprListener_mapWindow.initCallback(&XWSURFACE->events.map, &Events::listener_mapWindow, PNEWWINDOW, "XWayland Window");
|
||||
PNEWWINDOW->hyprListener_associateX11.initCallback(&XWSURFACE->events.associate, &Events::listener_associateX11, PNEWWINDOW, "XWayland Window");
|
||||
PNEWWINDOW->hyprListener_dissociateX11.initCallback(&XWSURFACE->events.dissociate, &Events::listener_dissociateX11, PNEWWINDOW, "XWayland Window");
|
||||
PNEWWINDOW->hyprListener_destroyWindow.initCallback(&XWSURFACE->events.destroy, &Events::listener_destroyWindow, PNEWWINDOW, "XWayland Window");
|
||||
PNEWWINDOW->hyprListener_setOverrideRedirect.initCallback(&XWSURFACE->events.set_override_redirect, &Events::listener_setOverrideRedirect, PNEWWINDOW, "XWayland Window");
|
||||
PNEWWINDOW->hyprListener_configureX11.initCallback(&XWSURFACE->events.request_configure, &Events::listener_configureX11, PNEWWINDOW, "XWayland Window");
|
||||
@@ -1047,12 +1163,12 @@ void Events::listener_newXDGSurface(wl_listener* listener, void* data) {
|
||||
if (XDGSURFACE->role != WLR_XDG_SURFACE_ROLE_TOPLEVEL)
|
||||
return;
|
||||
|
||||
Debug::log(LOG, "New XDG Surface created. (class: %s)", XDGSURFACE->toplevel->app_id);
|
||||
Debug::log(LOG, "New XDG Surface created. (class: {})", XDGSURFACE->toplevel->app_id ? XDGSURFACE->toplevel->app_id : "null");
|
||||
|
||||
const auto PNEWWINDOW = g_pCompositor->m_vWindows.emplace_back(std::make_unique<CWindow>()).get();
|
||||
PNEWWINDOW->m_uSurface.xdg = XDGSURFACE;
|
||||
|
||||
PNEWWINDOW->hyprListener_mapWindow.initCallback(&XDGSURFACE->events.map, &Events::listener_mapWindow, PNEWWINDOW, "XDG Window");
|
||||
PNEWWINDOW->hyprListener_mapWindow.initCallback(&XDGSURFACE->surface->events.map, &Events::listener_mapWindow, PNEWWINDOW, "XDG Window");
|
||||
PNEWWINDOW->hyprListener_destroyWindow.initCallback(&XDGSURFACE->events.destroy, &Events::listener_destroyWindow, PNEWWINDOW, "XDG Window");
|
||||
}
|
||||
|
||||
@@ -1064,10 +1180,10 @@ void Events::listener_NewXDGDeco(wl_listener* listener, void* data) {
|
||||
void Events::listener_requestMaximize(void* owner, void* data) {
|
||||
const auto PWINDOW = (CWindow*)owner;
|
||||
|
||||
if (PWINDOW->m_bNoFullscreenRequest)
|
||||
if (PWINDOW->m_bNoMaximizeRequest)
|
||||
return;
|
||||
|
||||
Debug::log(LOG, "Maximize request for %lx", PWINDOW);
|
||||
Debug::log(LOG, "Maximize request for {}", PWINDOW);
|
||||
if (!PWINDOW->m_bIsX11) {
|
||||
const auto EV = (wlr_foreign_toplevel_handle_v1_maximized_event*)data;
|
||||
|
||||
@@ -1086,7 +1202,7 @@ void Events::listener_requestMaximize(void* owner, void* data) {
|
||||
void Events::listener_requestMinimize(void* owner, void* data) {
|
||||
const auto PWINDOW = (CWindow*)owner;
|
||||
|
||||
Debug::log(LOG, "Minimize request for %lx", PWINDOW);
|
||||
Debug::log(LOG, "Minimize request for {}", PWINDOW);
|
||||
|
||||
if (PWINDOW->m_bIsX11) {
|
||||
if (!PWINDOW->m_bMappedX11 || PWINDOW->m_iX11Type != 1)
|
||||
@@ -1094,13 +1210,13 @@ void Events::listener_requestMinimize(void* owner, void* data) {
|
||||
|
||||
const auto E = (wlr_xwayland_minimize_event*)data;
|
||||
|
||||
g_pEventManager->postEvent({"minimize", getFormat("%lx,%i", PWINDOW, (int)E->minimize)});
|
||||
g_pEventManager->postEvent({"minimize", std::format("{:x},{}", (uintptr_t)PWINDOW, (int)E->minimize)});
|
||||
EMIT_HOOK_EVENT("minimize", (std::vector<void*>{PWINDOW, (void*)E->minimize}));
|
||||
|
||||
wlr_xwayland_surface_set_minimized(PWINDOW->m_uSurface.xwayland, E->minimize && g_pCompositor->m_pLastWindow != PWINDOW); // fucking DXVK
|
||||
} else {
|
||||
const auto E = (wlr_foreign_toplevel_handle_v1_minimized_event*)data;
|
||||
g_pEventManager->postEvent({"minimize", getFormat("%lx,%i", PWINDOW, E ? (int)E->minimized : 1)});
|
||||
g_pEventManager->postEvent({"minimize", std::format("{:x},{}", (uintptr_t)PWINDOW, E ? (int)E->minimized : 1)});
|
||||
EMIT_HOOK_EVENT("minimize", (std::vector<void*>{PWINDOW, (void*)(E ? (uint64_t)E->minimized : 1)}));
|
||||
}
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
@@ -79,3 +82,17 @@ float CAnimatedVariable::getCurveValue() {
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -239,6 +269,7 @@ class CAnimatedVariable {
|
||||
|
||||
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;
|
||||
below = m_aPointsBaked[index].x < x;
|
||||
}
|
||||
|
||||
mid = (upperT + lowerT) / 2;
|
||||
}
|
||||
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);
|
||||
|
||||
|
@@ -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.
|
||||
|
112
src/helpers/Box.cpp
Normal file
112
src/helpers/Box.cpp
Normal file
@@ -0,0 +1,112 @@
|
||||
#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::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};
|
||||
}
|
80
src/helpers/Box.hpp
Normal file
80
src/helpers/Box.hpp
Normal file
@@ -0,0 +1,80 @@
|
||||
#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);
|
||||
|
||||
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() {}
|
||||
|
||||
|
@@ -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 %lx: %lx -> %lx (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,16 +1,27 @@
|
||||
#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>
|
||||
|
||||
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 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&);
|
||||
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*);
|
||||
@@ -20,3 +31,14 @@ 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...));
|
||||
}
|
@@ -14,6 +14,14 @@ CMonitor::CMonitor() {
|
||||
|
||||
CMonitor::~CMonitor() {
|
||||
wlr_damage_ring_finish(&damage);
|
||||
|
||||
hyprListener_monitorDestroy.removeCallback();
|
||||
hyprListener_monitorFrame.removeCallback();
|
||||
hyprListener_monitorStateRequest.removeCallback();
|
||||
hyprListener_monitorDamage.removeCallback();
|
||||
hyprListener_monitorNeedsFrame.removeCallback();
|
||||
hyprListener_monitorCommit.removeCallback();
|
||||
hyprListener_monitorBind.removeCallback();
|
||||
}
|
||||
|
||||
void CMonitor::onConnect(bool noRule) {
|
||||
@@ -23,12 +31,16 @@ void CMonitor::onConnect(bool noRule) {
|
||||
hyprListener_monitorDamage.removeCallback();
|
||||
hyprListener_monitorNeedsFrame.removeCallback();
|
||||
hyprListener_monitorCommit.removeCallback();
|
||||
hyprListener_monitorBind.removeCallback();
|
||||
hyprListener_monitorFrame.initCallback(&output->events.frame, &Events::listener_monitorFrame, this);
|
||||
hyprListener_monitorDestroy.initCallback(&output->events.destroy, &Events::listener_monitorDestroy, this);
|
||||
hyprListener_monitorStateRequest.initCallback(&output->events.request_state, &Events::listener_monitorStateRequest, this);
|
||||
hyprListener_monitorDamage.initCallback(&output->events.damage, &Events::listener_monitorDamage, this);
|
||||
hyprListener_monitorNeedsFrame.initCallback(&output->events.needs_frame, &Events::listener_monitorNeedsFrame, this);
|
||||
hyprListener_monitorCommit.initCallback(&output->events.commit, &Events::listener_monitorCommit, this);
|
||||
hyprListener_monitorBind.initCallback(&output->events.bind, &Events::listener_monitorBind, this);
|
||||
|
||||
tearingState.canTear = wlr_backend_is_drm(output->backend); // tearing only works on drm
|
||||
|
||||
if (m_bEnabled) {
|
||||
wlr_output_enable(output, 1);
|
||||
@@ -69,15 +81,12 @@ void CMonitor::onConnect(bool noRule) {
|
||||
if (PREFSTATE)
|
||||
wlr_output_set_mode(output, PREFSTATE);
|
||||
else
|
||||
Debug::log(WARN, "No mode found for disabled output %s", output->name);
|
||||
Debug::log(WARN, "No mode found for disabled output {}", output->name);
|
||||
|
||||
wlr_output_enable(output, 0);
|
||||
|
||||
if (!wlr_output_commit(output)) {
|
||||
Debug::log(ERR, "Couldn't commit disabled state on output %s", output->name);
|
||||
}
|
||||
|
||||
Events::listener_change(nullptr, nullptr);
|
||||
if (!wlr_output_commit(output))
|
||||
Debug::log(ERR, "Couldn't commit disabled state on output {}", output->name);
|
||||
|
||||
m_bEnabled = false;
|
||||
|
||||
@@ -100,52 +109,41 @@ void CMonitor::onConnect(bool noRule) {
|
||||
m_bRenderingInitPassed = true;
|
||||
}
|
||||
|
||||
if (!m_pThisWrap) {
|
||||
std::shared_ptr<CMonitor>* thisWrapper = nullptr;
|
||||
|
||||
// find the wrap
|
||||
for (auto& m : g_pCompositor->m_vRealMonitors) {
|
||||
if (m->ID == ID) {
|
||||
m_pThisWrap = &m;
|
||||
thisWrapper = &m;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (std::find_if(g_pCompositor->m_vMonitors.begin(), g_pCompositor->m_vMonitors.end(), [&](auto& other) { return other.get() == this; }) == g_pCompositor->m_vMonitors.end()) {
|
||||
g_pCompositor->m_vMonitors.push_back(*m_pThisWrap);
|
||||
}
|
||||
RASSERT(thisWrapper->get(), "CMonitor::onConnect: Had no wrapper???");
|
||||
|
||||
if (std::find_if(g_pCompositor->m_vMonitors.begin(), g_pCompositor->m_vMonitors.end(), [&](auto& other) { return other.get() == this; }) == g_pCompositor->m_vMonitors.end())
|
||||
g_pCompositor->m_vMonitors.push_back(*thisWrapper);
|
||||
|
||||
m_bEnabled = true;
|
||||
|
||||
// create it in the arr
|
||||
vecPosition = monitorRule.offset;
|
||||
vecSize = monitorRule.resolution;
|
||||
refreshRate = monitorRule.refreshRate;
|
||||
|
||||
wlr_output_enable(output, 1);
|
||||
|
||||
// set mode, also applies
|
||||
if (!noRule)
|
||||
g_pHyprRenderer->applyMonitorRule(this, &monitorRule, true);
|
||||
|
||||
wlr_output_commit(output);
|
||||
|
||||
wlr_damage_ring_set_bounds(&damage, vecTransformedSize.x, vecTransformedSize.y);
|
||||
|
||||
wlr_xcursor_manager_load(g_pCompositor->m_sWLRXCursorMgr, scale);
|
||||
|
||||
Debug::log(LOG, "Added new monitor with name %s at %i,%i with size %ix%i, pointer %lx", output->name, (int)vecPosition.x, (int)vecPosition.y, (int)vecPixelSize.x,
|
||||
(int)vecPixelSize.y, output);
|
||||
|
||||
// add a WLR workspace group
|
||||
if (!pWLRWorkspaceGroupHandle) {
|
||||
pWLRWorkspaceGroupHandle = wlr_ext_workspace_group_handle_v1_create(g_pCompositor->m_sWLREXTWorkspaceMgr);
|
||||
}
|
||||
|
||||
wlr_ext_workspace_group_handle_v1_output_enter(pWLRWorkspaceGroupHandle, output);
|
||||
Debug::log(LOG, "Added new monitor with name {} at {:j0} with size {:j0}, pointer {:x}", output->name, vecPosition, vecPixelSize, (uintptr_t)output);
|
||||
|
||||
setupDefaultWS(monitorRule);
|
||||
|
||||
for (auto& ws : g_pCompositor->m_vWorkspaces) {
|
||||
if (ws->m_szLastMonitor == szName) {
|
||||
if (ws->m_szLastMonitor == szName || g_pCompositor->m_vMonitors.size() == 1 /* avoid lost workspaces on recover */) {
|
||||
g_pCompositor->moveWorkspaceToMonitor(ws.get(), this);
|
||||
ws->startAnim(true, true, true);
|
||||
ws->m_szLastMonitor = "";
|
||||
@@ -156,8 +154,6 @@ void CMonitor::onConnect(bool noRule) {
|
||||
if (scale < 0.1)
|
||||
scale = getDefaultScale();
|
||||
|
||||
m_pThisWrap = nullptr;
|
||||
|
||||
forceFullFrames = 3; // force 3 full frames to make sure there is no blinking due to double-buffering.
|
||||
//
|
||||
|
||||
@@ -188,6 +184,8 @@ void CMonitor::onConnect(bool noRule) {
|
||||
g_pCompositor->setActiveMonitor(this);
|
||||
|
||||
renderTimer = wl_event_loop_add_timer(g_pCompositor->m_sWLEventLoop, ratHandler, this);
|
||||
|
||||
g_pCompositor->scheduleFrameForMonitor(this);
|
||||
}
|
||||
|
||||
void CMonitor::onDisconnect() {
|
||||
@@ -200,7 +198,7 @@ void CMonitor::onDisconnect() {
|
||||
if (!m_bEnabled || g_pCompositor->m_bIsShuttingDown)
|
||||
return;
|
||||
|
||||
Debug::log(LOG, "onDisconnect called for %s", output->name);
|
||||
Debug::log(LOG, "onDisconnect called for {}", output->name);
|
||||
|
||||
// Cleanup everything. Move windows back, snap cursor, shit.
|
||||
CMonitor* BACKUPMON = nullptr;
|
||||
@@ -225,13 +223,11 @@ void CMonitor::onDisconnect() {
|
||||
g_pConfigManager->m_bWantsMonitorReload = true;
|
||||
}
|
||||
|
||||
m_bEnabled = false;
|
||||
m_bRenderingInitPassed = false;
|
||||
|
||||
hyprListener_monitorFrame.removeCallback();
|
||||
hyprListener_monitorDamage.removeCallback();
|
||||
hyprListener_monitorNeedsFrame.removeCallback();
|
||||
hyprListener_monitorCommit.removeCallback();
|
||||
hyprListener_monitorBind.removeCallback();
|
||||
|
||||
for (size_t i = 0; i < 4; ++i) {
|
||||
for (auto& ls : m_aLayerSurfaceLayers[i]) {
|
||||
@@ -241,24 +237,20 @@ void CMonitor::onDisconnect() {
|
||||
m_aLayerSurfaceLayers[i].clear();
|
||||
}
|
||||
|
||||
Debug::log(LOG, "Removed monitor %s!", szName.c_str());
|
||||
Debug::log(LOG, "Removed monitor {}!", szName);
|
||||
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{"monitorremoved", szName});
|
||||
EMIT_HOOK_EVENT("monitorRemoved", this);
|
||||
|
||||
if (!BACKUPMON) {
|
||||
Debug::log(WARN, "Unplugged last monitor, entering an unsafe state. Good luck my friend.");
|
||||
|
||||
hyprListener_monitorStateRequest.removeCallback();
|
||||
hyprListener_monitorDestroy.removeCallback();
|
||||
|
||||
g_pCompositor->m_bUnsafeState = true;
|
||||
|
||||
std::erase_if(g_pCompositor->m_vMonitors, [&](std::shared_ptr<CMonitor>& el) { return el.get() == this; });
|
||||
|
||||
return;
|
||||
g_pCompositor->enterUnsafeState();
|
||||
}
|
||||
|
||||
m_bEnabled = false;
|
||||
m_bRenderingInitPassed = false;
|
||||
|
||||
if (BACKUPMON) {
|
||||
// snap cursor
|
||||
wlr_cursor_warp(g_pCompositor->m_sWLRCursor, nullptr, BACKUPMON->vecPosition.x + BACKUPMON->vecTransformedSize.x / 2.f,
|
||||
BACKUPMON->vecPosition.y + BACKUPMON->vecTransformedSize.y / 2.f);
|
||||
@@ -266,7 +258,7 @@ void CMonitor::onDisconnect() {
|
||||
// move workspaces
|
||||
std::deque<CWorkspace*> wspToMove;
|
||||
for (auto& w : g_pCompositor->m_vWorkspaces) {
|
||||
if (w->m_iMonitorID == ID) {
|
||||
if (w->m_iMonitorID == ID || !g_pCompositor->getMonitorFromID(w->m_iMonitorID)) {
|
||||
wspToMove.push_back(w.get());
|
||||
}
|
||||
}
|
||||
@@ -276,6 +268,11 @@ void CMonitor::onDisconnect() {
|
||||
g_pCompositor->moveWorkspaceToMonitor(w, BACKUPMON);
|
||||
w->startAnim(true, true, true);
|
||||
}
|
||||
} else {
|
||||
g_pCompositor->m_pLastFocus = nullptr;
|
||||
g_pCompositor->m_pLastWindow = nullptr;
|
||||
g_pCompositor->m_pLastMonitor = nullptr;
|
||||
}
|
||||
|
||||
activeWorkspace = -1;
|
||||
|
||||
@@ -285,8 +282,6 @@ void CMonitor::onDisconnect() {
|
||||
|
||||
wlr_output_commit(output);
|
||||
|
||||
std::erase_if(g_pCompositor->m_vWorkspaces, [&](std::unique_ptr<CWorkspace>& el) { return el->m_iMonitorID == ID; });
|
||||
|
||||
if (g_pCompositor->m_pLastMonitor == this)
|
||||
g_pCompositor->setActiveMonitor(BACKUPMON);
|
||||
|
||||
@@ -318,14 +313,18 @@ void CMonitor::addDamage(const pixman_region32_t* rg) {
|
||||
g_pCompositor->scheduleFrameForMonitor(this);
|
||||
}
|
||||
|
||||
void CMonitor::addDamage(const wlr_box* box) {
|
||||
void CMonitor::addDamage(const CRegion* rg) {
|
||||
addDamage(const_cast<CRegion*>(rg)->pixman());
|
||||
}
|
||||
|
||||
void CMonitor::addDamage(const CBox* box) {
|
||||
static auto* const PZOOMFACTOR = &g_pConfigManager->getConfigValuePtr("misc:cursor_zoom_factor")->floatValue;
|
||||
if (*PZOOMFACTOR != 1.f && g_pCompositor->getMonitorFromCursor() == this) {
|
||||
wlr_damage_ring_add_whole(&damage);
|
||||
g_pCompositor->scheduleFrameForMonitor(this);
|
||||
}
|
||||
|
||||
if (wlr_damage_ring_add_box(&damage, box))
|
||||
if (wlr_damage_ring_add_box(&damage, const_cast<CBox*>(box)->pWlr()))
|
||||
g_pCompositor->scheduleFrameForMonitor(this);
|
||||
}
|
||||
|
||||
@@ -358,12 +357,12 @@ void CMonitor::setupDefaultWS(const SMonitorRule& monitorRule) {
|
||||
WORKSPACEID = g_pCompositor->m_vWorkspaces.size() + 1;
|
||||
newDefaultWorkspaceName = std::to_string(WORKSPACEID);
|
||||
|
||||
Debug::log(LOG, "Invalid workspace= directive name in monitor parsing, workspace name \"%s\" is invalid.", g_pConfigManager->getDefaultWorkspaceFor(szName).c_str());
|
||||
Debug::log(LOG, "Invalid workspace= directive name in monitor parsing, workspace name \"{}\" is invalid.", g_pConfigManager->getDefaultWorkspaceFor(szName));
|
||||
}
|
||||
|
||||
auto PNEWWORKSPACE = g_pCompositor->getWorkspaceByID(WORKSPACEID);
|
||||
|
||||
Debug::log(LOG, "New monitor: WORKSPACEID %d, exists: %d", WORKSPACEID, (int)(PNEWWORKSPACE != nullptr));
|
||||
Debug::log(LOG, "New monitor: WORKSPACEID {}, exists: {}", WORKSPACEID, (int)(PNEWWORKSPACE != nullptr));
|
||||
|
||||
if (PNEWWORKSPACE) {
|
||||
// workspace exists, move it to the newly connected monitor
|
||||
@@ -377,15 +376,11 @@ void CMonitor::setupDefaultWS(const SMonitorRule& monitorRule) {
|
||||
|
||||
PNEWWORKSPACE = g_pCompositor->m_vWorkspaces.emplace_back(std::make_unique<CWorkspace>(ID, newDefaultWorkspaceName)).get();
|
||||
|
||||
// We are required to set the name here immediately
|
||||
wlr_ext_workspace_handle_v1_set_name(PNEWWORKSPACE->m_pWlrHandle, newDefaultWorkspaceName.c_str());
|
||||
|
||||
PNEWWORKSPACE->m_iID = WORKSPACEID;
|
||||
}
|
||||
|
||||
activeWorkspace = PNEWWORKSPACE->m_iID;
|
||||
|
||||
g_pCompositor->deactivateAllWLRWorkspaces(PNEWWORKSPACE->m_pWlrHandle);
|
||||
PNEWWORKSPACE->setActive(true);
|
||||
PNEWWORKSPACE->m_szLastMonitor = "";
|
||||
}
|
||||
@@ -421,19 +416,22 @@ void CMonitor::setMirror(const std::string& mirrorOf) {
|
||||
vecPosition = RULE.offset;
|
||||
|
||||
// push to mvmonitors
|
||||
if (!m_pThisWrap) {
|
||||
|
||||
std::shared_ptr<CMonitor>* thisWrapper = nullptr;
|
||||
|
||||
// find the wrap
|
||||
for (auto& m : g_pCompositor->m_vRealMonitors) {
|
||||
if (m->ID == ID) {
|
||||
m_pThisWrap = &m;
|
||||
thisWrapper = &m;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RASSERT(thisWrapper->get(), "CMonitor::setMirror: Had no wrapper???");
|
||||
|
||||
if (std::find_if(g_pCompositor->m_vMonitors.begin(), g_pCompositor->m_vMonitors.end(), [&](auto& other) { return other.get() == this; }) ==
|
||||
g_pCompositor->m_vMonitors.end()) {
|
||||
g_pCompositor->m_vMonitors.push_back(*m_pThisWrap);
|
||||
g_pCompositor->m_vMonitors.push_back(*thisWrapper);
|
||||
}
|
||||
|
||||
setupDefaultWS(RULE);
|
||||
@@ -474,6 +472,8 @@ void CMonitor::setMirror(const std::string& mirrorOf) {
|
||||
// remove from mvmonitors
|
||||
std::erase_if(g_pCompositor->m_vMonitors, [&](const auto& other) { return other.get() == this; });
|
||||
|
||||
g_pCompositor->arrangeMonitors();
|
||||
|
||||
g_pCompositor->setActiveMonitor(g_pCompositor->m_vMonitors.front().get());
|
||||
|
||||
g_pCompositor->sanityCheckWorkspaces();
|
||||
@@ -498,22 +498,20 @@ float CMonitor::getDefaultScale() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
void CMonitor::changeWorkspace(CWorkspace* const pWorkspace, bool internal) {
|
||||
void CMonitor::changeWorkspace(CWorkspace* const pWorkspace, bool internal, bool noMouseMove) {
|
||||
if (!pWorkspace)
|
||||
return;
|
||||
|
||||
if (pWorkspace->m_bIsSpecialWorkspace) {
|
||||
Debug::log(ERR, "BUG THIS: Attempted to changeWorkspace to special!");
|
||||
if (specialWorkspaceID != pWorkspace->m_iID) {
|
||||
Debug::log(LOG, "changeworkspace on special, togglespecialworkspace to id {}", pWorkspace->m_iID);
|
||||
g_pKeybindManager->m_mDispatchers["togglespecialworkspace"](pWorkspace->m_szName == "special" ? "" : pWorkspace->m_szName);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (pWorkspace->m_iID == activeWorkspace) {
|
||||
// in some cases (e.g. workspace from one monitor to another)
|
||||
// we need to send this
|
||||
g_pCompositor->deactivateAllWLRWorkspaces(pWorkspace->m_pWlrHandle);
|
||||
pWorkspace->setActive(true);
|
||||
if (pWorkspace->m_iID == activeWorkspace)
|
||||
return;
|
||||
}
|
||||
|
||||
const auto POLDWORKSPACE = g_pCompositor->getWorkspaceByID(activeWorkspace);
|
||||
|
||||
@@ -531,18 +529,29 @@ void CMonitor::changeWorkspace(CWorkspace* const pWorkspace, bool internal) {
|
||||
}
|
||||
}
|
||||
|
||||
static auto* const PFOLLOWMOUSE = &g_pConfigManager->getConfigValuePtr("input:follow_mouse")->intValue;
|
||||
|
||||
if (const auto PLASTWINDOW = pWorkspace->getLastFocusedWindow(); PLASTWINDOW)
|
||||
g_pCompositor->focusWindow(PLASTWINDOW);
|
||||
else {
|
||||
g_pCompositor->focusWindow(nullptr);
|
||||
g_pInputManager->refocus();
|
||||
CWindow* pWindow = nullptr;
|
||||
|
||||
if (*PFOLLOWMOUSE == 1)
|
||||
pWindow = g_pCompositor->vectorToWindowIdeal(g_pInputManager->getMouseCoordsInternal());
|
||||
|
||||
if (!pWindow)
|
||||
pWindow = g_pCompositor->getTopLeftWindowOnWorkspace(pWorkspace->m_iID);
|
||||
|
||||
if (!pWindow)
|
||||
pWindow = g_pCompositor->getFirstWindowOnWorkspace(pWorkspace->m_iID);
|
||||
|
||||
g_pCompositor->focusWindow(pWindow);
|
||||
}
|
||||
if (!noMouseMove)
|
||||
g_pInputManager->simulateMouseMovement();
|
||||
|
||||
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(ID);
|
||||
|
||||
// set some flags and fire event
|
||||
g_pCompositor->deactivateAllWLRWorkspaces(pWorkspace->m_pWlrHandle);
|
||||
pWorkspace->setActive(true);
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{"workspace", pWorkspace->m_szName});
|
||||
EMIT_HOOK_EVENT("workspace", pWorkspace);
|
||||
}
|
||||
@@ -550,6 +559,8 @@ void CMonitor::changeWorkspace(CWorkspace* const pWorkspace, bool internal) {
|
||||
g_pHyprRenderer->damageMonitor(this);
|
||||
|
||||
g_pCompositor->updateFullscreenFadeOnWorkspace(pWorkspace);
|
||||
|
||||
g_pConfigManager->ensureVRR(this);
|
||||
}
|
||||
|
||||
void CMonitor::changeWorkspace(const int& id, bool internal) {
|
||||
@@ -561,8 +572,10 @@ void CMonitor::setSpecialWorkspace(CWorkspace* const pWorkspace) {
|
||||
|
||||
if (!pWorkspace) {
|
||||
// remove special if exists
|
||||
if (const auto EXISTINGSPECIAL = g_pCompositor->getWorkspaceByID(specialWorkspaceID); EXISTINGSPECIAL)
|
||||
if (const auto EXISTINGSPECIAL = g_pCompositor->getWorkspaceByID(specialWorkspaceID); EXISTINGSPECIAL) {
|
||||
EXISTINGSPECIAL->startAnim(false, false);
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{"activespecial", "," + szName});
|
||||
}
|
||||
specialWorkspaceID = 0;
|
||||
|
||||
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(ID);
|
||||
@@ -576,19 +589,57 @@ void CMonitor::setSpecialWorkspace(CWorkspace* const pWorkspace) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (specialWorkspaceID) {
|
||||
if (const auto EXISTINGSPECIAL = g_pCompositor->getWorkspaceByID(specialWorkspaceID); EXISTINGSPECIAL)
|
||||
EXISTINGSPECIAL->startAnim(false, false);
|
||||
}
|
||||
|
||||
bool animate = true;
|
||||
//close if open elsewhere
|
||||
const auto PMONITORWORKSPACEOWNER = g_pCompositor->getMonitorFromID(pWorkspace->m_iMonitorID);
|
||||
if (PMONITORWORKSPACEOWNER->specialWorkspaceID == pWorkspace->m_iID) {
|
||||
PMONITORWORKSPACEOWNER->specialWorkspaceID = 0;
|
||||
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PMONITORWORKSPACEOWNER->ID);
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{"activespecial", "," + PMONITORWORKSPACEOWNER->szName});
|
||||
animate = false;
|
||||
}
|
||||
|
||||
// open special
|
||||
pWorkspace->m_iMonitorID = ID;
|
||||
specialWorkspaceID = pWorkspace->m_iID;
|
||||
if (animate)
|
||||
pWorkspace->startAnim(true, true);
|
||||
|
||||
for (auto& w : g_pCompositor->m_vWindows) {
|
||||
if (w->m_iWorkspaceID == pWorkspace->m_iID) {
|
||||
w->m_iMonitorID = ID;
|
||||
w->updateSurfaceOutputs();
|
||||
}
|
||||
}
|
||||
|
||||
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(ID);
|
||||
|
||||
if (const auto PLAST = pWorkspace->getLastFocusedWindow(); PLAST)
|
||||
g_pCompositor->focusWindow(PLAST);
|
||||
else
|
||||
g_pInputManager->refocus();
|
||||
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{"activespecial", pWorkspace->m_szName + "," + szName});
|
||||
|
||||
g_pHyprRenderer->damageMonitor(this);
|
||||
}
|
||||
|
||||
void CMonitor::setSpecialWorkspace(const int& id) {
|
||||
setSpecialWorkspace(g_pCompositor->getWorkspaceByID(id));
|
||||
}
|
||||
|
||||
void CMonitor::moveTo(const Vector2D& pos) {
|
||||
vecPosition = pos;
|
||||
|
||||
if (!isMirror())
|
||||
wlr_output_layout_add(g_pCompositor->m_sWLROutputLayout, output, (int)vecPosition.x, (int)vecPosition.y);
|
||||
}
|
||||
|
||||
Vector2D CMonitor::middle() {
|
||||
return vecPosition + vecSize / 2.f;
|
||||
}
|
@@ -6,9 +6,24 @@
|
||||
#include <vector>
|
||||
#include <array>
|
||||
#include <memory>
|
||||
#include <xf86drmMode.h>
|
||||
#include "Timer.hpp"
|
||||
#include "Region.hpp"
|
||||
#include <optional>
|
||||
|
||||
struct SMonitorRule;
|
||||
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;
|
||||
drmModeModeInfo drmMode = {};
|
||||
std::optional<int> vrr;
|
||||
};
|
||||
|
||||
class CMonitor {
|
||||
public:
|
||||
@@ -16,6 +31,7 @@ class CMonitor {
|
||||
~CMonitor();
|
||||
|
||||
Vector2D vecPosition = Vector2D(-1, -1); // means unset
|
||||
Vector2D vecXWaylandPosition = Vector2D(-1, -1); // means unset
|
||||
Vector2D vecSize = Vector2D(0, 0);
|
||||
Vector2D vecPixelSize = Vector2D(0, 0);
|
||||
Vector2D vecTransformedSize = Vector2D(0, 0);
|
||||
@@ -31,6 +47,8 @@ class CMonitor {
|
||||
Vector2D vecReservedTopLeft = Vector2D(0, 0);
|
||||
Vector2D vecReservedBottomRight = Vector2D(0, 0);
|
||||
|
||||
drmModeModeInfo customDrmMode = {};
|
||||
|
||||
// WLR stuff
|
||||
wlr_damage_ring damage;
|
||||
wlr_output* output = nullptr;
|
||||
@@ -40,11 +58,15 @@ class CMonitor {
|
||||
bool noFrameSchedule = false;
|
||||
bool scheduledRecalc = false;
|
||||
wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL;
|
||||
bool gammaChanged = false;
|
||||
float xwaylandScale = 1.f;
|
||||
|
||||
bool dpmsStatus = true;
|
||||
bool vrrActive = false; // this can be TRUE even if VRR is not active in the case that this display does not support it.
|
||||
bool enabled10bit = false; // as above, this can be TRUE even if 10 bit failed.
|
||||
bool createdByUser = false;
|
||||
uint32_t drmFormat = DRM_FORMAT_INVALID;
|
||||
bool isUnsafeFallback = false;
|
||||
|
||||
bool pendingFrame = false; // if we schedule a frame during rendering, reschedule it after
|
||||
bool renderingActive = false;
|
||||
@@ -53,10 +75,26 @@ class CMonitor {
|
||||
bool RATScheduled = false;
|
||||
CTimer lastPresentationTimer;
|
||||
|
||||
SMonitorRule activeMonitorRule;
|
||||
|
||||
// mirroring
|
||||
CMonitor* pMirrorOf = nullptr;
|
||||
std::vector<CMonitor*> mirrors;
|
||||
|
||||
CRegion lastFrameDamage; // stores last frame damage
|
||||
|
||||
// for tearing
|
||||
CWindow* solitaryClient = nullptr;
|
||||
|
||||
struct {
|
||||
bool canTear = false;
|
||||
bool nextRenderTorn = false;
|
||||
bool activelyTearing = false;
|
||||
|
||||
bool busy = false;
|
||||
bool frameScheduledWhileBusy = false;
|
||||
} tearingState;
|
||||
|
||||
// for the special workspace. 0 means not open.
|
||||
int specialWorkspaceID = 0;
|
||||
|
||||
@@ -68,25 +106,24 @@ class CMonitor {
|
||||
DYNLISTENER(monitorDamage);
|
||||
DYNLISTENER(monitorNeedsFrame);
|
||||
DYNLISTENER(monitorCommit);
|
||||
|
||||
// hack: a group = workspaces on a monitor.
|
||||
// I don't really care lol :P
|
||||
wlr_ext_workspace_group_handle_v1* pWLRWorkspaceGroupHandle = nullptr;
|
||||
DYNLISTENER(monitorBind);
|
||||
|
||||
// methods
|
||||
void onConnect(bool noRule);
|
||||
void onDisconnect();
|
||||
void addDamage(const pixman_region32_t* rg);
|
||||
void addDamage(const wlr_box* box);
|
||||
void addDamage(const CRegion* rg);
|
||||
void addDamage(const CBox* box);
|
||||
void setMirror(const std::string&);
|
||||
bool isMirror();
|
||||
float getDefaultScale();
|
||||
void changeWorkspace(CWorkspace* const pWorkspace, bool internal = false);
|
||||
void changeWorkspace(CWorkspace* const pWorkspace, bool internal = false, bool noMouseMove = false);
|
||||
void changeWorkspace(const int& id, bool internal = false);
|
||||
void setSpecialWorkspace(CWorkspace* const pWorkspace);
|
||||
void setSpecialWorkspace(const int& id);
|
||||
void moveTo(const Vector2D& pos);
|
||||
Vector2D middle();
|
||||
|
||||
std::shared_ptr<CMonitor>* m_pThisWrap = nullptr;
|
||||
bool m_bEnabled = false;
|
||||
bool m_bRenderingInitPassed = false;
|
||||
|
||||
|
149
src/helpers/Region.cpp
Normal file
149
src/helpers/Region.cpp
Normal file
@@ -0,0 +1,149 @@
|
||||
#include "Region.hpp"
|
||||
extern "C" {
|
||||
#include <wlr/util/box.h>
|
||||
#include <wlr/util/region.h>
|
||||
}
|
||||
|
||||
CRegion::CRegion() {
|
||||
pixman_region32_init(&m_rRegion);
|
||||
}
|
||||
|
||||
CRegion::CRegion(pixman_region32_t* ref) {
|
||||
pixman_region32_init(&m_rRegion);
|
||||
pixman_region32_copy(&m_rRegion, ref);
|
||||
}
|
||||
|
||||
CRegion::CRegion(double x, double y, double w, double h) {
|
||||
pixman_region32_init_rect(&m_rRegion, x, y, w, h);
|
||||
}
|
||||
|
||||
CRegion::CRegion(wlr_box* box) {
|
||||
pixman_region32_init_rect(&m_rRegion, box->x, box->y, box->width, box->height);
|
||||
}
|
||||
|
||||
CRegion::CRegion(CBox* box) {
|
||||
pixman_region32_init_rect(&m_rRegion, box->x, box->y, box->w, box->h);
|
||||
}
|
||||
|
||||
CRegion::CRegion(pixman_box32_t* box) {
|
||||
pixman_region32_init_rect(&m_rRegion, box->x1, box->y1, box->x2 - box->x1, box->y2 - box->y1);
|
||||
}
|
||||
|
||||
CRegion::CRegion(const CRegion& other) {
|
||||
pixman_region32_init(&m_rRegion);
|
||||
pixman_region32_copy(&m_rRegion, const_cast<CRegion*>(&other)->pixman());
|
||||
}
|
||||
|
||||
CRegion::CRegion(CRegion&& other) {
|
||||
pixman_region32_init(&m_rRegion);
|
||||
pixman_region32_copy(&m_rRegion, other.pixman());
|
||||
}
|
||||
|
||||
CRegion::~CRegion() {
|
||||
pixman_region32_fini(&m_rRegion);
|
||||
}
|
||||
|
||||
CRegion& CRegion::clear() {
|
||||
pixman_region32_clear(&m_rRegion);
|
||||
return *this;
|
||||
}
|
||||
|
||||
CRegion& CRegion::set(const CRegion& other) {
|
||||
pixman_region32_copy(&m_rRegion, const_cast<CRegion*>(&other)->pixman());
|
||||
return *this;
|
||||
}
|
||||
|
||||
CRegion& CRegion::add(const CRegion& other) {
|
||||
pixman_region32_union(&m_rRegion, &m_rRegion, const_cast<CRegion*>(&other)->pixman());
|
||||
return *this;
|
||||
}
|
||||
|
||||
CRegion& CRegion::add(double x, double y, double w, double h) {
|
||||
pixman_region32_union_rect(&m_rRegion, &m_rRegion, x, y, w, h);
|
||||
return *this;
|
||||
}
|
||||
|
||||
CRegion& CRegion::subtract(const CRegion& other) {
|
||||
pixman_region32_subtract(&m_rRegion, &m_rRegion, const_cast<CRegion*>(&other)->pixman());
|
||||
return *this;
|
||||
}
|
||||
|
||||
CRegion& CRegion::intersect(const CRegion& other) {
|
||||
pixman_region32_intersect(&m_rRegion, &m_rRegion, const_cast<CRegion*>(&other)->pixman());
|
||||
return *this;
|
||||
}
|
||||
|
||||
CRegion& CRegion::intersect(double x, double y, double w, double h) {
|
||||
pixman_region32_intersect_rect(&m_rRegion, &m_rRegion, x, y, w, h);
|
||||
return *this;
|
||||
}
|
||||
|
||||
CRegion& CRegion::invert(pixman_box32_t* box) {
|
||||
pixman_region32_inverse(&m_rRegion, &m_rRegion, box);
|
||||
return *this;
|
||||
}
|
||||
|
||||
CRegion& CRegion::translate(const Vector2D& vec) {
|
||||
pixman_region32_translate(&m_rRegion, vec.x, vec.y);
|
||||
return *this;
|
||||
}
|
||||
|
||||
CRegion& CRegion::scale(float scale) {
|
||||
wlr_region_scale(&m_rRegion, &m_rRegion, scale);
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::vector<pixman_box32_t> CRegion::getRects() const {
|
||||
std::vector<pixman_box32_t> result;
|
||||
|
||||
int rectsNum = 0;
|
||||
const auto RECTSARR = pixman_region32_rectangles(&m_rRegion, &rectsNum);
|
||||
|
||||
result.assign(RECTSARR, RECTSARR + rectsNum);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
CBox CRegion::getExtents() {
|
||||
pixman_box32_t* box = pixman_region32_extents(&m_rRegion);
|
||||
return {box->x1, box->y1, box->x2 - box->x1, box->y2 - box->y1};
|
||||
}
|
||||
|
||||
bool CRegion::containsPoint(const Vector2D& vec) const {
|
||||
return pixman_region32_contains_point(&m_rRegion, vec.x, vec.y, nullptr);
|
||||
}
|
||||
|
||||
bool CRegion::empty() const {
|
||||
return !pixman_region32_not_empty(&m_rRegion);
|
||||
}
|
||||
|
||||
Vector2D CRegion::closestPoint(const Vector2D& vec) const {
|
||||
double bestDist = __FLT_MAX__;
|
||||
Vector2D leader = vec;
|
||||
|
||||
for (auto& box : getRects()) {
|
||||
double x = 0, y = 0;
|
||||
|
||||
if (vec.x >= box.x2)
|
||||
x = box.x2 - 1;
|
||||
else if (vec.x < box.x1)
|
||||
x = box.x1;
|
||||
else
|
||||
x = vec.x;
|
||||
|
||||
if (vec.y >= box.y2)
|
||||
y = box.y2 - 1;
|
||||
else if (vec.y < box.y1)
|
||||
y = box.y1;
|
||||
else
|
||||
y = vec.y;
|
||||
|
||||
double distance = sqrt(pow(x, 2) + pow(y, 2));
|
||||
if (distance < bestDist) {
|
||||
bestDist = distance;
|
||||
leader = {x, y};
|
||||
}
|
||||
}
|
||||
|
||||
return leader;
|
||||
}
|
62
src/helpers/Region.hpp
Normal file
62
src/helpers/Region.hpp
Normal file
@@ -0,0 +1,62 @@
|
||||
#pragma once
|
||||
#include <pixman.h>
|
||||
#include <vector>
|
||||
#include "Vector2D.hpp"
|
||||
#include "Box.hpp"
|
||||
|
||||
struct wlr_box;
|
||||
|
||||
class CRegion {
|
||||
public:
|
||||
/* Create an empty region */
|
||||
CRegion();
|
||||
/* Create from a reference. Copies, does not own. */
|
||||
CRegion(pixman_region32_t* ref);
|
||||
/* Create from a box */
|
||||
CRegion(double x, double y, double w, double h);
|
||||
/* Create from a wlr_box */
|
||||
CRegion(wlr_box* box);
|
||||
/* Create from a CBox */
|
||||
CRegion(CBox* box);
|
||||
/* Create from a pixman_box32_t */
|
||||
CRegion(pixman_box32_t* box);
|
||||
|
||||
CRegion(const CRegion&);
|
||||
CRegion(CRegion&&);
|
||||
|
||||
~CRegion();
|
||||
|
||||
CRegion& operator=(CRegion&& other) {
|
||||
pixman_region32_copy(&m_rRegion, other.pixman());
|
||||
return *this;
|
||||
}
|
||||
|
||||
CRegion& operator=(CRegion& other) {
|
||||
pixman_region32_copy(&m_rRegion, other.pixman());
|
||||
return *this;
|
||||
}
|
||||
|
||||
CRegion& clear();
|
||||
CRegion& set(const CRegion& other);
|
||||
CRegion& add(const CRegion& other);
|
||||
CRegion& add(double x, double y, double w, double h);
|
||||
CRegion& subtract(const CRegion& other);
|
||||
CRegion& intersect(const CRegion& other);
|
||||
CRegion& intersect(double x, double y, double w, double h);
|
||||
CRegion& translate(const Vector2D& vec);
|
||||
CRegion& invert(pixman_box32_t* box);
|
||||
CRegion& scale(float scale);
|
||||
CBox getExtents();
|
||||
bool containsPoint(const Vector2D& vec) const;
|
||||
bool empty() const;
|
||||
Vector2D closestPoint(const Vector2D& vec) const;
|
||||
|
||||
std::vector<pixman_box32_t> getRects() const;
|
||||
|
||||
pixman_region32_t* pixman() {
|
||||
return &m_rRegion;
|
||||
}
|
||||
|
||||
private:
|
||||
pixman_region32_t m_rRegion;
|
||||
};
|
@@ -1,9 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
inline const std::vector<std::string> SPLASHES = {
|
||||
// clang-format off
|
||||
"Woo, animations!",
|
||||
"It's like Hypr, but better.",
|
||||
"Release 1.0 when?",
|
||||
@@ -60,4 +61,5 @@ inline const std::vector<std::string> SPLASHES = {
|
||||
"Thanks ThatOneCalculator!",
|
||||
"The AUR packages always work, except for the times they don't.",
|
||||
"Funny animation compositor woo"
|
||||
// clang-format on
|
||||
};
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user