mirror of
https://github.com/rad4day/Waybar.git
synced 2023-12-21 10:22:59 +01:00
Compare commits
832 Commits
Author | SHA1 | Date | |
---|---|---|---|
e5787a2617 | |||
9aec6bbed4 | |||
4f6a9b1bc2 | |||
28e7a96e37 | |||
710f933fa6 | |||
bad72de960 | |||
65166109c9 | |||
91156dfc75 | |||
af2113931a | |||
68e4457f3a | |||
1b4ddbca3a | |||
445ad22580 | |||
88a5f713ed | |||
2009ceb350 | |||
77a2eff2ce | |||
cf832798fb | |||
3f3f2d9c2c | |||
b47705ac21 | |||
b33be38877 | |||
a5fe6f40b8 | |||
245f7f4b11 | |||
1418f96e46 | |||
84a8f79bbe | |||
4b6253e810 | |||
929fc16994 | |||
811f0896c9 | |||
7729ca3427 | |||
100d4d3499 | |||
7f5fd1ac86 | |||
1f5c07a07f | |||
67d482d28b | |||
1440ed29d4 | |||
311c5779ea | |||
9880c6929f | |||
99138ffdcd | |||
08e886ebc6 | |||
6fdbc27998 | |||
40e6360722 | |||
642e28166b | |||
6dfa31fb17 | |||
c91cc2218b | |||
6f2bfd43bf | |||
f43f8773c4 | |||
bb072675ba | |||
fa43072be7 | |||
86a43b9042 | |||
2506c0104a | |||
948eba92a5 | |||
ad09072a6d | |||
9c2b5efe7b | |||
91cdf80c65 | |||
9cce5ea6b5 | |||
8310700bbb | |||
78aaa5c1b4 | |||
7c1303f57c | |||
569517c531 | |||
1c2e0083ba | |||
a8edc0886d | |||
8e1f85e1c3 | |||
5420a91046 | |||
2a52efa99a | |||
d3c59c42ef | |||
368e4813de | |||
36857ae72b | |||
982d571b2e | |||
e62b634f72 | |||
e8278431d2 | |||
14f626d422 | |||
d08fbb2ef2 | |||
5da268077c | |||
20160749e7 | |||
194f4c2f18 | |||
9e34be7b16 | |||
6e041d5275 | |||
33617b67f0 | |||
efaac20d82 | |||
ce97df34e6 | |||
23b9923eeb | |||
999c1b6b81 | |||
1a98ecf6b0 | |||
5444a66e71 | |||
f49a7a1acb | |||
28dfb0ba41 | |||
94a882bf95 | |||
da2d603b53 | |||
7aaa3df701 | |||
729553d3bc | |||
f78a802d11 | |||
826a549d1f | |||
99918205ed | |||
c65ec9e14f | |||
c1427ff807 | |||
0bb436f949 | |||
0fc7ef6685 | |||
c9bbaa7241 | |||
63fdf66ad6 | |||
9357a6cb88 | |||
dbc06abf18 | |||
4d067619a8 | |||
cf3d6545c3 | |||
f3a6e2d494 | |||
cdce3e03ea | |||
b25b7d29fc | |||
71d7596b6f | |||
06e699c862 | |||
a03283d65f | |||
ef38061edd | |||
7e13e26c29 | |||
5f7329f5b9 | |||
2213380dc0 | |||
66d8035ed1 | |||
7cdf178f8d | |||
af3c868a5b | |||
b16c8972c7 | |||
1c9b62de07 | |||
fc89b01ba6 | |||
70e67c5daa | |||
5ad3b6018a | |||
ba278985e8 | |||
5300461c79 | |||
d0f60c47bf | |||
07f2470e36 | |||
f8f1e791a3 | |||
729a4fe37e | |||
97e4b53cf3 | |||
c850212288 | |||
600afaf530 | |||
c21dc681c9 | |||
f4ad5d36ec | |||
f627fe3a39 | |||
7b6dc33824 | |||
b4ee994515 | |||
b1dd62078f | |||
bf3efdb89c | |||
354de5f13f | |||
b4ffb8af45 | |||
a49b12b66b | |||
1573e1eb97 | |||
9b9daaee6f | |||
99643ba2e6 | |||
08ea5ebe1f | |||
cb1c7ea12c | |||
1026100c9d | |||
943ba3a2da | |||
bfa9f1e69b | |||
4d150e9340 | |||
2019028688 | |||
b4728f2e1d | |||
d8706af2ea | |||
08e19602f7 | |||
b12b500bfc | |||
e786ea601e | |||
36da8117c0 | |||
6d5afdaa5f | |||
52dd3d2446 | |||
ecc32ddd18 | |||
38c29fc242 | |||
40f4dc9ecf | |||
95a6689077 | |||
c5f875dc5f | |||
89b5e819a3 | |||
6585381230 | |||
f3ce7ff86c | |||
e4a65c72dd | |||
f14a73584f | |||
fffb52dd93 | |||
71f9ed3099 | |||
e293b89f6b | |||
8a284e7c74 | |||
22ed153004 | |||
ff9f09a24e | |||
7eb2a6b709 | |||
f2e9bb54f0 | |||
ac6667b1c9 | |||
7d78a3aeef | |||
aa088721c3 | |||
97f7050d7d | |||
e21be3382b | |||
72cd753c02 | |||
c8d7b6fa92 | |||
8c70513a24 | |||
35062ceb99 | |||
f05afb5468 | |||
ecba117dc0 | |||
d2a1f41750 | |||
be777b8525 | |||
3881af4bbe | |||
933e0f5280 | |||
149c1c2f1b | |||
6cc3212605 | |||
e19aa1d43a | |||
69a366dced | |||
c9ef731fd0 | |||
cd97bdb30f | |||
3bcf390484 | |||
7fa1c11833 | |||
ab0f2c13af | |||
dc38640341 | |||
66e5fda418 | |||
e06d603154 | |||
392b0679c9 | |||
336cc9f336 | |||
0bd96f339e | |||
ce0bf6269b | |||
fdaba72974 | |||
a2d98ddde8 | |||
51bfe9eaf6 | |||
a25cf4d188 | |||
ede1146ddc | |||
b916ed3cae | |||
9d5ce45f3b | |||
a7941a00c5 | |||
f4ffb21c8c | |||
29cba22405 | |||
b79301a5bd | |||
ef9c3ef1cb | |||
1f620828c2 | |||
f20dbbbd74 | |||
00046d309d | |||
7b7edc9029 | |||
bd208fcec6 | |||
f233d27b78 | |||
42e8667773 | |||
c0361e8546 | |||
3fbbbf8541 | |||
e5684c6127 | |||
0233e0eeec | |||
7fbd3657e8 | |||
005af7f7b7 | |||
94f8f74f51 | |||
f391186749 | |||
e4340a7536 | |||
dd2792b204 | |||
08ee5385ec | |||
73eb517b86 | |||
4b29aef048 | |||
cb7baee045 | |||
85ca5027f4 | |||
50ecc97284 | |||
d382734698 | |||
f91dc7fb6e | |||
0d03c1d4da | |||
68b6136989 | |||
930bb4ba97 | |||
18f129a712 | |||
bb60e68b9d | |||
a70468a2ea | |||
09c89bcd20 | |||
cc365a8175 | |||
ff0d3292a4 | |||
1fe0bcacc0 | |||
f74c22e851 | |||
1ea662a08d | |||
881bb62f88 | |||
f6ef8b41df | |||
c1640ed16c | |||
dd596a5c6c | |||
29f78e0426 | |||
407bf27401 | |||
85df7ce2da | |||
ad40511358 | |||
e8dbdee238 | |||
c784e8170e | |||
31a4aff1f8 | |||
89ca155c43 | |||
908fa2c6c2 | |||
f45d582957 | |||
eb3f4216d4 | |||
e0cdcb6e30 | |||
a7056f7cce | |||
14a6cec6d1 | |||
3b576ae12d | |||
2695985da0 | |||
85e00b2aab | |||
05b12602d4 | |||
374d5ae5a1 | |||
fd11711673 | |||
8282385074 | |||
ef7638d45a | |||
d8dafa7ecc | |||
faacd76f62 | |||
c21e0f6cf3 | |||
9785a89013 | |||
b015836e7b | |||
a9dae931c7 | |||
071cb86b45 | |||
c6743988d3 | |||
bb33427f65 | |||
4889e655eb | |||
aa4fc3dd29 | |||
188611a767 | |||
4872091442 | |||
5600783151 | |||
abe1fa5bd4 | |||
96d965fe04 | |||
9c566564e1 | |||
fc5906dbd4 | |||
fe3aeb36c5 | |||
591a417b7d | |||
d4d35e6b2b | |||
f97de599dd | |||
f01996ae99 | |||
7735c80d0e | |||
2b3d7be9cb | |||
9fa2cc45d2 | |||
7a0c0ca613 | |||
48a8dbece9 | |||
67d54ef3d5 | |||
d5fa20dd33 | |||
be3f47b374 | |||
9ea13e790d | |||
f13f49ccb5 | |||
2cc00ab853 | |||
ed402d7583 | |||
acf990743e | |||
587eb5fdb4 | |||
f151d435a8 | |||
8f961ac397 | |||
cf5db8f663 | |||
54beabb9dc | |||
41752ad5a2 | |||
8349316fcd | |||
4229e9b2ca | |||
5e86014443 | |||
d6381eeaff | |||
45f7f9b07a | |||
6dc1892494 | |||
e9b2d275c8 | |||
7b78a29f3f | |||
f270d317bb | |||
cc3acf8102 | |||
21fdcf41c3 | |||
bcb63b8ccb | |||
22e46ea6cc | |||
aa625f5196 | |||
1f66b06f93 | |||
e4427cb017 | |||
93afe5113a | |||
73681a30e5 | |||
e9b5be9adb | |||
83d679bf72 | |||
b9f83dc77d | |||
7ba14c2097 | |||
3014082ba2 | |||
12016d35bb | |||
6db795401a | |||
43ca8f7050 | |||
063c5a5ace | |||
fcab026512 | |||
95f505a457 | |||
577dc1fa00 | |||
dc625490f8 | |||
c651670222 | |||
459df4e0c9 | |||
eb53fa8d0e | |||
9e3e4368c7 | |||
98b6d7f283 | |||
225a0eccdd | |||
1b22e2b320 | |||
44119db436 | |||
943b6bc51b | |||
4a22057138 | |||
ba78199dd1 | |||
9b51094743 | |||
3c5fd4ba84 | |||
ea722615c4 | |||
6f7d7e645a | |||
8fb54f47ea | |||
447fad34c7 | |||
d263607b27 | |||
b54fb24745 | |||
0cf3b25d50 | |||
033f0b01b7 | |||
f4e15dd93d | |||
3663b9193d | |||
591eb2ea38 | |||
69f5d19455 | |||
4d775008df | |||
4565f7f8b9 | |||
fdfb60c633 | |||
62082bdb01 | |||
8cd6e13308 | |||
31243cdc20 | |||
0aa8c03bea | |||
51a66d5919 | |||
29fa74f621 | |||
4c4691dc2e | |||
8f10c9056c | |||
3bb04e82a5 | |||
9b41b95934 | |||
fb56f89ced | |||
56cbdd1403 | |||
50e8f7ca86 | |||
5ebd3594e4 | |||
d51adfe7bc | |||
a446cd692d | |||
4d6e20a96d | |||
9ebfc54eb5 | |||
f5efb50871 | |||
4cd31cf3c3 | |||
6a2d214b55 | |||
01c682c41e | |||
7d5da1df5e | |||
2ca20f9050 | |||
99f3e37ccf | |||
dcc0201b45 | |||
66aa3574d9 | |||
40d3f1c1fe | |||
1e2ce29f57 | |||
74018167ff | |||
0625bc7688 | |||
fb8cda9d90 | |||
a213aed4da | |||
17967da676 | |||
1f6277e35b | |||
006850ea5e | |||
c3359dec1b | |||
15fe73a252 | |||
246f7bf555 | |||
759602af64 | |||
273c2f3a8f | |||
a1f6e38624 | |||
e3fdd6d94a | |||
27f89bdcc3 | |||
15623ec487 | |||
bc112eaae1 | |||
70e368a1c6 | |||
7d9f6096fe | |||
06ad35c42b | |||
b7e8275d90 | |||
b9cf0a9c9a | |||
14bc842e77 | |||
7d9217b14a | |||
8a13ed59bc | |||
43500a9983 | |||
8e6cbc1021 | |||
d35e92569d | |||
b6067c7569 | |||
8f684f703e | |||
5662f80c43 | |||
5e044e5bba | |||
732ce7a27c | |||
fa6bf597cf | |||
b7a8e8e544 | |||
7429d1f9cc | |||
2c25153506 | |||
401ea05dd8 | |||
b23ba00cff | |||
343a8bef22 | |||
181fde254f | |||
0080feb9af | |||
91a2c4743e | |||
a50c12b6ae | |||
4b2e6b54a7 | |||
adaf843048 | |||
e96a0bf799 | |||
6e7f22ac3a | |||
3b16946c25 | |||
1d92d78de7 | |||
eb624c929d | |||
e72b153f87 | |||
7b4ded306b | |||
49ae944d65 | |||
2585360a3e | |||
2ffc96d0b2 | |||
9a123052a0 | |||
9b9d13ab0d | |||
6ca4e14b29 | |||
6b32aca094 | |||
b251c51936 | |||
a9b17681b0 | |||
60bad8279e | |||
a871dcaebe | |||
cef5b27b48 | |||
c5bbedfabb | |||
e7367c75aa | |||
8d8c048924 | |||
4f646543fc | |||
1885ecc958 | |||
71b7b4e0f4 | |||
4e567d0483 | |||
c4f7cdeec4 | |||
c844d7ac2e | |||
496e782544 | |||
cfd7577e1b | |||
d5df185ac6 | |||
c94ef092ff | |||
74db69dcb7 | |||
fe2dd1e843 | |||
1dc557456e | |||
45deb2472c | |||
8fbaf06cbe | |||
08dce576bd | |||
4b28518cd5 | |||
c9ee528880 | |||
0e869e3aab | |||
6fe764540c | |||
81abd9bb67 | |||
c602d38c8e | |||
c45adddd8e | |||
25648ed9c0 | |||
c8daa48e66 | |||
6a95179456 | |||
ea4dec96e6 | |||
44ed61b2c3 | |||
64f10f8f69 | |||
7b18bfd1a7 | |||
6e946bf872 | |||
e01a081f2f | |||
df0d34dbd4 | |||
b18262f6d0 | |||
d30b775d25 | |||
82c3cccd72 | |||
1814b3b593 | |||
ff7a28274f | |||
8909086b58 | |||
a851dd1198 | |||
9817955fef | |||
774d8ffdba | |||
4a80874da9 | |||
4e19ec93dc | |||
976d3332d4 | |||
2d02ae5e97 | |||
967001d9d3 | |||
09ec40e38d | |||
345c7da384 | |||
9350595158 | |||
a0d5826cbc | |||
7859bf2c60 | |||
acc3ae6e62 | |||
d1c4897f31 | |||
4a7dd400fe | |||
687c50dc13 | |||
b40cdcb5bd | |||
b9338c72c9 | |||
8f6273e9d0 | |||
1fd708cda8 | |||
ac3126b6cf | |||
7c4ea39774 | |||
27fbea2b5a | |||
f34163a065 | |||
6570aefeec | |||
5c5031fd69 | |||
8e0f3c7ddf | |||
8a5c3af949 | |||
d5bd3be8de | |||
bb2c16386b | |||
ec451b5908 | |||
ae3d4b9d28 | |||
af96150f5c | |||
10b152ac3e | |||
9acf5587fa | |||
c302116e73 | |||
ff36154c4b | |||
d12ad1128e | |||
cb2f5c154c | |||
c3cdd516ef | |||
19743f3085 | |||
5db06d99bb | |||
384200f27e | |||
5e712ca255 | |||
d405f28622 | |||
2f975f870a | |||
4471d4aba1 | |||
3945c77668 | |||
6c27af35e9 | |||
2a7e8f7d94 | |||
dd0144c3cd | |||
03130b7565 | |||
4eb462426d | |||
1209022492 | |||
bb88038c17 | |||
37b1b35035 | |||
190b2dd922 | |||
dd7d78cd60 | |||
9abe1e2790 | |||
7bebfebe5f | |||
2d8dc83480 | |||
382cf76503 | |||
9a5f5114c4 | |||
047c2929c1 | |||
9525663014 | |||
3ff1f28533 | |||
4fcf06a164 | |||
9b0660e751 | |||
543589a97b | |||
82d0c87934 | |||
4f8a396692 | |||
6141a26a09 | |||
bb7596045f | |||
16c68ee132 | |||
e0c42ae415 | |||
aae105c998 | |||
b719569243 | |||
e70f8d8730 | |||
e1215a6d17 | |||
119446d538 | |||
d1f427618f | |||
3c268d83c2 | |||
ae6ca36fa7 | |||
83b12fc8a7 | |||
f107aaddc3 | |||
cd2db19267 | |||
4c40f9c635 | |||
84e5b0e8c2 | |||
34a710cce3 | |||
218bb3bc2b | |||
f6b2005687 | |||
ea9591baea | |||
af2528952b | |||
414bf741f3 | |||
527fa982d2 | |||
8e05aab4d9 | |||
6ae9f436a9 | |||
58eb8ad11f | |||
c045288ce4 | |||
f9618d30f3 | |||
e3bf6b968c | |||
e9b0365327 | |||
97554b3532 | |||
1e969a48ae | |||
84b671f6b2 | |||
6e30b7af3c | |||
3130a57622 | |||
d85f0e1060 | |||
89cb9673d4 | |||
f0dbd8b78d | |||
626af1ddc1 | |||
2c4369a653 | |||
b8aeda794c | |||
2dc4ae78fc | |||
bd67c9e620 | |||
a555a72d7f | |||
99dde1aff8 | |||
d5875c468f | |||
9e877d3f57 | |||
f80270519b | |||
8fb3211594 | |||
b9cd51a9cc | |||
569f40de9b | |||
9c8d0865d1 | |||
129713fe1b | |||
e66c3bc965 | |||
75c6e2e7d5 | |||
d294352845 | |||
35f7fdf684 | |||
33798c31d0 | |||
ee0db26021 | |||
abcac464fa | |||
9602360d28 | |||
1d087f96bd | |||
01b8527333 | |||
abeb406166 | |||
443281f0bc | |||
de3be8b2ab | |||
4d7e19ae66 | |||
e8f2bd3ad1 | |||
c41cedd407 | |||
f6864e4a43 | |||
a833c51a28 | |||
1145788ab3 | |||
c0d4867421 | |||
d18ece13f2 | |||
1f379fa5f6 | |||
1125119dc6 | |||
173a7bb8cd | |||
4836333bff | |||
f01ddb9ab3 | |||
2f6a70f34e | |||
def4466953 | |||
db1136d647 | |||
c8821a5e7f | |||
d40cc6f23a | |||
c885be369e | |||
631695ec74 | |||
50275ae529 | |||
35d806b801 | |||
220028051f | |||
7f73a8cd45 | |||
dde700f2c9 | |||
0e87b3938a | |||
d1637d34cf | |||
2277ddd156 | |||
f9543e47dd | |||
4c548a95e8 | |||
6c3cb7c85a | |||
a307042d6b | |||
548589ee5d | |||
b2cec74c04 | |||
6895b3b6b6 | |||
ac8e892cbd | |||
1a05e230b9 | |||
ad08130b52 | |||
a94d5c5ff2 | |||
ecce607afe | |||
73bb42d40c | |||
3bb03852fe | |||
2aaf5510b8 | |||
278f26e597 | |||
03dab1bbdd | |||
0572f75055 | |||
0f0765e517 | |||
de0a3cb020 | |||
eb4c76f5e4 | |||
502b33b64a | |||
6d5b502bbb | |||
2faf629c88 | |||
c0355a3fd3 | |||
67f6dad717 | |||
7f7ebb5367 | |||
b97ca2ec9b | |||
358426cb1c | |||
5e4fdb1530 | |||
1e82982dbd | |||
048d8d328e | |||
6d5e328928 | |||
97e3226801 | |||
3d1fd4f5ea | |||
3131eb0774 | |||
f4d2ca2736 | |||
b3f9425d70 | |||
211b1c2785 | |||
9e13161385 | |||
bd5a215d2a | |||
247589efbb | |||
1d39ef5c8e | |||
4667afaa98 | |||
bae83ee4e3 | |||
52db1e8e68 | |||
334bc1e52a | |||
e6599d8ed5 | |||
5ee4c54b13 | |||
8830247b9e | |||
db74a46d7b | |||
4b24c19fa7 | |||
ce50249c04 | |||
02811293e0 | |||
5bb6fa384d | |||
b6cb02ce85 | |||
a0a218c6e2 | |||
f152ad9fa9 | |||
05d083726c | |||
a0a3c01e79 | |||
228078d538 | |||
e43b63ff02 | |||
dc93fa8218 | |||
a63bc84918 | |||
060b614eb3 | |||
dfb5ec0c65 | |||
1f84936639 | |||
f9b65baa2e | |||
ec23984c4d | |||
56d9cdc245 | |||
529daedcec | |||
089d1299c4 | |||
36fc8365ee | |||
f2f1c4f9cb | |||
2646390e28 | |||
66f2cbed51 | |||
19d7bd4ecf | |||
2e4de1ae3e | |||
ce909eea0b | |||
0b008154d9 | |||
fe88a3fa81 | |||
02e43a38d2 | |||
f592e3d38b | |||
c6d7a779b8 | |||
ceedc689ec | |||
b314cb16a9 | |||
a257126685 | |||
baaeda0ab7 | |||
e3dff6e0d8 | |||
e8a1e6ae35 | |||
3a86125495 | |||
da43336409 | |||
712424f9a8 | |||
e38df047fd | |||
0b237246f0 | |||
01ad3d96d8 | |||
642fd48af1 | |||
8f9e6c132d | |||
ba5592c86a | |||
2a3f40bc02 | |||
c60b905831 | |||
6536f7adb6 | |||
8134215839 | |||
e6fa37164c | |||
436fc94549 | |||
4f9c3d2413 | |||
c19a63e85e | |||
05e212f67a | |||
e01e3be488 | |||
f380844d61 | |||
7f6e4801eb | |||
ac461f38f4 | |||
30efd28b6a | |||
87392ef653 | |||
db85224d59 | |||
07d6a8e936 | |||
53614ab50c | |||
fba1f5c8af | |||
df83404c8c | |||
dd3da7b6ef | |||
cda9eb683f | |||
f0ad918feb | |||
8696ac77f9 | |||
9484cdff7d | |||
9b9818e95d | |||
cf72dee60c | |||
2e037df045 | |||
798fe1a622 | |||
9d0842db48 | |||
d8b1b0d0af | |||
e9b6380c18 | |||
43beefb00d | |||
12f869ccba | |||
7e9207d75c | |||
7a2dee7377 | |||
21a89ac46d | |||
bb99e6cf5b | |||
0834551161 | |||
ccd1586c65 | |||
617b370104 | |||
d607a4e33f | |||
a6c0bc5a52 | |||
67ad0e69ce | |||
ae88d6bc3c | |||
4f3c38c542 | |||
a6980fca7f | |||
bd5146fdcf | |||
22ddbde394 | |||
c916fe258e |
1
.github/FUNDING.yml
vendored
1
.github/FUNDING.yml
vendored
@ -1,3 +1,4 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: Alexays
|
||||
custom: https://paypal.me/ARouillard
|
||||
|
23
.github/workflows/freebsd.yml
vendored
Normal file
23
.github/workflows/freebsd.yml
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
name: freebsd
|
||||
|
||||
on: [ push, pull_request ]
|
||||
|
||||
jobs:
|
||||
clang:
|
||||
runs-on: macos-latest # until https://github.com/actions/runner/issues/385
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Test in FreeBSD VM
|
||||
uses: vmactions/freebsd-vm@v0.1.4 # aka FreeBSD 12.2
|
||||
with:
|
||||
usesh: true
|
||||
prepare: |
|
||||
export CPPFLAGS=-isystem/usr/local/include LDFLAGS=-L/usr/local/lib # sndio
|
||||
sed -i '' 's/quarterly/latest/' /etc/pkg/FreeBSD.conf
|
||||
pkg install -y git # subprojects/date
|
||||
pkg install -y evdev-proto gtk-layer-shell gtkmm30 jsoncpp libdbusmenu \
|
||||
libevdev libfmt libmpdclient libudev-devd meson pkgconf pulseaudio \
|
||||
scdoc sndio spdlog
|
||||
run: |
|
||||
meson build -Dman-pages=enabled
|
||||
ninja -C build
|
25
.github/workflows/linux.yml
vendored
Normal file
25
.github/workflows/linux.yml
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
name: linux
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
matrix:
|
||||
distro:
|
||||
- alpine
|
||||
- archlinux
|
||||
- debian
|
||||
- fedora
|
||||
- opensuse
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: alexays/waybar:${{ matrix.distro }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: configure
|
||||
run: meson -Dman-pages=enabled build
|
||||
- name: build
|
||||
run: ninja -C build
|
20
.travis.yml
20
.travis.yml
@ -1,20 +0,0 @@
|
||||
sudo: false
|
||||
|
||||
services:
|
||||
- docker
|
||||
|
||||
env:
|
||||
- distro: debian
|
||||
- distro: archlinux
|
||||
- distro: opensuse
|
||||
- distro: fedora
|
||||
- distro: alpine
|
||||
|
||||
before_install:
|
||||
- docker pull alexays/waybar:${distro}
|
||||
|
||||
script:
|
||||
- echo FROM alexays/waybar:${distro} > Dockerfile
|
||||
- echo ADD . /root >> Dockerfile
|
||||
- docker build -t waybar .
|
||||
- docker run waybar /bin/sh -c "cd /root && meson build && ninja -C build"
|
@ -1,3 +1,5 @@
|
||||
# vim: ft=Dockerfile
|
||||
|
||||
FROM alpine:latest
|
||||
|
||||
RUN apk add --no-cache git meson alpine-sdk libinput-dev wayland-dev wayland-protocols mesa-dev libxkbcommon-dev eudev-dev pixman-dev gtkmm3-dev jsoncpp-dev libnl3-dev pulseaudio-dev libmpdclient-dev
|
||||
RUN apk add --no-cache git meson alpine-sdk libinput-dev wayland-dev wayland-protocols mesa-dev libxkbcommon-dev eudev-dev pixman-dev gtkmm3-dev jsoncpp-dev pugixml-dev libnl3-dev pulseaudio-dev libmpdclient-dev sndio-dev scdoc libxkbcommon
|
||||
|
@ -1,4 +1,6 @@
|
||||
FROM archlinux/base:latest
|
||||
# vim: ft=Dockerfile
|
||||
|
||||
FROM archlinux:base-devel
|
||||
|
||||
RUN pacman -Syu --noconfirm && \
|
||||
pacman -S git meson base-devel libinput wayland wayland-protocols pixman libxkbcommon mesa gtkmm3 jsoncpp --noconfirm
|
||||
pacman -S git meson base-devel libinput wayland wayland-protocols pixman libxkbcommon mesa gtkmm3 jsoncpp pugixml scdoc libpulse libdbusmenu-gtk3 libmpdclient gobject-introspection --noconfirm libxkbcommon
|
||||
|
@ -1,5 +1,7 @@
|
||||
# vim: ft=Dockerfile
|
||||
|
||||
FROM debian:sid
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get install -y build-essential meson ninja-build git pkg-config libinput10 libinput-dev wayland-protocols libwayland-client0 libwayland-cursor0 libwayland-dev libegl1-mesa-dev libgles2-mesa-dev libgbm-dev libxkbcommon-dev libudev-dev libpixman-1-dev libgtkmm-3.0-dev libjsoncpp-dev && \
|
||||
apt-get clean
|
||||
apt-get install -y build-essential meson ninja-build git pkg-config libinput10 libpugixml-dev libinput-dev wayland-protocols libwayland-client0 libwayland-cursor0 libwayland-dev libegl1-mesa-dev libgles2-mesa-dev libgbm-dev libxkbcommon-dev libudev-dev libpixman-1-dev libgtkmm-3.0-dev libjsoncpp-dev scdoc libdbusmenu-gtk3-dev libnl-3-dev libnl-genl-3-dev libpulse-dev libmpdclient-dev gobject-introspection libgirepository1.0-dev libxkbcommon-dev libxkbregistry-dev libxkbregistry0 && \
|
||||
apt-get clean
|
||||
|
@ -1,5 +1,12 @@
|
||||
FROM fedora:30
|
||||
# vim: ft=Dockerfile
|
||||
|
||||
RUN dnf install sway meson git libinput-devel wayland-devel wayland-protocols-devel egl-wayland-devel mesa-libEGL-devel mesa-libGLES-devel mesa-libgbm-devel libxkbcommon-devel libudev-devel pixman-devel gtkmm30-devel jsoncpp-devel -y && \
|
||||
dnf group install "C Development Tools and Libraries" -y && \
|
||||
FROM fedora:latest
|
||||
|
||||
RUN dnf install -y @c-development git-core meson scdoc 'pkgconfig(date)' \
|
||||
'pkgconfig(dbusmenu-gtk3-0.4)' 'pkgconfig(fmt)' 'pkgconfig(gdk-pixbuf-2.0)' \
|
||||
'pkgconfig(gio-unix-2.0)' 'pkgconfig(gtk-layer-shell-0)' 'pkgconfig(gtkmm-3.0)' \
|
||||
'pkgconfig(jsoncpp)' 'pkgconfig(libinput)' 'pkgconfig(libmpdclient)' \
|
||||
'pkgconfig(libnl-3.0)' 'pkgconfig(libnl-genl-3.0)' 'pkgconfig(libpulse)' \
|
||||
'pkgconfig(libudev)' 'pkgconfig(pugixml)' 'pkgconfig(sigc++-2.0)' 'pkgconfig(spdlog)' \
|
||||
'pkgconfig(wayland-client)' 'pkgconfig(wayland-cursor)' 'pkgconfig(wayland-protocols)' 'pkgconfig(xkbregistry)' && \
|
||||
dnf clean all -y
|
||||
|
@ -1,5 +1,9 @@
|
||||
# vim: ft=Dockerfile
|
||||
|
||||
FROM opensuse/tumbleweed:latest
|
||||
|
||||
RUN zypper -n up && \
|
||||
zypper addrepo https://download.opensuse.org/repositories/X11:Wayland/openSUSE_Tumbleweed/X11:Wayland.repo | echo 'a' && \
|
||||
zypper -n refresh && \
|
||||
zypper -n install -t pattern devel_C_C++ && \
|
||||
zypper -n install git meson clang libinput10 libinput-devel libwayland-client0 libwayland-cursor0 wayland-protocols-devel wayland-devel Mesa-libEGL-devel Mesa-libGLESv2-devel libgbm-devel libxkbcommon-devel libudev-devel libpixman-1-0-devel gtkmm3-devel jsoncpp-devel
|
||||
zypper -n install git meson clang libinput10 libinput-devel pugixml-devel libwayland-client0 libwayland-cursor0 wayland-protocols-devel wayland-devel Mesa-libEGL-devel Mesa-libGLESv2-devel libgbm-devel libxkbcommon-devel libudev-devel libpixman-1-0-devel gtkmm3-devel jsoncpp-devel libxkbregistry-devel scdoc
|
||||
|
2
Makefile
2
Makefile
@ -1,6 +1,6 @@
|
||||
.PHONY: build build-debug run clean default install
|
||||
|
||||
default: run
|
||||
default: build
|
||||
|
||||
build:
|
||||
meson build
|
||||
|
66
README.md
66
README.md
@ -2,16 +2,18 @@
|
||||
|
||||
> Highly customizable Wayland bar for Sway and Wlroots based compositors.<br>
|
||||
> Available in Arch [community](https://www.archlinux.org/packages/community/x86_64/waybar/) or
|
||||
[AUR](https://aur.archlinux.org/packages/waybar-git/) and [openSUSE](https://build.opensuse.org/package/show/X11:Wayland/waybar)<br>
|
||||
[AUR](https://aur.archlinux.org/packages/waybar-git/), [openSUSE](https://build.opensuse.org/package/show/X11:Wayland/waybar), and [Alpine Linux](https://pkgs.alpinelinux.org/packages?name=waybar)<br>
|
||||
> *Waybar [examples](https://github.com/Alexays/Waybar/wiki/Examples)*
|
||||
|
||||
**Current features**
|
||||
#### Current features
|
||||
- Sway (Workspaces, Binding mode, Focused window name)
|
||||
- Tray [#21](https://github.com/Alexays/Waybar/issues/21)
|
||||
- Local time
|
||||
- Battery
|
||||
- Network
|
||||
- Bluetooth
|
||||
- Pulseaudio
|
||||
- Disk
|
||||
- Memory
|
||||
- Cpu load average
|
||||
- Temperature
|
||||
@ -20,11 +22,21 @@
|
||||
- Multiple output configuration
|
||||
- And much more customizations
|
||||
|
||||
**Configuration and Styling**
|
||||
#### Configuration and Styling
|
||||
|
||||
[See the wiki for more details](https://github.com/Alexays/Waybar/wiki).
|
||||
|
||||
**How to build**
|
||||
### Installation
|
||||
|
||||
Waybar is available from a number of Linux distributions:
|
||||
|
||||
[](https://repology.org/project/waybar/versions)
|
||||
|
||||
An Ubuntu PPA with more recent versions is available
|
||||
[here](https://launchpad.net/~nschloe/+archive/ubuntu/waybar).
|
||||
|
||||
|
||||
#### Building from source
|
||||
|
||||
```bash
|
||||
$ git clone https://github.com/Alexays/Waybar
|
||||
@ -42,19 +54,57 @@ $ waybar
|
||||
```
|
||||
gtkmm3
|
||||
jsoncpp
|
||||
libinput
|
||||
|
||||
libsigc++
|
||||
fmt
|
||||
wayland
|
||||
wlroots
|
||||
chrono-date
|
||||
spdlog
|
||||
libgtk-3-dev [gtk-layer-shell]
|
||||
gobject-introspection [gtk-layer-shell]
|
||||
libgirepository1.0-dev [gtk-layer-shell]
|
||||
libpulse [Pulseaudio module]
|
||||
libnl [Network module]
|
||||
sway [Sway modules]
|
||||
libappindicator-gtk3 [Tray module]
|
||||
libdbusmenu-gtk3 [Tray module]
|
||||
libmpdclient [MPD module]
|
||||
libsndio [sndio module]
|
||||
libevdev [KeyboardState module]
|
||||
```
|
||||
|
||||
**Build dependencies**
|
||||
|
||||
```
|
||||
cmake
|
||||
meson
|
||||
scdoc
|
||||
wayland-protocols
|
||||
```
|
||||
|
||||
On Ubuntu you can install all the relevant dependencies using this command (tested with 19.10 and 20.04):
|
||||
|
||||
```
|
||||
sudo apt install \
|
||||
clang-tidy \
|
||||
gobject-introspection \
|
||||
libdbusmenu-gtk3-dev \
|
||||
libevdev-dev \
|
||||
libfmt-dev \
|
||||
libgirepository1.0-dev \
|
||||
libgtk-3-dev \
|
||||
libgtkmm-3.0-dev \
|
||||
libinput-dev \
|
||||
libjsoncpp-dev \
|
||||
libmpdclient-dev \
|
||||
libnl-3-dev \
|
||||
libnl-genl-3-dev \
|
||||
libpulse-dev \
|
||||
libsigc++-2.0-dev \
|
||||
libspdlog-dev \
|
||||
libwayland-dev \
|
||||
scdoc
|
||||
```
|
||||
|
||||
|
||||
Contributions welcome! - have fun :)<br>
|
||||
The style guidelines is [Google's](https://google.github.io/styleguide/cppguide.html)
|
||||
|
||||
|
@ -10,15 +10,15 @@ namespace waybar {
|
||||
class ALabel : public AModule {
|
||||
public:
|
||||
ALabel(const Json::Value &, const std::string &, const std::string &, const std::string &format,
|
||||
uint16_t interval = 0);
|
||||
uint16_t interval = 0, bool ellipsize = false, bool enable_click = false, bool enable_scroll = false);
|
||||
virtual ~ALabel() = default;
|
||||
virtual auto update() -> void;
|
||||
virtual std::string getIcon(uint16_t, const std::string &alt = "", uint16_t max = 0);
|
||||
virtual std::string getIcon(uint16_t, const std::vector<std::string> &alts, uint16_t max = 0);
|
||||
|
||||
protected:
|
||||
Gtk::Label label_;
|
||||
std::string format_;
|
||||
std::string click_param;
|
||||
const std::chrono::seconds interval_;
|
||||
bool alt_ = false;
|
||||
std::string default_format_;
|
||||
|
@ -4,14 +4,15 @@
|
||||
#include <glibmm/markup.h>
|
||||
#include <gtkmm/eventbox.h>
|
||||
#include <json/json.h>
|
||||
|
||||
#include "IModule.hpp"
|
||||
|
||||
namespace waybar {
|
||||
|
||||
class AModule : public IModule {
|
||||
public:
|
||||
AModule(const Json::Value &, const std::string &, const std::string &,
|
||||
bool enable_click = false, bool enable_scroll = false);
|
||||
AModule(const Json::Value &, const std::string &, const std::string &, bool enable_click = false,
|
||||
bool enable_scroll = false);
|
||||
virtual ~AModule();
|
||||
virtual auto update() -> void;
|
||||
virtual operator Gtk::Widget &();
|
||||
@ -24,9 +25,9 @@ class AModule : public IModule {
|
||||
SCROLL_DIR getScrollDir(GdkEventScroll *e);
|
||||
bool tooltipEnabled();
|
||||
|
||||
const std::string name_;
|
||||
const Json::Value &config_;
|
||||
Gtk::EventBox event_box_;
|
||||
std::string click_param_;
|
||||
|
||||
virtual bool handleToggle(GdkEventButton *const &ev);
|
||||
virtual bool handleScroll(GdkEventScroll *);
|
||||
|
@ -1,24 +1,55 @@
|
||||
#pragma once
|
||||
|
||||
#include <gdkmm/monitor.h>
|
||||
#include <glibmm/refptr.h>
|
||||
#include <gtkmm/box.h>
|
||||
#include <gtkmm/cssprovider.h>
|
||||
#include <gtkmm/main.h>
|
||||
#include <gtkmm/window.h>
|
||||
#include <gtkmm/box.h>
|
||||
#include <json/json.h>
|
||||
|
||||
#include "AModule.hpp"
|
||||
#include "idle-inhibit-unstable-v1-client-protocol.h"
|
||||
#include "wlr-layer-shell-unstable-v1-client-protocol.h"
|
||||
#include "xdg-output-unstable-v1-client-protocol.h"
|
||||
|
||||
namespace waybar {
|
||||
|
||||
class Factory;
|
||||
struct waybar_output {
|
||||
struct wl_output * output;
|
||||
std::string name;
|
||||
uint32_t wl_name;
|
||||
struct zxdg_output_v1 *xdg_output;
|
||||
Glib::RefPtr<Gdk::Monitor> monitor;
|
||||
std::string name;
|
||||
std::string identifier;
|
||||
|
||||
std::unique_ptr<struct zxdg_output_v1, decltype(&zxdg_output_v1_destroy)> xdg_output = {
|
||||
nullptr, &zxdg_output_v1_destroy};
|
||||
};
|
||||
|
||||
enum class bar_layer : uint8_t {
|
||||
BOTTOM,
|
||||
TOP,
|
||||
OVERLAY,
|
||||
};
|
||||
|
||||
struct bar_margins {
|
||||
int top = 0;
|
||||
int right = 0;
|
||||
int bottom = 0;
|
||||
int left = 0;
|
||||
};
|
||||
|
||||
class BarSurface {
|
||||
protected:
|
||||
BarSurface() = default;
|
||||
|
||||
public:
|
||||
virtual void setExclusiveZone(bool enable) = 0;
|
||||
virtual void setLayer(bar_layer layer) = 0;
|
||||
virtual void setMargins(const struct bar_margins &margins) = 0;
|
||||
virtual void setPassThrough(bool enable) = 0;
|
||||
virtual void setPosition(const std::string_view &position) = 0;
|
||||
virtual void setSize(uint32_t width, uint32_t height) = 0;
|
||||
virtual void commit(){};
|
||||
|
||||
virtual ~BarSurface() = default;
|
||||
};
|
||||
|
||||
class Bar {
|
||||
@ -27,49 +58,27 @@ class Bar {
|
||||
Bar(const Bar &) = delete;
|
||||
~Bar() = default;
|
||||
|
||||
auto toggle() -> void;
|
||||
void setVisible(bool visible);
|
||||
void toggle();
|
||||
void handleSignal(int);
|
||||
|
||||
struct waybar_output * output;
|
||||
Json::Value config;
|
||||
Gtk::Window window;
|
||||
struct wl_surface * surface;
|
||||
struct zwlr_layer_surface_v1 *layer_surface;
|
||||
bool visible = true;
|
||||
bool vertical = false;
|
||||
struct waybar_output *output;
|
||||
Json::Value config;
|
||||
struct wl_surface * surface;
|
||||
bool exclusive = true;
|
||||
bool visible = true;
|
||||
bool vertical = false;
|
||||
Gtk::Window window;
|
||||
|
||||
private:
|
||||
static constexpr const char *MIN_HEIGHT_MSG =
|
||||
"Requested height: {} exceeds the minimum height: {} required by the modules";
|
||||
static constexpr const char *MIN_WIDTH_MSG =
|
||||
"Requested width: {} exceeds the minimum width: {} required by the modules";
|
||||
static constexpr const char *BAR_SIZE_MSG =
|
||||
"Bar configured (width: {}, height: {}) for output: {}";
|
||||
static constexpr const char *SIZE_DEFINED =
|
||||
"{} size is defined in the config file so it will stay like that";
|
||||
static void layerSurfaceHandleConfigure(void *, struct zwlr_layer_surface_v1 *, uint32_t,
|
||||
uint32_t, uint32_t);
|
||||
static void layerSurfaceHandleClosed(void *, struct zwlr_layer_surface_v1 *);
|
||||
|
||||
void destroyOutput();
|
||||
void onConfigure(GdkEventConfigure *ev);
|
||||
void onRealize();
|
||||
void onMap(GdkEventAny *ev);
|
||||
void setMarginsAndZone(uint32_t height, uint32_t width);
|
||||
void onMap(GdkEventAny *);
|
||||
auto setupWidgets() -> void;
|
||||
void getModules(const Factory &, const std::string &);
|
||||
void setupAltFormatKeyForModule(const std::string &module_name);
|
||||
void setupAltFormatKeyForModuleList(const char *module_list_name);
|
||||
|
||||
struct margins {
|
||||
int top = 0;
|
||||
int right = 0;
|
||||
int bottom = 0;
|
||||
int left = 0;
|
||||
} margins_;
|
||||
uint32_t width_ = 0;
|
||||
uint32_t height_ = 1;
|
||||
uint8_t anchor_;
|
||||
std::unique_ptr<BarSurface> surface_impl_;
|
||||
bar_layer layer_;
|
||||
Gtk::Box left_;
|
||||
Gtk::Box center_;
|
||||
Gtk::Box right_;
|
||||
|
@ -6,14 +6,20 @@
|
||||
#include <unistd.h>
|
||||
#include <wayland-client.h>
|
||||
#include <wordexp.h>
|
||||
|
||||
#include "bar.hpp"
|
||||
|
||||
struct zwlr_layer_shell_v1;
|
||||
struct zwp_idle_inhibitor_v1;
|
||||
struct zwp_idle_inhibit_manager_v1;
|
||||
|
||||
namespace waybar {
|
||||
|
||||
class Client {
|
||||
public:
|
||||
static Client *inst();
|
||||
int main(int argc, char *argv[]);
|
||||
void reset();
|
||||
|
||||
Glib::RefPtr<Gtk::Application> gtk_app;
|
||||
Glib::RefPtr<Gdk::Display> gdk_display;
|
||||
@ -29,27 +35,30 @@ class Client {
|
||||
std::tuple<const std::string, const std::string> getConfigs(const std::string &config,
|
||||
const std::string &style) const;
|
||||
void bindInterfaces();
|
||||
const std::string getValidPath(const std::vector<std::string> &paths) const;
|
||||
void handleOutput(std::unique_ptr<struct waybar_output> &output);
|
||||
bool isValidOutput(const Json::Value &config, std::unique_ptr<struct waybar_output> &output);
|
||||
auto setupConfig(const std::string &config_file) -> void;
|
||||
auto setupCss(const std::string &css_file) -> void;
|
||||
std::unique_ptr<struct waybar_output> &getOutput(uint32_t wl_name);
|
||||
std::vector<Json::Value> getOutputConfigs(std::unique_ptr<struct waybar_output> &output);
|
||||
const std::string getValidPath(const std::vector<std::string> &paths) const;
|
||||
void handleOutput(struct waybar_output &output);
|
||||
bool isValidOutput(const Json::Value &config, struct waybar_output &output);
|
||||
auto setupConfig(const std::string &config_file, int depth) -> void;
|
||||
auto resolveConfigIncludes(Json::Value &config, int depth) -> void;
|
||||
auto mergeConfig(Json::Value &a_config_, Json::Value &b_config_) -> void;
|
||||
auto setupCss(const std::string &css_file) -> void;
|
||||
struct waybar_output & getOutput(void *);
|
||||
std::vector<Json::Value> getOutputConfigs(struct waybar_output &output);
|
||||
|
||||
static void handleGlobal(void *data, struct wl_registry *registry, uint32_t name,
|
||||
const char *interface, uint32_t version);
|
||||
static void handleGlobalRemove(void *data, struct wl_registry *registry, uint32_t name);
|
||||
static void handleLogicalPosition(void *, struct zxdg_output_v1 *, int32_t, int32_t);
|
||||
static void handleLogicalSize(void *, struct zxdg_output_v1 *, int32_t, int32_t);
|
||||
static void handleDone(void *, struct zxdg_output_v1 *);
|
||||
static void handleName(void *, struct zxdg_output_v1 *, const char *);
|
||||
static void handleDescription(void *, struct zxdg_output_v1 *, const char *);
|
||||
static void handleOutputDone(void *, struct zxdg_output_v1 *);
|
||||
static void handleOutputName(void *, struct zxdg_output_v1 *, const char *);
|
||||
static void handleOutputDescription(void *, struct zxdg_output_v1 *, const char *);
|
||||
void handleMonitorAdded(Glib::RefPtr<Gdk::Monitor> monitor);
|
||||
void handleMonitorRemoved(Glib::RefPtr<Gdk::Monitor> monitor);
|
||||
void handleDeferredMonitorRemoval(Glib::RefPtr<Gdk::Monitor> monitor);
|
||||
|
||||
Json::Value config_;
|
||||
Glib::RefPtr<Gtk::StyleContext> style_context_;
|
||||
Glib::RefPtr<Gtk::CssProvider> css_provider_;
|
||||
std::vector<std::unique_ptr<struct waybar_output>> outputs_;
|
||||
Json::Value config_;
|
||||
Glib::RefPtr<Gtk::StyleContext> style_context_;
|
||||
Glib::RefPtr<Gtk::CssProvider> css_provider_;
|
||||
std::list<struct waybar_output> outputs_;
|
||||
};
|
||||
|
||||
} // namespace waybar
|
||||
|
@ -1,19 +1,35 @@
|
||||
#pragma once
|
||||
|
||||
#include <json/json.h>
|
||||
#ifdef HAVE_LIBDATE
|
||||
#include "modules/clock.hpp"
|
||||
#else
|
||||
#include "modules/simpleclock.hpp"
|
||||
#endif
|
||||
#ifdef HAVE_SWAY
|
||||
#include "modules/sway/mode.hpp"
|
||||
#include "modules/sway/window.hpp"
|
||||
#include "modules/sway/workspaces.hpp"
|
||||
#include "modules/sway/language.hpp"
|
||||
#endif
|
||||
#ifndef NO_FILESYSTEM
|
||||
#ifdef HAVE_WLR
|
||||
#include "modules/wlr/taskbar.hpp"
|
||||
#endif
|
||||
#ifdef HAVE_RIVER
|
||||
#include "modules/river/tags.hpp"
|
||||
#endif
|
||||
#if defined(__linux__) && !defined(NO_FILESYSTEM)
|
||||
#include "modules/battery.hpp"
|
||||
#endif
|
||||
#if defined(HAVE_CPU_LINUX) || defined(HAVE_CPU_BSD)
|
||||
#include "modules/cpu.hpp"
|
||||
#endif
|
||||
#include "modules/idle_inhibitor.hpp"
|
||||
#if defined(HAVE_MEMORY_LINUX) || defined(HAVE_MEMORY_BSD)
|
||||
#include "modules/memory.hpp"
|
||||
#if defined(HAVE_DBUSMENU) && !defined(NO_FILESYSTEM)
|
||||
#endif
|
||||
#include "modules/disk.hpp"
|
||||
#ifdef HAVE_DBUSMENU
|
||||
#include "modules/sni/tray.hpp"
|
||||
#endif
|
||||
#ifdef HAVE_LIBNL
|
||||
@ -22,15 +38,26 @@
|
||||
#ifdef HAVE_LIBUDEV
|
||||
#include "modules/backlight.hpp"
|
||||
#endif
|
||||
#ifdef HAVE_LIBEVDEV
|
||||
#include "modules/keyboard_state.hpp"
|
||||
#endif
|
||||
#ifdef HAVE_LIBPULSE
|
||||
#include "modules/pulseaudio.hpp"
|
||||
#endif
|
||||
#ifdef HAVE_LIBMPDCLIENT
|
||||
#include "modules/mpd.hpp"
|
||||
#include "modules/mpd/mpd.hpp"
|
||||
#endif
|
||||
#ifdef HAVE_LIBSNDIO
|
||||
#include "modules/sndio.hpp"
|
||||
#endif
|
||||
#include "bar.hpp"
|
||||
#include "modules/custom.hpp"
|
||||
#include "modules/temperature.hpp"
|
||||
#if defined(__linux__)
|
||||
# ifdef WANT_RFKILL
|
||||
# include "modules/bluetooth.hpp"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
namespace waybar {
|
||||
|
||||
|
@ -31,19 +31,22 @@ class Battery : public ALabel {
|
||||
private:
|
||||
static inline const fs::path data_dir_ = "/sys/class/power_supply/";
|
||||
|
||||
void getBatteries();
|
||||
void worker();
|
||||
const std::string getAdapterStatus(uint8_t capacity) const;
|
||||
const std::tuple<uint8_t, float, std::string> getInfos() const;
|
||||
const std::string formatTimeRemaining(float hoursRemaining);
|
||||
void refreshBatteries();
|
||||
void worker();
|
||||
const std::string getAdapterStatus(uint8_t capacity) const;
|
||||
const std::tuple<uint8_t, float, std::string, float> getInfos();
|
||||
const std::string formatTimeRemaining(float hoursRemaining);
|
||||
|
||||
std::vector<fs::path> batteries_;
|
||||
int global_watch;
|
||||
std::map<fs::path,int> batteries_;
|
||||
fs::path adapter_;
|
||||
int fd_;
|
||||
std::vector<int> wds_;
|
||||
int battery_watch_fd_;
|
||||
int global_watch_fd_;
|
||||
std::mutex battery_list_mutex_;
|
||||
std::string old_status_;
|
||||
|
||||
util::SleeperThread thread_;
|
||||
util::SleeperThread thread_battery_update_;
|
||||
util::SleeperThread thread_timer_;
|
||||
};
|
||||
|
||||
|
18
include/modules/bluetooth.hpp
Normal file
18
include/modules/bluetooth.hpp
Normal file
@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include "ALabel.hpp"
|
||||
#include "util/rfkill.hpp"
|
||||
|
||||
namespace waybar::modules {
|
||||
|
||||
class Bluetooth : public ALabel {
|
||||
public:
|
||||
Bluetooth(const std::string&, const Json::Value&);
|
||||
~Bluetooth() = default;
|
||||
auto update() -> void;
|
||||
|
||||
private:
|
||||
util::Rfkill rfkill_;
|
||||
};
|
||||
|
||||
} // namespace waybar::modules
|
@ -1,12 +1,22 @@
|
||||
#pragma once
|
||||
|
||||
#include <fmt/format.h>
|
||||
#if FMT_VERSION < 60000
|
||||
#include <fmt/time.h>
|
||||
#else
|
||||
#include <fmt/chrono.h>
|
||||
#endif
|
||||
#include <date/tz.h>
|
||||
#include "ALabel.hpp"
|
||||
#include "fmt/time.h"
|
||||
#include "util/sleeper_thread.hpp"
|
||||
|
||||
namespace waybar::modules {
|
||||
|
||||
struct waybar_time {
|
||||
std::locale locale;
|
||||
date::zoned_seconds ztime;
|
||||
};
|
||||
|
||||
class Clock : public ALabel {
|
||||
public:
|
||||
Clock(const std::string&, const Json::Value&);
|
||||
@ -15,6 +25,18 @@ class Clock : public ALabel {
|
||||
|
||||
private:
|
||||
util::SleeperThread thread_;
|
||||
std::locale locale_;
|
||||
const date::time_zone* time_zone_;
|
||||
bool fixed_time_zone_;
|
||||
int time_zone_idx_;
|
||||
date::year_month_day cached_calendar_ymd_ = date::January/1/0;
|
||||
std::string cached_calendar_text_;
|
||||
|
||||
bool handleScroll(GdkEventScroll* e);
|
||||
|
||||
auto calendar_text(const waybar_time& wtime) -> std::string;
|
||||
auto weekdays_header(const date::weekday& first_dow, std::ostream& os) -> void;
|
||||
auto first_day_of_week() -> date::weekday;
|
||||
};
|
||||
|
||||
} // namespace waybar::modules
|
||||
|
@ -1,7 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <fmt/format.h>
|
||||
#include <sys/sysinfo.h>
|
||||
#include <cstdint>
|
||||
#include <fstream>
|
||||
#include <numeric>
|
||||
@ -20,10 +19,11 @@ class Cpu : public ALabel {
|
||||
auto update() -> void;
|
||||
|
||||
private:
|
||||
static inline const std::string data_dir_ = "/proc/stat";
|
||||
uint16_t getCpuLoad();
|
||||
double getCpuLoad();
|
||||
std::tuple<uint16_t, std::string> getCpuUsage();
|
||||
std::tuple<float, float, float> getCpuFrequency();
|
||||
std::vector<std::tuple<size_t, size_t>> parseCpuinfo();
|
||||
std::vector<float> parseCpuFrequencies();
|
||||
|
||||
std::vector<std::tuple<size_t, size_t>> prev_times_;
|
||||
|
||||
|
@ -22,6 +22,7 @@ class Custom : public ALabel {
|
||||
void continuousWorker();
|
||||
void parseOutputRaw();
|
||||
void parseOutputJson();
|
||||
void handleEvent();
|
||||
bool handleScroll(GdkEventScroll* e);
|
||||
bool handleToggle(GdkEventButton* const& e);
|
||||
|
||||
|
23
include/modules/disk.hpp
Normal file
23
include/modules/disk.hpp
Normal file
@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
#include <fmt/format.h>
|
||||
#include <fstream>
|
||||
#include <sys/statvfs.h>
|
||||
#include "ALabel.hpp"
|
||||
#include "util/sleeper_thread.hpp"
|
||||
#include "util/format.hpp"
|
||||
|
||||
namespace waybar::modules {
|
||||
|
||||
class Disk : public ALabel {
|
||||
public:
|
||||
Disk(const std::string&, const Json::Value&);
|
||||
~Disk() = default;
|
||||
auto update() -> void;
|
||||
|
||||
private:
|
||||
util::SleeperThread thread_;
|
||||
std::string path_;
|
||||
};
|
||||
|
||||
} // namespace waybar::modules
|
@ -12,12 +12,13 @@ class IdleInhibitor : public ALabel {
|
||||
IdleInhibitor(const std::string&, const waybar::Bar&, const Json::Value&);
|
||||
~IdleInhibitor();
|
||||
auto update() -> void;
|
||||
static std::list<waybar::AModule*> modules;
|
||||
static bool status;
|
||||
|
||||
private:
|
||||
bool handleToggle(GdkEventButton* const& e);
|
||||
|
||||
const Bar& bar_;
|
||||
std::string status_;
|
||||
struct zwp_idle_inhibitor_v1* idle_inhibitor_;
|
||||
int pid_;
|
||||
};
|
||||
|
47
include/modules/keyboard_state.hpp
Normal file
47
include/modules/keyboard_state.hpp
Normal file
@ -0,0 +1,47 @@
|
||||
#pragma once
|
||||
|
||||
#include <fmt/format.h>
|
||||
#if FMT_VERSION < 60000
|
||||
#include <fmt/time.h>
|
||||
#else
|
||||
#include <fmt/chrono.h>
|
||||
#endif
|
||||
#include "AModule.hpp"
|
||||
#include "bar.hpp"
|
||||
#include "util/sleeper_thread.hpp"
|
||||
#include <gtkmm/label.h>
|
||||
|
||||
extern "C" {
|
||||
#include <libevdev/libevdev.h>
|
||||
}
|
||||
|
||||
namespace waybar::modules {
|
||||
|
||||
class KeyboardState : public AModule {
|
||||
public:
|
||||
KeyboardState(const std::string&, const waybar::Bar&, const Json::Value&);
|
||||
~KeyboardState();
|
||||
auto update() -> void;
|
||||
|
||||
private:
|
||||
static auto openDevice(const std::string&) -> std::pair<int, libevdev*>;
|
||||
|
||||
Gtk::Box box_;
|
||||
Gtk::Label numlock_label_;
|
||||
Gtk::Label capslock_label_;
|
||||
Gtk::Label scrolllock_label_;
|
||||
|
||||
std::string numlock_format_;
|
||||
std::string capslock_format_;
|
||||
std::string scrolllock_format_;
|
||||
const std::chrono::seconds interval_;
|
||||
std::string icon_locked_;
|
||||
std::string icon_unlocked_;
|
||||
|
||||
int fd_;
|
||||
libevdev* dev_;
|
||||
|
||||
util::SleeperThread thread_;
|
||||
};
|
||||
|
||||
} // namespace waybar::modules
|
@ -2,6 +2,7 @@
|
||||
|
||||
#include <fmt/format.h>
|
||||
#include <fstream>
|
||||
#include <unordered_map>
|
||||
#include "ALabel.hpp"
|
||||
#include "util/sleeper_thread.hpp"
|
||||
|
||||
@ -14,11 +15,9 @@ class Memory : public ALabel {
|
||||
auto update() -> void;
|
||||
|
||||
private:
|
||||
static inline const std::string data_dir_ = "/proc/meminfo";
|
||||
void parseMeminfo();
|
||||
|
||||
unsigned long memtotal_;
|
||||
unsigned long memfree_;
|
||||
std::unordered_map<std::string, unsigned long> meminfo_;
|
||||
|
||||
util::SleeperThread thread_;
|
||||
};
|
||||
|
@ -1,70 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <fmt/format.h>
|
||||
#include <mpd/client.h>
|
||||
#include <condition_variable>
|
||||
#include <thread>
|
||||
#include "ALabel.hpp"
|
||||
|
||||
namespace waybar::modules {
|
||||
|
||||
class MPD : public ALabel {
|
||||
public:
|
||||
MPD(const std::string&, const Json::Value&);
|
||||
auto update() -> void;
|
||||
|
||||
private:
|
||||
std::thread periodic_updater();
|
||||
std::string getTag(mpd_tag_type type, unsigned idx = 0);
|
||||
void setLabel();
|
||||
std::string getStateIcon();
|
||||
std::string getOptionIcon(std::string optionName, bool activated);
|
||||
|
||||
std::thread event_listener();
|
||||
|
||||
// Assumes `connection_lock_` is locked
|
||||
void tryConnect();
|
||||
// If checking errors on the main connection, make sure to lock it using
|
||||
// `connection_lock_` before calling checkErrors
|
||||
void checkErrors(mpd_connection* conn);
|
||||
|
||||
// Assumes `connection_lock_` is locked
|
||||
void fetchState();
|
||||
void waitForEvent();
|
||||
|
||||
bool handlePlayPause(GdkEventButton* const&);
|
||||
|
||||
bool stopped();
|
||||
bool playing();
|
||||
|
||||
const std::string module_name_;
|
||||
|
||||
using unique_connection = std::unique_ptr<mpd_connection, decltype(&mpd_connection_free)>;
|
||||
using unique_status = std::unique_ptr<mpd_status, decltype(&mpd_status_free)>;
|
||||
using unique_song = std::unique_ptr<mpd_song, decltype(&mpd_song_free)>;
|
||||
|
||||
// Not using unique_ptr since we don't manage the pointer
|
||||
// (It's either nullptr, or from the config)
|
||||
const char* server_;
|
||||
const unsigned port_;
|
||||
|
||||
unsigned timeout_;
|
||||
|
||||
// We need a mutex here because we can trigger updates from multiple thread:
|
||||
// the event based updates, the periodic updates needed for the elapsed time,
|
||||
// and the click play/pause feature
|
||||
std::mutex connection_lock_;
|
||||
unique_connection connection_;
|
||||
// The alternate connection will be used to wait for events: since it will
|
||||
// be blocking (idle) we can't send commands via this connection
|
||||
//
|
||||
// No lock since only used in the event listener thread
|
||||
unique_connection alternate_connection_;
|
||||
|
||||
// Protect them using the `connection_lock_`
|
||||
unique_status status_;
|
||||
mpd_state state_;
|
||||
unique_song song_;
|
||||
};
|
||||
|
||||
} // namespace waybar::modules
|
67
include/modules/mpd/mpd.hpp
Normal file
67
include/modules/mpd/mpd.hpp
Normal file
@ -0,0 +1,67 @@
|
||||
#pragma once
|
||||
|
||||
#include <fmt/format.h>
|
||||
#include <mpd/client.h>
|
||||
#include <spdlog/spdlog.h>
|
||||
|
||||
#include <condition_variable>
|
||||
#include <thread>
|
||||
|
||||
#include "ALabel.hpp"
|
||||
#include "modules/mpd/state.hpp"
|
||||
|
||||
namespace waybar::modules {
|
||||
|
||||
class MPD : public ALabel {
|
||||
friend class detail::Context;
|
||||
|
||||
// State machine
|
||||
detail::Context context_{this};
|
||||
|
||||
const std::string module_name_;
|
||||
|
||||
// Not using unique_ptr since we don't manage the pointer
|
||||
// (It's either nullptr, or from the config)
|
||||
const char* server_;
|
||||
const unsigned port_;
|
||||
const std::string password_;
|
||||
|
||||
unsigned timeout_;
|
||||
|
||||
detail::unique_connection connection_;
|
||||
|
||||
detail::unique_status status_;
|
||||
mpd_state state_;
|
||||
detail::unique_song song_;
|
||||
|
||||
public:
|
||||
MPD(const std::string&, const Json::Value&);
|
||||
virtual ~MPD() noexcept = default;
|
||||
auto update() -> void;
|
||||
|
||||
private:
|
||||
std::string getTag(mpd_tag_type type, unsigned idx = 0) const;
|
||||
void setLabel();
|
||||
std::string getStateIcon() const;
|
||||
std::string getOptionIcon(std::string optionName, bool activated) const;
|
||||
|
||||
// GUI-side methods
|
||||
bool handlePlayPause(GdkEventButton* const&);
|
||||
void emit() { dp.emit(); }
|
||||
|
||||
// MPD-side, Non-GUI methods.
|
||||
void tryConnect();
|
||||
void checkErrors(mpd_connection* conn);
|
||||
void fetchState();
|
||||
void queryMPD();
|
||||
|
||||
inline bool stopped() const { return connection_ && state_ == MPD_STATE_STOP; }
|
||||
inline bool playing() const { return connection_ && state_ == MPD_STATE_PLAY; }
|
||||
inline bool paused() const { return connection_ && state_ == MPD_STATE_PAUSE; }
|
||||
};
|
||||
|
||||
#if !defined(MPD_NOINLINE)
|
||||
#include "modules/mpd/state.inl.hpp"
|
||||
#endif
|
||||
|
||||
} // namespace waybar::modules
|
217
include/modules/mpd/state.hpp
Normal file
217
include/modules/mpd/state.hpp
Normal file
@ -0,0 +1,217 @@
|
||||
#pragma once
|
||||
|
||||
#include <mpd/client.h>
|
||||
#include <fmt/format.h>
|
||||
#include <spdlog/spdlog.h>
|
||||
|
||||
#include <condition_variable>
|
||||
#include <thread>
|
||||
|
||||
#include "ALabel.hpp"
|
||||
|
||||
namespace waybar::modules {
|
||||
class MPD;
|
||||
} // namespace waybar::modules
|
||||
|
||||
namespace waybar::modules::detail {
|
||||
|
||||
using unique_connection = std::unique_ptr<mpd_connection, decltype(&mpd_connection_free)>;
|
||||
using unique_status = std::unique_ptr<mpd_status, decltype(&mpd_status_free)>;
|
||||
using unique_song = std::unique_ptr<mpd_song, decltype(&mpd_song_free)>;
|
||||
|
||||
class Context;
|
||||
|
||||
/// This state machine loosely follows a non-hierarchical, statechart
|
||||
/// pattern, and includes ENTRY and EXIT actions.
|
||||
///
|
||||
/// The State class is the base class for all other states. The
|
||||
/// entry and exit methods are automatically called when entering
|
||||
/// into a new state and exiting from the current state. This
|
||||
/// includes initially entering (Disconnected class) and exiting
|
||||
/// Waybar.
|
||||
///
|
||||
/// The following nested "top-level" states are represented:
|
||||
/// 1. Idle - await notification of MPD activity.
|
||||
/// 2. All Non-Idle states:
|
||||
/// 1. Playing - An active song is producing audio output.
|
||||
/// 2. Paused - The current song is paused.
|
||||
/// 3. Stopped - No song is actively playing.
|
||||
/// 3. Disconnected - periodically attempt MPD (re-)connection.
|
||||
///
|
||||
/// NOTE: Since this statechart is non-hierarchical, the above
|
||||
/// states are flattened into a set.
|
||||
|
||||
class State {
|
||||
public:
|
||||
virtual ~State() noexcept = default;
|
||||
|
||||
virtual void entry() noexcept { spdlog::debug("mpd: ignore entry action"); }
|
||||
virtual void exit() noexcept { spdlog::debug("mpd: ignore exit action"); }
|
||||
|
||||
virtual void play() { spdlog::debug("mpd: ignore play state transition"); }
|
||||
virtual void stop() { spdlog::debug("mpd: ignore stop state transition"); }
|
||||
virtual void pause() { spdlog::debug("mpd: ignore pause state transition"); }
|
||||
|
||||
/// Request state update the GUI.
|
||||
virtual void update() noexcept { spdlog::debug("mpd: ignoring update method request"); }
|
||||
};
|
||||
|
||||
class Idle : public State {
|
||||
Context* const ctx_;
|
||||
sigc::connection idle_connection_;
|
||||
|
||||
public:
|
||||
Idle(Context* const ctx) : ctx_{ctx} {}
|
||||
virtual ~Idle() noexcept { this->exit(); };
|
||||
|
||||
void entry() noexcept override;
|
||||
void exit() noexcept override;
|
||||
|
||||
void play() override;
|
||||
void stop() override;
|
||||
void pause() override;
|
||||
void update() noexcept override;
|
||||
|
||||
private:
|
||||
Idle(const Idle&) = delete;
|
||||
Idle& operator=(const Idle&) = delete;
|
||||
|
||||
bool on_io(Glib::IOCondition const&);
|
||||
};
|
||||
|
||||
class Playing : public State {
|
||||
Context* const ctx_;
|
||||
sigc::connection timer_connection_;
|
||||
|
||||
public:
|
||||
Playing(Context* const ctx) : ctx_{ctx} {}
|
||||
virtual ~Playing() noexcept { this->exit(); }
|
||||
|
||||
void entry() noexcept override;
|
||||
void exit() noexcept override;
|
||||
|
||||
void pause() override;
|
||||
void stop() override;
|
||||
void update() noexcept override;
|
||||
|
||||
private:
|
||||
Playing(Playing const&) = delete;
|
||||
Playing& operator=(Playing const&) = delete;
|
||||
|
||||
bool on_timer();
|
||||
};
|
||||
|
||||
class Paused : public State {
|
||||
Context* const ctx_;
|
||||
sigc::connection timer_connection_;
|
||||
|
||||
public:
|
||||
Paused(Context* const ctx) : ctx_{ctx} {}
|
||||
virtual ~Paused() noexcept { this->exit(); }
|
||||
|
||||
void entry() noexcept override;
|
||||
void exit() noexcept override;
|
||||
|
||||
void play() override;
|
||||
void stop() override;
|
||||
void update() noexcept override;
|
||||
|
||||
private:
|
||||
Paused(Paused const&) = delete;
|
||||
Paused& operator=(Paused const&) = delete;
|
||||
|
||||
bool on_timer();
|
||||
};
|
||||
|
||||
class Stopped : public State {
|
||||
Context* const ctx_;
|
||||
sigc::connection timer_connection_;
|
||||
|
||||
public:
|
||||
Stopped(Context* const ctx) : ctx_{ctx} {}
|
||||
virtual ~Stopped() noexcept { this->exit(); }
|
||||
|
||||
void entry() noexcept override;
|
||||
void exit() noexcept override;
|
||||
|
||||
void play() override;
|
||||
void pause() override;
|
||||
void update() noexcept override;
|
||||
|
||||
private:
|
||||
Stopped(Stopped const&) = delete;
|
||||
Stopped& operator=(Stopped const&) = delete;
|
||||
|
||||
bool on_timer();
|
||||
};
|
||||
|
||||
class Disconnected : public State {
|
||||
Context* const ctx_;
|
||||
sigc::connection timer_connection_;
|
||||
|
||||
public:
|
||||
Disconnected(Context* const ctx) : ctx_{ctx} {}
|
||||
virtual ~Disconnected() noexcept { this->exit(); }
|
||||
|
||||
void entry() noexcept override;
|
||||
void exit() noexcept override;
|
||||
|
||||
void update() noexcept override;
|
||||
|
||||
private:
|
||||
Disconnected(Disconnected const&) = delete;
|
||||
Disconnected& operator=(Disconnected const&) = delete;
|
||||
|
||||
void arm_timer(int interval) noexcept;
|
||||
void disarm_timer() noexcept;
|
||||
|
||||
bool on_timer();
|
||||
};
|
||||
|
||||
class Context {
|
||||
std::unique_ptr<State> state_;
|
||||
waybar::modules::MPD* mpd_module_;
|
||||
|
||||
friend class State;
|
||||
friend class Playing;
|
||||
friend class Paused;
|
||||
friend class Stopped;
|
||||
friend class Disconnected;
|
||||
friend class Idle;
|
||||
|
||||
protected:
|
||||
void setState(std::unique_ptr<State>&& new_state) noexcept {
|
||||
if (state_.get() != nullptr) {
|
||||
state_->exit();
|
||||
}
|
||||
state_ = std::move(new_state);
|
||||
state_->entry();
|
||||
}
|
||||
|
||||
bool is_connected() const;
|
||||
bool is_playing() const;
|
||||
bool is_paused() const;
|
||||
bool is_stopped() const;
|
||||
constexpr std::size_t interval() const;
|
||||
void tryConnect() const;
|
||||
void checkErrors(mpd_connection*) const;
|
||||
void do_update();
|
||||
void queryMPD() const;
|
||||
void fetchState() const;
|
||||
constexpr mpd_state state() const;
|
||||
void emit() const;
|
||||
[[nodiscard]] unique_connection& connection();
|
||||
|
||||
public:
|
||||
explicit Context(waybar::modules::MPD* const mpd_module)
|
||||
: state_{std::make_unique<Disconnected>(this)}, mpd_module_{mpd_module} {
|
||||
state_->entry();
|
||||
}
|
||||
|
||||
void play() { state_->play(); }
|
||||
void stop() { state_->stop(); }
|
||||
void pause() { state_->pause(); }
|
||||
void update() noexcept { state_->update(); }
|
||||
};
|
||||
|
||||
} // namespace waybar::modules::detail
|
24
include/modules/mpd/state.inl.hpp
Normal file
24
include/modules/mpd/state.inl.hpp
Normal file
@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
namespace detail {
|
||||
|
||||
inline bool Context::is_connected() const { return mpd_module_->connection_ != nullptr; }
|
||||
inline bool Context::is_playing() const { return mpd_module_->playing(); }
|
||||
inline bool Context::is_paused() const { return mpd_module_->paused(); }
|
||||
inline bool Context::is_stopped() const { return mpd_module_->stopped(); }
|
||||
|
||||
constexpr inline std::size_t Context::interval() const { return mpd_module_->interval_.count(); }
|
||||
inline void Context::tryConnect() const { mpd_module_->tryConnect(); }
|
||||
inline unique_connection& Context::connection() { return mpd_module_->connection_; }
|
||||
constexpr inline mpd_state Context::state() const { return mpd_module_->state_; }
|
||||
|
||||
inline void Context::do_update() {
|
||||
mpd_module_->setLabel();
|
||||
}
|
||||
|
||||
inline void Context::checkErrors(mpd_connection* conn) const { mpd_module_->checkErrors(conn); }
|
||||
inline void Context::queryMPD() const { mpd_module_->queryMPD(); }
|
||||
inline void Context::fetchState() const { mpd_module_->fetchState(); }
|
||||
inline void Context::emit() const { mpd_module_->emit(); }
|
||||
|
||||
} // namespace detail
|
@ -2,15 +2,16 @@
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <fmt/format.h>
|
||||
#include <ifaddrs.h>
|
||||
#include <linux/nl80211.h>
|
||||
#include <net/if.h>
|
||||
#include <netlink/genl/ctrl.h>
|
||||
#include <netlink/genl/genl.h>
|
||||
#include <netlink/netlink.h>
|
||||
#include <sys/epoll.h>
|
||||
#include "ALabel.hpp"
|
||||
#include "util/sleeper_thread.hpp"
|
||||
#ifdef WANT_RFKILL
|
||||
#include "util/rfkill.hpp"
|
||||
#endif
|
||||
|
||||
namespace waybar::modules {
|
||||
|
||||
@ -25,23 +26,20 @@ class Network : public ALabel {
|
||||
static const uint8_t EPOLL_MAX = 200;
|
||||
|
||||
static int handleEvents(struct nl_msg*, void*);
|
||||
static int handleEventsDone(struct nl_msg*, void*);
|
||||
static int handleScan(struct nl_msg*, void*);
|
||||
|
||||
void askForStateDump(void);
|
||||
|
||||
void worker();
|
||||
void createInfoSocket();
|
||||
void createEventSocket();
|
||||
int getExternalInterface(int skip_idx = -1) const;
|
||||
void getInterfaceAddress();
|
||||
int netlinkRequest(void*, uint32_t, uint32_t groups = 0) const;
|
||||
int netlinkResponse(void*, uint32_t, uint32_t groups = 0) const;
|
||||
void parseEssid(struct nlattr**);
|
||||
void parseSignal(struct nlattr**);
|
||||
void parseFreq(struct nlattr**);
|
||||
bool associatedOrJoined(struct nlattr**);
|
||||
bool checkInterface(struct ifinfomsg* rtif, std::string name);
|
||||
int getPreferredIface(int skip_idx = -1) const;
|
||||
bool checkInterface(std::string name);
|
||||
auto getInfo() -> void;
|
||||
void checkNewInterface(struct ifinfomsg* rtif);
|
||||
const std::string getNetworkState() const;
|
||||
void clearIface();
|
||||
bool wildcardMatch(const std::string& pattern, const std::string& text) const;
|
||||
@ -56,11 +54,17 @@ class Network : public ALabel {
|
||||
int nl80211_id_;
|
||||
std::mutex mutex_;
|
||||
|
||||
bool want_route_dump_;
|
||||
bool want_link_dump_;
|
||||
bool want_addr_dump_;
|
||||
bool dump_in_progress_;
|
||||
|
||||
unsigned long long bandwidth_down_total_;
|
||||
unsigned long long bandwidth_up_total_;
|
||||
|
||||
std::string state_;
|
||||
std::string essid_;
|
||||
bool carrier_;
|
||||
std::string ifname_;
|
||||
std::string ipaddr_;
|
||||
std::string netmask_;
|
||||
@ -68,9 +72,13 @@ class Network : public ALabel {
|
||||
int32_t signal_strength_dbm_;
|
||||
uint8_t signal_strength_;
|
||||
uint32_t frequency_;
|
||||
uint32_t route_priority;
|
||||
|
||||
util::SleeperThread thread_;
|
||||
util::SleeperThread thread_timer_;
|
||||
#ifdef WANT_RFKILL
|
||||
util::Rfkill rfkill_;
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace waybar::modules
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include <pulse/pulseaudio.h>
|
||||
#include <pulse/volume.h>
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include "ALabel.hpp"
|
||||
|
||||
namespace waybar::modules {
|
||||
@ -23,7 +24,7 @@ class Pulseaudio : public ALabel {
|
||||
static void volumeModifyCb(pa_context*, int, void*);
|
||||
|
||||
bool handleScroll(GdkEventScroll* e);
|
||||
const std::string getPortIcon() const;
|
||||
const std::vector<std::string> getPulseIcon() const;
|
||||
|
||||
pa_threaded_mainloop* mainloop_;
|
||||
pa_mainloop_api* mainloop_api_;
|
||||
@ -34,14 +35,18 @@ class Pulseaudio : public ALabel {
|
||||
pa_cvolume pa_volume_;
|
||||
bool muted_;
|
||||
std::string port_name_;
|
||||
std::string form_factor_;
|
||||
std::string desc_;
|
||||
std::string monitor_;
|
||||
std::string current_sink_name_;
|
||||
bool current_sink_running_;
|
||||
// SOURCE
|
||||
uint32_t source_idx_{0};
|
||||
uint16_t source_volume_;
|
||||
bool source_muted_;
|
||||
std::string source_port_name_;
|
||||
std::string source_desc_;
|
||||
std::string default_source_name_;
|
||||
};
|
||||
|
||||
} // namespace waybar::modules
|
||||
|
31
include/modules/river/tags.hpp
Normal file
31
include/modules/river/tags.hpp
Normal file
@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
|
||||
#include <gtkmm/button.h>
|
||||
#include <wayland-client.h>
|
||||
|
||||
#include "AModule.hpp"
|
||||
#include "bar.hpp"
|
||||
#include "river-status-unstable-v1-client-protocol.h"
|
||||
#include "xdg-output-unstable-v1-client-protocol.h"
|
||||
|
||||
namespace waybar::modules::river {
|
||||
|
||||
class Tags : public waybar::AModule {
|
||||
public:
|
||||
Tags(const std::string &, const waybar::Bar &, const Json::Value &);
|
||||
~Tags();
|
||||
|
||||
// Handlers for wayland events
|
||||
void handle_focused_tags(uint32_t tags);
|
||||
void handle_view_tags(struct wl_array *tags);
|
||||
|
||||
struct zriver_status_manager_v1 *status_manager_;
|
||||
|
||||
private:
|
||||
const waybar::Bar & bar_;
|
||||
Gtk::Box box_;
|
||||
std::vector<Gtk::Button> buttons_;
|
||||
struct zriver_output_status_v1 *output_status_;
|
||||
};
|
||||
|
||||
} /* namespace waybar::modules::river */
|
24
include/modules/simpleclock.hpp
Normal file
24
include/modules/simpleclock.hpp
Normal file
@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
#include <fmt/format.h>
|
||||
#if FMT_VERSION < 60000
|
||||
#include <fmt/time.h>
|
||||
#else
|
||||
#include <fmt/chrono.h>
|
||||
#endif
|
||||
#include "ALabel.hpp"
|
||||
#include "util/sleeper_thread.hpp"
|
||||
|
||||
namespace waybar::modules {
|
||||
|
||||
class Clock : public ALabel {
|
||||
public:
|
||||
Clock(const std::string&, const Json::Value&);
|
||||
~Clock() = default;
|
||||
auto update() -> void;
|
||||
|
||||
private:
|
||||
util::SleeperThread thread_;
|
||||
};
|
||||
|
||||
} // namespace waybar::modules
|
30
include/modules/sndio.hpp
Normal file
30
include/modules/sndio.hpp
Normal file
@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
|
||||
#include <sndio.h>
|
||||
#include <vector>
|
||||
#include "ALabel.hpp"
|
||||
#include "util/sleeper_thread.hpp"
|
||||
|
||||
namespace waybar::modules {
|
||||
|
||||
class Sndio : public ALabel {
|
||||
public:
|
||||
Sndio(const std::string&, const Json::Value&);
|
||||
~Sndio();
|
||||
auto update() -> void;
|
||||
auto set_desc(struct sioctl_desc *, unsigned int) -> void;
|
||||
auto put_val(unsigned int, unsigned int) -> void;
|
||||
bool handleScroll(GdkEventScroll *);
|
||||
bool handleToggle(GdkEventButton* const&);
|
||||
|
||||
private:
|
||||
auto connect_to_sndio() -> void;
|
||||
util::SleeperThread thread_;
|
||||
struct sioctl_hdl *hdl_;
|
||||
std::vector<struct pollfd> pfds_;
|
||||
unsigned int addr_;
|
||||
unsigned int volume_, old_volume_, maxval_;
|
||||
bool muted_;
|
||||
};
|
||||
|
||||
} // namespace waybar::modules
|
@ -10,14 +10,17 @@
|
||||
#include <json/json.h>
|
||||
#include <libdbusmenu-gtk/dbusmenu-gtk.h>
|
||||
#include <sigc++/trackable.h>
|
||||
#ifdef FILESYSTEM_EXPERIMENTAL
|
||||
#include <experimental/filesystem>
|
||||
#else
|
||||
#include <filesystem>
|
||||
#endif
|
||||
|
||||
#include <set>
|
||||
#include <string_view>
|
||||
|
||||
namespace waybar::modules::SNI {
|
||||
|
||||
struct ToolTip {
|
||||
Glib::ustring icon_name;
|
||||
Glib::ustring text;
|
||||
};
|
||||
|
||||
class Item : public sigc::trackable {
|
||||
public:
|
||||
Item(const std::string&, const std::string&, const Json::Value&);
|
||||
@ -32,10 +35,8 @@ class Item : public sigc::trackable {
|
||||
Gtk::EventBox event_box;
|
||||
std::string category;
|
||||
std::string id;
|
||||
std::string status;
|
||||
|
||||
std::string title;
|
||||
int32_t window_id;
|
||||
std::string icon_name;
|
||||
Glib::RefPtr<Gdk::Pixbuf> icon_pixmap;
|
||||
Glib::RefPtr<Gtk::IconTheme> icon_theme;
|
||||
@ -44,13 +45,20 @@ class Item : public sigc::trackable {
|
||||
std::string attention_movie_name;
|
||||
std::string icon_theme_path;
|
||||
std::string menu;
|
||||
ToolTip tooltip;
|
||||
DbusmenuGtkMenu* dbus_menu = nullptr;
|
||||
Gtk::Menu* gtk_menu = nullptr;
|
||||
bool item_is_menu = false;
|
||||
/**
|
||||
* ItemIsMenu flag means that the item only supports the context menu.
|
||||
* Default value is true because libappindicator supports neither ItemIsMenu nor Activate method
|
||||
* while compliant SNI implementation would always reset the flag to desired value.
|
||||
*/
|
||||
bool item_is_menu = true;
|
||||
|
||||
private:
|
||||
void proxyReady(Glib::RefPtr<Gio::AsyncResult>& result);
|
||||
void setProperty(const Glib::ustring& name, Glib::VariantBase& value);
|
||||
void setStatus(const Glib::ustring& value);
|
||||
void getUpdatedProperties();
|
||||
void processUpdatedProperties(Glib::RefPtr<Gio::AsyncResult>& result);
|
||||
void onSignal(const Glib::ustring& sender_name, const Glib::ustring& signal_name,
|
||||
@ -58,14 +66,24 @@ class Item : public sigc::trackable {
|
||||
|
||||
void updateImage();
|
||||
Glib::RefPtr<Gdk::Pixbuf> extractPixBuf(GVariant* variant);
|
||||
Glib::RefPtr<Gdk::Pixbuf> getIconPixbuf();
|
||||
Glib::RefPtr<Gdk::Pixbuf> getIconByName(const std::string& name, int size);
|
||||
double getScaledIconSize();
|
||||
static void onMenuDestroyed(Item* self, GObject* old_menu_pointer);
|
||||
void makeMenu(GdkEventButton* const& ev);
|
||||
void makeMenu();
|
||||
bool handleClick(GdkEventButton* const& /*ev*/);
|
||||
bool handleScroll(GdkEventScroll* const&);
|
||||
|
||||
// smooth scrolling threshold
|
||||
gdouble scroll_threshold_ = 0;
|
||||
gdouble distance_scrolled_x_ = 0;
|
||||
gdouble distance_scrolled_y_ = 0;
|
||||
// visibility of items with Status == Passive
|
||||
bool show_passive_ = false;
|
||||
|
||||
Glib::RefPtr<Gio::DBus::Proxy> proxy_;
|
||||
Glib::RefPtr<Gio::Cancellable> cancellable_;
|
||||
bool update_pending_;
|
||||
std::set<std::string_view> update_pending_;
|
||||
};
|
||||
|
||||
} // namespace waybar::modules::SNI
|
||||
|
@ -21,7 +21,7 @@ class Tray : public AModule {
|
||||
|
||||
static inline std::size_t nb_hosts_ = 0;
|
||||
Gtk::Box box_;
|
||||
SNI::Watcher watcher_;
|
||||
SNI::Watcher::singleton watcher_;
|
||||
SNI::Host host_;
|
||||
};
|
||||
|
||||
|
@ -7,10 +7,24 @@
|
||||
namespace waybar::modules::SNI {
|
||||
|
||||
class Watcher {
|
||||
private:
|
||||
Watcher();
|
||||
|
||||
public:
|
||||
Watcher(std::size_t id);
|
||||
~Watcher();
|
||||
|
||||
using singleton = std::shared_ptr<Watcher>;
|
||||
static singleton getInstance() {
|
||||
static std::weak_ptr<Watcher> weak;
|
||||
|
||||
std::shared_ptr<Watcher> strong = weak.lock();
|
||||
if (!strong) {
|
||||
strong = std::shared_ptr<Watcher>(new Watcher());
|
||||
weak = strong;
|
||||
}
|
||||
return strong;
|
||||
}
|
||||
|
||||
private:
|
||||
typedef enum { GF_WATCH_TYPE_HOST, GF_WATCH_TYPE_ITEM } GfWatchType;
|
||||
|
||||
@ -34,7 +48,6 @@ class Watcher {
|
||||
void updateRegisteredItems(SnWatcher *obj);
|
||||
|
||||
uint32_t bus_name_id_;
|
||||
uint32_t watcher_id_;
|
||||
GSList * hosts_ = nullptr;
|
||||
GSList * items_ = nullptr;
|
||||
SnWatcher *watcher_ = nullptr;
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include "ipc.hpp"
|
||||
#include "util/sleeper_thread.hpp"
|
||||
|
||||
namespace waybar::modules::sway {
|
||||
|
||||
@ -28,6 +29,7 @@ class Ipc {
|
||||
void sendCmd(uint32_t type, const std::string &payload = "");
|
||||
void subscribe(const std::string &payload);
|
||||
void handleEvent();
|
||||
void setWorker(std::function<void()> &&func);
|
||||
|
||||
protected:
|
||||
static inline const std::string ipc_magic_ = "i3-ipc";
|
||||
@ -38,9 +40,10 @@ class Ipc {
|
||||
struct ipc_response send(int fd, uint32_t type, const std::string &payload = "");
|
||||
struct ipc_response recv(int fd);
|
||||
|
||||
int fd_;
|
||||
int fd_event_;
|
||||
std::mutex mutex_;
|
||||
int fd_;
|
||||
int fd_event_;
|
||||
std::mutex mutex_;
|
||||
util::SleeperThread thread_;
|
||||
};
|
||||
|
||||
} // namespace waybar::modules::sway
|
||||
|
@ -29,4 +29,8 @@ enum ipc_command_type {
|
||||
IPC_EVENT_BINDING = ((1 << 31) | 5),
|
||||
IPC_EVENT_SHUTDOWN = ((1 << 31) | 6),
|
||||
IPC_EVENT_TICK = ((1 << 31) | 7),
|
||||
|
||||
// sway-specific event types
|
||||
IPC_EVENT_BAR_STATE_UPDATE = ((1<<31) | 20),
|
||||
IPC_EVENT_INPUT = ((1<<31) | 21),
|
||||
};
|
||||
|
61
include/modules/sway/language.hpp
Normal file
61
include/modules/sway/language.hpp
Normal file
@ -0,0 +1,61 @@
|
||||
#pragma once
|
||||
|
||||
#include <fmt/format.h>
|
||||
#include <xkbcommon/xkbregistry.h>
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include "ALabel.hpp"
|
||||
#include "bar.hpp"
|
||||
#include "client.hpp"
|
||||
#include "modules/sway/ipc/client.hpp"
|
||||
#include "util/json.hpp"
|
||||
|
||||
namespace waybar::modules::sway {
|
||||
|
||||
class Language : public ALabel, public sigc::trackable {
|
||||
public:
|
||||
Language(const std::string& id, const Json::Value& config);
|
||||
~Language() = default;
|
||||
auto update() -> void;
|
||||
|
||||
private:
|
||||
struct Layout {
|
||||
std::string full_name;
|
||||
std::string short_name;
|
||||
std::string variant;
|
||||
};
|
||||
|
||||
class XKBContext {
|
||||
public:
|
||||
XKBContext();
|
||||
~XKBContext();
|
||||
auto next_layout() -> Layout*;
|
||||
private:
|
||||
rxkb_context* context_ = nullptr;
|
||||
rxkb_layout* xkb_layout_ = nullptr;
|
||||
Layout* layout_ = nullptr;
|
||||
};
|
||||
|
||||
void onEvent(const struct Ipc::ipc_response&);
|
||||
void onCmd(const struct Ipc::ipc_response&);
|
||||
|
||||
auto set_current_layout(std::string current_layout) -> void;
|
||||
auto init_layouts_map(const std::vector<std::string>& used_layouts) -> void;
|
||||
|
||||
const static std::string XKB_LAYOUT_NAMES_KEY;
|
||||
const static std::string XKB_ACTIVE_LAYOUT_NAME_KEY;
|
||||
|
||||
Layout layout_;
|
||||
std::string tooltip_format_ = "";
|
||||
std::map<std::string, Layout> layouts_map_;
|
||||
XKBContext xkb_context_;
|
||||
bool is_variant_displayed;
|
||||
|
||||
util::JsonParser parser_;
|
||||
std::mutex mutex_;
|
||||
Ipc ipc_;
|
||||
};
|
||||
|
||||
} // namespace waybar::modules::sway
|
@ -6,7 +6,6 @@
|
||||
#include "client.hpp"
|
||||
#include "modules/sway/ipc/client.hpp"
|
||||
#include "util/json.hpp"
|
||||
#include "util/sleeper_thread.hpp"
|
||||
|
||||
namespace waybar::modules::sway {
|
||||
|
||||
@ -18,14 +17,11 @@ class Mode : public ALabel, public sigc::trackable {
|
||||
|
||||
private:
|
||||
void onEvent(const struct Ipc::ipc_response&);
|
||||
void worker();
|
||||
|
||||
std::string mode_;
|
||||
util::JsonParser parser_;
|
||||
std::mutex mutex_;
|
||||
|
||||
util::SleeperThread thread_;
|
||||
Ipc ipc_;
|
||||
Ipc ipc_;
|
||||
};
|
||||
|
||||
} // namespace waybar::modules::sway
|
||||
|
@ -7,7 +7,6 @@
|
||||
#include "client.hpp"
|
||||
#include "modules/sway/ipc/client.hpp"
|
||||
#include "util/json.hpp"
|
||||
#include "util/sleeper_thread.hpp"
|
||||
|
||||
namespace waybar::modules::sway {
|
||||
|
||||
@ -20,10 +19,10 @@ class Window : public ALabel, public sigc::trackable {
|
||||
private:
|
||||
void onEvent(const struct Ipc::ipc_response&);
|
||||
void onCmd(const struct Ipc::ipc_response&);
|
||||
void worker();
|
||||
std::tuple<std::size_t, int, std::string, std::string> getFocusedNode(const Json::Value& nodes,
|
||||
std::string& output);
|
||||
void getTree();
|
||||
std::string rewriteTitle(const std::string& title);
|
||||
|
||||
const Bar& bar_;
|
||||
std::string window_;
|
||||
@ -33,9 +32,7 @@ class Window : public ALabel, public sigc::trackable {
|
||||
std::size_t app_nb_;
|
||||
util::JsonParser parser_;
|
||||
std::mutex mutex_;
|
||||
|
||||
util::SleeperThread thread_;
|
||||
Ipc ipc_;
|
||||
Ipc ipc_;
|
||||
};
|
||||
|
||||
} // namespace waybar::modules::sway
|
||||
|
@ -1,14 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include <unordered_map>
|
||||
#include <fmt/format.h>
|
||||
#include <gtkmm/button.h>
|
||||
#include <gtkmm/label.h>
|
||||
#include <unordered_map>
|
||||
#include "AModule.hpp"
|
||||
#include "bar.hpp"
|
||||
#include "client.hpp"
|
||||
#include "modules/sway/ipc/client.hpp"
|
||||
#include "util/json.hpp"
|
||||
#include "util/sleeper_thread.hpp"
|
||||
|
||||
namespace waybar::modules::sway {
|
||||
|
||||
@ -19,9 +20,12 @@ class Workspaces : public AModule, public sigc::trackable {
|
||||
auto update() -> void;
|
||||
|
||||
private:
|
||||
static inline const std::string workspace_switch_cmd_ = "workspace {} \"{}\"";
|
||||
|
||||
static int convertWorkspaceNameToNum(std::string name);
|
||||
|
||||
void onCmd(const struct Ipc::ipc_response&);
|
||||
void onEvent(const struct Ipc::ipc_response&);
|
||||
void worker();
|
||||
bool filterButtons();
|
||||
Gtk::Button& addButton(const Json::Value&);
|
||||
void onButtonReady(const Json::Value&, Gtk::Button&);
|
||||
@ -38,9 +42,7 @@ class Workspaces : public AModule, public sigc::trackable {
|
||||
util::JsonParser parser_;
|
||||
std::unordered_map<std::string, Gtk::Button> buttons_;
|
||||
std::mutex mutex_;
|
||||
|
||||
util::SleeperThread thread_;
|
||||
Ipc ipc_;
|
||||
Ipc ipc_;
|
||||
};
|
||||
|
||||
} // namespace waybar::modules::sway
|
||||
|
@ -14,8 +14,8 @@ class Temperature : public ALabel {
|
||||
auto update() -> void;
|
||||
|
||||
private:
|
||||
std::tuple<uint16_t, uint16_t> getTemperature();
|
||||
bool isCritical(uint16_t);
|
||||
float getTemperature();
|
||||
bool isCritical(uint16_t);
|
||||
|
||||
std::string file_path_;
|
||||
util::SleeperThread thread_;
|
||||
|
164
include/modules/wlr/taskbar.hpp
Normal file
164
include/modules/wlr/taskbar.hpp
Normal file
@ -0,0 +1,164 @@
|
||||
#pragma once
|
||||
|
||||
#include "AModule.hpp"
|
||||
#include "bar.hpp"
|
||||
#include "client.hpp"
|
||||
#include "util/json.hpp"
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <unordered_set>
|
||||
|
||||
#include <gdk/gdk.h>
|
||||
|
||||
#include <glibmm/refptr.h>
|
||||
|
||||
#include <gtkmm/box.h>
|
||||
#include <gtkmm/button.h>
|
||||
#include <gtkmm/image.h>
|
||||
#include <gtkmm/label.h>
|
||||
#include <gtkmm/icontheme.h>
|
||||
|
||||
#include <wayland-client.h>
|
||||
#include "wlr-foreign-toplevel-management-unstable-v1-client-protocol.h"
|
||||
|
||||
|
||||
namespace waybar::modules::wlr {
|
||||
|
||||
class Taskbar;
|
||||
|
||||
class Task
|
||||
{
|
||||
public:
|
||||
Task(const waybar::Bar&, const Json::Value&, Taskbar*,
|
||||
struct zwlr_foreign_toplevel_handle_v1 *, struct wl_seat*);
|
||||
~Task();
|
||||
|
||||
public:
|
||||
enum State {
|
||||
MAXIMIZED = (1 << 0),
|
||||
MINIMIZED = (1 << 1),
|
||||
ACTIVE = (1 << 2),
|
||||
FULLSCREEN = (1 << 3),
|
||||
INVALID = (1 << 4)
|
||||
};
|
||||
|
||||
private:
|
||||
static uint32_t global_id;
|
||||
|
||||
private:
|
||||
const waybar::Bar &bar_;
|
||||
const Json::Value &config_;
|
||||
Taskbar *tbar_;
|
||||
struct zwlr_foreign_toplevel_handle_v1 *handle_;
|
||||
struct wl_seat *seat_;
|
||||
|
||||
uint32_t id_;
|
||||
|
||||
Gtk::Button button_;
|
||||
Gtk::Box content_;
|
||||
Gtk::Image icon_;
|
||||
Gtk::Label text_before_;
|
||||
Gtk::Label text_after_;
|
||||
bool button_visible_;
|
||||
bool ignored_;
|
||||
|
||||
bool with_icon_;
|
||||
std::string format_before_;
|
||||
std::string format_after_;
|
||||
|
||||
std::string format_tooltip_;
|
||||
|
||||
std::string title_;
|
||||
std::string app_id_;
|
||||
uint32_t state_ = 0;
|
||||
|
||||
private:
|
||||
std::string repr() const;
|
||||
std::string state_string(bool = false) const;
|
||||
|
||||
public:
|
||||
/* Getter functions */
|
||||
uint32_t id() const { return id_; }
|
||||
std::string title() const { return title_; }
|
||||
std::string app_id() const { return app_id_; }
|
||||
uint32_t state() const { return state_; }
|
||||
bool maximized() const { return state_ & MAXIMIZED; }
|
||||
bool minimized() const { return state_ & MINIMIZED; }
|
||||
bool active() const { return state_ & ACTIVE; }
|
||||
bool fullscreen() const { return state_ & FULLSCREEN; }
|
||||
|
||||
public:
|
||||
/* Callbacks for the wlr protocol */
|
||||
void handle_title(const char *);
|
||||
void handle_app_id(const char *);
|
||||
void handle_output_enter(struct wl_output *);
|
||||
void handle_output_leave(struct wl_output *);
|
||||
void handle_state(struct wl_array *);
|
||||
void handle_done();
|
||||
void handle_closed();
|
||||
|
||||
/* Callbacks for Gtk events */
|
||||
bool handle_clicked(GdkEventButton *);
|
||||
|
||||
public:
|
||||
bool operator==(const Task&) const;
|
||||
bool operator!=(const Task&) const;
|
||||
|
||||
public:
|
||||
void update();
|
||||
|
||||
public:
|
||||
/* Interaction with the tasks */
|
||||
void maximize(bool);
|
||||
void minimize(bool);
|
||||
void activate();
|
||||
void fullscreen(bool);
|
||||
void close();
|
||||
};
|
||||
|
||||
using TaskPtr = std::unique_ptr<Task>;
|
||||
|
||||
|
||||
class Taskbar : public waybar::AModule
|
||||
{
|
||||
public:
|
||||
Taskbar(const std::string&, const waybar::Bar&, const Json::Value&);
|
||||
~Taskbar();
|
||||
void update();
|
||||
|
||||
private:
|
||||
const waybar::Bar &bar_;
|
||||
Gtk::Box box_;
|
||||
std::vector<TaskPtr> tasks_;
|
||||
|
||||
std::vector<Glib::RefPtr<Gtk::IconTheme>> icon_themes_;
|
||||
std::unordered_set<std::string> ignore_list_;
|
||||
|
||||
struct zwlr_foreign_toplevel_manager_v1 *manager_;
|
||||
struct wl_seat *seat_;
|
||||
|
||||
public:
|
||||
/* Callbacks for global registration */
|
||||
void register_manager(struct wl_registry*, uint32_t name, uint32_t version);
|
||||
void register_seat(struct wl_registry*, uint32_t name, uint32_t version);
|
||||
|
||||
/* Callbacks for the wlr protocol */
|
||||
void handle_toplevel_create(struct zwlr_foreign_toplevel_handle_v1 *);
|
||||
void handle_finished();
|
||||
|
||||
public:
|
||||
void add_button(Gtk::Button &);
|
||||
void move_button(Gtk::Button &, int);
|
||||
void remove_button(Gtk::Button &);
|
||||
void remove_task(uint32_t);
|
||||
|
||||
bool show_output(struct wl_output *) const;
|
||||
bool all_outputs() const;
|
||||
|
||||
std::vector<Glib::RefPtr<Gtk::IconTheme>> icon_themes() const;
|
||||
const std::unordered_set<std::string>& ignore_list() const;
|
||||
};
|
||||
|
||||
} /* namespace waybar::modules::wlr */
|
@ -1,9 +1,22 @@
|
||||
#pragma once
|
||||
|
||||
#include <giomm.h>
|
||||
#include <spdlog/spdlog.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef __linux__
|
||||
#include <sys/prctl.h>
|
||||
#endif
|
||||
#ifdef __FreeBSD__
|
||||
#include <sys/procctl.h>
|
||||
#endif
|
||||
|
||||
#include <array>
|
||||
|
||||
extern std::mutex reap_mtx;
|
||||
extern std::list<pid_t> reap;
|
||||
|
||||
namespace waybar::util::command {
|
||||
|
||||
struct res {
|
||||
@ -28,20 +41,31 @@ inline std::string read(FILE* fp) {
|
||||
}
|
||||
|
||||
inline int close(FILE* fp, pid_t pid) {
|
||||
int stat;
|
||||
int stat = -1;
|
||||
pid_t ret;
|
||||
|
||||
fclose(fp);
|
||||
while (waitpid(pid, &stat, 0) == -1) {
|
||||
if (errno != EINTR) {
|
||||
stat = 0;
|
||||
do {
|
||||
ret = waitpid(pid, &stat, WCONTINUED | WUNTRACED);
|
||||
|
||||
if (WIFEXITED(stat)) {
|
||||
spdlog::debug("Cmd exited with code {}", WEXITSTATUS(stat));
|
||||
} else if (WIFSIGNALED(stat)) {
|
||||
spdlog::debug("Cmd killed by {}", WTERMSIG(stat));
|
||||
} else if (WIFSTOPPED(stat)) {
|
||||
spdlog::debug("Cmd stopped by {}", WSTOPSIG(stat));
|
||||
} else if (WIFCONTINUED(stat)) {
|
||||
spdlog::debug("Cmd continued");
|
||||
} else if (ret == -1) {
|
||||
spdlog::debug("waitpid failed: {}", strerror(errno));
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} while (!WIFEXITED(stat) && !WIFSIGNALED(stat));
|
||||
return stat;
|
||||
}
|
||||
|
||||
inline FILE* open(const std::string cmd, int& pid) {
|
||||
inline FILE* open(const std::string& cmd, int& pid) {
|
||||
if (cmd == "") return nullptr;
|
||||
int fd[2];
|
||||
pipe(fd);
|
||||
@ -49,15 +73,33 @@ inline FILE* open(const std::string cmd, int& pid) {
|
||||
pid_t child_pid = fork();
|
||||
|
||||
if (child_pid < 0) {
|
||||
printf("Unable to exec cmd %s, error %s", cmd.c_str(), strerror(errno));
|
||||
spdlog::error("Unable to exec cmd {}, error {}", cmd.c_str(), strerror(errno));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!child_pid) {
|
||||
int err;
|
||||
sigset_t mask;
|
||||
sigfillset(&mask);
|
||||
// Reset sigmask
|
||||
err = pthread_sigmask(SIG_UNBLOCK, &mask, nullptr);
|
||||
if (err != 0) spdlog::error("pthread_sigmask in open failed: {}", strerror(err));
|
||||
// Kill child if Waybar exits
|
||||
int deathsig = SIGTERM;
|
||||
#ifdef __linux__
|
||||
if (prctl(PR_SET_PDEATHSIG, deathsig) != 0) {
|
||||
spdlog::error("prctl(PR_SET_PDEATHSIG) in open failed: {}", strerror(errno));
|
||||
}
|
||||
#endif
|
||||
#ifdef __FreeBSD__
|
||||
if (procctl(P_PID, 0, PROC_PDEATHSIG_CTL, reinterpret_cast<void*>(&deathsig)) == -1) {
|
||||
spdlog::error("procctl(PROC_PDEATHSIG_CTL) in open failed: {}", strerror(errno));
|
||||
}
|
||||
#endif
|
||||
::close(fd[0]);
|
||||
dup2(fd[1], 1);
|
||||
setpgid(child_pid, child_pid);
|
||||
execl("/bin/sh", "sh", "-c", cmd.c_str(), (char*)0);
|
||||
execlp("/bin/sh", "sh", "-c", cmd.c_str(), (char*)0);
|
||||
exit(0);
|
||||
} else {
|
||||
::close(fd[1]);
|
||||
@ -66,7 +108,7 @@ inline FILE* open(const std::string cmd, int& pid) {
|
||||
return fdopen(fd[0], "r");
|
||||
}
|
||||
|
||||
inline struct res exec(std::string cmd) {
|
||||
inline struct res exec(const std::string& cmd) {
|
||||
int pid;
|
||||
auto fp = command::open(cmd, pid);
|
||||
if (!fp) return {-1, ""};
|
||||
@ -75,23 +117,40 @@ inline struct res exec(std::string cmd) {
|
||||
return {WEXITSTATUS(stat), output};
|
||||
}
|
||||
|
||||
inline int32_t forkExec(std::string cmd) {
|
||||
inline struct res execNoRead(const std::string& cmd) {
|
||||
int pid;
|
||||
auto fp = command::open(cmd, pid);
|
||||
if (!fp) return {-1, ""};
|
||||
auto stat = command::close(fp, pid);
|
||||
return {WEXITSTATUS(stat), ""};
|
||||
}
|
||||
|
||||
inline int32_t forkExec(const std::string& cmd) {
|
||||
if (cmd == "") return -1;
|
||||
|
||||
int32_t pid = fork();
|
||||
pid_t pid = fork();
|
||||
|
||||
if (pid < 0) {
|
||||
printf("Unable to exec cmd %s, error %s", cmd.c_str(), strerror(errno));
|
||||
spdlog::error("Unable to exec cmd {}, error {}", cmd.c_str(), strerror(errno));
|
||||
return pid;
|
||||
}
|
||||
|
||||
// Child executes the command
|
||||
if (!pid) {
|
||||
int err;
|
||||
sigset_t mask;
|
||||
sigfillset(&mask);
|
||||
// Reset sigmask
|
||||
err = pthread_sigmask(SIG_UNBLOCK, &mask, nullptr);
|
||||
if (err != 0) spdlog::error("pthread_sigmask in forkExec failed: {}", strerror(err));
|
||||
setpgid(pid, pid);
|
||||
execl("/bin/sh", "sh", "-c", cmd.c_str(), (char*)0);
|
||||
exit(0);
|
||||
} else {
|
||||
signal(SIGCHLD,SIG_IGN);
|
||||
reap_mtx.lock();
|
||||
reap.push_back(pid);
|
||||
reap_mtx.unlock();
|
||||
spdlog::debug("Added child to reap list: {}", pid);
|
||||
}
|
||||
|
||||
return pid;
|
||||
|
88
include/util/format.hpp
Normal file
88
include/util/format.hpp
Normal file
@ -0,0 +1,88 @@
|
||||
#pragma once
|
||||
|
||||
#include <fmt/format.h>
|
||||
|
||||
class pow_format {
|
||||
public:
|
||||
pow_format(long long val, std::string&& unit, bool binary = false):
|
||||
val_(val), unit_(unit), binary_(binary) { };
|
||||
|
||||
long long val_;
|
||||
std::string unit_;
|
||||
bool binary_;
|
||||
};
|
||||
|
||||
|
||||
namespace fmt {
|
||||
template <>
|
||||
struct formatter<pow_format> {
|
||||
char spec = 0;
|
||||
int width = 0;
|
||||
|
||||
template <typename ParseContext>
|
||||
constexpr auto parse(ParseContext& ctx) -> decltype (ctx.begin()) {
|
||||
auto it = ctx.begin(), end = ctx.end();
|
||||
if (it != end && *it == ':') ++it;
|
||||
if (it && (*it == '>' || *it == '<' || *it == '=')) {
|
||||
spec = *it;
|
||||
++it;
|
||||
}
|
||||
if (it == end || *it == '}') return it;
|
||||
if ('0' <= *it && *it <= '9') {
|
||||
// We ignore it for now, but keep it for compatibility with
|
||||
// existing configs where the format for pow_format'ed numbers was
|
||||
// 'string' and specifications such as {:>9} were valid.
|
||||
// The rationale for ignoring it is that the only reason to specify
|
||||
// an alignment and a with is to get a fixed width bar, and ">" is
|
||||
// sufficient in this implementation.
|
||||
#if FMT_VERSION < 80000
|
||||
width = parse_nonnegative_int(it, end, ctx);
|
||||
#else
|
||||
width = detail::parse_nonnegative_int(it, end, -1);
|
||||
#endif
|
||||
}
|
||||
return it;
|
||||
}
|
||||
|
||||
template<class FormatContext>
|
||||
auto format(const pow_format& s, FormatContext &ctx) -> decltype (ctx.out()) {
|
||||
const char* units[] = { "", "k", "M", "G", "T", "P", nullptr};
|
||||
|
||||
auto base = s.binary_ ? 1024ull : 1000ll;
|
||||
auto fraction = (double) s.val_;
|
||||
|
||||
int pow;
|
||||
for (pow = 0; units[pow+1] != nullptr && fraction / base >= 1; ++pow) {
|
||||
fraction /= base;
|
||||
}
|
||||
|
||||
auto max_width = 4 // coeff in {:.3g} format
|
||||
+ 1 // prefix from units array
|
||||
+ s.binary_ // for the 'i' in GiB.
|
||||
+ s.unit_.length();
|
||||
|
||||
const char * format;
|
||||
std::string string;
|
||||
switch (spec) {
|
||||
case '>':
|
||||
return format_to(ctx.out(), "{:>{}}", fmt::format("{}", s), max_width);
|
||||
case '<':
|
||||
return format_to(ctx.out(), "{:<{}}", fmt::format("{}", s), max_width);
|
||||
case '=':
|
||||
format = "{coefficient:<4.3g}{padding}{prefix}{unit}";
|
||||
break;
|
||||
case 0:
|
||||
default:
|
||||
format = "{coefficient:.3g}{prefix}{unit}";
|
||||
break;
|
||||
}
|
||||
return format_to(ctx.out(), format
|
||||
, fmt::arg("coefficient", fraction)
|
||||
, fmt::arg("prefix", std::string() + units[pow] + ((s.binary_ && pow) ? "i" : ""))
|
||||
, fmt::arg("unit", s.unit_)
|
||||
, fmt::arg("padding", pow ? "" : s.binary_ ? " " : " ")
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
26
include/util/rfkill.hpp
Normal file
26
include/util/rfkill.hpp
Normal file
@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
|
||||
#include <glibmm/iochannel.h>
|
||||
#include <linux/rfkill.h>
|
||||
#include <sigc++/signal.h>
|
||||
#include <sigc++/trackable.h>
|
||||
|
||||
namespace waybar::util {
|
||||
|
||||
class Rfkill : public sigc::trackable {
|
||||
public:
|
||||
Rfkill(enum rfkill_type rfkill_type);
|
||||
~Rfkill();
|
||||
bool getState() const;
|
||||
|
||||
sigc::signal<void(struct rfkill_event&)> on_update;
|
||||
|
||||
private:
|
||||
enum rfkill_type rfkill_type_;
|
||||
bool state_ = false;
|
||||
int fd_ = -1;
|
||||
|
||||
bool on_event(Glib::IOCondition cond);
|
||||
};
|
||||
|
||||
} // namespace waybar::util
|
@ -8,6 +8,20 @@
|
||||
|
||||
namespace waybar::util {
|
||||
|
||||
/**
|
||||
* Defer pthread_cancel until the end of a current scope.
|
||||
*
|
||||
* Required to protect a scope where it's unsafe to raise `__forced_unwind` exception.
|
||||
* An example of these is a call of a method marked as `noexcept`; an attempt to cancel within such
|
||||
* a method may result in a `std::terminate` call.
|
||||
*/
|
||||
class CancellationGuard {
|
||||
int oldstate;
|
||||
public:
|
||||
CancellationGuard() { pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate); }
|
||||
~CancellationGuard() { pthread_setcancelstate(oldstate, &oldstate); }
|
||||
};
|
||||
|
||||
class SleeperThread {
|
||||
public:
|
||||
SleeperThread() = default;
|
||||
@ -33,14 +47,16 @@ class SleeperThread {
|
||||
bool isRunning() const { return do_run_; }
|
||||
|
||||
auto sleep_for(std::chrono::system_clock::duration dur) {
|
||||
std::unique_lock lk(mutex_);
|
||||
std::unique_lock lk(mutex_);
|
||||
CancellationGuard cancel_lock;
|
||||
return condvar_.wait_for(lk, dur, [this] { return signal_ || !do_run_; });
|
||||
}
|
||||
|
||||
auto sleep_until(
|
||||
std::chrono::time_point<std::chrono::system_clock, std::chrono::system_clock::duration>
|
||||
time_point) {
|
||||
std::unique_lock lk(mutex_);
|
||||
std::unique_lock lk(mutex_);
|
||||
CancellationGuard cancel_lock;
|
||||
return condvar_.wait_until(lk, time_point, [this] { return signal_ || !do_run_; });
|
||||
}
|
||||
|
||||
@ -59,6 +75,11 @@ class SleeperThread {
|
||||
do_run_ = false;
|
||||
}
|
||||
condvar_.notify_all();
|
||||
auto handle = thread_.native_handle();
|
||||
if (handle != 0) {
|
||||
// TODO: find a proper way to terminate thread...
|
||||
pthread_cancel(handle);
|
||||
}
|
||||
}
|
||||
|
||||
~SleeperThread() {
|
||||
|
15
include/util/string.hpp
Normal file
15
include/util/string.hpp
Normal file
@ -0,0 +1,15 @@
|
||||
#include <string>
|
||||
|
||||
const std::string WHITESPACE = " \n\r\t\f\v";
|
||||
|
||||
std::string ltrim(const std::string s) {
|
||||
size_t begin = s.find_first_not_of(WHITESPACE);
|
||||
return (begin == std::string::npos) ? "" : s.substr(begin);
|
||||
}
|
||||
|
||||
std::string rtrim(const std::string s) {
|
||||
size_t end = s.find_last_not_of(WHITESPACE);
|
||||
return (end == std::string::npos) ? "" : s.substr(0, end + 1);
|
||||
}
|
||||
|
||||
std::string trim(const std::string& s) { return rtrim(ltrim(s)); }
|
5
include/util/ustring_clen.hpp
Normal file
5
include/util/ustring_clen.hpp
Normal file
@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
#include <glibmm/ustring.h>
|
||||
|
||||
// calculate column width of ustring
|
||||
int ustring_clen(const Glib::ustring &str);
|
83
man/waybar-backlight.5.scd
Normal file
83
man/waybar-backlight.5.scd
Normal file
@ -0,0 +1,83 @@
|
||||
waybar-backlight(5)
|
||||
|
||||
# NAME
|
||||
|
||||
waybar - backlight module
|
||||
|
||||
# DESCRIPTION
|
||||
|
||||
The *backlight* module displays the current backlight level.
|
||||
|
||||
# CONFIGURATION
|
||||
|
||||
*interval*: ++
|
||||
typeof: integer ++
|
||||
default: 2 ++
|
||||
The interval in which information gets polled.
|
||||
|
||||
*format*: ++
|
||||
typeof: string ++
|
||||
default: {percent}% ++
|
||||
The format, how information should be displayed. On {} data gets inserted.
|
||||
|
||||
*max-length*: ++
|
||||
typeof: integer ++
|
||||
The maximum length in characters the module should display.
|
||||
|
||||
*min-length*: ++
|
||||
typeof: integer ++
|
||||
The minimum length in characters the module should take up.
|
||||
|
||||
*align*: ++
|
||||
typeof: float ++
|
||||
The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
|
||||
|
||||
*rotate*: ++
|
||||
typeof: integer ++
|
||||
Positive value to rotate the text label.
|
||||
|
||||
*states*: ++
|
||||
typeof: array ++
|
||||
A number of backlight states which get activated on certain brightness levels.
|
||||
|
||||
*on-click*: ++
|
||||
typeof: string ++
|
||||
Command to execute when the module is clicked.
|
||||
|
||||
*on-click-middle*: ++
|
||||
typeof: string ++
|
||||
Command to execute when middle-clicked on the module using mousewheel.
|
||||
|
||||
*on-click-right*: ++
|
||||
typeof: string ++
|
||||
Command to execute when the module is right clicked.
|
||||
|
||||
*on-update*: ++
|
||||
typeof: string ++
|
||||
Command to execute when the module is updated.
|
||||
|
||||
*on-scroll-up*: ++
|
||||
typeof: string ++
|
||||
Command to execute when performing a scroll up on the module.
|
||||
|
||||
*on-scroll-down*: ++
|
||||
typeof: string
|
||||
Command to execute when performing a scroll down on the module.
|
||||
|
||||
*smooth-scrolling-threshold*: ++
|
||||
typeof: double
|
||||
Threshold to be used when scrolling.
|
||||
|
||||
# EXAMPLE:
|
||||
|
||||
```
|
||||
"backlight": {
|
||||
"device": "intel_backlight",
|
||||
"format": "{percent}% {icon}",
|
||||
"format-icons": ["", ""]
|
||||
}
|
||||
```
|
||||
|
||||
# STYLE
|
||||
|
||||
- *#backlight*
|
163
man/waybar-battery.5.scd
Normal file
163
man/waybar-battery.5.scd
Normal file
@ -0,0 +1,163 @@
|
||||
waybar-battery(5)
|
||||
|
||||
# NAME
|
||||
|
||||
waybar - battery module
|
||||
|
||||
# DESCRIPTION
|
||||
|
||||
The *battery* module displays the current capacity and state (eg. charging) of your battery.
|
||||
|
||||
# CONFIGURATION
|
||||
|
||||
*bat*: ++
|
||||
typeof: string ++
|
||||
The battery to monitor, as in /sys/class/power_supply/ instead of auto detect.
|
||||
|
||||
*adapter*: ++
|
||||
typeof: string ++
|
||||
The adapter to monitor, as in /sys/class/power_supply/ instead of auto detect.
|
||||
|
||||
*full-at*: ++
|
||||
typeof: integer ++
|
||||
Define the max percentage of the battery, for when you've set the battery to stop charging at a lower level to save it. For example, if you've set the battery to stop at 80% that will become the new 100%.
|
||||
|
||||
*design-capacity*: ++
|
||||
typeof: bool ++
|
||||
default: false ++
|
||||
Option to use the battery design capacity instead of it's current maximal capacity.
|
||||
|
||||
*interval*: ++
|
||||
typeof: integer ++
|
||||
default: 60 ++
|
||||
The interval in which the information gets polled.
|
||||
|
||||
*states*: ++
|
||||
typeof: array ++
|
||||
A number of battery states which get activated on certain capacity levels. See *waybar-states(5)*.
|
||||
|
||||
*format*: ++
|
||||
typeof: string ++
|
||||
default: {capacity}% ++
|
||||
The format, how the time should be displayed.
|
||||
|
||||
*format-time*: ++
|
||||
typeof: string ++
|
||||
default: {H} h {M} min ++
|
||||
The format, how the time should be displayed.
|
||||
|
||||
*format-icons*: ++
|
||||
typeof: array/object ++
|
||||
Based on the current capacity, the corresponding icon gets selected. ++
|
||||
The order is *low* to *high*. Or by the state if it is an object.
|
||||
|
||||
*max-length*: ++
|
||||
typeof: integer++
|
||||
The maximum length in character the module should display.
|
||||
|
||||
*min-length*: ++
|
||||
typeof: integer ++
|
||||
The minimum length in characters the module should take up.
|
||||
|
||||
*align*: ++
|
||||
typeof: float ++
|
||||
The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
|
||||
|
||||
*rotate*: ++
|
||||
typeof: integer++
|
||||
Positive value to rotate the text label.
|
||||
|
||||
*on-click*: ++
|
||||
typeof: string ++
|
||||
Command to execute when clicked on the module.
|
||||
|
||||
*on-click-middle*: ++
|
||||
typeof: string ++
|
||||
Command to execute when middle-clicked on the module using mousewheel.
|
||||
|
||||
*on-click-right*: ++
|
||||
typeof: string ++
|
||||
Command to execute when you right clicked on the module.
|
||||
|
||||
*on-update*: ++
|
||||
typeof: string ++
|
||||
Command to execute when the module is updated.
|
||||
|
||||
*on-scroll-up*: ++
|
||||
typeof: string ++
|
||||
Command to execute when scrolling up on the module.
|
||||
|
||||
*on-scroll-down*: ++
|
||||
typeof: string ++
|
||||
Command to execute when scrolling down on the module.
|
||||
|
||||
*smooth-scrolling-threshold*: ++
|
||||
typeof: double ++
|
||||
Threshold to be used when scrolling.
|
||||
|
||||
*tooltip*: ++
|
||||
typeof: bool ++
|
||||
default: true ++
|
||||
Option to disable tooltip on hover.
|
||||
|
||||
# FORMAT REPLACEMENTS
|
||||
|
||||
*{capacity}*: Capacity in percentage
|
||||
|
||||
*{power}*: Power in watts
|
||||
|
||||
*{icon}*: Icon, as defined in *format-icons*.
|
||||
|
||||
*{time}*: Estimate of time until full or empty. Note that this is based on the power draw at the last refresh time, not an average.
|
||||
|
||||
# TIME FORMAT
|
||||
|
||||
The *battery* module allows you to define how time should be formatted via *format-time*.
|
||||
|
||||
The two arguments are:
|
||||
*{H}*: Hours
|
||||
*{M}*: Minutes
|
||||
|
||||
# CUSTOM FORMATS
|
||||
|
||||
The *battery* module allows to define custom formats based on up to two factors. The best fitting format will be selected.
|
||||
|
||||
*format-<state>*: With *states*, a custom format can be set depending on the capacity of your battery.
|
||||
|
||||
*format-<status>*: With the status, a custom format can be set depending on the status in /sys/class/power_supply/<bat>/status (in lowercase).
|
||||
|
||||
*format-<status>-<state>*: You can also set a custom format depending on both values.
|
||||
|
||||
# STATES
|
||||
|
||||
- Every entry (*state*) consists of a *<name>* (typeof: *string*) and a *<value>* (typeof: *integer*).
|
||||
- The state can be addressed as a CSS class in the *style.css*. The name of the CSS class is the *<name>* of the state. Each class gets activated when the current capacity is equal or below the configured *<value>*.
|
||||
- Also each state can have its own *format*. Those con be configured via *format-<name>*. Or if you want to differentiate a bit more even as *format-<status>-<state>*. For more information see *custom-formats*.
|
||||
|
||||
|
||||
|
||||
# EXAMPLES
|
||||
|
||||
```
|
||||
"battery": {
|
||||
"bat": "BAT2",
|
||||
"interval": 60,
|
||||
"states": {
|
||||
"warning": 30,
|
||||
"critical": 15
|
||||
},
|
||||
"format": "{capacity}% {icon}",
|
||||
"format-icons": ["", "", "", "", ""],
|
||||
"max-length": 25
|
||||
}
|
||||
```
|
||||
|
||||
# STYLE
|
||||
|
||||
- *#battery*
|
||||
- *#battery.<status>*
|
||||
- *<status>* is the value of /sys/class/power_supply/<bat>/status in lowercase.
|
||||
- *#battery.<state>*
|
||||
- *<state>* can be defined in the *config*. For more information see *states*.
|
||||
- *#battery.<status>.<state>*
|
||||
- Combination of both *<status>* and *<state>*.
|
96
man/waybar-bluetooth.5.scd
Normal file
96
man/waybar-bluetooth.5.scd
Normal file
@ -0,0 +1,96 @@
|
||||
waybar-bluetooth(5)
|
||||
|
||||
# NAME
|
||||
|
||||
waybar - bluetooth module
|
||||
|
||||
# DESCRIPTION
|
||||
|
||||
The *bluetooth* module displays information about the status of the device's bluetooth device.
|
||||
|
||||
# CONFIGURATION
|
||||
|
||||
Addressed by *bluetooth*
|
||||
|
||||
*format*: ++
|
||||
typeof: string ++
|
||||
default: *{icon}* ++
|
||||
The format, how information should be displayed. This format is used when other formats aren't specified.
|
||||
|
||||
*format-icons*: ++
|
||||
typeof: array/object ++
|
||||
Based on the device status, the corresponding icon gets selected. ++
|
||||
The order is *low* to *high*. Or by the state if it is an object.
|
||||
|
||||
*rotate*: ++
|
||||
typeof: integer ++
|
||||
Positive value to rotate the text label.
|
||||
|
||||
*max-length*: ++
|
||||
typeof: integer ++
|
||||
The maximum length in character the module should display.
|
||||
|
||||
*min-length*: ++
|
||||
typeof: integer ++
|
||||
The minimum length in characters the module should take up.
|
||||
|
||||
*align*: ++
|
||||
typeof: float ++
|
||||
The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
|
||||
|
||||
*on-click*: ++
|
||||
typeof: string ++
|
||||
Command to execute when clicked on the module.
|
||||
|
||||
*on-click-middle*: ++
|
||||
typeof: string ++
|
||||
Command to execute when middle-clicked on the module using mousewheel.
|
||||
|
||||
*on-click-right*: ++
|
||||
typeof: string ++
|
||||
Command to execute when you right clicked on the module.
|
||||
|
||||
*on-scroll-up*: ++
|
||||
typeof: string ++
|
||||
Command to execute when scrolling up on the module.
|
||||
|
||||
*on-scroll-down*: ++
|
||||
typeof: string ++
|
||||
Command to execute when scrolling down on the module.
|
||||
|
||||
*smooth-scrolling-threshold*: ++
|
||||
typeof: double ++
|
||||
Threshold to be used when scrolling.
|
||||
|
||||
*tooltip*: ++
|
||||
typeof: bool ++
|
||||
default: *true* ++
|
||||
Option to disable tooltip on hover.
|
||||
|
||||
*tooltip-format*: ++
|
||||
typeof: string ++
|
||||
The format, how information should be displayed in the tooltip. This format is used when other formats aren't specified.
|
||||
|
||||
# FORMAT REPLACEMENTS
|
||||
|
||||
*{status}*: Status of the bluetooth device.
|
||||
|
||||
*{icon}*: Icon, as defined in *format-icons*.
|
||||
|
||||
# EXAMPLES
|
||||
|
||||
```
|
||||
"bluetooth": {
|
||||
"format": "{icon}",
|
||||
"format-alt": "bluetooth: {status}",
|
||||
"format-icons": {
|
||||
"enabled": "",
|
||||
"disabled": ""
|
||||
},
|
||||
"tooltip-format": "{}"
|
||||
}
|
||||
```
|
||||
|
||||
# STYLE
|
||||
|
||||
- *#bluetooth*
|
106
man/waybar-clock.5.scd
Normal file
106
man/waybar-clock.5.scd
Normal file
@ -0,0 +1,106 @@
|
||||
waybar-clock(5)
|
||||
|
||||
# NAME
|
||||
|
||||
waybar - clock module
|
||||
|
||||
# DESCRIPTION
|
||||
|
||||
The *clock* module displays the current date and time.
|
||||
|
||||
# CONFIGURATION
|
||||
|
||||
*interval*: ++
|
||||
typeof: integer ++
|
||||
default: 60 ++
|
||||
The interval in which the information gets polled.
|
||||
|
||||
*format*: ++
|
||||
typeof: string ++
|
||||
default: {:%H:%M} ++
|
||||
The format, how the date and time should be displayed. ++
|
||||
It uses the format of the date library. See https://howardhinnant.github.io/date/date.html#to_stream_formatting for details.
|
||||
|
||||
*timezone*: ++
|
||||
typeof: string ++
|
||||
default: inferred local timezone ++
|
||||
The timezone to display the time in, e.g. America/New_York.
|
||||
|
||||
*timezones*: ++
|
||||
typeof: list of strings ++
|
||||
A list of timezones to use for time display, changed using the scroll wheel. ++
|
||||
Use "" to represent the system's local timezone. Using %Z in the format or tooltip format is useful to track which time zone is currently displayed.
|
||||
|
||||
*locale*: ++
|
||||
typeof: string ++
|
||||
default: inferred from current locale ++
|
||||
A locale to be used to display the time. Intended to render times in custom timezones with the proper language and format.
|
||||
|
||||
*today-format*: ++
|
||||
typeof: string ++
|
||||
default: <b><u>{}</u></b> ++
|
||||
The format of today's date in the calendar.
|
||||
|
||||
*max-length*: ++
|
||||
typeof: integer ++
|
||||
The maximum length in character the module should display.
|
||||
|
||||
*min-length*: ++
|
||||
typeof: integer ++
|
||||
The minimum length in characters the module should take up.
|
||||
|
||||
*align*: ++
|
||||
typeof: float ++
|
||||
The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
|
||||
|
||||
*rotate*: ++
|
||||
typeof: integer ++
|
||||
Positive value to rotate the text label.
|
||||
|
||||
*on-click*: ++
|
||||
typeof: string ++
|
||||
Command to execute when clicked on the module.
|
||||
|
||||
*on-click-middle*: ++
|
||||
typeof: string ++
|
||||
Command to execute when middle-clicked on the module using mousewheel.
|
||||
|
||||
*on-click-right*: ++
|
||||
typeof: string ++
|
||||
Command to execute when you right clicked on the module.
|
||||
|
||||
*on-update*: ++
|
||||
typeof: string ++
|
||||
Command to execute when the module is updated.
|
||||
|
||||
*on-scroll-up*: ++
|
||||
typeof: string ++
|
||||
Command to execute when scrolling up on the module.
|
||||
|
||||
*on-scroll-down*: ++
|
||||
typeof: string ++
|
||||
Command to execute when scrolling down on the module.
|
||||
|
||||
*smooth-scrolling-threshold*: ++
|
||||
typeof: double ++
|
||||
Threshold to be used when scrolling.
|
||||
|
||||
View all valid format options in *strftime(3)*.
|
||||
|
||||
# FORMAT REPLACEMENTS
|
||||
|
||||
*{calendar}*: Current month calendar
|
||||
|
||||
# EXAMPLES
|
||||
|
||||
```
|
||||
"clock": {
|
||||
"interval": 60,
|
||||
"format": "{:%H:%M}",
|
||||
"max-length": 25
|
||||
}
|
||||
```
|
||||
|
||||
# STYLE
|
||||
|
||||
- *#clock*
|
100
man/waybar-cpu.5.scd
Normal file
100
man/waybar-cpu.5.scd
Normal file
@ -0,0 +1,100 @@
|
||||
waybar-cpu(5)
|
||||
|
||||
# NAME
|
||||
|
||||
waybar - cpu module
|
||||
|
||||
# DESCRIPTION
|
||||
|
||||
The *cpu* module displays the current cpu utilization.
|
||||
|
||||
# CONFIGURATION
|
||||
|
||||
*interval*: ++
|
||||
typeof: integer ++
|
||||
default: 10 ++
|
||||
The interval in which the information gets polled.
|
||||
|
||||
*format*: ++
|
||||
typeof: string ++
|
||||
default: {usage}% ++
|
||||
The format, how information should be displayed. On {} data gets inserted.
|
||||
|
||||
*max-length*: ++
|
||||
typeof: integer ++
|
||||
The maximum length in character the module should display.
|
||||
|
||||
*min-length*: ++
|
||||
typeof: integer ++
|
||||
The minimum length in characters the module should take up.
|
||||
|
||||
*align*: ++
|
||||
typeof: float ++
|
||||
The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
|
||||
|
||||
*rotate*: ++
|
||||
typeof: integer ++
|
||||
Positive value to rotate the text label.
|
||||
|
||||
*states*: ++
|
||||
typeof: array ++
|
||||
A number of cpu usage states which get activated on certain usage levels. See *waybar-states(5)*.
|
||||
|
||||
*on-click*: ++
|
||||
typeof: string ++
|
||||
Command to execute when clicked on the module.
|
||||
|
||||
*on-click-middle*: ++
|
||||
typeof: string ++
|
||||
Command to execute when middle-clicked on the module using mousewheel.
|
||||
|
||||
*on-click-right*: ++
|
||||
typeof: string ++
|
||||
Command to execute when you right clicked on the module.
|
||||
|
||||
*on-update*: ++
|
||||
typeof: string ++
|
||||
Command to execute when the module is updated.
|
||||
|
||||
*on-scroll-up*: ++
|
||||
typeof: string ++
|
||||
Command to execute when scrolling up on the module.
|
||||
|
||||
*on-scroll-down*: ++
|
||||
typeof: string ++
|
||||
Command to execute when scrolling down on the module.
|
||||
|
||||
*smooth-scrolling-threshold*: ++
|
||||
typeof: double ++
|
||||
Threshold to be used when scrolling.
|
||||
|
||||
*tooltip*: ++
|
||||
typeof: bool ++
|
||||
default: true ++
|
||||
Option to disable tooltip on hover.
|
||||
|
||||
# FORMAT REPLACEMENTS
|
||||
|
||||
*{load}*: Current cpu load.
|
||||
|
||||
*{usage}*: Current cpu usage.
|
||||
|
||||
*{avg_frequency}*: Current cpu average frequency (based on all cores) in GHz.
|
||||
|
||||
*{max_frequency}*: Current cpu max frequency (based on the core with the highest frequency) in GHz.
|
||||
|
||||
*{min_frequency}*: Current cpu min frequency (based on the core with the lowest frequency) in GHz.
|
||||
|
||||
# EXAMPLE
|
||||
|
||||
```
|
||||
"cpu": {
|
||||
"interval": 10,
|
||||
"format": "{}% ",
|
||||
"max-length": 10
|
||||
}
|
||||
```
|
||||
|
||||
# STYLE
|
||||
|
||||
- *#cpu*
|
218
man/waybar-custom.5.scd
Normal file
218
man/waybar-custom.5.scd
Normal file
@ -0,0 +1,218 @@
|
||||
waybar-custom(5)
|
||||
|
||||
# NAME
|
||||
|
||||
waybar - custom module
|
||||
|
||||
# DESCRIPTION
|
||||
|
||||
The *custom* module displays either the output of a script or static text.
|
||||
To display static text, specify only the *format* field.
|
||||
|
||||
# CONFIGURATION
|
||||
|
||||
Addressed by *custom/<name>*
|
||||
|
||||
*exec*: ++
|
||||
typeof: string ++
|
||||
The path to the script, which should be executed.
|
||||
|
||||
*exec-if*: ++
|
||||
typeof: string ++
|
||||
The path to a script, which determines if the script in *exec* should be executed.
|
||||
*exec* will be executed if the exit code of *exec-if* equals 0.
|
||||
|
||||
*exec-on-event*: ++
|
||||
typeof: bool ++
|
||||
default: true ++
|
||||
If an event command is set (e.g. *on-click* or *on-scroll-up*) then re-execute the script after
|
||||
executing the event command.
|
||||
|
||||
*return-type*: ++
|
||||
typeof: string ++
|
||||
See *return-type*
|
||||
|
||||
*interval*: ++
|
||||
typeof: integer ++
|
||||
The interval (in seconds) in which the information gets polled.
|
||||
Use *once* if you want to execute the module only on startup.
|
||||
You can update it manually with a signal. If no *interval* is defined,
|
||||
it is assumed that the out script loops it self.
|
||||
|
||||
*restart-interval*: ++
|
||||
typeof: integer ++
|
||||
The restart interval (in seconds).
|
||||
Can't be used with the *interval* option, so only with continuous scripts.
|
||||
Once the script exit, it'll be re-executed after the *restart-interval*.
|
||||
|
||||
*signal*: ++
|
||||
typeof: integer ++
|
||||
The signal number used to update the module.
|
||||
The number is valid between 1 and N, where *SIGRTMIN+N* = *SIGRTMAX*.
|
||||
|
||||
*format*: ++
|
||||
typeof: string ++
|
||||
default: {} ++
|
||||
The format, how information should be displayed. On {} data gets inserted.
|
||||
|
||||
*format-icons*: ++
|
||||
typeof: array ++
|
||||
Based on the set percentage, the corresponding icon gets selected. The order is *low* to *high*.
|
||||
|
||||
*rotate*: ++
|
||||
typeof: integer ++
|
||||
Positive value to rotate the text label.
|
||||
|
||||
*max-length*: ++
|
||||
typeof: integer ++
|
||||
The maximum length in character the module should display.
|
||||
|
||||
*min-length*: ++
|
||||
typeof: integer ++
|
||||
The minimum length in characters the module should take up.
|
||||
|
||||
*align*: ++
|
||||
typeof: float ++
|
||||
The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
|
||||
|
||||
*on-click*: ++
|
||||
typeof: string ++
|
||||
Command to execute when clicked on the module.
|
||||
|
||||
*on-click-middle*: ++
|
||||
typeof: string ++
|
||||
Command to execute when middle-clicked on the module using mousewheel.
|
||||
|
||||
*on-click-right*: ++
|
||||
typeof: string ++
|
||||
Command to execute when you right clicked on the module.
|
||||
|
||||
*on-update*: ++
|
||||
typeof: string ++
|
||||
Command to execute when the module is updated.
|
||||
|
||||
*on-scroll-up*: ++
|
||||
typeof: string ++
|
||||
Command to execute when scrolling up on the module.
|
||||
|
||||
*on-scroll-down*: ++
|
||||
typeof: string ++
|
||||
Command to execute when scrolling down on the module.
|
||||
|
||||
*smooth-scrolling-threshold*: ++
|
||||
typeof: double ++
|
||||
Threshold to be used when scrolling.
|
||||
|
||||
*tooltip*: ++
|
||||
typeof: bool ++
|
||||
default: true ++
|
||||
Option to disable tooltip on hover.
|
||||
|
||||
*escape*: ++
|
||||
typeof: bool ++
|
||||
default: false ++
|
||||
Option to enable escaping of script output.
|
||||
|
||||
# RETURN-TYPE
|
||||
|
||||
When *return-type* is set to *json*, Waybar expects the *exec*-script to output its data in JSON format.
|
||||
This should look like this:
|
||||
|
||||
```
|
||||
{"text": "$text", "tooltip": "$tooltip", "class": "$class", "percentage": $percentage }
|
||||
```
|
||||
|
||||
The *class* parameter also accepts an array of strings.
|
||||
|
||||
If nothing or an invalid option is specified, Waybar expects i3blocks style output. Values are *newline* separated.
|
||||
This should look like this:
|
||||
|
||||
```
|
||||
$text\\n$tooltip\\n$class*
|
||||
```
|
||||
|
||||
*class* is a CSS class, to apply different styles in *style.css*
|
||||
|
||||
# FORMAT REPLACEMENTS
|
||||
|
||||
*{}*: Output of the script.
|
||||
|
||||
*{percentage}* Percentage which can be set via a json return-type.
|
||||
|
||||
*{icon}*: An icon from 'format-icons' according to percentage.
|
||||
|
||||
# EXAMPLES
|
||||
|
||||
## Spotify:
|
||||
|
||||
```
|
||||
"custom/spotify": {
|
||||
"format": " {}",
|
||||
"max-length": 40,
|
||||
"interval": 30, // Remove this if your script is endless and write in loop
|
||||
"exec": "$HOME/.config/waybar/mediaplayer.sh 2> /dev/null", // Script in resources folder
|
||||
"exec-if": "pgrep spotify"
|
||||
}
|
||||
```
|
||||
|
||||
## mpd:
|
||||
|
||||
```
|
||||
"custom/mpd": {
|
||||
"format": "♪ {}",
|
||||
//"max-length": 15,
|
||||
"interval": 10,
|
||||
"exec": "mpc current",
|
||||
"exec-if": "pgrep mpd",
|
||||
"on-click": "mpc toggle",
|
||||
"on-click-right": "sonata"
|
||||
}
|
||||
```
|
||||
|
||||
## cmus:
|
||||
|
||||
```
|
||||
"custom/cmus": {
|
||||
"format": "♪ {}",
|
||||
//"max-length": 15,
|
||||
"interval": 10,
|
||||
"exec": "cmus-remote -C \"format_print '%a - %t'\"", // artist - title
|
||||
"exec-if": "pgrep cmus",
|
||||
"on-click": "cmus-remote -u", //toggle pause
|
||||
"escape": true //handle markup entities
|
||||
}
|
||||
```
|
||||
|
||||
## Pacman
|
||||
|
||||
```
|
||||
|
||||
"custom/pacman": {
|
||||
"format": "{} ",
|
||||
"interval": "once",
|
||||
"exec": "pacman_packages",
|
||||
"on-click": "update-system",
|
||||
"signal": 8
|
||||
}
|
||||
```
|
||||
|
||||
## Alternate Pacman
|
||||
|
||||
```
|
||||
"custom/pacman": {
|
||||
"format": "{} ",
|
||||
"interval": 3600, // every hour
|
||||
"exec": "checkupdates | wc -l", // # of updates
|
||||
"exec-if": "exit 0", // always run; consider advanced run conditions
|
||||
"on-click": "termite -e 'sudo pacman -Syu'; pkill -SIGRTMIN+8 waybar", // update system
|
||||
"signal": 8
|
||||
}
|
||||
```
|
||||
|
||||
You can use the signal and update the number of available packages with *pkill -RTMIN+8 waybar*.
|
||||
|
||||
# STYLE
|
||||
|
||||
- *#custom-<name>*
|
||||
- *#custom-<name>.<class>*
|
||||
- *<class>* can be set by the script. For more information see *return-type*
|
113
man/waybar-disk.5.scd
Normal file
113
man/waybar-disk.5.scd
Normal file
@ -0,0 +1,113 @@
|
||||
waybar-disk(5)
|
||||
|
||||
# NAME
|
||||
|
||||
waybar - disk module
|
||||
|
||||
# DESCRIPTION
|
||||
|
||||
The *disk* module displays the current disk space used.
|
||||
|
||||
# CONFIGURATION
|
||||
|
||||
Addressed by *disk*
|
||||
|
||||
*path*: ++
|
||||
typeof: string ++
|
||||
default: "/" ++
|
||||
Any path residing in the filesystem or mountpoint for which the information should be displayed.
|
||||
|
||||
*interval*: ++
|
||||
typeof: integer++
|
||||
default: 30 ++
|
||||
The interval in which the information gets polled.
|
||||
|
||||
*format*: ++
|
||||
typeof: string ++
|
||||
default: "{percentage_used}%" ++
|
||||
The format, how information should be displayed.
|
||||
|
||||
*rotate*: ++
|
||||
typeof: integer ++
|
||||
Positive value to rotate the text label.
|
||||
|
||||
*states*: ++
|
||||
typeof: array ++
|
||||
A number of disk utilization states which get activated on certain percentage thresholds (percentage_used). See *waybar-states(5)*.
|
||||
|
||||
*max-length*: ++
|
||||
typeof: integer ++
|
||||
The maximum length in character the module should display.
|
||||
|
||||
*min-length*: ++
|
||||
typeof: integer ++
|
||||
The minimum length in characters the module should take up.
|
||||
|
||||
*align*: ++
|
||||
typeof: float ++
|
||||
The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
|
||||
|
||||
*on-click*: ++
|
||||
typeof: string ++
|
||||
Command to execute when clicked on the module.
|
||||
|
||||
*on-click-middle*: ++
|
||||
typeof: string ++
|
||||
Command to execute when middle-clicked on the module using mousewheel.
|
||||
|
||||
*on-click-right*: ++
|
||||
typeof: string ++
|
||||
Command to execute when you right clicked on the module.
|
||||
|
||||
*on-update*: ++
|
||||
typeof: string ++
|
||||
Command to execute when the module is updated.
|
||||
|
||||
*on-scroll-up*: ++
|
||||
typeof: string ++
|
||||
Command to execute when scrolling up on the module.
|
||||
|
||||
*on-scroll-down*: ++
|
||||
typeof: string ++
|
||||
Command to execute when scrolling down on the module.
|
||||
|
||||
*smooth-scrolling-threshold*: ++
|
||||
typeof: double ++
|
||||
Threshold to be used when scrolling.
|
||||
|
||||
*tooltip*: ++
|
||||
typeof: bool ++
|
||||
default: true ++
|
||||
Option to disable tooltip on hover.
|
||||
|
||||
*tooltip-format*: ++
|
||||
typeof: string ++
|
||||
default: "{used} out of {total} used ({percentage_used}%)" ++
|
||||
The format of the information displayed in the tooltip.
|
||||
|
||||
# FORMAT REPLACEMENTS
|
||||
|
||||
*{percentage_used}*: Percentage of disk in use.
|
||||
|
||||
*{percentage_free}*: Percentage of free disk space
|
||||
|
||||
*{total}*: Total amount of space on the disk, partition or mountpoint.
|
||||
|
||||
*{used}*: Amount of used disk space.
|
||||
|
||||
*{free}*: Amount of available disk space for normal users.
|
||||
|
||||
*{path}*: The path specified in the configuration.
|
||||
|
||||
# EXAMPLES
|
||||
|
||||
```
|
||||
"disk": {
|
||||
"interval": 30,
|
||||
"format": "{percentage_free}% free on {path}",
|
||||
}
|
||||
```
|
||||
|
||||
# STYLE
|
||||
|
||||
- *#disk*
|
87
man/waybar-idle-inhibitor.5.scd
Normal file
87
man/waybar-idle-inhibitor.5.scd
Normal file
@ -0,0 +1,87 @@
|
||||
waybar-idle-inhibitor(5)
|
||||
|
||||
# NAME
|
||||
|
||||
waybar - idle_inhibitor module
|
||||
|
||||
# DESCRIPTION
|
||||
|
||||
The *idle_inhibitor* module can inhibiting the idle behavior such as screen blanking, locking, and
|
||||
screensaving, also known as "presentation mode".
|
||||
|
||||
# CONFIGURATION
|
||||
|
||||
*format*: ++
|
||||
typeof: string ++
|
||||
The format, how the state should be displayed.
|
||||
|
||||
*format-icons*: ++
|
||||
typeof: array ++
|
||||
Based on the current state, the corresponding icon gets selected.
|
||||
|
||||
*rotate*: ++
|
||||
typeof: integer ++
|
||||
Positive value to rotate the text label.
|
||||
|
||||
*max-length*: ++
|
||||
typeof: integer ++
|
||||
The maximum length in character the module should display.
|
||||
|
||||
*min-length*: ++
|
||||
typeof: integer ++
|
||||
The minimum length in characters the module should take up.
|
||||
|
||||
*align*: ++
|
||||
typeof: float ++
|
||||
The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
|
||||
|
||||
*on-click*: ++
|
||||
typeof: string ++
|
||||
Command to execute when clicked on the module. A click also toggles the state
|
||||
|
||||
*on-click-middle*: ++
|
||||
typeof: string ++
|
||||
Command to execute when middle-clicked on the module using mousewheel.
|
||||
|
||||
*on-click-right*: ++
|
||||
typeof: string ++
|
||||
Command to execute when you right clicked on the module.
|
||||
|
||||
*on-update*: ++
|
||||
typeof: string ++
|
||||
Command to execute when the module is updated.
|
||||
|
||||
*on-scroll-up*: ++
|
||||
typeof: string ++
|
||||
Command to execute when scrolling up on the module.
|
||||
|
||||
*on-scroll-down*: ++
|
||||
typeof: string ++
|
||||
Command to execute when scrolling down on the module.
|
||||
|
||||
*smooth-scrolling-threshold*: ++
|
||||
typeof: double ++
|
||||
Threshold to be used when scrolling.
|
||||
|
||||
*tooltip*: ++
|
||||
typeof: bool ++
|
||||
default: true ++
|
||||
Option to disable tooltip on hover.
|
||||
|
||||
# FORMAT REPLACEMENTS
|
||||
|
||||
*{status}*: status (*activated* or *deactivated*)
|
||||
|
||||
*{icon}*: Icon, as defined in *format-icons*
|
||||
|
||||
# EXAMPLES
|
||||
|
||||
```
|
||||
"idle_inhibitor": {
|
||||
"format": "{icon}",
|
||||
"format-icons": {
|
||||
"activated": "",
|
||||
"deactivated": ""
|
||||
}
|
||||
}
|
||||
```
|
80
man/waybar-keyboard-state.5.scd
Normal file
80
man/waybar-keyboard-state.5.scd
Normal file
@ -0,0 +1,80 @@
|
||||
waybar-keyboard-state(5)
|
||||
|
||||
# NAME
|
||||
|
||||
waybar - keyboard-state module
|
||||
|
||||
# DESCRIPTION
|
||||
|
||||
The *keyboard-state* module displays the state of number lock, caps lock, and scroll lock.
|
||||
|
||||
# CONFIGURATION
|
||||
|
||||
*interval*: ++
|
||||
typeof: integer ++
|
||||
default: 1 ++
|
||||
The interval, in seconds, to poll the keyboard state.
|
||||
|
||||
*format*: ++
|
||||
typeof: string|object ++
|
||||
default: {name} {icon} ++
|
||||
The format, how information should be displayed. If a string, the same format is used for all keyboard states. If an object, the fields "numlock", "capslock", and "scrolllock" each specify the format for the corresponding state. Any unspecified states use the default format.
|
||||
|
||||
*format-icons*: ++
|
||||
typeof: object ++
|
||||
default: {"locked": "locked", "unlocked": "unlocked"} ++
|
||||
Based on the keyboard state, the corresponding icon gets selected. The same set of icons is used for number, caps, and scroll lock, but the icon is selected from the set independently for each. See *icons*.
|
||||
|
||||
*numlock*: ++
|
||||
typeof: bool ++
|
||||
default: false ++
|
||||
Display the number lock state.
|
||||
|
||||
*capslock*: ++
|
||||
typeof: bool ++
|
||||
default: false ++
|
||||
Display the caps lock state.
|
||||
|
||||
*scrolllock*: ++
|
||||
typeof: bool ++
|
||||
default: false ++
|
||||
Display the scroll lock state.
|
||||
|
||||
*device-path*: ++
|
||||
typeof: string ++
|
||||
default: chooses first valid input device ++
|
||||
Which libevdev input device to show the state of. Libevdev devices can be found in /dev/input. The device should support number lock, caps lock, and scroll lock events.
|
||||
|
||||
# FORMAT REPLACEMENTS
|
||||
|
||||
*{name}*: Caps, Num, or Scroll.
|
||||
|
||||
*{icon}*: Icon, as defined in *format-icons*.
|
||||
|
||||
# ICONS
|
||||
|
||||
The following *format-icons* can be set.
|
||||
|
||||
- *locked*: Will be shown when the keyboard state is locked. Default "locked".
|
||||
- *unlocked*: Will be shown when the keyboard state is not locked. Default "unlocked"
|
||||
|
||||
# EXAMPLE:
|
||||
|
||||
```
|
||||
"keyboard-state": {
|
||||
"numlock": true,
|
||||
"capslock": true,
|
||||
"format": "{name} {icon}",
|
||||
"format-icons": {
|
||||
"locked": "",
|
||||
"unlocked": ""
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
# STYLE
|
||||
|
||||
- *#keyboard-state*
|
||||
- *#keyboard-state label*
|
||||
- *#keyboard-state label.locked*
|
||||
|
109
man/waybar-memory.5.scd
Normal file
109
man/waybar-memory.5.scd
Normal file
@ -0,0 +1,109 @@
|
||||
waybar-memory(5)
|
||||
|
||||
# NAME
|
||||
|
||||
waybar - memory module
|
||||
|
||||
# DESCRIPTION
|
||||
|
||||
The *memory* module displays the current memory utilization.
|
||||
|
||||
# CONFIGURATION
|
||||
|
||||
Addressed by *memory*
|
||||
|
||||
*interval*: ++
|
||||
typeof: integer++
|
||||
default: 30 ++
|
||||
The interval in which the information gets polled.
|
||||
|
||||
*format*: ++
|
||||
typeof: string ++
|
||||
default: {percentage}% ++
|
||||
The format, how information should be displayed.
|
||||
|
||||
*rotate*: ++
|
||||
typeof: integer ++
|
||||
Positive value to rotate the text label.
|
||||
|
||||
*states*: ++
|
||||
typeof: array ++
|
||||
A number of memory utilization states which get activated on certain percentage thresholds. See *waybar-states(5)*.
|
||||
|
||||
*max-length*: ++
|
||||
typeof: integer ++
|
||||
The maximum length in character the module should display.
|
||||
|
||||
*min-length*: ++
|
||||
typeof: integer ++
|
||||
The minimum length in characters the module should take up.
|
||||
|
||||
*align*: ++
|
||||
typeof: float ++
|
||||
The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
|
||||
|
||||
*on-click*: ++
|
||||
typeof: string ++
|
||||
Command to execute when clicked on the module.
|
||||
|
||||
*on-click-middle*: ++
|
||||
typeof: string ++
|
||||
Command to execute when middle-clicked on the module using mousewheel.
|
||||
|
||||
*on-click-right*: ++
|
||||
typeof: string ++
|
||||
Command to execute when you right clicked on the module.
|
||||
|
||||
*on-update*: ++
|
||||
typeof: string ++
|
||||
Command to execute when the module is updated.
|
||||
|
||||
*on-scroll-up*: ++
|
||||
typeof: string ++
|
||||
Command to execute when scrolling up on the module.
|
||||
|
||||
*on-scroll-down*: ++
|
||||
typeof: string ++
|
||||
Command to execute when scrolling down on the module.
|
||||
|
||||
*smooth-scrolling-threshold*: ++
|
||||
typeof: double ++
|
||||
Threshold to be used when scrolling.
|
||||
|
||||
*tooltip*: ++
|
||||
typeof: bool ++
|
||||
default: true ++
|
||||
Option to disable tooltip on hover.
|
||||
|
||||
# FORMAT REPLACEMENTS
|
||||
|
||||
*{percentage}*: Percentage of memory in use.
|
||||
|
||||
*{total}*: Amount of total memory available in GiB.
|
||||
|
||||
*{used}*: Amount of used memory in GiB.
|
||||
|
||||
*{avail}*: Amount of available memory in GiB.
|
||||
|
||||
# EXAMPLES
|
||||
|
||||
```
|
||||
"memory": {
|
||||
"interval": 30,
|
||||
"format": "{}% ",
|
||||
"max-length": 10
|
||||
}
|
||||
```
|
||||
|
||||
## FORMATTED MEMORY VALUES
|
||||
|
||||
```
|
||||
"memory": {
|
||||
"interval": 30,
|
||||
"format": "{used:0.1f}G/{total:0.1f}G "
|
||||
}
|
||||
```
|
||||
|
||||
# STYLE
|
||||
|
||||
- *#memory*
|
246
man/waybar-mpd.5.scd
Normal file
246
man/waybar-mpd.5.scd
Normal file
@ -0,0 +1,246 @@
|
||||
waybar-mpd(5)
|
||||
|
||||
# NAME
|
||||
|
||||
waybar - mpd module
|
||||
|
||||
# DESCRIPTION
|
||||
|
||||
The *mpd* module displays information about a running "Music Player Daemon" instance.
|
||||
|
||||
# CONFIGURATION
|
||||
|
||||
Addressed by *mpd*
|
||||
|
||||
*server*: ++
|
||||
typeof: string ++
|
||||
The network address or Unix socket path of the MPD server. If empty, connect to the default host.
|
||||
|
||||
*port*: ++
|
||||
typeof: integer ++
|
||||
The port MPD listens to. If empty, use the default port.
|
||||
|
||||
*password*: ++
|
||||
typeof: string ++
|
||||
The password required to connect to the MPD server. If empty, no password is sent to MPD.
|
||||
|
||||
*interval*: ++
|
||||
typeof: integer++
|
||||
default: 5 ++
|
||||
The interval in which the connection to the MPD server is retried
|
||||
|
||||
*timeout*: ++
|
||||
typeof: integer++
|
||||
default: 30 ++
|
||||
The timeout for the connection. Change this if your MPD server has a low `connection_timeout` setting
|
||||
|
||||
*unknown-tag*: ++
|
||||
typeof: string ++
|
||||
default: "N/A" ++
|
||||
The text to display when a tag is not present in the current song, but used in `format`
|
||||
|
||||
*format*: ++
|
||||
typeof: string ++
|
||||
default: "{album} - {artist} - {title}" ++
|
||||
Information displayed when a song is playing.
|
||||
|
||||
*format-stopped*: ++
|
||||
typeof: string ++
|
||||
default: "stopped" ++
|
||||
Information displayed when the player is stopped.
|
||||
|
||||
*format-paused*: ++
|
||||
typeof: string ++
|
||||
This format is used when a song is paused.
|
||||
|
||||
*format-disconnected*: ++
|
||||
typeof: string ++
|
||||
default: "disconnected" ++
|
||||
Information displayed when the MPD server can't be reached.
|
||||
|
||||
*tooltip*: ++
|
||||
typeof: bool ++
|
||||
default: true ++
|
||||
Option to disable tooltip on hover.
|
||||
|
||||
*tooltip-format*: ++
|
||||
typeof: string ++
|
||||
default: "MPD (connected)" ++
|
||||
Tooltip information displayed when connected to MPD.
|
||||
|
||||
*tooltip-format-disconnected*: ++
|
||||
typeof: string ++
|
||||
default: "MPD (disconnected)" ++
|
||||
Tooltip information displayed when the MPD server can't be reached.
|
||||
|
||||
*artist-len*: ++
|
||||
typeof: integer ++
|
||||
Maximum length of the Artist tag.
|
||||
|
||||
*album-len*: ++
|
||||
typeof: integer ++
|
||||
Maximum length of the Album tag.
|
||||
|
||||
*album-artist-len*: ++
|
||||
typeof: integer ++
|
||||
Maximum length of the Album Artist tag.
|
||||
|
||||
*title-len*: ++
|
||||
typeof: integer ++
|
||||
Maximum length of the Title tag.
|
||||
|
||||
*rotate*: ++
|
||||
typeof: integer ++
|
||||
Positive value to rotate the text label.
|
||||
|
||||
*max-length*: ++
|
||||
typeof: integer ++
|
||||
The maximum length in character the module should display.
|
||||
|
||||
*min-length*: ++
|
||||
typeof: integer ++
|
||||
The minimum length in characters the module should take up.
|
||||
|
||||
*align*: ++
|
||||
typeof: float ++
|
||||
The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
|
||||
|
||||
*on-click*: ++
|
||||
typeof: string ++
|
||||
Command to execute when clicked on the module.
|
||||
|
||||
*on-click-middle*: ++
|
||||
typeof: string ++
|
||||
Command to execute when middle-clicked on the module using mousewheel.
|
||||
|
||||
*on-click-right*: ++
|
||||
typeof: string ++
|
||||
Command to execute when you right clicked on the module.
|
||||
|
||||
*on-update*: ++
|
||||
typeof: string ++
|
||||
Command to execute when the module is updated.
|
||||
|
||||
*on-scroll-up*: ++
|
||||
typeof: string ++
|
||||
Command to execute when scrolling up on the module.
|
||||
|
||||
*on-scroll-down*: ++
|
||||
typeof: string ++
|
||||
Command to execute when scrolling down on the module.
|
||||
|
||||
*smooth-scrolling-threshold*: ++
|
||||
typeof: double ++
|
||||
Threshold to be used when scrolling.
|
||||
|
||||
*state-icons*: ++
|
||||
typeof: object ++
|
||||
default: {} ++
|
||||
Icon to show depending on the play/pause state of the player (*{ "playing": "...", "paused": "..." }*)
|
||||
|
||||
*consume-icons*: ++
|
||||
typeof: object ++
|
||||
default: {} ++
|
||||
Icon to show depending on the "consume" option (*{ "on": "...", "off": "..." }*)
|
||||
|
||||
*random-icons*: ++
|
||||
typeof: object ++
|
||||
default: {} ++
|
||||
Icon to show depending on the "random" option (*{ "on": "...", "off": "..." }*)
|
||||
|
||||
*repeat-icons*: ++
|
||||
typeof: object ++
|
||||
default: {} ++
|
||||
Icon to show depending on the "repeat" option (*{ "on": "...", "off": "..." }*)
|
||||
|
||||
*single-icons*: ++
|
||||
typeof: object ++
|
||||
default: {} ++
|
||||
Icon to show depending on the "single" option (*{ "on": "...", "off": "..." }*)
|
||||
|
||||
# FORMAT REPLACEMENTS
|
||||
|
||||
## WHEN PLAYING/PAUSED
|
||||
|
||||
*{artist}*: The artist of the current song
|
||||
|
||||
*{albumArtist}*: The artist of the current album
|
||||
|
||||
*{album}*: The album of the current song
|
||||
|
||||
*{title}*: The title of the current song
|
||||
|
||||
*{date}*: The date of the current song
|
||||
|
||||
*{volume}*: The current volume in percent
|
||||
|
||||
*{elapsedTime}*: The current position of the current song. To format as a date/time (see example configuration)
|
||||
|
||||
*{totalTime}*: The length of the current song. To format as a date/time (see example configuration)
|
||||
|
||||
*{songPosition}*: The position of the current song.
|
||||
|
||||
*{queueLength}*: The length of the current queue.
|
||||
|
||||
*{stateIcon}*: The icon corresponding the playing or paused status of the player (see *state-icons* option)
|
||||
|
||||
*{consumeIcon}*: The icon corresponding the "consume" option (see *consume-icons* option)
|
||||
|
||||
*{randomIcon}*: The icon corresponding the "random" option (see *random-icons* option)
|
||||
|
||||
*{repeatIcon}*: The icon corresponding the "repeat" option (see *repeat-icons* option)
|
||||
|
||||
*{singleIcon}*: The icon corresponding the "single" option (see *single-icons* option)
|
||||
|
||||
|
||||
## WHEN STOPPED
|
||||
|
||||
*{consumeIcon}*: The icon corresponding the "consume" option (see *consume-icons* option)
|
||||
|
||||
*{randomIcon}*: The icon corresponding the "random" option (see *random-icons* option)
|
||||
|
||||
*{repeatIcon}*: The icon corresponding the "repeat" option (see *repeat-icons* option)
|
||||
|
||||
*{singleIcon}*: The icon corresponding the "single" option (see *single-icons* option)
|
||||
|
||||
## WHEN DISCONNECTED
|
||||
|
||||
Currently, no format replacements when disconnected.
|
||||
|
||||
# EXAMPLES
|
||||
|
||||
```
|
||||
"mpd": {
|
||||
"format": "{stateIcon} {consumeIcon}{randomIcon}{repeatIcon}{singleIcon}{artist} - {album} - {title} ({elapsedTime:%M:%S}/{totalTime:%M:%S}) ",
|
||||
"format-disconnected": "Disconnected ",
|
||||
"format-stopped": "{consumeIcon}{randomIcon}{repeatIcon}{singleIcon}Stopped ",
|
||||
"interval": 2,
|
||||
"consume-icons": {
|
||||
"on": " " // Icon shows only when "consume" is on
|
||||
},
|
||||
"random-icons": {
|
||||
"off": "<span color=\"#f53c3c\"></span> ", // Icon grayed out when "random" is off
|
||||
"on": " "
|
||||
},
|
||||
"repeat-icons": {
|
||||
"on": " "
|
||||
},
|
||||
"single-icons": {
|
||||
"on": "1 "
|
||||
},
|
||||
"state-icons": {
|
||||
"paused": "",
|
||||
"playing": ""
|
||||
},
|
||||
"tooltip-format": "MPD (connected)",
|
||||
"tooltip-format-disconnected": "MPD (disconnected)"
|
||||
}
|
||||
```
|
||||
|
||||
# STYLE
|
||||
|
||||
- *#mpd*
|
||||
- *#mpd.disconnected*
|
||||
- *#mpd.stopped*
|
||||
- *#mpd.playing*
|
||||
- *#mpd.paused*
|
181
man/waybar-network.5.scd
Normal file
181
man/waybar-network.5.scd
Normal file
@ -0,0 +1,181 @@
|
||||
waybar-network(5)
|
||||
|
||||
# NAME
|
||||
|
||||
waybar - network module
|
||||
|
||||
# DESCRIPTION
|
||||
|
||||
The *network* module displays information about the current network connections.
|
||||
|
||||
# CONFIGURATION
|
||||
|
||||
Addressed by *network*
|
||||
|
||||
*interface*: ++
|
||||
typeof: string ++
|
||||
Use the defined interface instead of auto detection. Accepts wildcard.
|
||||
|
||||
*interval*: ++
|
||||
typeof: integer ++
|
||||
default: 60 ++
|
||||
The interval in which the network information gets polled (e.g. signal strength).
|
||||
|
||||
*family*: ++
|
||||
typeof: string ++
|
||||
default: *ipv4* ++
|
||||
The address family that is used for the format replacement {ipaddr} and to determine if a network connection is present.
|
||||
|
||||
*format*: ++
|
||||
typeof: string ++
|
||||
default: *{ifname}* ++
|
||||
The format, how information should be displayed. This format is used when other formats aren't specified.
|
||||
|
||||
*format-ethernet*: ++
|
||||
typeof: string ++
|
||||
This format is used when an ethernet interface is displayed.
|
||||
|
||||
*format-wifi*: ++
|
||||
typeof: string ++
|
||||
This format is used when a wireless interface is displayed.
|
||||
|
||||
*format-linked*: ++
|
||||
typeof: string ++
|
||||
This format is used when a linked interface with no ip address is displayed.
|
||||
|
||||
*format-disconnected*: ++
|
||||
typeof: string ++
|
||||
This format is used when the displayed interface is disconnected.
|
||||
|
||||
*format-disabled*: ++
|
||||
typeof: string ++
|
||||
This format is used when the displayed interface is disabled.
|
||||
|
||||
*format-icons*: ++
|
||||
typeof: array/object ++
|
||||
Based on the current signal strength, the corresponding icon gets selected. ++
|
||||
The order is *low* to *high*. Or by the state if it is an object.
|
||||
|
||||
*rotate*: ++
|
||||
typeof: integer ++
|
||||
Positive value to rotate the text label.
|
||||
|
||||
*max-length*: ++
|
||||
typeof: integer ++
|
||||
The maximum length in character the module should display.
|
||||
|
||||
*min-length*: ++
|
||||
typeof: integer ++
|
||||
The minimum length in characters the module should take up.
|
||||
|
||||
*align*: ++
|
||||
typeof: float ++
|
||||
The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
|
||||
|
||||
*on-click*: ++
|
||||
typeof: string ++
|
||||
Command to execute when clicked on the module.
|
||||
|
||||
*on-click-middle*: ++
|
||||
typeof: string ++
|
||||
Command to execute when middle-clicked on the module using mousewheel.
|
||||
|
||||
*on-click-right*: ++
|
||||
typeof: string ++
|
||||
Command to execute when you right clicked on the module.
|
||||
|
||||
*on-update*: ++
|
||||
typeof: string ++
|
||||
Command to execute when the module is updated.
|
||||
|
||||
*on-scroll-up*: ++
|
||||
typeof: string ++
|
||||
Command to execute when scrolling up on the module.
|
||||
|
||||
*on-scroll-down*: ++
|
||||
typeof: string ++
|
||||
Command to execute when scrolling down on the module.
|
||||
|
||||
*smooth-scrolling-threshold*: ++
|
||||
typeof: double ++
|
||||
Threshold to be used when scrolling.
|
||||
|
||||
*tooltip*: ++
|
||||
typeof: bool ++
|
||||
default: *true* ++
|
||||
Option to disable tooltip on hover.
|
||||
|
||||
*tooltip-format*: ++
|
||||
typeof: string ++
|
||||
The format, how information should be displayed in the tooltip. This format is used when other formats aren't specified.
|
||||
|
||||
*tooltip-format-ethernet*: ++
|
||||
typeof: string ++
|
||||
This format is used when an ethernet interface is displayed.
|
||||
|
||||
*tooltip-format-wifi*: ++
|
||||
typeof: string ++
|
||||
This format is used when a wireless interface is displayed.
|
||||
|
||||
*tooltip-format-disconnected*: ++
|
||||
typeof: string ++
|
||||
This format is used when the displayed interface is disconnected.
|
||||
|
||||
*tooltip-format-disabled*: ++
|
||||
typeof: string ++
|
||||
This format is used when the displayed interface is disabled.
|
||||
|
||||
# FORMAT REPLACEMENTS
|
||||
|
||||
*{ifname}*: Name of the network interface.
|
||||
|
||||
*{ipaddr}*: The first IP of the interface.
|
||||
|
||||
*{netmask}*: The subnetmask corresponding to the IP.
|
||||
|
||||
*{cidr}*: The subnetmask corresponding to the IP in CIDR notation.
|
||||
|
||||
*{essid}*: Name (SSID) of the wireless network.
|
||||
|
||||
*{signalStrength}*: Signal strength of the wireless network.
|
||||
|
||||
*{signaldBm}*: Signal strength of the wireless network in dBm.
|
||||
|
||||
*{frequency}*: Frequency of the wireless network in MHz.
|
||||
|
||||
*{bandwidthUpBits}*: Instant up speed in bits/seconds.
|
||||
|
||||
*{bandwidthDownBits}*: Instant down speed in bits/seconds.
|
||||
|
||||
*{bandwidthUpOctets}*: Instant up speed in octets/seconds.
|
||||
|
||||
*{bandwidthDownOctets}*: Instant down speed in octets/seconds.
|
||||
|
||||
*{icon}*: Icon, as defined in *format-icons*.
|
||||
|
||||
# EXAMPLES
|
||||
|
||||
```
|
||||
"network": {
|
||||
"interface": "wlp2s0",
|
||||
"format": "{ifname}",
|
||||
"format-wifi": "{essid} ({signalStrength}%) ",
|
||||
"format-ethernet": "{ifname} ",
|
||||
"format-disconnected": "", //An empty format will hide the module.
|
||||
"format-disconnected": "",
|
||||
"tooltip-format": "{ifname}",
|
||||
"tooltip-format-wifi": "{essid} ({signalStrength}%) ",
|
||||
"tooltip-format-ethernet": "{ifname} ",
|
||||
"tooltip-format-disconnected": "Disconnected",
|
||||
"max-length": 50
|
||||
}
|
||||
```
|
||||
|
||||
# STYLE
|
||||
|
||||
- *#network*
|
||||
- *#network.disconnected*
|
||||
- *#network.disabled*
|
||||
- *#network.linked*
|
||||
- *#network.ethernet*
|
||||
- *#network.wifi*
|
155
man/waybar-pulseaudio.5.scd
Normal file
155
man/waybar-pulseaudio.5.scd
Normal file
@ -0,0 +1,155 @@
|
||||
waybar-pulseaudio(5)
|
||||
|
||||
# NAME
|
||||
|
||||
waybar - pulseaudio module
|
||||
|
||||
# DESCRIPTION
|
||||
|
||||
The *pulseaudio* module displays the current volume reported by PulseAudio.
|
||||
|
||||
Additionally you can control the volume by scrolling *up* or *down* while the cursor is over the module.
|
||||
|
||||
# CONFIGURATION
|
||||
|
||||
*format*: ++
|
||||
typeof: string ++
|
||||
default: {volume}% ++
|
||||
The format, how information should be displayed. This format is used when other formats aren't specified.
|
||||
|
||||
*format-bluetooth*: ++
|
||||
typeof: string ++
|
||||
This format is used when using bluetooth speakers.
|
||||
|
||||
*format-muted*: ++
|
||||
typeof: string ++
|
||||
This format is used when the sound is muted.
|
||||
|
||||
*format-source*: ++
|
||||
typeof: string ++
|
||||
default: {volume}% ++
|
||||
This format used for the source.
|
||||
|
||||
*format-source-muted*: ++
|
||||
typeof: string ++
|
||||
This format is used when the source is muted.
|
||||
|
||||
*format-icons*: ++
|
||||
typeof: array ++
|
||||
Based on the current port-name and volume, the corresponding icon gets selected. The order is *low* to *high*. See *Icons*.
|
||||
|
||||
*rotate*: ++
|
||||
typeof: integer ++
|
||||
Positive value to rotate the text label.
|
||||
|
||||
*states*: ++
|
||||
typeof: array ++
|
||||
A number of volume states which get activated on certain volume levels. See *waybar-states(5)*
|
||||
|
||||
*max-length*: ++
|
||||
typeof: integer ++
|
||||
The maximum length in character the module should display.
|
||||
|
||||
*min-length*: ++
|
||||
typeof: integer ++
|
||||
The minimum length in characters the module should take up.
|
||||
|
||||
*align*: ++
|
||||
typeof: float ++
|
||||
The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
|
||||
|
||||
*scroll-step*: ++
|
||||
typeof: float ++
|
||||
default: 1.0 ++
|
||||
The speed in which to change the volume when scrolling.
|
||||
|
||||
*on-click*: ++
|
||||
typeof: string ++
|
||||
Command to execute when clicked on the module.
|
||||
|
||||
*on-click-middle*: ++
|
||||
typeof: string ++
|
||||
Command to execute when middle-clicked on the module using mousewheel.
|
||||
|
||||
*on-click-right*: ++
|
||||
typeof: string ++
|
||||
Command to execute when you right clicked on the module.
|
||||
|
||||
*on-update*: ++
|
||||
typeof: string ++
|
||||
Command to execute when the module is updated.
|
||||
|
||||
*on-scroll-up*: ++
|
||||
typeof: string ++
|
||||
Command to execute when scrolling up on the module. This replaces the default behaviour of volume control.
|
||||
|
||||
*on-scroll-down*: ++
|
||||
typeof: string ++
|
||||
Command to execute when scrolling down on the module. This replaces the default behaviour of volume control.
|
||||
|
||||
*smooth-scrolling-threshold*: ++
|
||||
typeof: double ++
|
||||
Threshold to be used when scrolling.
|
||||
|
||||
*tooltip*: ++
|
||||
typeof: bool ++
|
||||
default: true ++
|
||||
Option to disable tooltip on hover.
|
||||
|
||||
# FORMAT REPLACEMENTS
|
||||
|
||||
*{desc}*: Pulseaudio port's description, for bluetooth it'll be the device name.
|
||||
|
||||
*{volume}*: Volume in percentage.
|
||||
|
||||
*{icon}*: Icon, as defined in *format-icons*.
|
||||
|
||||
*{format_source}*: Source format, *format-source*, *format-source-muted*.
|
||||
|
||||
# ICONS:
|
||||
|
||||
The following strings for *format-icons* are supported.
|
||||
|
||||
- the device name
|
||||
|
||||
If they are found in the current PulseAudio port name, the corresponding icons will be selected.
|
||||
|
||||
- *default* (Shown, when no other port is found)
|
||||
- *headphone*
|
||||
- *speaker*
|
||||
- *hdmi*
|
||||
- *headset*
|
||||
- *hands-free*
|
||||
- *portable*
|
||||
- *car*
|
||||
- *hifi*
|
||||
- *phone*
|
||||
|
||||
|
||||
# EXAMPLES
|
||||
|
||||
```
|
||||
"pulseaudio": {
|
||||
"format": "{volume}% {icon}",
|
||||
"format-bluetooth": "{volume}% {icon}",
|
||||
"format-muted": "",
|
||||
"format-icons": {
|
||||
"alsa_output.pci-0000_00_1f.3.analog-stereo": "",
|
||||
"headphones": "",
|
||||
"handsfree": "",
|
||||
"headset": "",
|
||||
"phone": "",
|
||||
"portable": "",
|
||||
"car": "",
|
||||
"default": ["", ""]
|
||||
},
|
||||
"scroll-step": 1,
|
||||
"on-click": "pavucontrol"
|
||||
}
|
||||
```
|
||||
|
||||
# STYLE
|
||||
|
||||
- *#pulseaudio*
|
||||
- *#pulseaudio.bluetooth*
|
||||
- *#pulseaudio.muted*
|
42
man/waybar-river-tags.5.scd
Normal file
42
man/waybar-river-tags.5.scd
Normal file
@ -0,0 +1,42 @@
|
||||
waybar-river-tags(5)
|
||||
|
||||
# NAME
|
||||
|
||||
waybar - river tags module
|
||||
|
||||
# DESCRIPTION
|
||||
|
||||
The *tags* module displays the current state of tags in river.
|
||||
|
||||
# CONFIGURATION
|
||||
|
||||
Addressed by *river/tags*
|
||||
|
||||
*num-tags*: ++
|
||||
typeof: uint ++
|
||||
default: 9 ++
|
||||
The number of tags that should be displayed.
|
||||
|
||||
*tag-labels*: ++
|
||||
typeof: array ++
|
||||
The label to display for each tag.
|
||||
|
||||
# EXAMPLE
|
||||
|
||||
```
|
||||
"river/tags": {
|
||||
"num-tags": 5
|
||||
}
|
||||
```
|
||||
|
||||
# STYLE
|
||||
|
||||
- *#tags button*
|
||||
- *#tags button.occupied*
|
||||
- *#tags button.focused*
|
||||
|
||||
Note that a tag can be both occupied and focused at the same time.
|
||||
|
||||
# SEE ALSO
|
||||
|
||||
waybar(5), river(1)
|
91
man/waybar-sndio.5.scd
Normal file
91
man/waybar-sndio.5.scd
Normal file
@ -0,0 +1,91 @@
|
||||
waybar-sndio(5)
|
||||
|
||||
# NAME
|
||||
|
||||
waybar - sndio module
|
||||
|
||||
# DESCRIPTION
|
||||
|
||||
The *sndio* module displays the current volume reported by sndio(7).
|
||||
|
||||
Additionally, you can control the volume by scrolling *up* or *down* while the
|
||||
cursor is over the module, and clicking on the module toggles mute.
|
||||
|
||||
# CONFIGURATION
|
||||
|
||||
*format*: ++
|
||||
typeof: string ++
|
||||
default: {volume}% ++
|
||||
The format for how information should be displayed.
|
||||
|
||||
*rotate*: ++
|
||||
typeof: integer ++
|
||||
Positive value to rotate the text label.
|
||||
|
||||
*max-length*: ++
|
||||
typeof: integer ++
|
||||
The maximum length in character the module should display.
|
||||
|
||||
*min-length*: ++
|
||||
typeof: integer ++
|
||||
The minimum length in characters the module should take up.
|
||||
|
||||
*align*: ++
|
||||
typeof: float ++
|
||||
The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
|
||||
|
||||
*scroll-step*: ++
|
||||
typeof: int ++
|
||||
default: 5 ++
|
||||
The speed in which to change the volume when scrolling.
|
||||
|
||||
*on-click*: ++
|
||||
typeof: string ++
|
||||
Command to execute when clicked on the module.
|
||||
This replaces the default behaviour of toggling mute.
|
||||
|
||||
*on-click-middle*: ++
|
||||
typeof: string ++
|
||||
Command to execute when middle-clicked on the module using mousewheel.
|
||||
|
||||
*on-click-right*: ++
|
||||
typeof: string ++
|
||||
Command to execute when you right clicked on the module.
|
||||
|
||||
*on-update*: ++
|
||||
typeof: string ++
|
||||
Command to execute when the module is updated.
|
||||
|
||||
*on-scroll-up*: ++
|
||||
typeof: string ++
|
||||
Command to execute when scrolling up on the module.
|
||||
This replaces the default behaviour of volume control.
|
||||
|
||||
*on-scroll-down*: ++
|
||||
typeof: string ++
|
||||
Command to execute when scrolling down on the module.
|
||||
This replaces the default behaviour of volume control.
|
||||
|
||||
*smooth-scrolling-threshold*: ++
|
||||
typeof: double ++
|
||||
Threshold to be used when scrolling.
|
||||
|
||||
# FORMAT REPLACEMENTS
|
||||
|
||||
*{volume}*: Volume in percentage.
|
||||
|
||||
*{raw_value}*: Volume as value reported by sndio.
|
||||
|
||||
# EXAMPLES
|
||||
|
||||
```
|
||||
"sndio": {
|
||||
"format": "{raw_value} 🎜",
|
||||
"scroll-step": 3
|
||||
}
|
||||
```
|
||||
|
||||
# STYLE
|
||||
|
||||
- *#sndio*
|
||||
- *#sndio.muted*
|
43
man/waybar-states.5.scd
Normal file
43
man/waybar-states.5.scd
Normal file
@ -0,0 +1,43 @@
|
||||
waybar-states(5)
|
||||
|
||||
# OVERVIEW
|
||||
|
||||
Some modules support 'states' which allows percentage values to be used as styling triggers to
|
||||
apply a class when the value matches the declared state value.
|
||||
|
||||
# STATES
|
||||
|
||||
- Every entry (*state*) consists of a *<name>* (typeof: *string*) and a *<value>* (typeof: *integer*).
|
||||
|
||||
- The state can be addressed as a CSS class in the *style.css*. The name of the CSS class is the *<name>* of the state.
|
||||
Each class gets activated when the current capacity is equal or below the configured *<value>*.
|
||||
|
||||
- Also each state can have its own *format*.
|
||||
Those can be configured via *format-<name>*.
|
||||
Or if you want to differentiate a bit more even as *format-<status>-<state>*.
|
||||
|
||||
# EXAMPLE
|
||||
|
||||
```
|
||||
"battery": {
|
||||
"bat": "BAT2",
|
||||
"interval": 60,
|
||||
"states": {
|
||||
"warning": 30,
|
||||
"critical": 15
|
||||
},
|
||||
"format": "{capacity}% {icon}",
|
||||
"format-icons": ["", "", "", "", ""],
|
||||
"max-length": 25
|
||||
}
|
||||
```
|
||||
|
||||
# STYLING STATES
|
||||
|
||||
- *#battery.<state>*
|
||||
- *<state>* can be defined in the *config*.
|
||||
|
||||
# EXAMPLE:
|
||||
|
||||
- *#battery.warning: { background: orange; }*
|
||||
- *#battery.critical: { background: red; }*
|
52
man/waybar-sway-language.5.scd
Normal file
52
man/waybar-sway-language.5.scd
Normal file
@ -0,0 +1,52 @@
|
||||
waybar-sway-language(5)
|
||||
|
||||
# NAME
|
||||
|
||||
waybar - sway language module
|
||||
|
||||
# DESCRIPTION
|
||||
|
||||
The *language* module displays the current keyboard layout in Sway
|
||||
|
||||
# CONFIGURATION
|
||||
|
||||
Addressed by *sway/language*
|
||||
|
||||
*format*: ++
|
||||
typeof: string ++
|
||||
default: {} ++
|
||||
The format, how layout should be displayed.
|
||||
|
||||
*tooltip-format*: ++
|
||||
typeof: string ++
|
||||
default: {} ++
|
||||
The format, how layout should be displayed in tooltip.
|
||||
|
||||
*tooltip*: ++
|
||||
typeof: bool ++
|
||||
default: true ++
|
||||
Option to disable tooltip on hover.
|
||||
|
||||
# FORMAT REPLACEMENTS
|
||||
|
||||
*{short}*: Short name of layout (e.g. "en"). Equals to {}.
|
||||
|
||||
*{long}*: Long name of layout (e.g. "English (Dvorak)").
|
||||
|
||||
*{variant}*: Variant of layout (e.g. "Dvorak").
|
||||
|
||||
# EXAMPLES
|
||||
|
||||
```
|
||||
"sway/language": {
|
||||
"format": "{}",
|
||||
},
|
||||
|
||||
"sway/language": {
|
||||
"format": "{short} {variant}",
|
||||
}
|
||||
```
|
||||
|
||||
# STYLE
|
||||
|
||||
- *#language*
|
80
man/waybar-sway-mode.5.scd
Normal file
80
man/waybar-sway-mode.5.scd
Normal file
@ -0,0 +1,80 @@
|
||||
waybar-sway-mode(5)
|
||||
|
||||
# NAME
|
||||
|
||||
waybar - sway mode module
|
||||
|
||||
# DESCRIPTION
|
||||
|
||||
The *mode* module displays the current binding mode of Sway
|
||||
|
||||
# CONFIGURATION
|
||||
|
||||
Addressed by *sway/mode*
|
||||
|
||||
*format*: ++
|
||||
typeof: string ++
|
||||
default: {} ++
|
||||
The format, how information should be displayed. On {} data gets inserted.
|
||||
|
||||
*rotate*: ++
|
||||
typeof: integer ++
|
||||
Positive value to rotate the text label.
|
||||
|
||||
*max-length*: ++
|
||||
typeof: integer ++
|
||||
The maximum length in character the module should display.
|
||||
|
||||
*min-length*: ++
|
||||
typeof: integer ++
|
||||
The minimum length in characters the module should take up.
|
||||
|
||||
*align*: ++
|
||||
typeof: float ++
|
||||
The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
|
||||
|
||||
*on-click*: ++
|
||||
typeof: string ++
|
||||
Command to execute when clicked on the module.
|
||||
|
||||
*on-click-middle*: ++
|
||||
typeof: string ++
|
||||
Command to execute when middle-clicked on the module using mousewheel.
|
||||
|
||||
*on-click-right*: ++
|
||||
typeof: string ++
|
||||
Command to execute when you right clicked on the module.
|
||||
|
||||
*on-update*: ++
|
||||
typeof: string ++
|
||||
Command to execute when the module is updated.
|
||||
|
||||
*on-scroll-up*: ++
|
||||
typeof: string ++
|
||||
Command to execute when scrolling up on the module.
|
||||
|
||||
*on-scroll-down*: ++
|
||||
typeof: string ++
|
||||
Command to execute when scrolling down on the module.
|
||||
|
||||
*smooth-scrolling-threshold*: ++
|
||||
typeof: double ++
|
||||
Threshold to be used when scrolling.
|
||||
|
||||
*tooltip*: ++
|
||||
typeof: bool ++
|
||||
default: true ++
|
||||
Option to disable tooltip on hover.
|
||||
|
||||
# EXAMPLES
|
||||
|
||||
```
|
||||
"sway/window": {
|
||||
"format": " {}",
|
||||
"max-length": 50
|
||||
}
|
||||
```
|
||||
|
||||
# STYLE
|
||||
|
||||
- *#mode*
|
103
man/waybar-sway-window.5.scd
Normal file
103
man/waybar-sway-window.5.scd
Normal file
@ -0,0 +1,103 @@
|
||||
waybar-sway-window(5)
|
||||
|
||||
# NAME
|
||||
|
||||
waybar - sway window module
|
||||
|
||||
# DESCRIPTION
|
||||
|
||||
The *window* module displays the title of the currently focused window in Sway
|
||||
|
||||
# CONFIGURATION
|
||||
|
||||
Addressed by *sway/window*
|
||||
|
||||
*format*: ++
|
||||
typeof: string ++
|
||||
default: {} ++
|
||||
The format, how information should be displayed. On {} data gets inserted.
|
||||
|
||||
*rotate*: ++
|
||||
typeof: integer ++
|
||||
Positive value to rotate the text label.
|
||||
|
||||
*max-length*: ++
|
||||
typeof: integer ++
|
||||
The maximum length in character the module should display.
|
||||
|
||||
*min-length*: ++
|
||||
typeof: integer ++
|
||||
The minimum length in characters the module should take up.
|
||||
|
||||
*align*: ++
|
||||
typeof: float ++
|
||||
The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
|
||||
|
||||
*on-click*: ++
|
||||
typeof: string ++
|
||||
Command to execute when clicked on the module.
|
||||
|
||||
*on-click-middle*: ++
|
||||
typeof: string ++
|
||||
Command to execute when middle-clicked on the module using mousewheel.
|
||||
|
||||
*on-click-right*: ++
|
||||
typeof: string ++
|
||||
Command to execute when you right clicked on the module.
|
||||
|
||||
*on-update*: ++
|
||||
typeof: string ++
|
||||
Command to execute when the module is updated.
|
||||
|
||||
*on-scroll-up*: ++
|
||||
typeof: string ++
|
||||
Command to execute when scrolling up on the module.
|
||||
|
||||
*on-scroll-down*: ++
|
||||
typeof: string ++
|
||||
Command to execute when scrolling down on the module.
|
||||
|
||||
*smooth-scrolling-threshold*: ++
|
||||
typeof: double ++
|
||||
Threshold to be used when scrolling.
|
||||
|
||||
*tooltip*: ++
|
||||
typeof: bool ++
|
||||
default: true ++
|
||||
Option to disable tooltip on hover.
|
||||
|
||||
*rewrite*: ++
|
||||
typeof: object ++
|
||||
Rules to rewrite window title. See *rewrite rules*.
|
||||
|
||||
# REWRITE RULES
|
||||
|
||||
*rewrite* is an object where keys are regular expressions and values are
|
||||
rewrite rules if the expression matches. Rules may contain references to
|
||||
captures of the expression.
|
||||
|
||||
Regular expression and replacement follow ECMA-script rules.
|
||||
|
||||
If no expression matches, the title is left unchanged.
|
||||
|
||||
Invalid expressions (e.g., mismatched parentheses) are skipped.
|
||||
|
||||
# EXAMPLES
|
||||
|
||||
```
|
||||
"sway/window": {
|
||||
"format": "{}",
|
||||
"max-length": 50,
|
||||
"rewrite": {
|
||||
"(.*) - Mozilla Firefox": "🌎 $1",
|
||||
"(.*) - zsh": "> [$1]"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
# STYLE
|
||||
|
||||
- *#window*
|
||||
- *window#waybar.empty* When no windows is in the workspace
|
||||
- *window#waybar.solo* When one window is in the workspace
|
||||
- *window#waybar.<app_id>* Where *app_id* is the app_id or *instance* name like (*chromium*) of the only window in the workspace
|
146
man/waybar-sway-workspaces.5.scd
Normal file
146
man/waybar-sway-workspaces.5.scd
Normal file
@ -0,0 +1,146 @@
|
||||
waybar-sway-workspaces(5)
|
||||
|
||||
# NAME
|
||||
|
||||
waybar - sway workspaces module
|
||||
|
||||
# DESCRIPTION
|
||||
|
||||
The *workspaces* module displays the currently used workspaces in Sway.
|
||||
|
||||
# CONFIGURATION
|
||||
|
||||
Addressed by *sway/workspaces*
|
||||
|
||||
*all-outputs*: ++
|
||||
typeof: bool ++
|
||||
default: false ++
|
||||
If set to false, workspaces will only be shown on the output they are on. If set to true all workspaces will be shown on every output.
|
||||
|
||||
*format*: ++
|
||||
typeof: string ++
|
||||
default: {value} ++
|
||||
The format, how information should be displayed.
|
||||
|
||||
*format-icons*: ++
|
||||
typeof: array ++
|
||||
Based on the workspace name and state, the corresponding icon gets selected. See *icons*.
|
||||
|
||||
*disable-scroll*: ++
|
||||
typeof: bool ++
|
||||
default: false ++
|
||||
If set to false, you can scroll to cycle through workspaces. If set to true this behaviour is disabled.
|
||||
|
||||
*disable-click*: ++
|
||||
typeof: bool ++
|
||||
default: false ++
|
||||
If set to false, you can click to change workspace. If set to true this behaviour is disabled.
|
||||
|
||||
*smooth-scrolling-threshold*: ++
|
||||
typeof: double ++
|
||||
Threshold to be used when scrolling.
|
||||
|
||||
*disable-scroll-wraparound*: ++
|
||||
typeof: bool ++
|
||||
default: false ++
|
||||
If set to false, scrolling on the workspace indicator will wrap around to the first workspace when reading the end, and vice versa. If set to true this behavior is disabled.
|
||||
|
||||
*enable-bar-scroll*: ++
|
||||
typeof: bool ++
|
||||
default: false ++
|
||||
If set to false, you can't scroll to cycle throughout workspaces from the entire bar. If set to true this behaviour is enabled.
|
||||
|
||||
*disable-markup*: ++
|
||||
typeof: bool ++
|
||||
default: false ++
|
||||
If set to true, button label will escape pango markup.
|
||||
|
||||
*current-only*: ++
|
||||
typeof: bool ++
|
||||
default: false ++
|
||||
If set to true. Only focused workspaces will be shown.
|
||||
|
||||
*persistent_workspaces*: ++
|
||||
typeof: json (see below) ++
|
||||
default: empty ++
|
||||
Lists workspaces that should always be shown, even when non existent
|
||||
|
||||
*on-update*: ++
|
||||
typeof: string ++
|
||||
Command to execute when the module is updated.
|
||||
|
||||
*numeric-first*: ++
|
||||
typeof: bool ++
|
||||
Whether to put workspaces starting with numbers before workspaces that do not start with a number.
|
||||
|
||||
*disable-auto-back-and-forth*: ++
|
||||
typeof: bool ++
|
||||
Whether to disable *workspace_auto_back_and_forth* when clicking on workspaces. If this is set to *true*, clicking on a workspace you are already on won't do anything, even if *workspace_auto_back_and_forth* is enabled in the Sway configuration.
|
||||
|
||||
# FORMAT REPLACEMENTS
|
||||
|
||||
*{value}*: Name of the workspace, as defined by sway.
|
||||
|
||||
*{name}*: Number stripped from workspace value.
|
||||
|
||||
*{icon}*: Icon, as defined in *format-icons*.
|
||||
|
||||
*{index}*: Index of the workspace.
|
||||
|
||||
# ICONS
|
||||
|
||||
Additional to workspace name matching, the following *format-icons* can be set.
|
||||
|
||||
- *default*: Will be shown, when no string matches is found.
|
||||
- *urgent*: Will be shown, when workspace is flagged as urgent
|
||||
- *focused*: Will be shown, when workspace is focused
|
||||
- *persistent*: Will be shown, when workspace is persistent one.
|
||||
|
||||
# PERSISTENT WORKSPACES
|
||||
|
||||
Each entry of *persistent_workspace* names a workspace that should always be shown.
|
||||
Associated with that value is a list of outputs indicating *where* the workspace should be shown,
|
||||
an empty list denoting all outputs.
|
||||
|
||||
```
|
||||
"sway/workspaces": {
|
||||
"persistent_workspaces": {
|
||||
"3": [], // Always show a workspace with name '3', on all outputs if it does not exists
|
||||
"4": ["eDP-1"], // Always show a workspace with name '4', on output 'eDP-1' if it does not exists
|
||||
"5": ["eDP-1", "DP-2"] // Always show a workspace with name '5', on outputs 'eDP-1' and 'DP-2' if it does not exists
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
n.b.: the list of outputs can be obtained from command line using *swaymsg -t get_outputs*
|
||||
|
||||
# EXAMPLES
|
||||
|
||||
```
|
||||
"sway/workspaces": {
|
||||
"disable-scroll": true,
|
||||
"all-outputs": true,
|
||||
"numeric-first": false,
|
||||
"format": "{name}: {icon}",
|
||||
"format-icons": {
|
||||
"1": "",
|
||||
"2": "",
|
||||
"3": "",
|
||||
"4": "",
|
||||
"5": "",
|
||||
"urgent": "",
|
||||
"focused": "",
|
||||
"default": ""
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
# Style
|
||||
|
||||
- *#workspaces button*
|
||||
- *#workspaces button.visible*
|
||||
- *#workspaces button.focused*
|
||||
- *#workspaces button.urgent*
|
||||
- *#workspaces button.persistent*
|
||||
- *#workspaces button.current_output*
|
||||
- *#workspaces button#sway-workspace-${name}*
|
130
man/waybar-temperature.5.scd
Normal file
130
man/waybar-temperature.5.scd
Normal file
@ -0,0 +1,130 @@
|
||||
waybar-temperature(5)
|
||||
|
||||
# NAME
|
||||
|
||||
waybar - temperature module
|
||||
|
||||
# DESCRIPTION
|
||||
|
||||
The *temperature* module displays the current temperature from a thermal zone.
|
||||
|
||||
# CONFIGURATION
|
||||
|
||||
Addressed by *temperature*
|
||||
|
||||
*thermal-zone*: ++
|
||||
typeof: integer ++
|
||||
The thermal zone, as in */sys/class/thermal/*.
|
||||
|
||||
*hwmon-path*: ++
|
||||
typeof: string ++
|
||||
The temperature path to use, e.g. */sys/class/hwmon/hwmon2/temp1_input* instead of one in */sys/class/thermal/*.
|
||||
|
||||
*hwmon-path-abs*: ++
|
||||
typeof: string ++
|
||||
The path of the hwmon-directory of the device, e.g. */sys/devices/pci0000:00/0000:00:18.3/hwmon*. (Note that the subdirectory *hwmon/hwmon#*, where *#* is a number is not part of the path!) Has to be used together with *input-filename*.
|
||||
|
||||
*input-filename*: ++
|
||||
typeof: string ++
|
||||
The temperature filename of your *hwmon-path-abs*, e.g. *temp1_input*
|
||||
|
||||
*critical-threshold*: ++
|
||||
typeof: integer ++
|
||||
The threshold before it is considered critical (Celsius).
|
||||
|
||||
*interval*: ++
|
||||
typeof: integer ++
|
||||
default: 10 ++
|
||||
The interval in which the information gets polled.
|
||||
|
||||
*format-critical*: ++
|
||||
typeof: string ++
|
||||
The format to use when temperature is considered critical
|
||||
|
||||
*format*: ++
|
||||
typeof: string ++
|
||||
default: {temperatureC}°C ++
|
||||
The format (Celsius/Fahrenheit/Kelvin) in which the temperature should be displayed.
|
||||
|
||||
*format-icons*: ++
|
||||
typeof: array ++
|
||||
Based on the current temperature (Celsius) and *critical-threshold* if available, the corresponding icon gets selected. The order is *low* to *high*.
|
||||
|
||||
*tooltip-format*: ++
|
||||
typeof: string ++
|
||||
default: {temperatureC}°C ++
|
||||
The format for the tooltip
|
||||
|
||||
*rotate*: ++
|
||||
typeof: integer ++
|
||||
Positive value to rotate the text label.
|
||||
|
||||
*max-length*: ++
|
||||
typeof: integer ++
|
||||
The maximum length in characters the module should display.
|
||||
|
||||
*min-length*: ++
|
||||
typeof: integer ++
|
||||
The minimum length in characters the module should take up.
|
||||
|
||||
*align*: ++
|
||||
typeof: float ++
|
||||
The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
|
||||
|
||||
*on-click*: ++
|
||||
typeof: string ++
|
||||
Command to execute when you clicked on the module.
|
||||
|
||||
*on-click-middle*: ++
|
||||
typeof: string ++
|
||||
Command to execute when middle-clicked on the module using mousewheel.
|
||||
|
||||
*on-click-right*: ++
|
||||
typeof: string ++
|
||||
Command to execute when you right clicked on the module.
|
||||
|
||||
*on-update*: ++
|
||||
typeof: string ++
|
||||
Command to execute when the module is updated.
|
||||
|
||||
*on-scroll-up*: ++
|
||||
typeof: string ++
|
||||
Command to execute when scrolling up on the module.
|
||||
|
||||
*on-scroll-down*: ++
|
||||
typeof: string ++
|
||||
Command to execute when scrolling down on the module.
|
||||
|
||||
*smooth-scrolling-threshold*: ++
|
||||
typeof: double ++
|
||||
Threshold to be used when scrolling.
|
||||
|
||||
*tooltip*: ++
|
||||
typeof: bool ++
|
||||
default: true ++
|
||||
Option to disable tooltip on hover.
|
||||
|
||||
# FORMAT REPLACEMENTS
|
||||
|
||||
*{temperatureC}*: Temperature in Celsius.
|
||||
|
||||
*{temperatureF}*: Temperature in Fahrenheit.
|
||||
|
||||
*{temperatureK}*: Temperature in Kelvin.
|
||||
|
||||
# EXAMPLES
|
||||
|
||||
```
|
||||
"temperature": {
|
||||
// "thermal-zone": 2,
|
||||
// "hwmon-path": "/sys/class/hwmon/hwmon2/temp1_input",
|
||||
// "critical-threshold": 80,
|
||||
// "format-critical": "{temperatureC}°C ",
|
||||
"format": "{temperatureC}°C "
|
||||
}
|
||||
```
|
||||
|
||||
# STYLE
|
||||
|
||||
- *#temperature*
|
||||
- *#temperature.critical*
|
51
man/waybar-tray.5.scd
Normal file
51
man/waybar-tray.5.scd
Normal file
@ -0,0 +1,51 @@
|
||||
waybar-tray(5)
|
||||
|
||||
# NAME
|
||||
|
||||
waybar - tray module
|
||||
|
||||
# DESCRIPTION
|
||||
|
||||
_WARNING_ *tray* is still in beta. There may me bugs. Breaking changes may occur.
|
||||
|
||||
# CONFIGURATION
|
||||
|
||||
Addressed by *tray*
|
||||
|
||||
*icon-size*: ++
|
||||
typeof: integer ++
|
||||
Defines the size of the tray icons.
|
||||
|
||||
*show-passive-items*: ++
|
||||
typeof: bool ++
|
||||
default: false ++
|
||||
Defines visibility of the tray icons with *Passive* status.
|
||||
|
||||
*smooth-scrolling-threshold*: ++
|
||||
typeof: double ++
|
||||
Threshold to be used when scrolling.
|
||||
|
||||
*spacing*: ++
|
||||
typeof: integer ++
|
||||
Defines the spacing between the tray icons.
|
||||
|
||||
*on-update*: ++
|
||||
typeof: string ++
|
||||
Command to execute when the module is updated.
|
||||
|
||||
# EXAMPLES
|
||||
|
||||
```
|
||||
"tray": {
|
||||
"icon-size": 21,
|
||||
"spacing": 10
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
# STYLE
|
||||
|
||||
- *#tray*
|
||||
- *#tray > .passive*
|
||||
- *#tray > .active*
|
||||
- *#tray > .needs-attention*
|
119
man/waybar-wlr-taskbar.5.scd
Normal file
119
man/waybar-wlr-taskbar.5.scd
Normal file
@ -0,0 +1,119 @@
|
||||
waybar-wlr-taskbar(5)
|
||||
|
||||
# NAME
|
||||
|
||||
wlroots - Taskbar module
|
||||
|
||||
# DESCRIPTION
|
||||
|
||||
The *taskbar* module displays the currently open applications. This module requires
|
||||
a compositor that implements the foreign-toplevel-manager interface.
|
||||
|
||||
# CONFIGURATION
|
||||
|
||||
Addressed by *wlr/taskbar*
|
||||
|
||||
*all-outputs*: ++
|
||||
typeof: bool ++
|
||||
default: false ++
|
||||
If set to false applications on the waybar's current output will be shown. Otherwise all applications are shown.
|
||||
|
||||
*format*: ++
|
||||
typeof: string ++
|
||||
default: {icon} ++
|
||||
The format, how information should be displayed.
|
||||
|
||||
*icon-theme*: ++
|
||||
typeof: array|string ++
|
||||
The names of the icon-themes that should be used to find an icon. The list will be traversed from left to right. If omitted, the system default will be used.
|
||||
|
||||
*icon-size*: ++
|
||||
typeof: integer ++
|
||||
default: 16 ++
|
||||
The size of the icon.
|
||||
|
||||
*markup*: ++
|
||||
typeof: bool ++
|
||||
default: false ++
|
||||
If set to true, pango markup will be accepted in format and tooltip-format.
|
||||
|
||||
*tooltip*: ++
|
||||
typeof: bool ++
|
||||
default: true ++
|
||||
If set to false no tooltip will be shown.
|
||||
|
||||
*tooltip-format*: ++
|
||||
typeof: string ++
|
||||
default: {title} ++
|
||||
The format, how information in the tooltip should be displayed.
|
||||
|
||||
*active-first*: ++
|
||||
typeof: bool ++
|
||||
default: false ++
|
||||
If set to true, always reorder the tasks in the taskbar so that the currently active one is first. Otherwise don't reorder.
|
||||
|
||||
*on-click*: ++
|
||||
typeof: string ++
|
||||
The action which should be triggered when clicking on the application button with the left mouse button.
|
||||
|
||||
*on-click-middle*: ++
|
||||
typeof: string ++
|
||||
The action which should be triggered when clicking on the application button with the middle mouse button.
|
||||
|
||||
*on-click-right*: ++
|
||||
typeof: string ++
|
||||
The action which should be triggered when clicking on the application button with the right mouse button.
|
||||
|
||||
*on-update*: ++
|
||||
typeof: string ++
|
||||
Command to execute when the module is updated.
|
||||
|
||||
*ignore-list*: ++
|
||||
typeof: array ++
|
||||
List of app_id to be invisible.
|
||||
|
||||
# FORMAT REPLACEMENTS
|
||||
|
||||
*{icon}*: The icon of the application.
|
||||
|
||||
*{title}*: The title of the application.
|
||||
|
||||
*{app_id}*: The app_id (== application name) of the application.
|
||||
|
||||
*{state}*: The state (minimized, maximized, active, fullscreen) of the application.
|
||||
|
||||
*{short_state}*: The state (minimize == m, maximized == M, active == A, fullscreen == F) represented as one character of the application.
|
||||
|
||||
# CLICK ACTIONS
|
||||
|
||||
*activate*: Bring the application into foreground.
|
||||
*minimize*: Toggle application's minimized state.
|
||||
*minimize-raise*: Bring the application into foreground or toggle its minimized state.
|
||||
*maximize*: Toggle application's maximized state.
|
||||
*fullscreen*: Toggle application's fullscreen state.
|
||||
*close*: Close the application.
|
||||
|
||||
# EXAMPLES
|
||||
|
||||
```
|
||||
"wlr/taskbar": {
|
||||
"format": "{icon}",
|
||||
"icon-size": 14,
|
||||
"icon-theme": "Numix-Circle",
|
||||
"tooltip-format": "{title}",
|
||||
"on-click": "activate",
|
||||
"on-click-middle": "close",
|
||||
"ignore-list": [
|
||||
"Alacritty"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
# Style
|
||||
|
||||
- *#taskbar*
|
||||
- *#taskbar button*
|
||||
- *#taskbar button.maximized*
|
||||
- *#taskbar button.minimized*
|
||||
- *#taskbar button.active*
|
||||
- *#taskbar button.fullscreen*
|
223
man/waybar.5.scd.in
Normal file
223
man/waybar.5.scd.in
Normal file
@ -0,0 +1,223 @@
|
||||
waybar(5)
|
||||
|
||||
# NAME
|
||||
|
||||
waybar - configuration file
|
||||
|
||||
# DESCRIPTION
|
||||
|
||||
The configuration uses the JSON file format and is named *config*.
|
||||
|
||||
Valid locations for this file are:
|
||||
|
||||
- *$XDG_CONFIG_HOME/waybar/config*
|
||||
- *~/.config/waybar/config*
|
||||
- *~/waybar/config*
|
||||
- */etc/xdg/waybar/config*
|
||||
- *@sysconfdir@/xdg/waybar/config*
|
||||
|
||||
A good starting point is the default configuration found at https://github.com/Alexays/Waybar/blob/master/resources/config
|
||||
Also a minimal example configuration can be found on the at the bottom of this man page.
|
||||
|
||||
# BAR CONFIGURATION
|
||||
|
||||
*layer* ++
|
||||
typeof: string ++
|
||||
default: bottom ++
|
||||
Decide if the bar is displayed in front (*top*) of the windows or behind (*bottom*)
|
||||
them.
|
||||
|
||||
*output* ++
|
||||
typeof: string|array ++
|
||||
Specifies on which screen this bar will be displayed. Exclamation mark(*!*) can be used to exclude specific output.
|
||||
|
||||
*position* ++
|
||||
typeof: string ++
|
||||
default: top ++
|
||||
Bar position, can be *top*, *bottom*, *left*, *right*.
|
||||
|
||||
*height* ++
|
||||
typeof: integer ++
|
||||
Height to be used by the bar if possible. Leave blank for a dynamic value.
|
||||
|
||||
*width* ++
|
||||
typeof: integer ++
|
||||
Width to be used by the bar if possible. Leave blank for a dynamic value.
|
||||
|
||||
*modules-left* ++
|
||||
typeof: array ++
|
||||
Modules that will be displayed on the left.
|
||||
|
||||
*modules-center* ++
|
||||
typeof: array ++
|
||||
Modules that will be displayed in the center.
|
||||
|
||||
*modules-right* ++
|
||||
typeof: array
|
||||
Modules that will be displayed on the right.
|
||||
|
||||
*margin* ++
|
||||
typeof: string ++
|
||||
Margins value using the CSS format without units.
|
||||
|
||||
*margin-<top\|left\|bottom\|right>* ++
|
||||
typeof: integer ++
|
||||
Margins value without units.
|
||||
|
||||
*name* ++
|
||||
typeof: string ++
|
||||
Optional name added as a CSS class, for styling multiple waybars.
|
||||
|
||||
*exclusive* ++
|
||||
typeof: bool ++
|
||||
default: *true* unless the layer is set to *overlay* ++
|
||||
Option to request an exclusive zone from the compositor. Disable this to allow drawing application windows underneath or on top of the bar.
|
||||
|
||||
*passthrough* ++
|
||||
typeof: bool ++
|
||||
default: *false* unless the layer is set to *overlay* ++
|
||||
Option to pass any pointer events to the window under the bar.
|
||||
Intended to be used with either *top* or *overlay* layers and without exclusive zone.
|
||||
|
||||
*gtk-layer-shell* ++
|
||||
typeof: bool ++
|
||||
default: true ++
|
||||
Option to disable the use of gtk-layer-shell for popups.
|
||||
Only functional if compiled with gtk-layer-shell support.
|
||||
|
||||
*include* ++
|
||||
typeof: string|array ++
|
||||
Paths to additional configuration files. In case of duplicate options, the including file's value takes precedence. Make sure to avoid circular imports.
|
||||
For a multi-bar config, specify at least an empty object for each bar also in every file being included.
|
||||
|
||||
# MODULE FORMAT
|
||||
|
||||
You can use PangoMarkupFormat (See https://developer.gnome.org/pango/stable/PangoMarkupFormat.html#PangoMarkupFormat).
|
||||
|
||||
e.g.
|
||||
|
||||
```
|
||||
"format": "<span style=\"italic\">{}</span>"
|
||||
```
|
||||
# MULTIPLE INSTANCES OF A MODULE
|
||||
|
||||
If you want to have a second instance of a module, you can suffix it by a '#' and a custom name.
|
||||
For example if you want a second battery module, you can add *"battery#bat2"* to your modules.
|
||||
To configure the newly added module, you then also add a module configuration with the same name.
|
||||
|
||||
This could then look something like this *(this is an incomplete example)*:
|
||||
|
||||
```
|
||||
"modules-right": ["battery", "battery#bat2"],
|
||||
"battery": {
|
||||
"bat": "BAT1"
|
||||
},
|
||||
"battery#bat2": {
|
||||
"bat": "BAT2"
|
||||
}
|
||||
```
|
||||
|
||||
# MINIMAL CONFIGURATION
|
||||
|
||||
A minimal *config* file could look like this:
|
||||
|
||||
```
|
||||
{
|
||||
"layer": "top",
|
||||
"modules-left": ["sway/workspaces", "sway/mode"],
|
||||
"modules-center": ["sway/window"],
|
||||
"modules-right": ["battery", "clock"],
|
||||
"sway/window": {
|
||||
"max-length": 50
|
||||
},
|
||||
"battery": {
|
||||
"format": "{capacity}% {icon}",
|
||||
"format-icons": ["", "", "", "", ""]
|
||||
},
|
||||
"clock": {
|
||||
"format-alt": "{:%a, %d. %b %H:%M}"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
# MULTI OUTPUT CONFIGURATION
|
||||
|
||||
## Limit a configuration to some outputs
|
||||
|
||||
```
|
||||
{
|
||||
"layer": "top",
|
||||
"output": "eDP-1",
|
||||
"modules-left": ["sway/workspaces", "sway/mode"],
|
||||
...
|
||||
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
```
|
||||
{
|
||||
"layer": "top",
|
||||
"output": ["eDP-1", "VGA"],
|
||||
"modules-left": ["sway/workspaces", "sway/mode"],
|
||||
...
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## Configuration of multiple outputs
|
||||
|
||||
Don't specify an output to create multiple bars on the same screen.
|
||||
|
||||
```
|
||||
[{
|
||||
"layer": "top",
|
||||
"output": "eDP-1",
|
||||
"modules-left": ["sway/workspaces", "sway/mode"],
|
||||
...
|
||||
}, {
|
||||
"layer": "top",
|
||||
"output": "VGA",
|
||||
"modules-right": ["clock"],
|
||||
...
|
||||
}]
|
||||
|
||||
```
|
||||
|
||||
## Rotating modules
|
||||
|
||||
When positioning Waybar on the left or right side of the screen, sometimes it's useful to be able to rotate the contents of a module so the text runs vertically. This can be done using the "rotate" property of the module. Example:
|
||||
|
||||
```
|
||||
{
|
||||
"clock": {
|
||||
"rotate": 90
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Valid options for the "rotate" property are: 0, 90, 180 and 270.
|
||||
|
||||
# SUPPORTED MODULES
|
||||
|
||||
- *waybar-backlight(5)*
|
||||
- *waybar-battery(5)*
|
||||
- *waybar-bluetooth(5)*
|
||||
- *waybar-clock(5)*
|
||||
- *waybar-cpu(5)*
|
||||
- *waybar-custom(5)*
|
||||
- *waybar-disk(5)*
|
||||
- *waybar-idle-inhibitor(5)*
|
||||
- *waybar-keyboard-state(5)*
|
||||
- *waybar-memory(5)*
|
||||
- *waybar-mpd(5)*
|
||||
- *waybar-network(5)*
|
||||
- *waybar-pulseaudio(5)*
|
||||
- *waybar-river-tags(5)*
|
||||
- *waybar-states(5)*
|
||||
- *waybar-sway-mode(5)*
|
||||
- *waybar-sway-window(5)*
|
||||
- *waybar-sway-workspaces(5)*
|
||||
- *waybar-wlr-taskbar(5)*
|
||||
- *waybar-temperature(5)*
|
||||
- *waybar-tray(5)*
|
266
meson.build
266
meson.build
@ -1,7 +1,8 @@
|
||||
project(
|
||||
'waybar', 'cpp', 'c',
|
||||
version: '0.7.0',
|
||||
version: '0.9.8',
|
||||
license: 'MIT',
|
||||
meson_version: '>= 0.49.0',
|
||||
default_options : [
|
||||
'cpp_std=c++17',
|
||||
'buildtype=release',
|
||||
@ -9,28 +10,38 @@ project(
|
||||
],
|
||||
)
|
||||
|
||||
compiler = meson.get_compiler('cpp')
|
||||
|
||||
cpp_args = []
|
||||
cpp_link_args = []
|
||||
|
||||
if get_option('libcxx')
|
||||
cpp_args += ['-stdlib=libc++']
|
||||
cpp_link_args += ['-stdlib=libc++', '-lc++abi']
|
||||
endif
|
||||
|
||||
if compiler.has_link_argument('-lc++fs')
|
||||
cpp_link_args += ['-lc++fs']
|
||||
else
|
||||
elif compiler.has_link_argument('-lc++experimental')
|
||||
cpp_link_args += ['-lc++experimental']
|
||||
elif compiler.has_link_argument('-lstdc++fs')
|
||||
cpp_link_args += ['-lstdc++fs']
|
||||
endif
|
||||
|
||||
compiler = meson.get_compiler('cpp')
|
||||
git = find_program('git', required: false)
|
||||
git = find_program('git', native: true, required: false)
|
||||
|
||||
if not git.found()
|
||||
add_project_arguments('-DVERSION="@0@"'.format(meson.project_version()), language: 'cpp')
|
||||
else
|
||||
git_commit_hash = run_command([git.path(), 'describe', '--always', '--tags']).stdout().strip()
|
||||
git_branch = run_command([git.path(), 'rev-parse', '--abbrev-ref', 'HEAD']).stdout().strip()
|
||||
version = '"@0@ (" __DATE__ ", branch \'@1@\')"'.format(git_commit_hash, git_branch)
|
||||
add_project_arguments('-DVERSION=@0@'.format(version), language: 'cpp')
|
||||
git_path = run_command([git.path(), 'rev-parse', '--show-toplevel']).stdout().strip()
|
||||
if meson.source_root() == git_path
|
||||
git_commit_hash = run_command([git.path(), 'describe', '--always', '--tags']).stdout().strip()
|
||||
git_branch = run_command([git.path(), 'rev-parse', '--abbrev-ref', 'HEAD']).stdout().strip()
|
||||
version = '"@0@ (branch \'@1@\')"'.format(git_commit_hash, git_branch)
|
||||
add_project_arguments('-DVERSION=@0@'.format(version), language: 'cpp')
|
||||
else
|
||||
add_project_arguments('-DVERSION="@0@"'.format(meson.project_version()), language: 'cpp')
|
||||
endif
|
||||
endif
|
||||
|
||||
if not compiler.has_header('filesystem')
|
||||
@ -42,51 +53,143 @@ if not compiler.has_header('filesystem')
|
||||
endif
|
||||
endif
|
||||
|
||||
code = '''
|
||||
#include <langinfo.h>
|
||||
#include <locale.h>
|
||||
int main(int argc, char** argv) {
|
||||
locale_t locale = newlocale(LC_ALL, "en_US.UTF-8", nullptr);
|
||||
char* str;
|
||||
str = nl_langinfo_l(_NL_TIME_WEEK_1STDAY, locale);
|
||||
str = nl_langinfo_l(_NL_TIME_FIRST_WEEKDAY, locale);
|
||||
freelocale(locale);
|
||||
return 0;
|
||||
}
|
||||
'''
|
||||
if compiler.links(code, name : 'nl_langinfo with _NL_TIME_WEEK_1STDAY, _NL_TIME_FIRST_WEEKDAY')
|
||||
add_project_arguments('-DHAVE_LANGINFO_1STDAY', language: 'cpp')
|
||||
endif
|
||||
|
||||
add_global_arguments(cpp_args, language : 'cpp')
|
||||
add_global_link_arguments(cpp_link_args, language : 'cpp')
|
||||
|
||||
is_linux = host_machine.system() == 'linux'
|
||||
is_dragonfly = host_machine.system() == 'dragonfly'
|
||||
is_freebsd = host_machine.system() == 'freebsd'
|
||||
is_netbsd = host_machine.system() == 'netbsd'
|
||||
is_openbsd = host_machine.system() == 'openbsd'
|
||||
|
||||
thread_dep = dependency('threads')
|
||||
libinput = dependency('libinput')
|
||||
fmt = dependency('fmt', version : ['>=5.3.0'], fallback : ['fmt', 'fmt_dep'])
|
||||
spdlog = dependency('spdlog', version : ['>=1.3.1'], fallback : ['spdlog', 'spdlog_dep'])
|
||||
spdlog = dependency('spdlog', version : ['>=1.8.5'], fallback : ['spdlog', 'spdlog_dep'], default_options : ['external_fmt=true'])
|
||||
wayland_client = dependency('wayland-client')
|
||||
wayland_cursor = dependency('wayland-cursor')
|
||||
wayland_protos = dependency('wayland-protocols')
|
||||
gtkmm = dependency('gtkmm-3.0')
|
||||
gtkmm = dependency('gtkmm-3.0', version : ['>=3.22.0'])
|
||||
dbusmenu_gtk = dependency('dbusmenu-gtk3-0.4', required: get_option('dbusmenu-gtk'))
|
||||
giounix = dependency('gio-unix-2.0', required: get_option('dbusmenu-gtk'))
|
||||
jsoncpp = dependency('jsoncpp')
|
||||
sigcpp = dependency('sigc++-2.0')
|
||||
libepoll = dependency('epoll-shim', required: false)
|
||||
libnl = dependency('libnl-3.0', required: get_option('libnl'))
|
||||
libnlgen = dependency('libnl-genl-3.0', required: get_option('libnl'))
|
||||
libpulse = dependency('libpulse', required: get_option('pulseaudio'))
|
||||
libudev = dependency('libudev', required: get_option('libudev'))
|
||||
libevdev = dependency('libevdev', required: get_option('libevdev'))
|
||||
libmpdclient = dependency('libmpdclient', required: get_option('mpd'))
|
||||
xkbregistry = dependency('xkbregistry')
|
||||
|
||||
libsndio = compiler.find_library('sndio', required: get_option('sndio'))
|
||||
if libsndio.found()
|
||||
if not compiler.has_function('sioctl_open', prefix: '#include <sndio.h>', dependencies: libsndio)
|
||||
if get_option('sndio').enabled()
|
||||
error('libsndio is too old, required >=1.7.0')
|
||||
else
|
||||
warning('libsndio is too old, required >=1.7.0')
|
||||
libsndio = dependency('', required: false)
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
gtk_layer_shell = dependency('gtk-layer-shell-0',
|
||||
required: get_option('gtk-layer-shell'),
|
||||
fallback : ['gtk-layer-shell', 'gtk_layer_shell_dep'])
|
||||
systemd = dependency('systemd', required: get_option('systemd'))
|
||||
tz_dep = dependency('date',
|
||||
required: false,
|
||||
default_options : [ 'use_system_tzdb=true' ],
|
||||
modules : [ 'date::date', 'date::date-tz' ],
|
||||
fallback: [ 'date', 'tz_dep' ])
|
||||
|
||||
prefix = get_option('prefix')
|
||||
sysconfdir = get_option('sysconfdir')
|
||||
conf_data = configuration_data()
|
||||
conf_data.set('prefix', prefix)
|
||||
|
||||
add_project_arguments('-DSYSCONFDIR="/@0@"'.format(join_paths(prefix, sysconfdir)), language : 'cpp')
|
||||
|
||||
if systemd.found()
|
||||
user_units_dir = systemd.get_pkgconfig_variable('systemduserunitdir')
|
||||
|
||||
configure_file(
|
||||
configuration: conf_data,
|
||||
input: './resources/waybar.service.in',
|
||||
output: '@BASENAME@',
|
||||
install_dir: user_units_dir
|
||||
)
|
||||
endif
|
||||
|
||||
src_files = files(
|
||||
'src/factory.cpp',
|
||||
'src/AModule.cpp',
|
||||
'src/ALabel.cpp',
|
||||
'src/modules/memory.cpp',
|
||||
'src/modules/battery.cpp',
|
||||
'src/modules/clock.cpp',
|
||||
'src/modules/custom.cpp',
|
||||
'src/modules/cpu.cpp',
|
||||
'src/modules/idle_inhibitor.cpp',
|
||||
'src/modules/disk.cpp',
|
||||
'src/modules/idle_inhibitor.cpp',
|
||||
'src/modules/temperature.cpp',
|
||||
'src/main.cpp',
|
||||
'src/bar.cpp',
|
||||
'src/client.cpp'
|
||||
'src/client.cpp',
|
||||
'src/util/ustring_clen.cpp'
|
||||
)
|
||||
|
||||
if true # find_program('sway', required : false).found()
|
||||
add_project_arguments('-DHAVE_SWAY', language: 'cpp')
|
||||
src_files += [
|
||||
'src/modules/sway/ipc/client.cpp',
|
||||
'src/modules/sway/mode.cpp',
|
||||
'src/modules/sway/window.cpp',
|
||||
'src/modules/sway/workspaces.cpp'
|
||||
]
|
||||
if is_linux
|
||||
add_project_arguments('-DHAVE_CPU_LINUX', language: 'cpp')
|
||||
add_project_arguments('-DHAVE_MEMORY_LINUX', language: 'cpp')
|
||||
src_files += files(
|
||||
'src/modules/battery.cpp',
|
||||
'src/modules/cpu/common.cpp',
|
||||
'src/modules/cpu/linux.cpp',
|
||||
'src/modules/memory/common.cpp',
|
||||
'src/modules/memory/linux.cpp',
|
||||
)
|
||||
elif is_dragonfly or is_freebsd or is_netbsd or is_openbsd
|
||||
add_project_arguments('-DHAVE_CPU_BSD', language: 'cpp')
|
||||
add_project_arguments('-DHAVE_MEMORY_BSD', language: 'cpp')
|
||||
src_files += files(
|
||||
'src/modules/cpu/bsd.cpp',
|
||||
'src/modules/cpu/common.cpp',
|
||||
'src/modules/memory/bsd.cpp',
|
||||
'src/modules/memory/common.cpp',
|
||||
)
|
||||
endif
|
||||
|
||||
add_project_arguments('-DHAVE_SWAY', language: 'cpp')
|
||||
src_files += [
|
||||
'src/modules/sway/ipc/client.cpp',
|
||||
'src/modules/sway/mode.cpp',
|
||||
'src/modules/sway/language.cpp',
|
||||
'src/modules/sway/window.cpp',
|
||||
'src/modules/sway/workspaces.cpp'
|
||||
]
|
||||
|
||||
if true
|
||||
add_project_arguments('-DHAVE_WLR', language: 'cpp')
|
||||
src_files += 'src/modules/wlr/taskbar.cpp'
|
||||
endif
|
||||
|
||||
if true
|
||||
add_project_arguments('-DHAVE_RIVER', language: 'cpp')
|
||||
src_files += 'src/modules/river/tags.cpp'
|
||||
endif
|
||||
|
||||
if libnl.found() and libnlgen.found()
|
||||
@ -109,14 +212,46 @@ if dbusmenu_gtk.found()
|
||||
)
|
||||
endif
|
||||
|
||||
if libudev.found()
|
||||
if libudev.found() and (is_linux or libepoll.found())
|
||||
add_project_arguments('-DHAVE_LIBUDEV', language: 'cpp')
|
||||
src_files += 'src/modules/backlight.cpp'
|
||||
endif
|
||||
|
||||
if libevdev.found() and (is_linux or libepoll.found())
|
||||
add_project_arguments('-DHAVE_LIBEVDEV', language: 'cpp')
|
||||
src_files += 'src/modules/keyboard_state.cpp'
|
||||
endif
|
||||
|
||||
if libmpdclient.found()
|
||||
add_project_arguments('-DHAVE_LIBMPDCLIENT', language: 'cpp')
|
||||
src_files += 'src/modules/mpd.cpp'
|
||||
src_files += 'src/modules/mpd/mpd.cpp'
|
||||
src_files += 'src/modules/mpd/state.cpp'
|
||||
endif
|
||||
|
||||
if gtk_layer_shell.found()
|
||||
add_project_arguments('-DHAVE_GTK_LAYER_SHELL', language: 'cpp')
|
||||
endif
|
||||
|
||||
if libsndio.found()
|
||||
add_project_arguments('-DHAVE_LIBSNDIO', language: 'cpp')
|
||||
src_files += 'src/modules/sndio.cpp'
|
||||
endif
|
||||
|
||||
if get_option('rfkill').enabled()
|
||||
if is_linux
|
||||
add_project_arguments('-DWANT_RFKILL', language: 'cpp')
|
||||
src_files += files(
|
||||
'src/modules/bluetooth.cpp',
|
||||
'src/util/rfkill.cpp'
|
||||
)
|
||||
endif
|
||||
endif
|
||||
|
||||
if tz_dep.found()
|
||||
add_project_arguments('-DHAVE_LIBDATE', language: 'cpp')
|
||||
src_files += 'src/modules/clock.cpp'
|
||||
else
|
||||
src_files += 'src/modules/simpleclock.cpp'
|
||||
endif
|
||||
|
||||
subdir('protocol')
|
||||
@ -132,7 +267,6 @@ executable(
|
||||
spdlog,
|
||||
sigcpp,
|
||||
jsoncpp,
|
||||
libinput,
|
||||
wayland_cursor,
|
||||
gtkmm,
|
||||
dbusmenu_gtk,
|
||||
@ -141,7 +275,13 @@ executable(
|
||||
libnlgen,
|
||||
libpulse,
|
||||
libudev,
|
||||
libmpdclient
|
||||
libepoll,
|
||||
libmpdclient,
|
||||
libevdev,
|
||||
gtk_layer_shell,
|
||||
libsndio,
|
||||
tz_dep,
|
||||
xkbregistry
|
||||
],
|
||||
include_directories: [include_directories('include')],
|
||||
install: true,
|
||||
@ -150,9 +290,75 @@ executable(
|
||||
install_data(
|
||||
'./resources/config',
|
||||
'./resources/style.css',
|
||||
install_dir: join_paths(get_option('out'), 'etc/xdg/waybar')
|
||||
install_dir: sysconfdir + '/xdg/waybar'
|
||||
)
|
||||
|
||||
scdoc = dependency('scdoc', version: '>=1.9.2', native: true, required: get_option('man-pages'))
|
||||
|
||||
if scdoc.found()
|
||||
scdoc_prog = find_program(scdoc.get_pkgconfig_variable('scdoc'), native: true)
|
||||
sh = find_program('sh', native: true)
|
||||
|
||||
main_manpage = configure_file(
|
||||
input: 'man/waybar.5.scd.in',
|
||||
output: 'waybar.5.scd',
|
||||
configuration: {
|
||||
'sysconfdir': join_paths(prefix, sysconfdir)
|
||||
}
|
||||
)
|
||||
|
||||
main_manpage_path = join_paths(meson.build_root(), '@0@'.format(main_manpage))
|
||||
|
||||
mandir = get_option('mandir')
|
||||
man_files = [
|
||||
main_manpage_path,
|
||||
'waybar-backlight.5.scd',
|
||||
'waybar-battery.5.scd',
|
||||
'waybar-clock.5.scd',
|
||||
'waybar-cpu.5.scd',
|
||||
'waybar-custom.5.scd',
|
||||
'waybar-disk.5.scd',
|
||||
'waybar-idle-inhibitor.5.scd',
|
||||
'waybar-keyboard-state.5.scd',
|
||||
'waybar-memory.5.scd',
|
||||
'waybar-mpd.5.scd',
|
||||
'waybar-network.5.scd',
|
||||
'waybar-pulseaudio.5.scd',
|
||||
'waybar-river-tags.5.scd',
|
||||
'waybar-sway-language.5.scd',
|
||||
'waybar-sway-mode.5.scd',
|
||||
'waybar-sway-window.5.scd',
|
||||
'waybar-sway-workspaces.5.scd',
|
||||
'waybar-temperature.5.scd',
|
||||
'waybar-tray.5.scd',
|
||||
'waybar-states.5.scd',
|
||||
'waybar-wlr-taskbar.5.scd',
|
||||
'waybar-bluetooth.5.scd',
|
||||
'waybar-sndio.5.scd',
|
||||
]
|
||||
|
||||
foreach file : man_files
|
||||
path = '@0@'.format(file)
|
||||
basename = path.split('/')[-1]
|
||||
|
||||
topic = basename.split('.')[-3]
|
||||
section = basename.split('.')[-2]
|
||||
output = '@0@.@1@'.format(topic, section)
|
||||
|
||||
custom_target(
|
||||
output,
|
||||
# drops the 'man' if `path` is an absolute path
|
||||
input: join_paths('man', path),
|
||||
output: output,
|
||||
command: [
|
||||
sh, '-c', '@0@ < @INPUT@ > @1@'.format(scdoc_prog.path(), output)
|
||||
],
|
||||
install: true,
|
||||
install_dir: '@0@/man@1@'.format(mandir, section)
|
||||
)
|
||||
endforeach
|
||||
endif
|
||||
|
||||
clangtidy = find_program('clang-tidy', required: false)
|
||||
|
||||
if clangtidy.found()
|
||||
|
@ -1,7 +1,12 @@
|
||||
option('libcxx', type : 'boolean', value : false, description : 'Build with Clang\'s libc++ instead of libstdc++ on Linux.')
|
||||
option('libnl', type: 'feature', value: 'auto', description: 'Enable libnl support for network related features')
|
||||
option('libudev', type: 'feature', value: 'auto', description: 'Enable libudev support for udev related features')
|
||||
option('libevdev', type: 'feature', value: 'auto', description: 'Enable libevdev support for evdev related features')
|
||||
option('pulseaudio', type: 'feature', value: 'auto', description: 'Enable support for pulseaudio')
|
||||
option('systemd', type: 'feature', value: 'auto', description: 'Install systemd user service unit')
|
||||
option('dbusmenu-gtk', type: 'feature', value: 'auto', description: 'Enable support for tray')
|
||||
option('man-pages', type: 'feature', value: 'auto', description: 'Generate and install man pages')
|
||||
option('mpd', type: 'feature', value: 'auto', description: 'Enable support for the Music Player Daemon')
|
||||
option('out', type: 'string', value : '/', description: 'output prefix directory')
|
||||
option('gtk-layer-shell', type: 'feature', value: 'auto', description: 'Use gtk-layer-shell library for popups support')
|
||||
option('rfkill', type: 'feature', value: 'auto', description: 'Enable support for RFKILL')
|
||||
option('sndio', type: 'feature', value: 'auto', description: 'Enable support for sndio')
|
||||
|
@ -31,7 +31,9 @@
|
||||
<property name='Id' type='s' access='read'/>
|
||||
<property name='Title' type='s' access='read'/>
|
||||
<property name='Status' type='s' access='read'/>
|
||||
<!-- See discussion on pull #536
|
||||
<property name='WindowId' type='u' access='read'/>
|
||||
-->
|
||||
<property name='IconThemePath' type='s' access='read'/>
|
||||
<property name='IconName' type='s' access='read'/>
|
||||
<property name='IconPixmap' type='a(iiay)' access='read'/>
|
||||
@ -44,4 +46,4 @@
|
||||
<property name='Menu' type='o' access='read'/>
|
||||
<property name='ItemIsMenu' type='b' access='read'/>
|
||||
</interface>
|
||||
</node>
|
||||
</node>
|
||||
|
@ -26,6 +26,8 @@ client_protocols = [
|
||||
[wl_protocol_dir, 'unstable/xdg-output/xdg-output-unstable-v1.xml'],
|
||||
[wl_protocol_dir, 'unstable/idle-inhibit/idle-inhibit-unstable-v1.xml'],
|
||||
['wlr-layer-shell-unstable-v1.xml'],
|
||||
['wlr-foreign-toplevel-management-unstable-v1.xml'],
|
||||
['river-status-unstable-v1.xml'],
|
||||
]
|
||||
|
||||
client_protos_src = []
|
||||
|
116
protocol/river-status-unstable-v1.xml
Normal file
116
protocol/river-status-unstable-v1.xml
Normal file
@ -0,0 +1,116 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<protocol name="river_status_unstable_v1">
|
||||
<copyright>
|
||||
Copyright 2020 Isaac Freund
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, 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="zriver_status_manager_v1" version="1">
|
||||
<description summary="manage river status objects">
|
||||
A global factory for objects that receive status information specific
|
||||
to river. It could be used to implement, for example, a status bar.
|
||||
</description>
|
||||
|
||||
<request name="destroy" type="destructor">
|
||||
<description summary="destroy the river_status_manager object">
|
||||
This request indicates that the client will not use the
|
||||
river_status_manager object any more. Objects that have been created
|
||||
through this instance are not affected.
|
||||
</description>
|
||||
</request>
|
||||
|
||||
<request name="get_river_output_status">
|
||||
<description summary="create an output status object">
|
||||
This creates a new river_output_status object for the given wl_output.
|
||||
</description>
|
||||
<arg name="id" type="new_id" interface="zriver_output_status_v1"/>
|
||||
<arg name="output" type="object" interface="wl_output"/>
|
||||
</request>
|
||||
|
||||
<request name="get_river_seat_status">
|
||||
<description summary="create a seat status object">
|
||||
This creates a new river_seat_status object for the given wl_seat.
|
||||
</description>
|
||||
<arg name="id" type="new_id" interface="zriver_seat_status_v1"/>
|
||||
<arg name="seat" type="object" interface="wl_seat"/>
|
||||
</request>
|
||||
</interface>
|
||||
|
||||
<interface name="zriver_output_status_v1" version="1">
|
||||
<description summary="track output tags and focus">
|
||||
This interface allows clients to receive information about the current
|
||||
windowing state of an output.
|
||||
</description>
|
||||
|
||||
<request name="destroy" type="destructor">
|
||||
<description summary="destroy the river_output_status object">
|
||||
This request indicates that the client will not use the
|
||||
river_output_status object any more.
|
||||
</description>
|
||||
</request>
|
||||
|
||||
<event name="focused_tags">
|
||||
<description summary="focused tags of the output">
|
||||
Sent once binding the interface and again whenever the tag focus of
|
||||
the output changes.
|
||||
</description>
|
||||
<arg name="tags" type="uint" summary="32-bit bitfield"/>
|
||||
</event>
|
||||
|
||||
<event name="view_tags">
|
||||
<description summary="tag state of an output's views">
|
||||
Sent once on binding the interface and again whenever the tag state
|
||||
of the output changes.
|
||||
</description>
|
||||
<arg name="tags" type="array" summary="array of 32-bit bitfields"/>
|
||||
</event>
|
||||
</interface>
|
||||
|
||||
<interface name="zriver_seat_status_v1" version="1">
|
||||
<description summary="track seat focus">
|
||||
This interface allows clients to receive information about the current
|
||||
focus of a seat.
|
||||
</description>
|
||||
|
||||
<request name="destroy" type="destructor">
|
||||
<description summary="destroy the river_seat_status object">
|
||||
This request indicates that the client will not use the
|
||||
river_seat_status object any more.
|
||||
</description>
|
||||
</request>
|
||||
|
||||
<event name="focused_output">
|
||||
<description summary="the seat focused an output">
|
||||
Sent on binding the interface and again whenever an output gains focus.
|
||||
</description>
|
||||
<arg name="output" type="object" interface="wl_output"/>
|
||||
</event>
|
||||
|
||||
<event name="unfocused_output">
|
||||
<description summary="the seat unfocused an output">
|
||||
Sent whenever an output loses focus.
|
||||
</description>
|
||||
<arg name="output" type="object" interface="wl_output"/>
|
||||
</event>
|
||||
|
||||
<event name="focused_view">
|
||||
<description summary="information on the focused view">
|
||||
Sent once on binding the interface and again whenever the focused
|
||||
view or a property thereof changes. The title may be an empty string
|
||||
if no view is focused or the focused view did not set a title.
|
||||
</description>
|
||||
<arg name="title" type="string" summary="title of the focused view"/>
|
||||
</event>
|
||||
</interface>
|
||||
</protocol>
|
270
protocol/wlr-foreign-toplevel-management-unstable-v1.xml
Normal file
270
protocol/wlr-foreign-toplevel-management-unstable-v1.xml
Normal file
@ -0,0 +1,270 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<protocol name="wlr_foreign_toplevel_management_unstable_v1">
|
||||
<copyright>
|
||||
Copyright © 2018 Ilia Bozhinov
|
||||
|
||||
Permission to use, copy, modify, distribute, and sell this
|
||||
software and its documentation for any purpose is hereby granted
|
||||
without fee, provided that the above copyright notice appear in
|
||||
all copies and that both that copyright notice and this permission
|
||||
notice appear in supporting documentation, and that the name of
|
||||
the copyright holders not be used in advertising or publicity
|
||||
pertaining to distribution of the software without specific,
|
||||
written prior permission. The copyright holders make no
|
||||
representations about the suitability of this software for any
|
||||
purpose. It is provided "as is" without express or implied
|
||||
warranty.
|
||||
|
||||
THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
|
||||
SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
|
||||
AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
|
||||
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
|
||||
THIS SOFTWARE.
|
||||
</copyright>
|
||||
|
||||
<interface name="zwlr_foreign_toplevel_manager_v1" version="3">
|
||||
<description summary="list and control opened apps">
|
||||
The purpose of this protocol is to enable the creation of taskbars
|
||||
and docks by providing them with a list of opened applications and
|
||||
letting them request certain actions on them, like maximizing, etc.
|
||||
|
||||
After a client binds the zwlr_foreign_toplevel_manager_v1, each opened
|
||||
toplevel window will be sent via the toplevel event
|
||||
</description>
|
||||
|
||||
<event name="toplevel">
|
||||
<description summary="a toplevel has been created">
|
||||
This event is emitted whenever a new toplevel window is created. It
|
||||
is emitted for all toplevels, regardless of the app that has created
|
||||
them.
|
||||
|
||||
All initial details of the toplevel(title, app_id, states, etc.) will
|
||||
be sent immediately after this event via the corresponding events in
|
||||
zwlr_foreign_toplevel_handle_v1.
|
||||
</description>
|
||||
<arg name="toplevel" type="new_id" interface="zwlr_foreign_toplevel_handle_v1"/>
|
||||
</event>
|
||||
|
||||
<request name="stop">
|
||||
<description summary="stop sending events">
|
||||
Indicates the client no longer wishes to receive events for new toplevels.
|
||||
However the compositor may emit further toplevel_created events, until
|
||||
the finished event is emitted.
|
||||
|
||||
The client must not send any more requests after this one.
|
||||
</description>
|
||||
</request>
|
||||
|
||||
<event name="finished">
|
||||
<description summary="the compositor has finished with the toplevel manager">
|
||||
This event indicates that the compositor is done sending events to the
|
||||
zwlr_foreign_toplevel_manager_v1. The server will destroy the object
|
||||
immediately after sending this request, so it will become invalid and
|
||||
the client should free any resources associated with it.
|
||||
</description>
|
||||
</event>
|
||||
</interface>
|
||||
|
||||
<interface name="zwlr_foreign_toplevel_handle_v1" version="3">
|
||||
<description summary="an opened toplevel">
|
||||
A zwlr_foreign_toplevel_handle_v1 object represents an opened toplevel
|
||||
window. Each app may have multiple opened toplevels.
|
||||
|
||||
Each toplevel has a list of outputs it is visible on, conveyed to the
|
||||
client with the output_enter and output_leave events.
|
||||
</description>
|
||||
|
||||
<event name="title">
|
||||
<description summary="title change">
|
||||
This event is emitted whenever the title of the toplevel changes.
|
||||
</description>
|
||||
<arg name="title" type="string"/>
|
||||
</event>
|
||||
|
||||
<event name="app_id">
|
||||
<description summary="app-id change">
|
||||
This event is emitted whenever the app-id of the toplevel changes.
|
||||
</description>
|
||||
<arg name="app_id" type="string"/>
|
||||
</event>
|
||||
|
||||
<event name="output_enter">
|
||||
<description summary="toplevel entered an output">
|
||||
This event is emitted whenever the toplevel becomes visible on
|
||||
the given output. A toplevel may be visible on multiple outputs.
|
||||
</description>
|
||||
<arg name="output" type="object" interface="wl_output"/>
|
||||
</event>
|
||||
|
||||
<event name="output_leave">
|
||||
<description summary="toplevel left an output">
|
||||
This event is emitted whenever the toplevel stops being visible on
|
||||
the given output. It is guaranteed that an entered-output event
|
||||
with the same output has been emitted before this event.
|
||||
</description>
|
||||
<arg name="output" type="object" interface="wl_output"/>
|
||||
</event>
|
||||
|
||||
<request name="set_maximized">
|
||||
<description summary="requests that the toplevel be maximized">
|
||||
Requests that the toplevel be maximized. If the maximized state actually
|
||||
changes, this will be indicated by the state event.
|
||||
</description>
|
||||
</request>
|
||||
|
||||
<request name="unset_maximized">
|
||||
<description summary="requests that the toplevel be unmaximized">
|
||||
Requests that the toplevel be unmaximized. If the maximized state actually
|
||||
changes, this will be indicated by the state event.
|
||||
</description>
|
||||
</request>
|
||||
|
||||
<request name="set_minimized">
|
||||
<description summary="requests that the toplevel be minimized">
|
||||
Requests that the toplevel be minimized. If the minimized state actually
|
||||
changes, this will be indicated by the state event.
|
||||
</description>
|
||||
</request>
|
||||
|
||||
<request name="unset_minimized">
|
||||
<description summary="requests that the toplevel be unminimized">
|
||||
Requests that the toplevel be unminimized. If the minimized state actually
|
||||
changes, this will be indicated by the state event.
|
||||
</description>
|
||||
</request>
|
||||
|
||||
<request name="activate">
|
||||
<description summary="activate the toplevel">
|
||||
Request that this toplevel be activated on the given seat.
|
||||
There is no guarantee the toplevel will be actually activated.
|
||||
</description>
|
||||
<arg name="seat" type="object" interface="wl_seat"/>
|
||||
</request>
|
||||
|
||||
<enum name="state">
|
||||
<description summary="types of states on the toplevel">
|
||||
The different states that a toplevel can have. These have the same meaning
|
||||
as the states with the same names defined in xdg-toplevel
|
||||
</description>
|
||||
|
||||
<entry name="maximized" value="0" summary="the toplevel is maximized"/>
|
||||
<entry name="minimized" value="1" summary="the toplevel is minimized"/>
|
||||
<entry name="activated" value="2" summary="the toplevel is active"/>
|
||||
<entry name="fullscreen" value="3" summary="the toplevel is fullscreen" since="2"/>
|
||||
</enum>
|
||||
|
||||
<event name="state">
|
||||
<description summary="the toplevel state changed">
|
||||
This event is emitted immediately after the zlw_foreign_toplevel_handle_v1
|
||||
is created and each time the toplevel state changes, either because of a
|
||||
compositor action or because of a request in this protocol.
|
||||
</description>
|
||||
|
||||
<arg name="state" type="array"/>
|
||||
</event>
|
||||
|
||||
<event name="done">
|
||||
<description summary="all information about the toplevel has been sent">
|
||||
This event is sent after all changes in the toplevel state have been
|
||||
sent.
|
||||
|
||||
This allows changes to the zwlr_foreign_toplevel_handle_v1 properties
|
||||
to be seen as atomic, even if they happen via multiple events.
|
||||
</description>
|
||||
</event>
|
||||
|
||||
<request name="close">
|
||||
<description summary="request that the toplevel be closed">
|
||||
Send a request to the toplevel to close itself. The compositor would
|
||||
typically use a shell-specific method to carry out this request, for
|
||||
example by sending the xdg_toplevel.close event. However, this gives
|
||||
no guarantees the toplevel will actually be destroyed. If and when
|
||||
this happens, the zwlr_foreign_toplevel_handle_v1.closed event will
|
||||
be emitted.
|
||||
</description>
|
||||
</request>
|
||||
|
||||
<request name="set_rectangle">
|
||||
<description summary="the rectangle which represents the toplevel">
|
||||
The rectangle of the surface specified in this request corresponds to
|
||||
the place where the app using this protocol represents the given toplevel.
|
||||
It can be used by the compositor as a hint for some operations, e.g
|
||||
minimizing. The client is however not required to set this, in which
|
||||
case the compositor is free to decide some default value.
|
||||
|
||||
If the client specifies more than one rectangle, only the last one is
|
||||
considered.
|
||||
|
||||
The dimensions are given in surface-local coordinates.
|
||||
Setting width=height=0 removes the already-set rectangle.
|
||||
</description>
|
||||
|
||||
<arg name="surface" type="object" interface="wl_surface"/>
|
||||
<arg name="x" type="int"/>
|
||||
<arg name="y" type="int"/>
|
||||
<arg name="width" type="int"/>
|
||||
<arg name="height" type="int"/>
|
||||
</request>
|
||||
|
||||
<enum name="error">
|
||||
<entry name="invalid_rectangle" value="0"
|
||||
summary="the provided rectangle is invalid"/>
|
||||
</enum>
|
||||
|
||||
<event name="closed">
|
||||
<description summary="this toplevel has been destroyed">
|
||||
This event means the toplevel has been destroyed. It is guaranteed there
|
||||
won't be any more events for this zwlr_foreign_toplevel_handle_v1. The
|
||||
toplevel itself becomes inert so any requests will be ignored except the
|
||||
destroy request.
|
||||
</description>
|
||||
</event>
|
||||
|
||||
<request name="destroy" type="destructor">
|
||||
<description summary="destroy the zwlr_foreign_toplevel_handle_v1 object">
|
||||
Destroys the zwlr_foreign_toplevel_handle_v1 object.
|
||||
|
||||
This request should be called either when the client does not want to
|
||||
use the toplevel anymore or after the closed event to finalize the
|
||||
destruction of the object.
|
||||
</description>
|
||||
</request>
|
||||
|
||||
<!-- Version 2 additions -->
|
||||
|
||||
<request name="set_fullscreen" since="2">
|
||||
<description summary="request that the toplevel be fullscreened">
|
||||
Requests that the toplevel be fullscreened on the given output. If the
|
||||
fullscreen state and/or the outputs the toplevel is visible on actually
|
||||
change, this will be indicated by the state and output_enter/leave
|
||||
events.
|
||||
|
||||
The output parameter is only a hint to the compositor. Also, if output
|
||||
is NULL, the compositor should decide which output the toplevel will be
|
||||
fullscreened on, if at all.
|
||||
</description>
|
||||
<arg name="output" type="object" interface="wl_output" allow-null="true"/>
|
||||
</request>
|
||||
|
||||
<request name="unset_fullscreen" since="2">
|
||||
<description summary="request that the toplevel be unfullscreened">
|
||||
Requests that the toplevel be unfullscreened. If the fullscreen state
|
||||
actually changes, this will be indicated by the state event.
|
||||
</description>
|
||||
</request>
|
||||
|
||||
<!-- Version 3 additions -->
|
||||
|
||||
<event name="parent" since="3">
|
||||
<description summary="parent change">
|
||||
This event is emitted whenever the parent of the toplevel changes.
|
||||
|
||||
No event is emitted when the parent handle is destroyed by the client.
|
||||
</description>
|
||||
<arg name="parent" type="object" interface="zwlr_foreign_toplevel_handle_v1" allow-null="true"/>
|
||||
</event>
|
||||
</interface>
|
||||
</protocol>
|
@ -25,7 +25,7 @@
|
||||
THIS SOFTWARE.
|
||||
</copyright>
|
||||
|
||||
<interface name="zwlr_layer_shell_v1" version="1">
|
||||
<interface name="zwlr_layer_shell_v1" version="3">
|
||||
<description summary="create surfaces that are layers of the desktop">
|
||||
Clients can use this interface to assign the surface_layer role to
|
||||
wl_surfaces. Such surfaces are assigned to a "layer" of the output and
|
||||
@ -82,17 +82,27 @@
|
||||
<entry name="top" value="2"/>
|
||||
<entry name="overlay" value="3"/>
|
||||
</enum>
|
||||
|
||||
<!-- Version 3 additions -->
|
||||
|
||||
<request name="destroy" type="destructor" since="3">
|
||||
<description summary="destroy the layer_shell object">
|
||||
This request indicates that the client will not use the layer_shell
|
||||
object any more. Objects that have been created through this instance
|
||||
are not affected.
|
||||
</description>
|
||||
</request>
|
||||
</interface>
|
||||
|
||||
<interface name="zwlr_layer_surface_v1" version="1">
|
||||
<interface name="zwlr_layer_surface_v1" version="3">
|
||||
<description summary="layer metadata interface">
|
||||
An interface that may be implemented by a wl_surface, for surfaces that
|
||||
are designed to be rendered as a layer of a stacked desktop-like
|
||||
environment.
|
||||
|
||||
Layer surface state (size, anchor, exclusive zone, margin, interactivity)
|
||||
is double-buffered, and will be applied at the time wl_surface.commit of
|
||||
the corresponding wl_surface is called.
|
||||
Layer surface state (layer, size, anchor, exclusive zone,
|
||||
margin, interactivity) is double-buffered, and will be applied at the
|
||||
time wl_surface.commit of the corresponding wl_surface is called.
|
||||
</description>
|
||||
|
||||
<request name="set_size">
|
||||
@ -115,7 +125,7 @@
|
||||
<request name="set_anchor">
|
||||
<description summary="configures the anchor point of the surface">
|
||||
Requests that the compositor anchor the surface to the specified edges
|
||||
and corners. If two orthoginal edges are specified (e.g. 'top' and
|
||||
and corners. If two orthogonal edges are specified (e.g. 'top' and
|
||||
'left'), then the anchor point will be the intersection of the edges
|
||||
(e.g. the top left corner of the output); otherwise the anchor point
|
||||
will be centered on that edge, or in the center if none is specified.
|
||||
@ -127,20 +137,25 @@
|
||||
|
||||
<request name="set_exclusive_zone">
|
||||
<description summary="configures the exclusive geometry of this surface">
|
||||
Requests that the compositor avoids occluding an area of the surface
|
||||
with other surfaces. The compositor's use of this information is
|
||||
Requests that the compositor avoids occluding an area with other
|
||||
surfaces. The compositor's use of this information is
|
||||
implementation-dependent - do not assume that this region will not
|
||||
actually be occluded.
|
||||
|
||||
A positive value is only meaningful if the surface is anchored to an
|
||||
edge, rather than a corner. The zone is the number of surface-local
|
||||
coordinates from the edge that are considered exclusive.
|
||||
A positive value is only meaningful if the surface is anchored to one
|
||||
edge or an edge and both perpendicular edges. If the surface is not
|
||||
anchored, anchored to only two perpendicular edges (a corner), anchored
|
||||
to only two parallel edges or anchored to all edges, a positive value
|
||||
will be treated the same as zero.
|
||||
|
||||
A positive zone is the distance from the edge in surface-local
|
||||
coordinates to consider exclusive.
|
||||
|
||||
Surfaces that do not wish to have an exclusive zone may instead specify
|
||||
how they should interact with surfaces that do. If set to zero, the
|
||||
surface indicates that it would like to be moved to avoid occluding
|
||||
surfaces with a positive excluzive zone. If set to -1, the surface
|
||||
indicates that it would not like to be moved to accomodate for other
|
||||
surfaces with a positive exclusive zone. If set to -1, the surface
|
||||
indicates that it would not like to be moved to accommodate for other
|
||||
surfaces, and the compositor should extend it all the way to the edges
|
||||
it is anchored to.
|
||||
|
||||
@ -281,5 +296,16 @@
|
||||
<entry name="left" value="4" summary="the left edge of the anchor rectangle"/>
|
||||
<entry name="right" value="8" summary="the right edge of the anchor rectangle"/>
|
||||
</enum>
|
||||
|
||||
<!-- Version 2 additions -->
|
||||
|
||||
<request name="set_layer" since="2">
|
||||
<description summary="change the layer of the surface">
|
||||
Change the layer that the surface is rendered on.
|
||||
|
||||
Layer is double-buffered, see wl_surface.commit.
|
||||
</description>
|
||||
<arg name="layer" type="uint" enum="zwlr_layer_shell_v1.layer" summary="layer to move this surface to"/>
|
||||
</request>
|
||||
</interface>
|
||||
</protocol>
|
||||
|
@ -1,12 +1,12 @@
|
||||
{
|
||||
"layer": "top", // Waybar at top layer
|
||||
// "layer": "top", // Waybar at top layer
|
||||
// "position": "bottom", // Waybar position (top|bottom|left|right)
|
||||
"height": 30, // Waybar height (to be removed for auto height)
|
||||
// "width": 1280, // Waybar width
|
||||
// Choose the order of the modules
|
||||
"modules-left": ["sway/workspaces", "sway/mode", "custom/media"],
|
||||
"modules-center": ["sway/window"],
|
||||
"modules-right": ["mpd", "idle_inhibitor", "pulseaudio", "network", "cpu", "memory", "temperature", "backlight", "battery", "battery#bat2", "clock", "tray"],
|
||||
"modules-right": ["mpd", "idle_inhibitor", "pulseaudio", "network", "cpu", "memory", "temperature", "backlight", "keyboard-state", "sway/language", "battery", "battery#bat2", "clock", "tray"],
|
||||
// Modules configuration
|
||||
// "sway/workspaces": {
|
||||
// "disable-scroll": true,
|
||||
@ -23,11 +23,20 @@
|
||||
// "default": ""
|
||||
// }
|
||||
// },
|
||||
"keyboard-state": {
|
||||
"numlock": true,
|
||||
"capslock": true,
|
||||
"format": "{name} {icon}",
|
||||
"format-icons": {
|
||||
"locked": "",
|
||||
"unlocked": ""
|
||||
}
|
||||
},
|
||||
"sway/mode": {
|
||||
"format": "<span style=\"italic\">{}</span>"
|
||||
},
|
||||
"mpd": {
|
||||
"format": "{stateIcon} {consumeIcon}{randomIcon}{repeatIcon}{singleIcon}{artist} - {album} - {title} ({elapsedTime:%M:%S}/{totalTime:%M:%S}) ",
|
||||
"format": "{stateIcon} {consumeIcon}{randomIcon}{repeatIcon}{singleIcon}{artist} - {album} - {title} ({elapsedTime:%M:%S}/{totalTime:%M:%S}) ⸨{songPosition}|{queueLength}⸩ {volume}% ",
|
||||
"format-disconnected": "Disconnected ",
|
||||
"format-stopped": "{consumeIcon}{randomIcon}{repeatIcon}{singleIcon}Stopped ",
|
||||
"unknown-tag": "N/A",
|
||||
@ -64,7 +73,8 @@
|
||||
"spacing": 10
|
||||
},
|
||||
"clock": {
|
||||
"tooltip-format": "{:%Y-%m-%d | %H:%M}",
|
||||
// "timezone": "America/New_York",
|
||||
"tooltip-format": "<big>{:%Y %B}</big>\n<tt><small>{calendar}</small></tt>",
|
||||
"format-alt": "{:%Y-%m-%d}"
|
||||
},
|
||||
"cpu": {
|
||||
@ -116,12 +126,13 @@
|
||||
// "scroll-step": 1, // %, can be a float
|
||||
"format": "{volume}% {icon} {format_source}",
|
||||
"format-bluetooth": "{volume}% {icon} {format_source}",
|
||||
"format-bluetooth-muted": " {icon} {format_source}",
|
||||
"format-muted": " {format_source}",
|
||||
"format-source": "{volume}% ",
|
||||
"format-source-muted": "",
|
||||
"format-icons": {
|
||||
"headphones": "",
|
||||
"handsfree": "",
|
||||
"headphone": "",
|
||||
"hands-free": "",
|
||||
"headset": "",
|
||||
"phone": "",
|
||||
"portable": "",
|
||||
@ -140,5 +151,7 @@
|
||||
},
|
||||
"escape": true,
|
||||
"exec": "$HOME/.config/waybar/mediaplayer.py 2> /dev/null" // Script in resources folder
|
||||
// "exec": "$HOME/.config/waybar/mediaplayer.py --player spotify 2> /dev/null" // Filter player based on name
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -38,6 +38,8 @@ def on_metadata(player, metadata, manager):
|
||||
elif player.get_artist() != '' and player.get_title() != '':
|
||||
track_info = '{artist} - {title}'.format(artist=player.get_artist(),
|
||||
title=player.get_title())
|
||||
else:
|
||||
track_info = player.get_title()
|
||||
|
||||
if player.props.status != 'Playing' and track_info:
|
||||
track_info = ' ' + track_info
|
||||
@ -45,7 +47,7 @@ def on_metadata(player, metadata, manager):
|
||||
|
||||
|
||||
def on_player_appeared(manager, player, selected_player=None):
|
||||
if player is not None and player.name == selected_player:
|
||||
if player is not None and (selected_player is None or player.name == selected_player):
|
||||
init_player(manager, player)
|
||||
else:
|
||||
logger.debug("New player appeared, but it's not the selected player, skipping")
|
||||
@ -77,7 +79,7 @@ def signal_handler(sig, frame):
|
||||
def parse_arguments():
|
||||
parser = argparse.ArgumentParser()
|
||||
|
||||
# Increase verbosity with every occurance of -v
|
||||
# Increase verbosity with every occurence of -v
|
||||
parser.add_argument('-v', '--verbose', action='count', default=0)
|
||||
|
||||
# Define for which player we're listening
|
||||
@ -123,4 +125,3 @@ def main():
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
* {
|
||||
border: none;
|
||||
border-radius: 0;
|
||||
/* `otf-font-awesome` is required to be installed for icons */
|
||||
font-family: Roboto, Helvetica, Arial, sans-serif;
|
||||
font-size: 13px;
|
||||
min-height: 0;
|
||||
@ -36,17 +37,23 @@ window#waybar.chromium {
|
||||
border: none;
|
||||
}
|
||||
|
||||
/* https://github.com/Alexays/Waybar/wiki/FAQ#the-workspace-buttons-have-a-strange-hover-effect */
|
||||
#workspaces button {
|
||||
padding: 0 5px;
|
||||
background-color: transparent;
|
||||
color: #ffffff;
|
||||
border-bottom: 3px solid transparent;
|
||||
/* Use box-shadow instead of border so the text isn't offset */
|
||||
box-shadow: inset 0 -3px transparent;
|
||||
}
|
||||
|
||||
/* https://github.com/Alexays/Waybar/wiki/FAQ#the-workspace-buttons-have-a-strange-hover-effect */
|
||||
#workspaces button:hover {
|
||||
background: rgba(0, 0, 0, 0.2);
|
||||
box-shadow: inset 0 -3px #ffffff;
|
||||
}
|
||||
|
||||
#workspaces button.focused {
|
||||
background-color: #64727D;
|
||||
border-bottom: 3px solid #ffffff;
|
||||
box-shadow: inset 0 -3px #ffffff;
|
||||
}
|
||||
|
||||
#workspaces button.urgent {
|
||||
@ -62,6 +69,7 @@ window#waybar.chromium {
|
||||
#battery,
|
||||
#cpu,
|
||||
#memory,
|
||||
#disk,
|
||||
#temperature,
|
||||
#backlight,
|
||||
#network,
|
||||
@ -69,12 +77,28 @@ window#waybar.chromium {
|
||||
#custom-media,
|
||||
#tray,
|
||||
#mode,
|
||||
#idle_inhibitor {
|
||||
#idle_inhibitor,
|
||||
#mpd {
|
||||
padding: 0 10px;
|
||||
margin: 0 4px;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
#window,
|
||||
#workspaces {
|
||||
margin: 0 4px;
|
||||
}
|
||||
|
||||
/* If workspaces is the leftmost module, omit left margin */
|
||||
.modules-left > widget:first-child > #workspaces {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
/* If workspaces is the rightmost module, omit right margin */
|
||||
.modules-right > widget:last-child > #workspaces {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
#clock {
|
||||
background-color: #64727D;
|
||||
}
|
||||
@ -84,7 +108,7 @@ window#waybar.chromium {
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
#battery.charging {
|
||||
#battery.charging, #battery.plugged {
|
||||
color: #ffffff;
|
||||
background-color: #26A65B;
|
||||
}
|
||||
@ -119,6 +143,10 @@ label:focus {
|
||||
background-color: #9b59b6;
|
||||
}
|
||||
|
||||
#disk {
|
||||
background-color: #964B00;
|
||||
}
|
||||
|
||||
#backlight {
|
||||
background-color: #90b1b1;
|
||||
}
|
||||
@ -167,6 +195,15 @@ label:focus {
|
||||
background-color: #2980b9;
|
||||
}
|
||||
|
||||
#tray > .passive {
|
||||
-gtk-icon-effect: dim;
|
||||
}
|
||||
|
||||
#tray > .needs-attention {
|
||||
-gtk-icon-effect: highlight;
|
||||
background-color: #eb4d4b;
|
||||
}
|
||||
|
||||
#idle_inhibitor {
|
||||
background-color: #2d3436;
|
||||
}
|
||||
@ -192,3 +229,27 @@ label:focus {
|
||||
#mpd.paused {
|
||||
background-color: #51a37a;
|
||||
}
|
||||
|
||||
#language {
|
||||
background: #00b093;
|
||||
color: #740864;
|
||||
padding: 0 5px;
|
||||
margin: 0 5px;
|
||||
min-width: 16px;
|
||||
}
|
||||
|
||||
#keyboard-state {
|
||||
background: #97e1ad;
|
||||
color: #000000;
|
||||
padding: 0 0px;
|
||||
margin: 0 5px;
|
||||
min-width: 16px;
|
||||
}
|
||||
|
||||
#keyboard-state > label {
|
||||
padding: 0 5px;
|
||||
}
|
||||
|
||||
#keyboard-state > label.locked {
|
||||
background: rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
14
resources/waybar.service.in
Normal file
14
resources/waybar.service.in
Normal file
@ -0,0 +1,14 @@
|
||||
[Unit]
|
||||
Description=Highly customizable Wayland bar for Sway and Wlroots based compositors.
|
||||
Documentation=https://github.com/Alexays/Waybar/wiki/
|
||||
PartOf=graphical-session.target
|
||||
After=graphical-session.target
|
||||
Requisite=graphical-session.target
|
||||
|
||||
[Service]
|
||||
ExecStart=@prefix@/bin/waybar
|
||||
ExecReload=kill -SIGUSR2 $MAINPID
|
||||
Restart=on-failure
|
||||
|
||||
[Install]
|
||||
WantedBy=graphical-session.target
|
@ -5,8 +5,9 @@
|
||||
namespace waybar {
|
||||
|
||||
ALabel::ALabel(const Json::Value& config, const std::string& name, const std::string& id,
|
||||
const std::string& format, uint16_t interval)
|
||||
: AModule(config, name, id, config["format-alt"].isString()),
|
||||
const std::string& format, uint16_t interval, bool ellipsize, bool enable_click,
|
||||
bool enable_scroll)
|
||||
: AModule(config, name, id, config["format-alt"].isString() || enable_click, enable_scroll),
|
||||
format_(config_["format"].isString() ? config_["format"].asString() : format),
|
||||
interval_(config_["interval"] == "once"
|
||||
? std::chrono::seconds(100000000)
|
||||
@ -19,17 +20,40 @@ ALabel::ALabel(const Json::Value& config, const std::string& name, const std::st
|
||||
}
|
||||
event_box_.add(label_);
|
||||
if (config_["max-length"].isUInt()) {
|
||||
label_.set_max_width_chars(config_["max-length"].asUInt());
|
||||
label_.set_max_width_chars(config_["max-length"].asInt());
|
||||
label_.set_ellipsize(Pango::EllipsizeMode::ELLIPSIZE_END);
|
||||
label_.set_single_line_mode(true);
|
||||
} else if (ellipsize && label_.get_max_width_chars() == -1) {
|
||||
label_.set_ellipsize(Pango::EllipsizeMode::ELLIPSIZE_END);
|
||||
label_.set_single_line_mode(true);
|
||||
}
|
||||
|
||||
if (config_["rotate"].isUInt()) {
|
||||
label_.set_angle(config["rotate"].asUInt());
|
||||
if (config_["min-length"].isUInt()) {
|
||||
label_.set_width_chars(config_["min-length"].asUInt());
|
||||
}
|
||||
|
||||
uint rotate = 0;
|
||||
|
||||
if (config_["rotate"].isUInt()) {
|
||||
rotate = config["rotate"].asUInt();
|
||||
label_.set_angle(rotate);
|
||||
}
|
||||
|
||||
if (config_["align"].isDouble()) {
|
||||
auto align = config_["align"].asFloat();
|
||||
if (rotate == 90 || rotate == 270) {
|
||||
label_.set_yalign(align);
|
||||
} else {
|
||||
label_.set_xalign(align);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
auto ALabel::update() -> void {
|
||||
// Nothing here
|
||||
AModule::update();
|
||||
}
|
||||
|
||||
std::string ALabel::getIcon(uint16_t percentage, const std::string& alt, uint16_t max) {
|
||||
@ -52,6 +76,29 @@ std::string ALabel::getIcon(uint16_t percentage, const std::string& alt, uint16_
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string ALabel::getIcon(uint16_t percentage, const std::vector<std::string>& alts, uint16_t max) {
|
||||
auto format_icons = config_["format-icons"];
|
||||
if (format_icons.isObject()) {
|
||||
std::string _alt = "default";
|
||||
for (const auto& alt : alts) {
|
||||
if (!alt.empty() && (format_icons[alt].isString() || format_icons[alt].isArray())) {
|
||||
_alt = alt;
|
||||
break;
|
||||
}
|
||||
}
|
||||
format_icons = format_icons[_alt];
|
||||
}
|
||||
if (format_icons.isArray()) {
|
||||
auto size = format_icons.size();
|
||||
auto idx = std::clamp(percentage / ((max == 0 ? 100 : max) / size), 0U, size - 1);
|
||||
format_icons = format_icons[idx];
|
||||
}
|
||||
if (format_icons.isString()) {
|
||||
return format_icons.asString();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
bool waybar::ALabel::handleToggle(GdkEventButton* const& e) {
|
||||
if (config_["format-alt-click"].isUInt() && e->button == config_["format-alt-click"].asUInt()) {
|
||||
alt_ = !alt_;
|
||||
|
@ -6,7 +6,7 @@ namespace waybar {
|
||||
|
||||
AModule::AModule(const Json::Value& config, const std::string& name, const std::string& id,
|
||||
bool enable_click, bool enable_scroll)
|
||||
: config_(std::move(config)) {
|
||||
: name_(std::move(name)), config_(std::move(config)) {
|
||||
// configure events' user commands
|
||||
if (config_["on-click"].isString() || config_["on-click-middle"].isString() ||
|
||||
config_["on-click-backward"].isString() || config_["on-click-forward"].isString() ||
|
||||
@ -23,13 +23,17 @@ AModule::AModule(const Json::Value& config, const std::string& name, const std::
|
||||
AModule::~AModule() {
|
||||
for (const auto& pid : pid_) {
|
||||
if (pid != -1) {
|
||||
kill(-pid, 9);
|
||||
killpg(pid, SIGTERM);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
auto AModule::update() -> void {
|
||||
// Nothing here
|
||||
// Run user-provided update handler if configured
|
||||
if (config_["on-update"].isString()) {
|
||||
pid_.push_back(util::command::forkExec(config_["on-update"].asString()));
|
||||
}
|
||||
}
|
||||
|
||||
bool AModule::handleToggle(GdkEventButton* const& e) {
|
||||
@ -40,13 +44,13 @@ bool AModule::handleToggle(GdkEventButton* const& e) {
|
||||
format = config_["on-click-middle"].asString();
|
||||
} else if (config_["on-click-right"].isString() && e->button == 3) {
|
||||
format = config_["on-click-right"].asString();
|
||||
} else if (config_["on-click-forward"].isString() && e->button == 8) {
|
||||
} else if (config_["on-click-backward"].isString() && e->button == 8) {
|
||||
format = config_["on-click-backward"].asString();
|
||||
} else if (config_["on-click-backward"].isString() && e->button == 9) {
|
||||
} else if (config_["on-click-forward"].isString() && e->button == 9) {
|
||||
format = config_["on-click-forward"].asString();
|
||||
}
|
||||
if (!format.empty()) {
|
||||
pid_.push_back(util::command::forkExec(fmt::format(format, fmt::arg("arg", click_param_))));
|
||||
pid_.push_back(util::command::forkExec(format));
|
||||
}
|
||||
dp.emit();
|
||||
return true;
|
||||
|
619
src/bar.cpp
619
src/bar.cpp
@ -1,15 +1,397 @@
|
||||
#include "bar.hpp"
|
||||
#ifdef HAVE_GTK_LAYER_SHELL
|
||||
#include <gtk-layer-shell.h>
|
||||
#endif
|
||||
|
||||
#include <spdlog/spdlog.h>
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#include "bar.hpp"
|
||||
#include "client.hpp"
|
||||
#include "factory.hpp"
|
||||
#include "wlr-layer-shell-unstable-v1-client-protocol.h"
|
||||
|
||||
namespace waybar {
|
||||
static constexpr const char* MIN_HEIGHT_MSG =
|
||||
"Requested height: {} exceeds the minimum height: {} required by the modules";
|
||||
|
||||
static constexpr const char* MIN_WIDTH_MSG =
|
||||
"Requested width: {} exceeds the minimum width: {} required by the modules";
|
||||
|
||||
static constexpr const char* BAR_SIZE_MSG = "Bar configured (width: {}, height: {}) for output: {}";
|
||||
|
||||
static constexpr const char* SIZE_DEFINED =
|
||||
"{} size is defined in the config file so it will stay like that";
|
||||
|
||||
#ifdef HAVE_GTK_LAYER_SHELL
|
||||
struct GLSSurfaceImpl : public BarSurface, public sigc::trackable {
|
||||
GLSSurfaceImpl(Gtk::Window& window, struct waybar_output& output) : window_{window} {
|
||||
output_name_ = output.name;
|
||||
// this has to be executed before GtkWindow.realize
|
||||
gtk_layer_init_for_window(window_.gobj());
|
||||
gtk_layer_set_keyboard_interactivity(window.gobj(), FALSE);
|
||||
gtk_layer_set_monitor(window_.gobj(), output.monitor->gobj());
|
||||
gtk_layer_set_namespace(window_.gobj(), "waybar");
|
||||
|
||||
window.signal_map_event().connect_notify(sigc::mem_fun(*this, &GLSSurfaceImpl::onMap));
|
||||
window.signal_configure_event().connect_notify(
|
||||
sigc::mem_fun(*this, &GLSSurfaceImpl::onConfigure));
|
||||
}
|
||||
|
||||
void setExclusiveZone(bool enable) override {
|
||||
if (enable) {
|
||||
gtk_layer_auto_exclusive_zone_enable(window_.gobj());
|
||||
} else {
|
||||
gtk_layer_set_exclusive_zone(window_.gobj(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
void setMargins(const struct bar_margins& margins) override {
|
||||
gtk_layer_set_margin(window_.gobj(), GTK_LAYER_SHELL_EDGE_LEFT, margins.left);
|
||||
gtk_layer_set_margin(window_.gobj(), GTK_LAYER_SHELL_EDGE_RIGHT, margins.right);
|
||||
gtk_layer_set_margin(window_.gobj(), GTK_LAYER_SHELL_EDGE_TOP, margins.top);
|
||||
gtk_layer_set_margin(window_.gobj(), GTK_LAYER_SHELL_EDGE_BOTTOM, margins.bottom);
|
||||
}
|
||||
|
||||
void setLayer(bar_layer value) override {
|
||||
auto layer = GTK_LAYER_SHELL_LAYER_BOTTOM;
|
||||
if (value == bar_layer::TOP) {
|
||||
layer = GTK_LAYER_SHELL_LAYER_TOP;
|
||||
} else if (value == bar_layer::OVERLAY) {
|
||||
layer = GTK_LAYER_SHELL_LAYER_OVERLAY;
|
||||
}
|
||||
gtk_layer_set_layer(window_.gobj(), layer);
|
||||
}
|
||||
|
||||
void setPassThrough(bool enable) override {
|
||||
passthrough_ = enable;
|
||||
auto gdk_window = window_.get_window();
|
||||
if (gdk_window) {
|
||||
Cairo::RefPtr<Cairo::Region> region;
|
||||
if (enable) {
|
||||
region = Cairo::Region::create();
|
||||
}
|
||||
gdk_window->input_shape_combine_region(region, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void setPosition(const std::string_view& position) override {
|
||||
auto unanchored = GTK_LAYER_SHELL_EDGE_BOTTOM;
|
||||
vertical_ = false;
|
||||
if (position == "bottom") {
|
||||
unanchored = GTK_LAYER_SHELL_EDGE_TOP;
|
||||
} else if (position == "left") {
|
||||
unanchored = GTK_LAYER_SHELL_EDGE_RIGHT;
|
||||
vertical_ = true;
|
||||
} else if (position == "right") {
|
||||
vertical_ = true;
|
||||
unanchored = GTK_LAYER_SHELL_EDGE_LEFT;
|
||||
}
|
||||
for (auto edge : {GTK_LAYER_SHELL_EDGE_LEFT,
|
||||
GTK_LAYER_SHELL_EDGE_RIGHT,
|
||||
GTK_LAYER_SHELL_EDGE_TOP,
|
||||
GTK_LAYER_SHELL_EDGE_BOTTOM}) {
|
||||
gtk_layer_set_anchor(window_.gobj(), edge, unanchored != edge);
|
||||
}
|
||||
}
|
||||
|
||||
void setSize(uint32_t width, uint32_t height) override {
|
||||
width_ = width;
|
||||
height_ = height;
|
||||
window_.set_size_request(width_, height_);
|
||||
};
|
||||
|
||||
private:
|
||||
Gtk::Window& window_;
|
||||
std::string output_name_;
|
||||
uint32_t width_;
|
||||
uint32_t height_;
|
||||
bool passthrough_ = false;
|
||||
bool vertical_ = false;
|
||||
|
||||
void onMap(GdkEventAny* ev) { setPassThrough(passthrough_); }
|
||||
|
||||
void onConfigure(GdkEventConfigure* ev) {
|
||||
/*
|
||||
* GTK wants new size for the window.
|
||||
* Actual resizing and management of the exclusve zone is handled within the gtk-layer-shell
|
||||
* code. This event handler only updates stored size of the window and prints some warnings.
|
||||
*
|
||||
* Note: forced resizing to a window smaller than required by GTK would not work with
|
||||
* gtk-layer-shell.
|
||||
*/
|
||||
if (vertical_) {
|
||||
if (width_ > 1 && ev->width > static_cast<int>(width_)) {
|
||||
spdlog::warn(MIN_WIDTH_MSG, width_, ev->width);
|
||||
}
|
||||
} else {
|
||||
if (height_ > 1 && ev->height > static_cast<int>(height_)) {
|
||||
spdlog::warn(MIN_HEIGHT_MSG, height_, ev->height);
|
||||
}
|
||||
}
|
||||
width_ = ev->width;
|
||||
height_ = ev->height;
|
||||
spdlog::info(BAR_SIZE_MSG, width_, height_, output_name_);
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
struct RawSurfaceImpl : public BarSurface, public sigc::trackable {
|
||||
RawSurfaceImpl(Gtk::Window& window, struct waybar_output& output) : window_{window} {
|
||||
output_ = gdk_wayland_monitor_get_wl_output(output.monitor->gobj());
|
||||
output_name_ = output.name;
|
||||
|
||||
window.signal_realize().connect_notify(sigc::mem_fun(*this, &RawSurfaceImpl::onRealize));
|
||||
window.signal_map_event().connect_notify(sigc::mem_fun(*this, &RawSurfaceImpl::onMap));
|
||||
window.signal_configure_event().connect_notify(
|
||||
sigc::mem_fun(*this, &RawSurfaceImpl::onConfigure));
|
||||
|
||||
if (window.get_realized()) {
|
||||
onRealize();
|
||||
}
|
||||
}
|
||||
|
||||
void setExclusiveZone(bool enable) override {
|
||||
exclusive_zone_ = enable;
|
||||
if (layer_surface_) {
|
||||
auto zone = 0;
|
||||
if (enable) {
|
||||
// exclusive zone already includes margin for anchored edge,
|
||||
// only opposite margin should be added
|
||||
if ((anchor_ & VERTICAL_ANCHOR) == VERTICAL_ANCHOR) {
|
||||
zone += width_;
|
||||
zone += (anchor_ & ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT) ? margins_.right : margins_.left;
|
||||
} else {
|
||||
zone += height_;
|
||||
zone += (anchor_ & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP) ? margins_.bottom : margins_.top;
|
||||
}
|
||||
}
|
||||
spdlog::debug("Set exclusive zone {} for output {}", zone, output_name_);
|
||||
zwlr_layer_surface_v1_set_exclusive_zone(layer_surface_.get(), zone);
|
||||
}
|
||||
}
|
||||
|
||||
void setLayer(bar_layer layer) override {
|
||||
layer_ = ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM;
|
||||
if (layer == bar_layer::TOP) {
|
||||
layer_ = ZWLR_LAYER_SHELL_V1_LAYER_TOP;
|
||||
} else if (layer == bar_layer::OVERLAY) {
|
||||
layer_ = ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY;
|
||||
}
|
||||
// updating already mapped window
|
||||
if (layer_surface_) {
|
||||
if (zwlr_layer_surface_v1_get_version(layer_surface_.get()) >=
|
||||
ZWLR_LAYER_SURFACE_V1_SET_LAYER_SINCE_VERSION) {
|
||||
zwlr_layer_surface_v1_set_layer(layer_surface_.get(), layer_);
|
||||
} else {
|
||||
spdlog::warn("Unable to change layer: layer-shell implementation is too old");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void setMargins(const struct bar_margins& margins) override {
|
||||
margins_ = margins;
|
||||
// updating already mapped window
|
||||
if (layer_surface_) {
|
||||
zwlr_layer_surface_v1_set_margin(
|
||||
layer_surface_.get(), margins_.top, margins_.right, margins_.bottom, margins_.left);
|
||||
}
|
||||
}
|
||||
|
||||
void setPassThrough(bool enable) override {
|
||||
passthrough_ = enable;
|
||||
/* GTK overwrites any region changes applied directly to the wl_surface,
|
||||
* thus the same GTK region API as in the GLS impl has to be used. */
|
||||
auto gdk_window = window_.get_window();
|
||||
if (gdk_window) {
|
||||
Cairo::RefPtr<Cairo::Region> region;
|
||||
if (enable) {
|
||||
region = Cairo::Region::create();
|
||||
}
|
||||
gdk_window->input_shape_combine_region(region, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void setPosition(const std::string_view& position) override {
|
||||
anchor_ = HORIZONTAL_ANCHOR | ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP;
|
||||
if (position == "bottom") {
|
||||
anchor_ = HORIZONTAL_ANCHOR | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM;
|
||||
} else if (position == "left") {
|
||||
anchor_ = VERTICAL_ANCHOR | ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT;
|
||||
} else if (position == "right") {
|
||||
anchor_ = VERTICAL_ANCHOR | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT;
|
||||
}
|
||||
|
||||
// updating already mapped window
|
||||
if (layer_surface_) {
|
||||
zwlr_layer_surface_v1_set_anchor(layer_surface_.get(), anchor_);
|
||||
}
|
||||
}
|
||||
|
||||
void setSize(uint32_t width, uint32_t height) override {
|
||||
configured_width_ = width_ = width;
|
||||
configured_height_ = height_ = height;
|
||||
// layer_shell.configure handler should update exclusive zone if size changes
|
||||
window_.set_size_request(width, height);
|
||||
};
|
||||
|
||||
void commit() override {
|
||||
if (surface_) {
|
||||
wl_surface_commit(surface_);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
constexpr static uint8_t VERTICAL_ANCHOR =
|
||||
ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM;
|
||||
constexpr static uint8_t HORIZONTAL_ANCHOR =
|
||||
ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT;
|
||||
|
||||
template <auto fn>
|
||||
using deleter_fn = std::integral_constant<decltype(fn), fn>;
|
||||
using layer_surface_ptr =
|
||||
std::unique_ptr<zwlr_layer_surface_v1, deleter_fn<zwlr_layer_surface_v1_destroy>>;
|
||||
|
||||
Gtk::Window& window_;
|
||||
std::string output_name_;
|
||||
uint32_t configured_width_ = 0;
|
||||
uint32_t configured_height_ = 0;
|
||||
uint32_t width_ = 0;
|
||||
uint32_t height_ = 0;
|
||||
uint8_t anchor_ = HORIZONTAL_ANCHOR | ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP;
|
||||
bool exclusive_zone_ = true;
|
||||
bool passthrough_ = false;
|
||||
struct bar_margins margins_;
|
||||
|
||||
zwlr_layer_shell_v1_layer layer_ = ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM;
|
||||
struct wl_output* output_ = nullptr; // owned by GTK
|
||||
struct wl_surface* surface_ = nullptr; // owned by GTK
|
||||
layer_surface_ptr layer_surface_;
|
||||
|
||||
void onRealize() {
|
||||
auto gdk_window = window_.get_window()->gobj();
|
||||
gdk_wayland_window_set_use_custom_surface(gdk_window);
|
||||
}
|
||||
|
||||
void onMap(GdkEventAny* ev) {
|
||||
static const struct zwlr_layer_surface_v1_listener layer_surface_listener = {
|
||||
.configure = onSurfaceConfigure,
|
||||
.closed = onSurfaceClosed,
|
||||
};
|
||||
auto client = Client::inst();
|
||||
auto gdk_window = window_.get_window()->gobj();
|
||||
surface_ = gdk_wayland_window_get_wl_surface(gdk_window);
|
||||
|
||||
layer_surface_.reset(zwlr_layer_shell_v1_get_layer_surface(
|
||||
client->layer_shell, surface_, output_, layer_, "waybar"));
|
||||
|
||||
zwlr_layer_surface_v1_add_listener(layer_surface_.get(), &layer_surface_listener, this);
|
||||
zwlr_layer_surface_v1_set_keyboard_interactivity(layer_surface_.get(), false);
|
||||
zwlr_layer_surface_v1_set_anchor(layer_surface_.get(), anchor_);
|
||||
zwlr_layer_surface_v1_set_margin(
|
||||
layer_surface_.get(), margins_.top, margins_.right, margins_.bottom, margins_.left);
|
||||
|
||||
setSurfaceSize(width_, height_);
|
||||
setExclusiveZone(exclusive_zone_);
|
||||
setPassThrough(passthrough_);
|
||||
|
||||
commit();
|
||||
wl_display_roundtrip(client->wl_display);
|
||||
}
|
||||
|
||||
void onConfigure(GdkEventConfigure* ev) {
|
||||
/*
|
||||
* GTK wants new size for the window.
|
||||
*
|
||||
* Prefer configured size if it's non-default.
|
||||
* If the size is not set and the window is smaller than requested by GTK, request resize from
|
||||
* layer surface.
|
||||
*/
|
||||
auto tmp_height = height_;
|
||||
auto tmp_width = width_;
|
||||
if (ev->height > static_cast<int>(height_)) {
|
||||
// Default minimal value
|
||||
if (height_ > 1) {
|
||||
spdlog::warn(MIN_HEIGHT_MSG, height_, ev->height);
|
||||
}
|
||||
if (configured_height_ > 1) {
|
||||
spdlog::info(SIZE_DEFINED, "Height");
|
||||
} else {
|
||||
tmp_height = ev->height;
|
||||
}
|
||||
}
|
||||
if (ev->width > static_cast<int>(width_)) {
|
||||
// Default minimal value
|
||||
if (width_ > 1) {
|
||||
spdlog::warn(MIN_WIDTH_MSG, width_, ev->width);
|
||||
}
|
||||
if (configured_width_ > 1) {
|
||||
spdlog::info(SIZE_DEFINED, "Width");
|
||||
} else {
|
||||
tmp_width = ev->width;
|
||||
}
|
||||
}
|
||||
if (tmp_width != width_ || tmp_height != height_) {
|
||||
setSurfaceSize(tmp_width, tmp_height);
|
||||
commit();
|
||||
}
|
||||
}
|
||||
|
||||
void setSurfaceSize(uint32_t width, uint32_t height) {
|
||||
/* If the client is anchored to two opposite edges, layer_surface.configure will return
|
||||
* size without margins for the axis.
|
||||
* layer_surface.set_size, however, expects size with margins for the anchored axis.
|
||||
* This is not specified by wlr-layer-shell and based on actual behavior of sway.
|
||||
*
|
||||
* If the size for unanchored axis is not set (0), change request to 1 to avoid automatic
|
||||
* assignment by the compositor.
|
||||
*/
|
||||
if ((anchor_ & VERTICAL_ANCHOR) == VERTICAL_ANCHOR) {
|
||||
width = width > 0 ? width : 1;
|
||||
if (height > 1) {
|
||||
height += margins_.top + margins_.bottom;
|
||||
}
|
||||
} else {
|
||||
height = height > 0 ? height : 1;
|
||||
if (width > 1) {
|
||||
width += margins_.right + margins_.left;
|
||||
}
|
||||
}
|
||||
spdlog::debug("Set surface size {}x{} for output {}", width, height, output_name_);
|
||||
zwlr_layer_surface_v1_set_size(layer_surface_.get(), width, height);
|
||||
}
|
||||
|
||||
static void onSurfaceConfigure(void* data, struct zwlr_layer_surface_v1* surface, uint32_t serial,
|
||||
uint32_t width, uint32_t height) {
|
||||
auto o = static_cast<RawSurfaceImpl*>(data);
|
||||
if (width != o->width_ || height != o->height_) {
|
||||
o->width_ = width;
|
||||
o->height_ = height;
|
||||
o->window_.set_size_request(o->width_, o->height_);
|
||||
o->window_.resize(o->width_, o->height_);
|
||||
o->setExclusiveZone(o->exclusive_zone_);
|
||||
spdlog::info(BAR_SIZE_MSG,
|
||||
o->width_ == 1 ? "auto" : std::to_string(o->width_),
|
||||
o->height_ == 1 ? "auto" : std::to_string(o->height_),
|
||||
o->output_name_);
|
||||
o->commit();
|
||||
}
|
||||
zwlr_layer_surface_v1_ack_configure(surface, serial);
|
||||
}
|
||||
|
||||
static void onSurfaceClosed(void* data, struct zwlr_layer_surface_v1* /* surface */) {
|
||||
auto o = static_cast<RawSurfaceImpl*>(data);
|
||||
o->layer_surface_.reset();
|
||||
}
|
||||
};
|
||||
|
||||
}; // namespace waybar
|
||||
|
||||
waybar::Bar::Bar(struct waybar_output* w_output, const Json::Value& w_config)
|
||||
: output(w_output),
|
||||
config(w_config),
|
||||
window{Gtk::WindowType::WINDOW_TOPLEVEL},
|
||||
surface(nullptr),
|
||||
layer_surface(nullptr),
|
||||
anchor_(ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP),
|
||||
layer_{bar_layer::BOTTOM},
|
||||
left_(Gtk::ORIENTATION_HORIZONTAL, 0),
|
||||
center_(Gtk::ORIENTATION_HORIZONTAL, 0),
|
||||
right_(Gtk::ORIENTATION_HORIZONTAL, 0),
|
||||
@ -18,32 +400,33 @@ waybar::Bar::Bar(struct waybar_output* w_output, const Json::Value& w_config)
|
||||
window.set_name("waybar");
|
||||
window.set_decorated(false);
|
||||
window.get_style_context()->add_class(output->name);
|
||||
window.get_style_context()->add_class(config["name"].asString());
|
||||
window.get_style_context()->add_class(config["position"].asString());
|
||||
|
||||
if (config["position"] == "right" || config["position"] == "left") {
|
||||
height_ = 0;
|
||||
width_ = 1;
|
||||
if (config["layer"] == "top") {
|
||||
layer_ = bar_layer::TOP;
|
||||
} else if (config["layer"] == "overlay") {
|
||||
layer_ = bar_layer::OVERLAY;
|
||||
}
|
||||
height_ = config["height"].isUInt() ? config["height"].asUInt() : height_;
|
||||
width_ = config["width"].isUInt() ? config["width"].asUInt() : width_;
|
||||
|
||||
window.signal_realize().connect_notify(sigc::mem_fun(*this, &Bar::onRealize));
|
||||
window.signal_map_event().connect_notify(sigc::mem_fun(*this, &Bar::onMap));
|
||||
window.signal_configure_event().connect_notify(sigc::mem_fun(*this, &Bar::onConfigure));
|
||||
window.set_size_request(width_, height_);
|
||||
|
||||
if (config["position"] == "bottom") {
|
||||
anchor_ = ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM;
|
||||
} else if (config["position"] == "left") {
|
||||
anchor_ = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT;
|
||||
} else if (config["position"] == "right") {
|
||||
anchor_ = ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT;
|
||||
if (config["exclusive"].isBool()) {
|
||||
exclusive = config["exclusive"].asBool();
|
||||
} else if (layer_ == bar_layer::OVERLAY) {
|
||||
// swaybar defaults: overlay mode does not reserve an exclusive zone
|
||||
exclusive = false;
|
||||
}
|
||||
if (anchor_ == ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM ||
|
||||
anchor_ == ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP) {
|
||||
anchor_ |= ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT;
|
||||
} else if (anchor_ == ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT ||
|
||||
anchor_ == ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT) {
|
||||
anchor_ |= ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM;
|
||||
|
||||
bool passthrough = false;
|
||||
if (config["passthrough"].isBool()) {
|
||||
passthrough = config["passthrough"].asBool();
|
||||
} else if (layer_ == bar_layer::OVERLAY) {
|
||||
// swaybar defaults: overlay mode does not accept pointer events.
|
||||
passthrough = true;
|
||||
}
|
||||
|
||||
auto position = config["position"].asString();
|
||||
|
||||
if (position == "right" || position == "left") {
|
||||
left_ = Gtk::Box(Gtk::ORIENTATION_VERTICAL, 0);
|
||||
center_ = Gtk::Box(Gtk::ORIENTATION_VERTICAL, 0);
|
||||
right_ = Gtk::Box(Gtk::ORIENTATION_VERTICAL, 0);
|
||||
@ -51,74 +434,15 @@ waybar::Bar::Bar(struct waybar_output* w_output, const Json::Value& w_config)
|
||||
vertical = true;
|
||||
}
|
||||
|
||||
setupWidgets();
|
||||
left_.get_style_context()->add_class("modules-left");
|
||||
center_.get_style_context()->add_class("modules-center");
|
||||
right_.get_style_context()->add_class("modules-right");
|
||||
|
||||
if (window.get_realized()) {
|
||||
onRealize();
|
||||
}
|
||||
window.show_all();
|
||||
}
|
||||
uint32_t height = config["height"].isUInt() ? config["height"].asUInt() : 0;
|
||||
uint32_t width = config["width"].isUInt() ? config["width"].asUInt() : 0;
|
||||
|
||||
void waybar::Bar::onConfigure(GdkEventConfigure* ev) {
|
||||
auto tmp_height = height_;
|
||||
auto tmp_width = width_;
|
||||
if (ev->height > static_cast<int>(height_)) {
|
||||
// Default minimal value
|
||||
if (height_ != 1) {
|
||||
spdlog::warn(MIN_HEIGHT_MSG, height_, ev->height);
|
||||
}
|
||||
if (config["height"].isUInt()) {
|
||||
spdlog::info(SIZE_DEFINED, "Height");
|
||||
} else {
|
||||
tmp_height = ev->height;
|
||||
}
|
||||
}
|
||||
if (ev->width > static_cast<int>(width_)) {
|
||||
// Default minimal value
|
||||
if (width_ != 1) {
|
||||
spdlog::warn(MIN_WIDTH_MSG, width_, ev->width);
|
||||
}
|
||||
if (config["width"].isUInt()) {
|
||||
spdlog::info(SIZE_DEFINED, "Width");
|
||||
} else {
|
||||
tmp_width = ev->width;
|
||||
}
|
||||
}
|
||||
if (tmp_width != width_ || tmp_height != height_) {
|
||||
zwlr_layer_surface_v1_set_size(layer_surface, tmp_width, tmp_height);
|
||||
}
|
||||
}
|
||||
struct bar_margins margins_;
|
||||
|
||||
void waybar::Bar::onRealize() {
|
||||
auto gdk_window = window.get_window()->gobj();
|
||||
gdk_wayland_window_set_use_custom_surface(gdk_window);
|
||||
}
|
||||
|
||||
void waybar::Bar::onMap(GdkEventAny* ev) {
|
||||
auto gdk_window = window.get_window()->gobj();
|
||||
surface = gdk_wayland_window_get_wl_surface(gdk_window);
|
||||
|
||||
auto client = waybar::Client::inst();
|
||||
auto layer =
|
||||
config["layer"] == "top" ? ZWLR_LAYER_SHELL_V1_LAYER_TOP : ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM;
|
||||
layer_surface = zwlr_layer_shell_v1_get_layer_surface(
|
||||
client->layer_shell, surface, output->output, layer, "waybar");
|
||||
|
||||
zwlr_layer_surface_v1_set_keyboard_interactivity(layer_surface, false);
|
||||
zwlr_layer_surface_v1_set_anchor(layer_surface, anchor_);
|
||||
zwlr_layer_surface_v1_set_size(layer_surface, width_, height_);
|
||||
setMarginsAndZone(height_, width_);
|
||||
static const struct zwlr_layer_surface_v1_listener layer_surface_listener = {
|
||||
.configure = layerSurfaceHandleConfigure,
|
||||
.closed = layerSurfaceHandleClosed,
|
||||
};
|
||||
zwlr_layer_surface_v1_add_listener(layer_surface, &layer_surface_listener, this);
|
||||
|
||||
wl_surface_commit(surface);
|
||||
wl_display_roundtrip(client->wl_display);
|
||||
}
|
||||
|
||||
void waybar::Bar::setMarginsAndZone(uint32_t height, uint32_t width) {
|
||||
if (config["margin-top"].isInt() || config["margin-right"].isInt() ||
|
||||
config["margin-bottom"].isInt() || config["margin-left"].isInt()) {
|
||||
margins_ = {
|
||||
@ -163,12 +487,65 @@ void waybar::Bar::setMarginsAndZone(uint32_t height, uint32_t width) {
|
||||
auto gaps = config["margin"].asInt();
|
||||
margins_ = {.top = gaps, .right = gaps, .bottom = gaps, .left = gaps};
|
||||
}
|
||||
zwlr_layer_surface_v1_set_margin(
|
||||
layer_surface, margins_.top, margins_.right, margins_.bottom, margins_.left);
|
||||
auto zone = vertical ? width + margins_.right : height + margins_.bottom;
|
||||
zwlr_layer_surface_v1_set_exclusive_zone(layer_surface, zone);
|
||||
|
||||
#ifdef HAVE_GTK_LAYER_SHELL
|
||||
bool use_gls = config["gtk-layer-shell"].isBool() ? config["gtk-layer-shell"].asBool() : true;
|
||||
if (use_gls) {
|
||||
surface_impl_ = std::make_unique<GLSSurfaceImpl>(window, *output);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
surface_impl_ = std::make_unique<RawSurfaceImpl>(window, *output);
|
||||
}
|
||||
|
||||
surface_impl_->setLayer(layer_);
|
||||
surface_impl_->setExclusiveZone(exclusive);
|
||||
surface_impl_->setMargins(margins_);
|
||||
surface_impl_->setPassThrough(passthrough);
|
||||
surface_impl_->setPosition(position);
|
||||
surface_impl_->setSize(width, height);
|
||||
|
||||
window.signal_map_event().connect_notify(sigc::mem_fun(*this, &Bar::onMap));
|
||||
|
||||
setupWidgets();
|
||||
window.show_all();
|
||||
|
||||
if (spdlog::should_log(spdlog::level::debug)) {
|
||||
// Unfortunately, this function isn't in the C++ bindings, so we have to call the C version.
|
||||
char* gtk_tree = gtk_style_context_to_string(
|
||||
window.get_style_context()->gobj(),
|
||||
(GtkStyleContextPrintFlags)(GTK_STYLE_CONTEXT_PRINT_RECURSE |
|
||||
GTK_STYLE_CONTEXT_PRINT_SHOW_STYLE));
|
||||
spdlog::debug("GTK widget tree:\n{}", gtk_tree);
|
||||
g_free(gtk_tree);
|
||||
}
|
||||
}
|
||||
|
||||
void waybar::Bar::onMap(GdkEventAny*) {
|
||||
/*
|
||||
* Obtain a pointer to the custom layer surface for modules that require it (idle_inhibitor).
|
||||
*/
|
||||
auto gdk_window = window.get_window()->gobj();
|
||||
surface = gdk_wayland_window_get_wl_surface(gdk_window);
|
||||
}
|
||||
|
||||
void waybar::Bar::setVisible(bool value) {
|
||||
visible = value;
|
||||
if (!visible) {
|
||||
window.get_style_context()->add_class("hidden");
|
||||
window.set_opacity(0);
|
||||
surface_impl_->setLayer(bar_layer::BOTTOM);
|
||||
} else {
|
||||
window.get_style_context()->remove_class("hidden");
|
||||
window.set_opacity(1);
|
||||
surface_impl_->setLayer(layer_);
|
||||
}
|
||||
surface_impl_->setExclusiveZone(exclusive && visible);
|
||||
surface_impl_->commit();
|
||||
}
|
||||
|
||||
void waybar::Bar::toggle() { setVisible(!visible); }
|
||||
|
||||
// Converting string to button code rn as to avoid doing it later
|
||||
void waybar::Bar::setupAltFormatKeyForModule(const std::string& module_name) {
|
||||
if (config.isMember(module_name)) {
|
||||
@ -230,48 +607,6 @@ void waybar::Bar::handleSignal(int signal) {
|
||||
}
|
||||
}
|
||||
|
||||
void waybar::Bar::layerSurfaceHandleConfigure(void* data, struct zwlr_layer_surface_v1* surface,
|
||||
uint32_t serial, uint32_t width, uint32_t height) {
|
||||
auto o = static_cast<waybar::Bar*>(data);
|
||||
if (width != o->width_ || height != o->height_) {
|
||||
o->width_ = width;
|
||||
o->height_ = height;
|
||||
o->window.set_size_request(o->width_, o->height_);
|
||||
o->window.resize(o->width_, o->height_);
|
||||
auto zone = o->vertical ? width + o->margins_.right : height + o->margins_.bottom;
|
||||
zwlr_layer_surface_v1_set_exclusive_zone(o->layer_surface, zone);
|
||||
spdlog::info(BAR_SIZE_MSG,
|
||||
o->width_ == 1 ? "auto" : std::to_string(o->width_),
|
||||
o->height_ == 1 ? "auto" : std::to_string(o->height_),
|
||||
o->output->name);
|
||||
wl_surface_commit(o->surface);
|
||||
}
|
||||
zwlr_layer_surface_v1_ack_configure(surface, serial);
|
||||
}
|
||||
|
||||
void waybar::Bar::layerSurfaceHandleClosed(void* data, struct zwlr_layer_surface_v1* /*surface*/) {
|
||||
auto o = static_cast<waybar::Bar*>(data);
|
||||
if (o->layer_surface) {
|
||||
zwlr_layer_surface_v1_destroy(o->layer_surface);
|
||||
o->layer_surface = nullptr;
|
||||
}
|
||||
o->modules_left_.clear();
|
||||
o->modules_center_.clear();
|
||||
o->modules_right_.clear();
|
||||
}
|
||||
|
||||
auto waybar::Bar::toggle() -> void {
|
||||
visible = !visible;
|
||||
auto zone = visible ? height_ : 0;
|
||||
if (!visible) {
|
||||
window.get_style_context()->add_class("hidden");
|
||||
} else {
|
||||
window.get_style_context()->remove_class("hidden");
|
||||
}
|
||||
zwlr_layer_surface_v1_set_exclusive_zone(layer_surface, zone);
|
||||
wl_surface_commit(surface);
|
||||
}
|
||||
|
||||
void waybar::Bar::getModules(const Factory& factory, const std::string& pos) {
|
||||
if (config[pos].isArray()) {
|
||||
for (const auto& name : config[pos]) {
|
||||
@ -302,9 +637,9 @@ void waybar::Bar::getModules(const Factory& factory, const std::string& pos) {
|
||||
|
||||
auto waybar::Bar::setupWidgets() -> void {
|
||||
window.add(box_);
|
||||
box_.pack_start(left_, true, true);
|
||||
box_.pack_start(left_, false, false);
|
||||
box_.set_center_widget(center_);
|
||||
box_.pack_end(right_, true, true);
|
||||
box_.pack_end(right_, false, false);
|
||||
|
||||
// Convert to button code for every module that is used.
|
||||
setupAltFormatKeyForModuleList("modules-left");
|
||||
@ -316,13 +651,13 @@ auto waybar::Bar::setupWidgets() -> void {
|
||||
getModules(factory, "modules-center");
|
||||
getModules(factory, "modules-right");
|
||||
for (auto const& module : modules_left_) {
|
||||
left_.pack_start(*module, false, true, 0);
|
||||
left_.pack_start(*module, false, false);
|
||||
}
|
||||
for (auto const& module : modules_center_) {
|
||||
center_.pack_start(*module, true, true, 0);
|
||||
center_.pack_start(*module, false, false);
|
||||
}
|
||||
std::reverse(modules_right_.begin(), modules_right_.end());
|
||||
for (auto const& module : modules_right_) {
|
||||
right_.pack_end(*module, false, false, 0);
|
||||
right_.pack_end(*module, false, false);
|
||||
}
|
||||
}
|
||||
|
282
src/client.cpp
282
src/client.cpp
@ -1,9 +1,15 @@
|
||||
#include "client.hpp"
|
||||
|
||||
#include <fmt/ostream.h>
|
||||
#include <spdlog/spdlog.h>
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
#include "idle-inhibit-unstable-v1-client-protocol.h"
|
||||
#include "util/clara.hpp"
|
||||
#include "util/json.hpp"
|
||||
#include "wlr-layer-shell-unstable-v1-client-protocol.h"
|
||||
|
||||
waybar::Client *waybar::Client::inst() {
|
||||
static auto c = new Client();
|
||||
@ -31,13 +37,10 @@ void waybar::Client::handleGlobal(void *data, struct wl_registry *registry, uint
|
||||
const char *interface, uint32_t version) {
|
||||
auto client = static_cast<Client *>(data);
|
||||
if (strcmp(interface, zwlr_layer_shell_v1_interface.name) == 0) {
|
||||
// limit version to a highest supported by the client protocol file
|
||||
version = std::min<uint32_t>(version, zwlr_layer_shell_v1_interface.version);
|
||||
client->layer_shell = static_cast<struct zwlr_layer_shell_v1 *>(
|
||||
wl_registry_bind(registry, name, &zwlr_layer_shell_v1_interface, version));
|
||||
} else if (strcmp(interface, wl_output_interface.name) == 0) {
|
||||
auto wl_output = static_cast<struct wl_output *>(
|
||||
wl_registry_bind(registry, name, &wl_output_interface, version));
|
||||
client->outputs_.emplace_back(new struct waybar_output({wl_output, "", name, nullptr}));
|
||||
client->handleOutput(client->outputs_.back());
|
||||
} else if (strcmp(interface, zxdg_output_manager_v1_interface.name) == 0 &&
|
||||
version >= ZXDG_OUTPUT_V1_NAME_SINCE_VERSION) {
|
||||
client->xdg_output_manager = static_cast<struct zxdg_output_manager_v1 *>(wl_registry_bind(
|
||||
@ -50,85 +53,56 @@ void waybar::Client::handleGlobal(void *data, struct wl_registry *registry, uint
|
||||
|
||||
void waybar::Client::handleGlobalRemove(void * data, struct wl_registry * /*registry*/,
|
||||
uint32_t name) {
|
||||
auto client = static_cast<Client *>(data);
|
||||
for (auto it = client->bars.begin(); it != client->bars.end();) {
|
||||
if ((*it)->output->wl_name == name) {
|
||||
auto output_name = (*it)->output->name;
|
||||
(*it)->window.close();
|
||||
it = client->bars.erase(it);
|
||||
spdlog::info("Bar removed from output: {}", output_name);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
auto it = std::find_if(client->outputs_.begin(),
|
||||
client->outputs_.end(),
|
||||
[&name](const auto &output) { return output->wl_name == name; });
|
||||
if (it != client->outputs_.end()) {
|
||||
zxdg_output_v1_destroy((*it)->xdg_output);
|
||||
wl_output_destroy((*it)->output);
|
||||
client->outputs_.erase(it);
|
||||
}
|
||||
// Nothing here
|
||||
}
|
||||
|
||||
void waybar::Client::handleOutput(std::unique_ptr<struct waybar_output> &output) {
|
||||
void waybar::Client::handleOutput(struct waybar_output &output) {
|
||||
static const struct zxdg_output_v1_listener xdgOutputListener = {
|
||||
.logical_position = handleLogicalPosition,
|
||||
.logical_size = handleLogicalSize,
|
||||
.done = handleDone,
|
||||
.name = handleName,
|
||||
.description = handleDescription,
|
||||
.logical_position = [](void *, struct zxdg_output_v1 *, int32_t, int32_t) {},
|
||||
.logical_size = [](void *, struct zxdg_output_v1 *, int32_t, int32_t) {},
|
||||
.done = &handleOutputDone,
|
||||
.name = &handleOutputName,
|
||||
.description = &handleOutputDescription,
|
||||
};
|
||||
output->xdg_output = zxdg_output_manager_v1_get_xdg_output(xdg_output_manager, output->output);
|
||||
zxdg_output_v1_add_listener(output->xdg_output, &xdgOutputListener, &output->wl_name);
|
||||
// owned by output->monitor; no need to destroy
|
||||
auto wl_output = gdk_wayland_monitor_get_wl_output(output.monitor->gobj());
|
||||
output.xdg_output.reset(zxdg_output_manager_v1_get_xdg_output(xdg_output_manager, wl_output));
|
||||
zxdg_output_v1_add_listener(output.xdg_output.get(), &xdgOutputListener, &output);
|
||||
}
|
||||
|
||||
void waybar::Client::handleLogicalPosition(void * /*data*/,
|
||||
struct zxdg_output_v1 * /*zxdg_output_v1*/,
|
||||
int32_t /*x*/, int32_t /*y*/) {
|
||||
// Nothing here
|
||||
}
|
||||
|
||||
void waybar::Client::handleLogicalSize(void * /*data*/, struct zxdg_output_v1 * /*zxdg_output_v1*/,
|
||||
int32_t /*width*/, int32_t /*height*/) {
|
||||
// Nothing here
|
||||
}
|
||||
|
||||
void waybar::Client::handleDone(void * /*data*/, struct zxdg_output_v1 * /*zxdg_output_v1*/) {
|
||||
// Nothing here
|
||||
}
|
||||
|
||||
bool waybar::Client::isValidOutput(const Json::Value & config,
|
||||
std::unique_ptr<struct waybar_output> &output) {
|
||||
bool found = true;
|
||||
bool waybar::Client::isValidOutput(const Json::Value &config, struct waybar_output &output) {
|
||||
if (config["output"].isArray()) {
|
||||
bool in_array = false;
|
||||
for (auto const &output_conf : config["output"]) {
|
||||
if (output_conf.isString() && output_conf.asString() == output->name) {
|
||||
in_array = true;
|
||||
break;
|
||||
if (output_conf.isString() &&
|
||||
(output_conf.asString() == output.name || output_conf.asString() == output.identifier)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
found = in_array;
|
||||
return false;
|
||||
} else if (config["output"].isString()) {
|
||||
auto config_output = config["output"].asString();
|
||||
if (!config_output.empty()) {
|
||||
if (config_output.substr(0, 1) == "!") {
|
||||
return config_output.substr(1) != output.name &&
|
||||
config_output.substr(1) != output.identifier;
|
||||
}
|
||||
return config_output == output.name || config_output == output.identifier;
|
||||
}
|
||||
}
|
||||
if (config["output"].isString() && config["output"].asString() != output->name) {
|
||||
found = false;
|
||||
}
|
||||
return found;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::unique_ptr<struct waybar::waybar_output> &waybar::Client::getOutput(uint32_t wl_name) {
|
||||
auto it = std::find_if(outputs_.begin(), outputs_.end(), [&wl_name](const auto &output) {
|
||||
return output->wl_name == wl_name;
|
||||
});
|
||||
struct waybar::waybar_output &waybar::Client::getOutput(void *addr) {
|
||||
auto it = std::find_if(
|
||||
outputs_.begin(), outputs_.end(), [&addr](const auto &output) { return &output == addr; });
|
||||
if (it == outputs_.end()) {
|
||||
throw std::runtime_error("Unable to find valid output");
|
||||
}
|
||||
return *it;
|
||||
}
|
||||
|
||||
std::vector<Json::Value> waybar::Client::getOutputConfigs(
|
||||
std::unique_ptr<struct waybar_output> &output) {
|
||||
std::vector<Json::Value> waybar::Client::getOutputConfigs(struct waybar_output &output) {
|
||||
std::vector<Json::Value> configs;
|
||||
if (config_.isArray()) {
|
||||
for (auto const &config : config_) {
|
||||
@ -142,24 +116,28 @@ std::vector<Json::Value> waybar::Client::getOutputConfigs(
|
||||
return configs;
|
||||
}
|
||||
|
||||
void waybar::Client::handleName(void * data, struct zxdg_output_v1 * /*xdg_output*/,
|
||||
const char *name) {
|
||||
auto wl_name = *static_cast<uint32_t *>(data);
|
||||
void waybar::Client::handleOutputDone(void *data, struct zxdg_output_v1 * /*xdg_output*/) {
|
||||
auto client = waybar::Client::inst();
|
||||
try {
|
||||
auto &output = client->getOutput(wl_name);
|
||||
output->name = name;
|
||||
auto configs = client->getOutputConfigs(output);
|
||||
if (configs.empty()) {
|
||||
wl_output_destroy(output->output);
|
||||
zxdg_output_v1_destroy(output->xdg_output);
|
||||
} else {
|
||||
wl_display_roundtrip(client->wl_display);
|
||||
for (const auto &config : configs) {
|
||||
client->bars.emplace_back(std::make_unique<Bar>(output.get(), config));
|
||||
Glib::RefPtr<Gdk::Screen> screen = client->bars.back()->window.get_screen();
|
||||
client->style_context_->add_provider_for_screen(
|
||||
screen, client->css_provider_, GTK_STYLE_PROVIDER_PRIORITY_USER);
|
||||
auto &output = client->getOutput(data);
|
||||
/**
|
||||
* Multiple .done events may arrive in batch. In this case libwayland would queue
|
||||
* xdg_output.destroy and dispatch all pending events, triggering this callback several times
|
||||
* for the same output. .done events can also arrive after that for a scale or position changes.
|
||||
* We wouldn't want to draw a duplicate bar for each such event either.
|
||||
*
|
||||
* All the properties we care about are immutable so it's safe to delete the xdg_output object
|
||||
* on the first event and use the ptr value to check that the callback was already invoked.
|
||||
*/
|
||||
if (output.xdg_output) {
|
||||
output.xdg_output.reset();
|
||||
spdlog::debug("Output detection done: {} ({})", output.name, output.identifier);
|
||||
|
||||
auto configs = client->getOutputConfigs(output);
|
||||
if (!configs.empty()) {
|
||||
for (const auto &config : configs) {
|
||||
client->bars.emplace_back(std::make_unique<Bar>(&output, config));
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (const std::exception &e) {
|
||||
@ -167,18 +145,76 @@ void waybar::Client::handleName(void * data, struct zxdg_output_v1 * /*xdg_
|
||||
}
|
||||
}
|
||||
|
||||
void waybar::Client::handleDescription(void * /*data*/, struct zxdg_output_v1 * /*zxdg_output_v1*/,
|
||||
const char * /*description*/) {
|
||||
// Nothing here
|
||||
void waybar::Client::handleOutputName(void * data, struct zxdg_output_v1 * /*xdg_output*/,
|
||||
const char *name) {
|
||||
auto client = waybar::Client::inst();
|
||||
try {
|
||||
auto &output = client->getOutput(data);
|
||||
output.name = name;
|
||||
} catch (const std::exception &e) {
|
||||
std::cerr << e.what() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void waybar::Client::handleOutputDescription(void *data, struct zxdg_output_v1 * /*xdg_output*/,
|
||||
const char *description) {
|
||||
auto client = waybar::Client::inst();
|
||||
try {
|
||||
auto & output = client->getOutput(data);
|
||||
const char *open_paren = strrchr(description, '(');
|
||||
|
||||
// Description format: "identifier (name)"
|
||||
size_t identifier_length = open_paren - description;
|
||||
output.identifier = std::string(description, identifier_length - 1);
|
||||
} catch (const std::exception &e) {
|
||||
std::cerr << e.what() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void waybar::Client::handleMonitorAdded(Glib::RefPtr<Gdk::Monitor> monitor) {
|
||||
auto &output = outputs_.emplace_back();
|
||||
output.monitor = monitor;
|
||||
handleOutput(output);
|
||||
}
|
||||
|
||||
void waybar::Client::handleMonitorRemoved(Glib::RefPtr<Gdk::Monitor> monitor) {
|
||||
spdlog::debug("Output removed: {} {}", monitor->get_manufacturer(), monitor->get_model());
|
||||
/* This event can be triggered from wl_display_roundtrip called by GTK or our code.
|
||||
* Defer destruction of bars for the output to the next iteration of the event loop to avoid
|
||||
* deleting objects referenced by currently executed code.
|
||||
*/
|
||||
Glib::signal_idle().connect_once(
|
||||
sigc::bind(sigc::mem_fun(*this, &Client::handleDeferredMonitorRemoval), monitor),
|
||||
Glib::PRIORITY_HIGH_IDLE);
|
||||
}
|
||||
|
||||
void waybar::Client::handleDeferredMonitorRemoval(Glib::RefPtr<Gdk::Monitor> monitor) {
|
||||
for (auto it = bars.begin(); it != bars.end();) {
|
||||
if ((*it)->output->monitor == monitor) {
|
||||
auto output_name = (*it)->output->name;
|
||||
(*it)->window.hide();
|
||||
gtk_app->remove_window((*it)->window);
|
||||
it = bars.erase(it);
|
||||
spdlog::info("Bar removed from output: {}", output_name);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
outputs_.remove_if([&monitor](const auto &output) { return output.monitor == monitor; });
|
||||
}
|
||||
|
||||
std::tuple<const std::string, const std::string> waybar::Client::getConfigs(
|
||||
const std::string &config, const std::string &style) const {
|
||||
auto config_file = config.empty() ? getValidPath({
|
||||
"$XDG_CONFIG_HOME/waybar/config",
|
||||
"$XDG_CONFIG_HOME/waybar/config.jsonc",
|
||||
"$HOME/.config/waybar/config",
|
||||
"$HOME/.config/waybar/config.jsonc",
|
||||
"$HOME/waybar/config",
|
||||
"$HOME/waybar/config.jsonc",
|
||||
"/etc/xdg/waybar/config",
|
||||
"/etc/xdg/waybar/config.jsonc",
|
||||
SYSCONFDIR "/xdg/waybar/config",
|
||||
"./resources/config",
|
||||
})
|
||||
: config;
|
||||
@ -187,6 +223,7 @@ std::tuple<const std::string, const std::string> waybar::Client::getConfigs(
|
||||
"$HOME/.config/waybar/style.css",
|
||||
"$HOME/waybar/style.css",
|
||||
"/etc/xdg/waybar/style.css",
|
||||
SYSCONFDIR "/xdg/waybar/style.css",
|
||||
"./resources/style.css",
|
||||
})
|
||||
: style;
|
||||
@ -197,14 +234,62 @@ std::tuple<const std::string, const std::string> waybar::Client::getConfigs(
|
||||
return {config_file, css_file};
|
||||
}
|
||||
|
||||
auto waybar::Client::setupConfig(const std::string &config_file) -> void {
|
||||
auto waybar::Client::setupConfig(const std::string &config_file, int depth) -> void {
|
||||
if (depth > 100) {
|
||||
throw std::runtime_error("Aborting due to likely recursive include in config files");
|
||||
}
|
||||
std::ifstream file(config_file);
|
||||
if (!file.is_open()) {
|
||||
throw std::runtime_error("Can't open config file");
|
||||
}
|
||||
std::string str((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
|
||||
util::JsonParser parser;
|
||||
config_ = parser.parse(str);
|
||||
Json::Value tmp_config_ = parser.parse(str);
|
||||
if (tmp_config_.isArray()) {
|
||||
for (auto &config_part : tmp_config_) {
|
||||
resolveConfigIncludes(config_part, depth);
|
||||
}
|
||||
} else {
|
||||
resolveConfigIncludes(tmp_config_, depth);
|
||||
}
|
||||
mergeConfig(config_, tmp_config_);
|
||||
}
|
||||
|
||||
auto waybar::Client::resolveConfigIncludes(Json::Value &config, int depth) -> void {
|
||||
Json::Value includes = config["include"];
|
||||
if (includes.isArray()) {
|
||||
for (const auto &include : includes) {
|
||||
spdlog::info("Including resource file: {}", include.asString());
|
||||
setupConfig(getValidPath({include.asString()}), ++depth);
|
||||
}
|
||||
} else if (includes.isString()) {
|
||||
spdlog::info("Including resource file: {}", includes.asString());
|
||||
setupConfig(getValidPath({includes.asString()}), ++depth);
|
||||
}
|
||||
}
|
||||
|
||||
auto waybar::Client::mergeConfig(Json::Value &a_config_, Json::Value &b_config_) -> void {
|
||||
if (!a_config_) {
|
||||
// For the first config
|
||||
a_config_ = b_config_;
|
||||
} else if (a_config_.isObject() && b_config_.isObject()) {
|
||||
for (const auto &key : b_config_.getMemberNames()) {
|
||||
if (a_config_[key].isObject() && b_config_[key].isObject()) {
|
||||
mergeConfig(a_config_[key], b_config_[key]);
|
||||
} else {
|
||||
a_config_[key] = b_config_[key];
|
||||
}
|
||||
}
|
||||
} else if (a_config_.isArray() && b_config_.isArray()) {
|
||||
// This can happen only on the top-level array of a multi-bar config
|
||||
for (Json::Value::ArrayIndex i = 0; i < b_config_.size(); i++) {
|
||||
if (a_config_[i].isObject() && b_config_[i].isObject()) {
|
||||
mergeConfig(a_config_[i], b_config_[i]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
spdlog::error("Cannot merge config, conflicting or invalid JSON types");
|
||||
}
|
||||
}
|
||||
|
||||
auto waybar::Client::setupCss(const std::string &css_file) -> void {
|
||||
@ -215,6 +300,9 @@ auto waybar::Client::setupCss(const std::string &css_file) -> void {
|
||||
if (!css_provider_->load_from_path(css_file)) {
|
||||
throw std::runtime_error("Can't open style file");
|
||||
}
|
||||
// there's always only one screen
|
||||
style_context_->add_provider_for_screen(
|
||||
Gdk::Screen::get_default(), css_provider_, GTK_STYLE_PROVIDER_PRIORITY_USER);
|
||||
}
|
||||
|
||||
void waybar::Client::bindInterfaces() {
|
||||
@ -228,6 +316,14 @@ void waybar::Client::bindInterfaces() {
|
||||
if (layer_shell == nullptr || xdg_output_manager == nullptr) {
|
||||
throw std::runtime_error("Failed to acquire required resources.");
|
||||
}
|
||||
// add existing outputs and subscribe to updates
|
||||
for (auto i = 0; i < gdk_display->get_n_monitors(); ++i) {
|
||||
auto monitor = gdk_display->get_monitor(i);
|
||||
handleMonitorAdded(monitor);
|
||||
}
|
||||
gdk_display->signal_monitor_added().connect(sigc::mem_fun(*this, &Client::handleMonitorAdded));
|
||||
gdk_display->signal_monitor_removed().connect(
|
||||
sigc::mem_fun(*this, &Client::handleMonitorRemoved));
|
||||
}
|
||||
|
||||
int waybar::Client::main(int argc, char *argv[]) {
|
||||
@ -261,7 +357,8 @@ int waybar::Client::main(int argc, char *argv[]) {
|
||||
if (!log_level.empty()) {
|
||||
spdlog::set_level(spdlog::level::from_str(log_level));
|
||||
}
|
||||
gtk_app = Gtk::Application::create(argc, argv, "fr.arouillard.waybar");
|
||||
gtk_app = Gtk::Application::create(
|
||||
argc, argv, "fr.arouillard.waybar", Gio::APPLICATION_HANDLES_COMMAND_LINE);
|
||||
gdk_display = Gdk::Display::get_default();
|
||||
if (!gdk_display) {
|
||||
throw std::runtime_error("Can't find display");
|
||||
@ -271,16 +368,15 @@ int waybar::Client::main(int argc, char *argv[]) {
|
||||
}
|
||||
wl_display = gdk_wayland_display_get_wl_display(gdk_display->gobj());
|
||||
auto [config_file, css_file] = getConfigs(config, style);
|
||||
setupConfig(config_file);
|
||||
setupConfig(config_file, 0);
|
||||
setupCss(css_file);
|
||||
bindInterfaces();
|
||||
gtk_app->hold();
|
||||
gtk_app->run();
|
||||
bars.clear();
|
||||
zxdg_output_manager_v1_destroy(xdg_output_manager);
|
||||
zwlr_layer_shell_v1_destroy(layer_shell);
|
||||
zwp_idle_inhibit_manager_v1_destroy(idle_inhibit_manager);
|
||||
wl_registry_destroy(registry);
|
||||
wl_display_disconnect(wl_display);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void waybar::Client::reset() {
|
||||
gtk_app->quit();
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ waybar::AModule* waybar::Factory::makeModule(const std::string& name) const {
|
||||
auto hash_pos = name.find('#');
|
||||
auto ref = name.substr(0, hash_pos);
|
||||
auto id = hash_pos != std::string::npos ? name.substr(hash_pos + 1) : "";
|
||||
#ifndef NO_FILESYSTEM
|
||||
#if defined(__linux__) && !defined(NO_FILESYSTEM)
|
||||
if (ref == "battery") {
|
||||
return new waybar::modules::Battery(id, config_[name]);
|
||||
}
|
||||
@ -22,20 +22,40 @@ waybar::AModule* waybar::Factory::makeModule(const std::string& name) const {
|
||||
if (ref == "sway/window") {
|
||||
return new waybar::modules::sway::Window(id, bar_, config_[name]);
|
||||
}
|
||||
if (ref == "sway/language") {
|
||||
return new waybar::modules::sway::Language(id, config_[name]);
|
||||
}
|
||||
#endif
|
||||
#ifdef HAVE_WLR
|
||||
if (ref == "wlr/taskbar") {
|
||||
return new waybar::modules::wlr::Taskbar(id, bar_, config_[name]);
|
||||
}
|
||||
#endif
|
||||
#ifdef HAVE_RIVER
|
||||
if (ref == "river/tags") {
|
||||
return new waybar::modules::river::Tags(id, bar_, config_[name]);
|
||||
}
|
||||
#endif
|
||||
if (ref == "idle_inhibitor") {
|
||||
return new waybar::modules::IdleInhibitor(id, bar_, config_[name]);
|
||||
}
|
||||
#if defined(HAVE_MEMORY_LINUX) || defined(HAVE_MEMORY_BSD)
|
||||
if (ref == "memory") {
|
||||
return new waybar::modules::Memory(id, config_[name]);
|
||||
}
|
||||
#endif
|
||||
#if defined(HAVE_CPU_LINUX) || defined(HAVE_CPU_BSD)
|
||||
if (ref == "cpu") {
|
||||
return new waybar::modules::Cpu(id, config_[name]);
|
||||
}
|
||||
#endif
|
||||
if (ref == "clock") {
|
||||
return new waybar::modules::Clock(id, config_[name]);
|
||||
}
|
||||
#if defined(HAVE_DBUSMENU) && !defined(NO_FILESYSTEM)
|
||||
if (ref == "disk") {
|
||||
return new waybar::modules::Disk(id, config_[name]);
|
||||
}
|
||||
#ifdef HAVE_DBUSMENU
|
||||
if (ref == "tray") {
|
||||
return new waybar::modules::SNI::Tray(id, bar_, config_[name]);
|
||||
}
|
||||
@ -50,6 +70,11 @@ waybar::AModule* waybar::Factory::makeModule(const std::string& name) const {
|
||||
return new waybar::modules::Backlight(id, config_[name]);
|
||||
}
|
||||
#endif
|
||||
#ifdef HAVE_LIBEVDEV
|
||||
if (ref == "keyboard-state") {
|
||||
return new waybar::modules::KeyboardState(id, bar_, config_[name]);
|
||||
}
|
||||
#endif
|
||||
#ifdef HAVE_LIBPULSE
|
||||
if (ref == "pulseaudio") {
|
||||
return new waybar::modules::Pulseaudio(id, config_[name]);
|
||||
@ -59,10 +84,22 @@ waybar::AModule* waybar::Factory::makeModule(const std::string& name) const {
|
||||
if (ref == "mpd") {
|
||||
return new waybar::modules::MPD(id, config_[name]);
|
||||
}
|
||||
#endif
|
||||
#ifdef HAVE_LIBSNDIO
|
||||
if (ref == "sndio") {
|
||||
return new waybar::modules::Sndio(id, config_[name]);
|
||||
}
|
||||
#endif
|
||||
if (ref == "temperature") {
|
||||
return new waybar::modules::Temperature(id, config_[name]);
|
||||
}
|
||||
#if defined(__linux__)
|
||||
# ifdef WANT_RFKILL
|
||||
if (ref == "bluetooth") {
|
||||
return new waybar::modules::Bluetooth(id, config_[name]);
|
||||
}
|
||||
# endif
|
||||
#endif
|
||||
if (ref.compare(0, 7, "custom/") == 0 && ref.size() > 7) {
|
||||
return new waybar::modules::Custom(ref.substr(7), id, config_[name]);
|
||||
}
|
||||
|
81
src/main.cpp
81
src/main.cpp
@ -1,16 +1,89 @@
|
||||
#include <csignal>
|
||||
#include <list>
|
||||
#include <mutex>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <spdlog/spdlog.h>
|
||||
#include "client.hpp"
|
||||
|
||||
std::mutex reap_mtx;
|
||||
std::list<pid_t> reap;
|
||||
volatile bool reload;
|
||||
|
||||
void* signalThread(void* args) {
|
||||
int err, signum;
|
||||
sigset_t mask;
|
||||
sigemptyset(&mask);
|
||||
sigaddset(&mask, SIGCHLD);
|
||||
|
||||
while (true) {
|
||||
err = sigwait(&mask, &signum);
|
||||
if (err != 0) {
|
||||
spdlog::error("sigwait failed: {}", strerror(errno));
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (signum) {
|
||||
case SIGCHLD:
|
||||
spdlog::debug("Received SIGCHLD in signalThread");
|
||||
if (!reap.empty()) {
|
||||
reap_mtx.lock();
|
||||
for (auto it = reap.begin(); it != reap.end(); ++it) {
|
||||
if (waitpid(*it, nullptr, WNOHANG) == *it) {
|
||||
spdlog::debug("Reaped child with PID: {}", *it);
|
||||
it = reap.erase(it);
|
||||
}
|
||||
}
|
||||
reap_mtx.unlock();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
spdlog::debug("Received signal with number {}, but not handling",
|
||||
signum);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void startSignalThread(void) {
|
||||
int err;
|
||||
sigset_t mask;
|
||||
sigemptyset(&mask);
|
||||
sigaddset(&mask, SIGCHLD);
|
||||
|
||||
// Block SIGCHLD so it can be handled by the signal thread
|
||||
// Any threads created by this one (the main thread) should not
|
||||
// modify their signal mask to unblock SIGCHLD
|
||||
err = pthread_sigmask(SIG_BLOCK, &mask, nullptr);
|
||||
if (err != 0) {
|
||||
spdlog::error("pthread_sigmask failed in startSignalThread: {}", strerror(err));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
pthread_t thread_id;
|
||||
err = pthread_create(&thread_id, nullptr, signalThread, nullptr);
|
||||
if (err != 0) {
|
||||
spdlog::error("pthread_create failed in startSignalThread: {}", strerror(err));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
try {
|
||||
auto client = waybar::Client::inst();
|
||||
|
||||
std::signal(SIGUSR1, [](int /*signal*/) {
|
||||
for (auto& bar : waybar::Client::inst()->bars) {
|
||||
bar->toggle();
|
||||
}
|
||||
});
|
||||
|
||||
std::signal(SIGUSR2, [](int /*signal*/) {
|
||||
spdlog::info("Reloading...");
|
||||
reload = true;
|
||||
waybar::Client::inst()->reset();
|
||||
});
|
||||
|
||||
for (int sig = SIGRTMIN + 1; sig <= SIGRTMAX; ++sig) {
|
||||
std::signal(sig, [](int sig) {
|
||||
for (auto& bar : waybar::Client::inst()->bars) {
|
||||
@ -18,8 +91,14 @@ int main(int argc, char* argv[]) {
|
||||
}
|
||||
});
|
||||
}
|
||||
startSignalThread();
|
||||
|
||||
auto ret = 0;
|
||||
do {
|
||||
reload = false;
|
||||
ret = client->main(argc, argv);
|
||||
} while (reload);
|
||||
|
||||
auto ret = client->main(argc, argv);
|
||||
delete client;
|
||||
return ret;
|
||||
} catch (const std::exception& e) {
|
||||
|
@ -1,16 +1,14 @@
|
||||
#include "modules/backlight.hpp"
|
||||
|
||||
#include <fmt/format.h>
|
||||
#include <libudev.h>
|
||||
#include <sys/epoll.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
|
||||
#include <libudev.h>
|
||||
|
||||
#include <sys/epoll.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <fmt/format.h>
|
||||
|
||||
namespace {
|
||||
class FileDescriptor {
|
||||
public:
|
||||
@ -187,6 +185,8 @@ auto waybar::modules::Backlight::update() -> void {
|
||||
}
|
||||
previous_best_ = best == nullptr ? std::nullopt : std::optional{*best};
|
||||
previous_format_ = format_;
|
||||
// Call parent update
|
||||
ALabel::update();
|
||||
}
|
||||
|
||||
template <class ForwardIt>
|
||||
@ -211,7 +211,7 @@ void waybar::modules::Backlight::upsert_device(ForwardIt first, ForwardIt last,
|
||||
check_nn(name);
|
||||
|
||||
const char *actual_brightness_attr =
|
||||
strcmp(name, "amdgpu_bl0") == 0 ? "brightness" : "actual_brightness";
|
||||
strncmp(name, "amdgpu_bl", 9) == 0 ? "brightness" : "actual_brightness";
|
||||
|
||||
const char *actual = udev_device_get_sysattr_value(dev, actual_brightness_attr);
|
||||
check_nn(actual);
|
||||
|
@ -1,48 +1,85 @@
|
||||
#include "modules/battery.hpp"
|
||||
|
||||
#include <spdlog/spdlog.h>
|
||||
|
||||
waybar::modules::Battery::Battery(const std::string& id, const Json::Value& config)
|
||||
: ALabel(config, "battery", id, "{capacity}%", 60) {
|
||||
getBatteries();
|
||||
fd_ = inotify_init1(IN_CLOEXEC);
|
||||
if (fd_ == -1) {
|
||||
battery_watch_fd_ = inotify_init1(IN_CLOEXEC);
|
||||
if (battery_watch_fd_ == -1) {
|
||||
throw std::runtime_error("Unable to listen batteries.");
|
||||
}
|
||||
for (auto const& bat : batteries_) {
|
||||
auto wd = inotify_add_watch(fd_, (bat / "uevent").c_str(), IN_ACCESS);
|
||||
if (wd != -1) {
|
||||
wds_.push_back(wd);
|
||||
}
|
||||
|
||||
global_watch_fd_ = inotify_init1(IN_CLOEXEC);
|
||||
if (global_watch_fd_ == -1) {
|
||||
throw std::runtime_error("Unable to listen batteries.");
|
||||
}
|
||||
|
||||
// Watch the directory for any added or removed batteries
|
||||
global_watch = inotify_add_watch(global_watch_fd_, data_dir_.c_str(), IN_CREATE | IN_DELETE);
|
||||
if (global_watch < 0) {
|
||||
throw std::runtime_error("Could not watch for battery plug/unplug");
|
||||
}
|
||||
|
||||
refreshBatteries();
|
||||
worker();
|
||||
}
|
||||
|
||||
waybar::modules::Battery::~Battery() {
|
||||
for (auto wd : wds_) {
|
||||
inotify_rm_watch(fd_, wd);
|
||||
std::lock_guard<std::mutex> guard(battery_list_mutex_);
|
||||
|
||||
if (global_watch >= 0) {
|
||||
inotify_rm_watch(global_watch_fd_, global_watch);
|
||||
}
|
||||
close(fd_);
|
||||
close(global_watch_fd_);
|
||||
|
||||
for (auto it = batteries_.cbegin(); it != batteries_.cend(); it++) {
|
||||
auto watch_id = (*it).second;
|
||||
if (watch_id >= 0) {
|
||||
inotify_rm_watch(battery_watch_fd_, watch_id);
|
||||
}
|
||||
batteries_.erase(it);
|
||||
}
|
||||
close(battery_watch_fd_);
|
||||
}
|
||||
|
||||
void waybar::modules::Battery::worker() {
|
||||
thread_timer_ = [this] {
|
||||
// Make sure we eventually update the list of batteries even if we miss an
|
||||
// inotify event for some reason
|
||||
refreshBatteries();
|
||||
dp.emit();
|
||||
thread_timer_.sleep_for(interval_);
|
||||
};
|
||||
thread_ = [this] {
|
||||
struct inotify_event event = {0};
|
||||
int nbytes = read(fd_, &event, sizeof(event));
|
||||
int nbytes = read(battery_watch_fd_, &event, sizeof(event));
|
||||
if (nbytes != sizeof(event) || event.mask & IN_IGNORED) {
|
||||
thread_.stop();
|
||||
return;
|
||||
}
|
||||
// TODO: don't stop timer for now since there is some bugs :?
|
||||
// thread_timer_.stop();
|
||||
dp.emit();
|
||||
};
|
||||
thread_battery_update_ = [this] {
|
||||
struct inotify_event event = {0};
|
||||
int nbytes = read(global_watch_fd_, &event, sizeof(event));
|
||||
if (nbytes != sizeof(event) || event.mask & IN_IGNORED) {
|
||||
thread_.stop();
|
||||
return;
|
||||
}
|
||||
refreshBatteries();
|
||||
dp.emit();
|
||||
};
|
||||
}
|
||||
|
||||
void waybar::modules::Battery::getBatteries() {
|
||||
void waybar::modules::Battery::refreshBatteries() {
|
||||
std::lock_guard<std::mutex> guard(battery_list_mutex_);
|
||||
|
||||
// Mark existing list of batteries as not necessarily found
|
||||
std::map<fs::path, bool> check_map;
|
||||
for (auto const& bat : batteries_) {
|
||||
check_map[bat.first] = false;
|
||||
}
|
||||
|
||||
try {
|
||||
for (auto& node : fs::directory_iterator(data_dir_)) {
|
||||
if (!fs::is_directory(node)) {
|
||||
@ -52,8 +89,23 @@ void waybar::modules::Battery::getBatteries() {
|
||||
auto bat_defined = config_["bat"].isString();
|
||||
if (((bat_defined && dir_name == config_["bat"].asString()) || !bat_defined) &&
|
||||
fs::exists(node.path() / "capacity") && fs::exists(node.path() / "uevent") &&
|
||||
fs::exists(node.path() / "status")) {
|
||||
batteries_.push_back(node.path());
|
||||
fs::exists(node.path() / "status") && fs::exists(node.path() / "type")) {
|
||||
std::string type;
|
||||
std::ifstream(node.path() / "type") >> type;
|
||||
|
||||
if (!type.compare("Battery")){
|
||||
check_map[node.path()] = true;
|
||||
auto search = batteries_.find(node.path());
|
||||
if (search == batteries_.end()) {
|
||||
// We've found a new battery save it and start listening for events
|
||||
auto event_path = (node.path() / "uevent");
|
||||
auto wd = inotify_add_watch(battery_watch_fd_, event_path.c_str(), IN_ACCESS);
|
||||
if (wd < 0) {
|
||||
throw std::runtime_error("Could not watch events for " + node.path().string());
|
||||
}
|
||||
batteries_[node.path()] = wd;
|
||||
}
|
||||
}
|
||||
}
|
||||
auto adap_defined = config_["adapter"].isString();
|
||||
if (((adap_defined && dir_name == config_["adapter"].asString()) || !adap_defined) &&
|
||||
@ -70,36 +122,86 @@ void waybar::modules::Battery::getBatteries() {
|
||||
}
|
||||
throw std::runtime_error("No batteries.");
|
||||
}
|
||||
|
||||
// Remove any batteries that are no longer present and unwatch them
|
||||
for (auto const& check : check_map) {
|
||||
if (!check.second) {
|
||||
auto watch_id = batteries_[check.first];
|
||||
if (watch_id >= 0) {
|
||||
inotify_rm_watch(battery_watch_fd_, watch_id);
|
||||
}
|
||||
batteries_.erase(check.first);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const std::tuple<uint8_t, float, std::string> waybar::modules::Battery::getInfos() const {
|
||||
// Unknown > Full > Not charging > Discharging > Charging
|
||||
static bool status_gt(const std::string& a, const std::string& b) {
|
||||
if (a == b) return false;
|
||||
else if (a == "Unknown") return true;
|
||||
else if (a == "Full" && b != "Unknown") return true;
|
||||
else if (a == "Not charging" && b != "Unknown" && b != "Full") return true;
|
||||
else if (a == "Discharging" && b != "Unknown" && b != "Full" && b != "Not charging") return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
const std::tuple<uint8_t, float, std::string, float> waybar::modules::Battery::getInfos() {
|
||||
std::lock_guard<std::mutex> guard(battery_list_mutex_);
|
||||
|
||||
try {
|
||||
uint16_t total = 0;
|
||||
uint32_t total_power = 0; // μW
|
||||
uint32_t total_energy = 0; // μWh
|
||||
uint32_t total_energy_full = 0;
|
||||
uint32_t total_energy_full_design = 0;
|
||||
std::string status = "Unknown";
|
||||
for (auto const& bat : batteries_) {
|
||||
uint16_t capacity;
|
||||
for (auto const& item : batteries_) {
|
||||
auto bat = item.first;
|
||||
uint32_t power_now;
|
||||
uint32_t energy_full;
|
||||
uint32_t energy_now;
|
||||
uint32_t energy_full_design;
|
||||
std::string _status;
|
||||
std::ifstream(bat / "capacity") >> capacity;
|
||||
std::ifstream(bat / "status") >> _status;
|
||||
auto rate_path = fs::exists(bat / "current_now") ? "current_now" : "power_now";
|
||||
std::ifstream(bat / rate_path) >> power_now;
|
||||
auto now_path = fs::exists(bat / "charge_now") ? "charge_now" : "energy_now";
|
||||
std::ifstream(bat / now_path) >> energy_now;
|
||||
auto full_path = fs::exists(bat / "charge_full") ? "charge_full" : "energy_full";
|
||||
std::ifstream(bat / full_path) >> energy_full;
|
||||
if (_status != "Unknown") {
|
||||
|
||||
// Some battery will report current and charge in μA/μAh.
|
||||
// Scale these by the voltage to get μW/μWh.
|
||||
if (fs::exists(bat / "current_now")) {
|
||||
uint32_t voltage_now;
|
||||
uint32_t current_now;
|
||||
uint32_t charge_now;
|
||||
uint32_t charge_full;
|
||||
uint32_t charge_full_design;
|
||||
std::ifstream(bat / "voltage_now") >> voltage_now;
|
||||
std::ifstream(bat / "current_now") >> current_now;
|
||||
std::ifstream(bat / "charge_full") >> charge_full;
|
||||
std::ifstream(bat / "charge_full_design") >> charge_full_design;
|
||||
if (fs::exists(bat / "charge_now"))
|
||||
std::ifstream(bat / "charge_now") >> charge_now;
|
||||
else {
|
||||
// charge_now is missing on some systems, estimate using capacity.
|
||||
uint32_t capacity;
|
||||
std::ifstream(bat / "capacity") >> capacity;
|
||||
charge_now = (capacity * charge_full) / 100;
|
||||
}
|
||||
power_now = ((uint64_t)current_now * (uint64_t)voltage_now) / 1000000;
|
||||
energy_now = ((uint64_t)charge_now * (uint64_t)voltage_now) / 1000000;
|
||||
energy_full = ((uint64_t)charge_full * (uint64_t)voltage_now) / 1000000;
|
||||
energy_full_design = ((uint64_t)charge_full_design * (uint64_t)voltage_now) / 1000000;
|
||||
} else {
|
||||
std::ifstream(bat / "power_now") >> power_now;
|
||||
std::ifstream(bat / "energy_now") >> energy_now;
|
||||
std::ifstream(bat / "energy_full") >> energy_full;
|
||||
std::ifstream(bat / "energy_full_design") >> energy_full_design;
|
||||
}
|
||||
|
||||
// Show the "smallest" status among all batteries
|
||||
if (status_gt(status, _status)) {
|
||||
status = _status;
|
||||
}
|
||||
total += capacity;
|
||||
total_power += power_now;
|
||||
total_energy += energy_now;
|
||||
total_energy_full += energy_full;
|
||||
total_energy_full_design += energy_full_design;
|
||||
}
|
||||
if (!adapter_.empty() && status == "Discharging") {
|
||||
bool online;
|
||||
@ -113,12 +215,40 @@ const std::tuple<uint8_t, float, std::string> waybar::modules::Battery::getInfos
|
||||
time_remaining = (float)total_energy / total_power;
|
||||
} else if (status == "Charging" && total_power != 0) {
|
||||
time_remaining = -(float)(total_energy_full - total_energy) / total_power;
|
||||
if (time_remaining > 0.0f) {
|
||||
// If we've turned positive it means the battery is past 100% and so
|
||||
// just report that as no time remaining
|
||||
time_remaining = 0.0f;
|
||||
}
|
||||
}
|
||||
uint16_t capacity = total / batteries_.size();
|
||||
return {capacity, time_remaining, status};
|
||||
float capacity = ((float)total_energy * 100.0f / (float) total_energy_full);
|
||||
// Handle design-capacity
|
||||
if (config_["design-capacity"].isBool() ? config_["design-capacity"].asBool() : false) {
|
||||
capacity = ((float)total_energy * 100.0f / (float) total_energy_full_design);
|
||||
}
|
||||
// Handle full-at
|
||||
if (config_["full-at"].isUInt()) {
|
||||
auto full_at = config_["full-at"].asUInt();
|
||||
if (full_at < 100) {
|
||||
capacity = 100.f * capacity / full_at;
|
||||
}
|
||||
}
|
||||
if (capacity > 100.f) {
|
||||
// This can happen when the battery is calibrating and goes above 100%
|
||||
// Handle it gracefully by clamping at 100%
|
||||
capacity = 100.f;
|
||||
}
|
||||
uint8_t cap = round(capacity);
|
||||
if (cap == 100 && status == "Charging") {
|
||||
// If we've reached 100% just mark as full as some batteries can stay
|
||||
// stuck reporting they're still charging but not yet done
|
||||
status = "Full";
|
||||
}
|
||||
|
||||
return {cap, time_remaining, status, total_power / 1e6};
|
||||
} catch (const std::exception& e) {
|
||||
spdlog::error("Battery: {}", e.what());
|
||||
return {0, 0, "Unknown"};
|
||||
return {0, 0, "Unknown", 0};
|
||||
}
|
||||
}
|
||||
|
||||
@ -130,7 +260,7 @@ const std::string waybar::modules::Battery::getAdapterStatus(uint8_t capacity) c
|
||||
return "Full";
|
||||
}
|
||||
if (online) {
|
||||
return "Charging";
|
||||
return "Plugged";
|
||||
}
|
||||
return "Discharging";
|
||||
}
|
||||
@ -141,27 +271,53 @@ const std::string waybar::modules::Battery::formatTimeRemaining(float hoursRemai
|
||||
hoursRemaining = std::fabs(hoursRemaining);
|
||||
uint16_t full_hours = static_cast<uint16_t>(hoursRemaining);
|
||||
uint16_t minutes = static_cast<uint16_t>(60 * (hoursRemaining - full_hours));
|
||||
return std::to_string(full_hours) + " h " + std::to_string(minutes) + " min";
|
||||
auto format = std::string("{H} h {M} min");
|
||||
if (full_hours == 0 && minutes == 0) {
|
||||
// Migh as well not show "0h 0min"
|
||||
return "";
|
||||
}
|
||||
if (config_["format-time"].isString()) {
|
||||
format = config_["format-time"].asString();
|
||||
}
|
||||
return fmt::format(format, fmt::arg("H", full_hours), fmt::arg("M", minutes));
|
||||
}
|
||||
|
||||
auto waybar::modules::Battery::update() -> void {
|
||||
auto [capacity, time_remaining, status] = getInfos();
|
||||
auto [capacity, time_remaining, status, power] = getInfos();
|
||||
if (status == "Unknown") {
|
||||
status = getAdapterStatus(capacity);
|
||||
}
|
||||
if (tooltipEnabled()) {
|
||||
std::string tooltip_text;
|
||||
if (time_remaining != 0) {
|
||||
std::string time_to = std::string("Time to ") + ((time_remaining > 0) ? "empty" : "full");
|
||||
tooltip_text = time_to + ": " + formatTimeRemaining(time_remaining);
|
||||
} else {
|
||||
tooltip_text = status;
|
||||
}
|
||||
label_.set_tooltip_text(tooltip_text);
|
||||
}
|
||||
std::transform(status.begin(), status.end(), status.begin(), ::tolower);
|
||||
auto status_pretty = status;
|
||||
// Transform to lowercase and replace space with dash
|
||||
std::transform(status.begin(), status.end(), status.begin(), [](char ch) {
|
||||
return ch == ' ' ? '-' : std::tolower(ch);
|
||||
});
|
||||
auto format = format_;
|
||||
auto state = getState(capacity, true);
|
||||
auto time_remaining_formatted = formatTimeRemaining(time_remaining);
|
||||
if (tooltipEnabled()) {
|
||||
std::string tooltip_text_default;
|
||||
std::string tooltip_format = "{timeTo}";
|
||||
if (time_remaining != 0) {
|
||||
std::string time_to = std::string("Time to ") + ((time_remaining > 0) ? "empty" : "full");
|
||||
tooltip_text_default = time_to + ": " + time_remaining_formatted;
|
||||
} else {
|
||||
tooltip_text_default = status_pretty;
|
||||
}
|
||||
if (!state.empty() && config_["tooltip-format-" + status + "-" + state].isString()) {
|
||||
tooltip_format = config_["tooltip-format-" + status + "-" + state].asString();
|
||||
} else if (config_["tooltip-format-" + status].isString()) {
|
||||
tooltip_format = config_["tooltip-format-" + status].asString();
|
||||
} else if (!state.empty() && config_["tooltip-format-" + state].isString()) {
|
||||
tooltip_format = config_["tooltip-format-" + state].asString();
|
||||
} else if (config_["tooltip-format"].isString()) {
|
||||
tooltip_format = config_["tooltip-format"].asString();
|
||||
}
|
||||
label_.set_tooltip_text(fmt::format(tooltip_format,
|
||||
fmt::arg("timeTo", tooltip_text_default),
|
||||
fmt::arg("capacity", capacity),
|
||||
fmt::arg("time", time_remaining_formatted)));
|
||||
}
|
||||
if (!old_status_.empty()) {
|
||||
label_.get_style_context()->remove_class(old_status_);
|
||||
}
|
||||
@ -178,9 +334,13 @@ auto waybar::modules::Battery::update() -> void {
|
||||
event_box_.hide();
|
||||
} else {
|
||||
event_box_.show();
|
||||
auto icons = std::vector<std::string>{status + "-" + state, status, state};
|
||||
label_.set_markup(fmt::format(format,
|
||||
fmt::arg("capacity", capacity),
|
||||
fmt::arg("icon", getIcon(capacity, state)),
|
||||
fmt::arg("time", formatTimeRemaining(time_remaining))));
|
||||
fmt::arg("power", power),
|
||||
fmt::arg("icon", getIcon(capacity, icons)),
|
||||
fmt::arg("time", time_remaining_formatted)));
|
||||
}
|
||||
// Call parent update
|
||||
ALabel::update();
|
||||
}
|
||||
|
25
src/modules/bluetooth.cpp
Normal file
25
src/modules/bluetooth.cpp
Normal file
@ -0,0 +1,25 @@
|
||||
#include "modules/bluetooth.hpp"
|
||||
|
||||
#include <fmt/format.h>
|
||||
|
||||
waybar::modules::Bluetooth::Bluetooth(const std::string& id, const Json::Value& config)
|
||||
: ALabel(config, "bluetooth", id, "{icon}", 10), rfkill_{RFKILL_TYPE_BLUETOOTH} {
|
||||
rfkill_.on_update.connect(sigc::hide(sigc::mem_fun(*this, &Bluetooth::update)));
|
||||
}
|
||||
|
||||
auto waybar::modules::Bluetooth::update() -> void {
|
||||
std::string status = rfkill_.getState() ? "disabled" : "enabled";
|
||||
|
||||
label_.set_markup(
|
||||
fmt::format(format_, fmt::arg("status", status), fmt::arg("icon", getIcon(0, status))));
|
||||
|
||||
if (tooltipEnabled()) {
|
||||
if (config_["tooltip-format"].isString()) {
|
||||
auto tooltip_format = config_["tooltip-format"].asString();
|
||||
auto tooltip_text = fmt::format(tooltip_format, status, fmt::arg("status", status));
|
||||
label_.set_tooltip_text(tooltip_text);
|
||||
} else {
|
||||
label_.set_tooltip_text(status);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,7 +1,32 @@
|
||||
#include "modules/clock.hpp"
|
||||
|
||||
#include <time.h>
|
||||
#include <spdlog/spdlog.h>
|
||||
|
||||
#include <sstream>
|
||||
#include <type_traits>
|
||||
#include "util/ustring_clen.hpp"
|
||||
#ifdef HAVE_LANGINFO_1STDAY
|
||||
#include <langinfo.h>
|
||||
#include <locale.h>
|
||||
#endif
|
||||
|
||||
using waybar::modules::waybar_time;
|
||||
|
||||
waybar::modules::Clock::Clock(const std::string& id, const Json::Value& config)
|
||||
: ALabel(config, "clock", id, "{:%H:%M}", 60) {
|
||||
: ALabel(config, "clock", id, "{:%H:%M}", 60, false, false, true), fixed_time_zone_(false) {
|
||||
if (config_["timezone"].isString()) {
|
||||
spdlog::warn("As using a timezone, some format args may be missing as the date library havn't got a release since 2018.");
|
||||
time_zone_ = date::locate_zone(config_["timezone"].asString());
|
||||
fixed_time_zone_ = true;
|
||||
}
|
||||
|
||||
if (config_["locale"].isString()) {
|
||||
locale_ = std::locale(config_["locale"].asString());
|
||||
} else {
|
||||
locale_ = std::locale("");
|
||||
}
|
||||
|
||||
thread_ = [this] {
|
||||
dp.emit();
|
||||
auto now = std::chrono::system_clock::now();
|
||||
@ -12,18 +37,168 @@ waybar::modules::Clock::Clock(const std::string& id, const Json::Value& config)
|
||||
}
|
||||
|
||||
auto waybar::modules::Clock::update() -> void {
|
||||
auto now = std::chrono::system_clock::now();
|
||||
auto localtime = fmt::localtime(std::chrono::system_clock::to_time_t(now));
|
||||
auto text = fmt::format(format_, localtime);
|
||||
label_.set_markup(text);
|
||||
if (!fixed_time_zone_) {
|
||||
// Time zone can change. Be sure to pick that.
|
||||
time_zone_ = date::current_zone();
|
||||
}
|
||||
|
||||
auto now = std::chrono::system_clock::now();
|
||||
waybar_time wtime = {locale_,
|
||||
date::make_zoned(time_zone_, date::floor<std::chrono::seconds>(now))};
|
||||
|
||||
std::string text;
|
||||
if (!fixed_time_zone_) {
|
||||
// As date dep is not fully compatible, prefer fmt
|
||||
tzset();
|
||||
auto localtime = fmt::localtime(std::chrono::system_clock::to_time_t(now));
|
||||
text = fmt::format(format_, localtime);
|
||||
label_.set_markup(text);
|
||||
} else {
|
||||
text = fmt::format(format_, wtime);
|
||||
label_.set_markup(text);
|
||||
}
|
||||
|
||||
if (tooltipEnabled()) {
|
||||
if (config_["tooltip-format"].isString()) {
|
||||
auto tooltip_format = config_["tooltip-format"].asString();
|
||||
auto tooltip_text = fmt::format(tooltip_format, localtime);
|
||||
label_.set_tooltip_text(tooltip_text);
|
||||
const auto calendar = calendar_text(wtime);
|
||||
auto tooltip_format = config_["tooltip-format"].asString();
|
||||
auto tooltip_text = fmt::format(tooltip_format, wtime, fmt::arg("calendar", calendar));
|
||||
label_.set_tooltip_markup(tooltip_text);
|
||||
} else {
|
||||
label_.set_tooltip_text(text);
|
||||
label_.set_tooltip_markup(text);
|
||||
}
|
||||
}
|
||||
// Call parent update
|
||||
ALabel::update();
|
||||
}
|
||||
|
||||
bool waybar::modules::Clock::handleScroll(GdkEventScroll *e) {
|
||||
// defer to user commands if set
|
||||
if (config_["on-scroll-up"].isString() || config_["on-scroll-down"].isString()) {
|
||||
return AModule::handleScroll(e);
|
||||
}
|
||||
|
||||
auto dir = AModule::getScrollDir(e);
|
||||
if (dir != SCROLL_DIR::UP && dir != SCROLL_DIR::DOWN) {
|
||||
return true;
|
||||
}
|
||||
if (!config_["timezones"].isArray() || config_["timezones"].empty()) {
|
||||
return true;
|
||||
}
|
||||
auto nr_zones = config_["timezones"].size();
|
||||
if (dir == SCROLL_DIR::UP) {
|
||||
size_t new_idx = time_zone_idx_ + 1;
|
||||
time_zone_idx_ = new_idx == nr_zones ? 0 : new_idx;
|
||||
} else {
|
||||
time_zone_idx_ = time_zone_idx_ == 0 ? nr_zones - 1 : time_zone_idx_ - 1;
|
||||
}
|
||||
auto zone_name = config_["timezones"][time_zone_idx_];
|
||||
if (!zone_name.isString() || zone_name.empty()) {
|
||||
fixed_time_zone_ = false;
|
||||
} else {
|
||||
time_zone_ = date::locate_zone(zone_name.asString());
|
||||
fixed_time_zone_ = true;
|
||||
}
|
||||
|
||||
update();
|
||||
return true;
|
||||
}
|
||||
|
||||
auto waybar::modules::Clock::calendar_text(const waybar_time& wtime) -> std::string {
|
||||
const auto daypoint = date::floor<date::days>(wtime.ztime.get_local_time());
|
||||
const auto ymd = date::year_month_day(daypoint);
|
||||
if (cached_calendar_ymd_ == ymd) {
|
||||
return cached_calendar_text_;
|
||||
}
|
||||
|
||||
const date::year_month ym(ymd.year(), ymd.month());
|
||||
const auto curr_day = ymd.day();
|
||||
|
||||
std::stringstream os;
|
||||
const auto first_dow = first_day_of_week();
|
||||
weekdays_header(first_dow, os);
|
||||
|
||||
// First week prefixed with spaces if needed.
|
||||
auto wd = date::weekday(ym / 1);
|
||||
auto empty_days = (wd - first_dow).count();
|
||||
if (empty_days > 0) {
|
||||
os << std::string(empty_days * 3 - 1, ' ');
|
||||
}
|
||||
auto last_day = (ym / date::literals::last).day();
|
||||
for (auto d = date::day(1); d <= last_day; ++d, ++wd) {
|
||||
if (wd != first_dow) {
|
||||
os << ' ';
|
||||
} else if (unsigned(d) != 1) {
|
||||
os << '\n';
|
||||
}
|
||||
if (d == curr_day) {
|
||||
if (config_["today-format"].isString()) {
|
||||
auto today_format = config_["today-format"].asString();
|
||||
os << fmt::format(today_format, date::format("%e", d));
|
||||
} else {
|
||||
os << "<b><u>" << date::format("%e", d) << "</u></b>";
|
||||
}
|
||||
} else {
|
||||
os << date::format("%e", d);
|
||||
}
|
||||
}
|
||||
|
||||
auto result = os.str();
|
||||
cached_calendar_ymd_ = ymd;
|
||||
cached_calendar_text_ = result;
|
||||
return result;
|
||||
}
|
||||
|
||||
auto waybar::modules::Clock::weekdays_header(const date::weekday& first_dow, std::ostream& os)
|
||||
-> void {
|
||||
auto wd = first_dow;
|
||||
do {
|
||||
if (wd != first_dow) os << ' ';
|
||||
Glib::ustring wd_ustring(date::format(locale_, "%a", wd));
|
||||
auto clen = ustring_clen(wd_ustring);
|
||||
auto wd_len = wd_ustring.length();
|
||||
while (clen > 2) {
|
||||
wd_ustring = wd_ustring.substr(0, wd_len-1);
|
||||
wd_len--;
|
||||
clen = ustring_clen(wd_ustring);
|
||||
}
|
||||
const std::string pad(2 - clen, ' ');
|
||||
os << pad << wd_ustring;
|
||||
} while (++wd != first_dow);
|
||||
os << "\n";
|
||||
}
|
||||
|
||||
#ifdef HAVE_LANGINFO_1STDAY
|
||||
template <auto fn>
|
||||
using deleter_from_fn = std::integral_constant<decltype(fn), fn>;
|
||||
|
||||
template <typename T, auto fn>
|
||||
using deleting_unique_ptr = std::unique_ptr<T, deleter_from_fn<fn>>;
|
||||
#endif
|
||||
|
||||
// Computations done similarly to Linux cal utility.
|
||||
auto waybar::modules::Clock::first_day_of_week() -> date::weekday {
|
||||
#ifdef HAVE_LANGINFO_1STDAY
|
||||
deleting_unique_ptr<std::remove_pointer<locale_t>::type, freelocale> posix_locale{
|
||||
newlocale(LC_ALL, locale_.name().c_str(), nullptr)};
|
||||
if (posix_locale) {
|
||||
const int i = (std::intptr_t)nl_langinfo_l(_NL_TIME_WEEK_1STDAY, posix_locale.get());
|
||||
auto ymd = date::year(i / 10000) / (i / 100 % 100) / (i % 100);
|
||||
auto wd = date::weekday(ymd);
|
||||
uint8_t j = *nl_langinfo_l(_NL_TIME_FIRST_WEEKDAY, posix_locale.get());
|
||||
return wd + date::days(j - 1);
|
||||
}
|
||||
#endif
|
||||
return date::Sunday;
|
||||
}
|
||||
|
||||
template <>
|
||||
struct fmt::formatter<waybar_time> : fmt::formatter<std::tm> {
|
||||
template <typename FormatContext>
|
||||
auto format(const waybar_time& t, FormatContext& ctx) {
|
||||
#if FMT_VERSION >= 80000
|
||||
auto& tm_format = specs;
|
||||
#endif
|
||||
return format_to(ctx.out(), "{}", date::format(t.locale, fmt::to_string(tm_format), t.ztime));
|
||||
}
|
||||
};
|
||||
|
@ -1,83 +0,0 @@
|
||||
#include "modules/cpu.hpp"
|
||||
#include <numeric>
|
||||
|
||||
waybar::modules::Cpu::Cpu(const std::string& id, const Json::Value& config)
|
||||
: ALabel(config, "cpu", id, "{usage}%", 10) {
|
||||
thread_ = [this] {
|
||||
dp.emit();
|
||||
thread_.sleep_for(interval_);
|
||||
};
|
||||
}
|
||||
|
||||
auto waybar::modules::Cpu::update() -> void {
|
||||
// TODO: as creating dynamic fmt::arg arrays is buggy we have to calc both
|
||||
auto cpu_load = getCpuLoad();
|
||||
auto [cpu_usage, tooltip] = getCpuUsage();
|
||||
if (tooltipEnabled()) {
|
||||
label_.set_tooltip_text(tooltip);
|
||||
}
|
||||
label_.set_markup(fmt::format(format_, fmt::arg("load", cpu_load), fmt::arg("usage", cpu_usage)));
|
||||
getState(cpu_usage);
|
||||
}
|
||||
|
||||
uint16_t waybar::modules::Cpu::getCpuLoad() {
|
||||
struct sysinfo info = {0};
|
||||
if (sysinfo(&info) == 0) {
|
||||
float f_load = 1.F / (1U << SI_LOAD_SHIFT);
|
||||
uint16_t load = info.loads[0] * f_load * 100 / get_nprocs();
|
||||
return load;
|
||||
}
|
||||
throw std::runtime_error("Can't get Cpu load");
|
||||
}
|
||||
|
||||
std::tuple<uint16_t, std::string> waybar::modules::Cpu::getCpuUsage() {
|
||||
if (prev_times_.empty()) {
|
||||
prev_times_ = parseCpuinfo();
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
}
|
||||
std::vector<std::tuple<size_t, size_t>> curr_times = parseCpuinfo();
|
||||
std::string tooltip;
|
||||
uint16_t usage = 0;
|
||||
for (size_t i = 0; i < curr_times.size(); ++i) {
|
||||
auto [curr_idle, curr_total] = curr_times[i];
|
||||
auto [prev_idle, prev_total] = prev_times_[i];
|
||||
const float delta_idle = curr_idle - prev_idle;
|
||||
const float delta_total = curr_total - prev_total;
|
||||
uint16_t tmp = 100 * (1 - delta_idle / delta_total);
|
||||
if (i == 0) {
|
||||
usage = tmp;
|
||||
tooltip = fmt::format("Total: {}%", tmp);
|
||||
} else {
|
||||
tooltip = tooltip + fmt::format("\nCore{}: {}%", i - 1, tmp);
|
||||
}
|
||||
}
|
||||
prev_times_ = curr_times;
|
||||
return {usage, tooltip};
|
||||
}
|
||||
|
||||
std::vector<std::tuple<size_t, size_t>> waybar::modules::Cpu::parseCpuinfo() {
|
||||
std::ifstream info(data_dir_);
|
||||
if (!info.is_open()) {
|
||||
throw std::runtime_error("Can't open " + data_dir_);
|
||||
}
|
||||
std::vector<std::tuple<size_t, size_t>> cpuinfo;
|
||||
std::string line;
|
||||
while (getline(info, line)) {
|
||||
if (line.substr(0, 3).compare("cpu") != 0) {
|
||||
break;
|
||||
}
|
||||
std::stringstream sline(line.substr(5));
|
||||
std::vector<size_t> times;
|
||||
for (size_t time = 0; sline >> time; times.push_back(time))
|
||||
;
|
||||
|
||||
size_t idle_time = 0;
|
||||
size_t total_time = 0;
|
||||
if (times.size() >= 4) {
|
||||
idle_time = times[3];
|
||||
total_time = std::accumulate(times.begin(), times.end(), 0);
|
||||
}
|
||||
cpuinfo.emplace_back(idle_time, total_time);
|
||||
}
|
||||
return cpuinfo;
|
||||
}
|
108
src/modules/cpu/bsd.cpp
Normal file
108
src/modules/cpu/bsd.cpp
Normal file
@ -0,0 +1,108 @@
|
||||
#include "modules/cpu.hpp"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <spdlog/spdlog.h>
|
||||
#include <cstdlib> // malloc
|
||||
#include <unistd.h> // sysconf
|
||||
#include <cmath> // NAN
|
||||
|
||||
#if defined(__NetBSD__) || defined(__OpenBSD__)
|
||||
# include <sys/sched.h>
|
||||
#else
|
||||
# include <sys/resource.h>
|
||||
#endif
|
||||
|
||||
#if defined(__NetBSD__)
|
||||
typedef uint64_t cp_time_t;
|
||||
#else
|
||||
typedef long cp_time_t;
|
||||
#endif
|
||||
#if defined(__NetBSD__) || defined(__OpenBSD__)
|
||||
typedef uint64_t pcp_time_t;
|
||||
#else
|
||||
typedef long pcp_time_t;
|
||||
#endif
|
||||
|
||||
std::vector<std::tuple<size_t, size_t>> waybar::modules::Cpu::parseCpuinfo() {
|
||||
cp_time_t sum_cp_time[CPUSTATES];
|
||||
size_t sum_sz = sizeof(sum_cp_time);
|
||||
int ncpu = sysconf(_SC_NPROCESSORS_CONF);
|
||||
size_t sz = CPUSTATES * (ncpu + 1) * sizeof(pcp_time_t);
|
||||
pcp_time_t *cp_time = static_cast<pcp_time_t *>(malloc(sz)), *pcp_time = cp_time;
|
||||
#if defined(__NetBSD__)
|
||||
int mib[] = {
|
||||
CTL_KERN,
|
||||
KERN_CP_TIME,
|
||||
};
|
||||
if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), sum_cp_time, &sum_sz, NULL, 0)) {
|
||||
throw std::runtime_error("sysctl kern.cp_time failed");
|
||||
}
|
||||
for (int state = 0; state < CPUSTATES; state++) {
|
||||
cp_time[state] = sum_cp_time[state];
|
||||
}
|
||||
pcp_time += CPUSTATES;
|
||||
if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), pcp_time, &sz, NULL, 0)) {
|
||||
throw std::runtime_error("sysctl kern.cp_time failed");
|
||||
}
|
||||
#elif defined(__OpenBSD__)
|
||||
{
|
||||
int mib[] = {
|
||||
CTL_KERN,
|
||||
KERN_CPTIME,
|
||||
};
|
||||
if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), sum_cp_time, &sum_sz, NULL, 0)) {
|
||||
throw std::runtime_error("sysctl kern.cp_time failed");
|
||||
}
|
||||
}
|
||||
for (int state = 0; state < CPUSTATES; state++) {
|
||||
cp_time[state] = sum_cp_time[state];
|
||||
}
|
||||
pcp_time = cp_time;
|
||||
sz /= ncpu + 1;
|
||||
{
|
||||
int mib[] = {
|
||||
CTL_KERN,
|
||||
KERN_CPTIME2,
|
||||
0,
|
||||
};
|
||||
for (int cpu = 0; cpu < ncpu; cpu++) {
|
||||
mib[2] = cpu;
|
||||
pcp_time += CPUSTATES;
|
||||
if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), pcp_time, &sz, NULL, 0)) {
|
||||
throw std::runtime_error("sysctl kern.cp_time2 failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
if (sysctlbyname("kern.cp_time", sum_cp_time, &sum_sz, NULL, 0)) {
|
||||
throw std::runtime_error("sysctl kern.cp_time failed");
|
||||
}
|
||||
for (int state = 0; state < CPUSTATES; state++) {
|
||||
cp_time[state] = sum_cp_time[state];
|
||||
}
|
||||
pcp_time += CPUSTATES;
|
||||
if (sysctlbyname("kern.cp_times", pcp_time, &sz, NULL, 0)) {
|
||||
throw std::runtime_error("sysctl kern.cp_times failed");
|
||||
}
|
||||
#endif
|
||||
std::vector<std::tuple<size_t, size_t>> cpuinfo;
|
||||
for (int cpu = 0; cpu < ncpu + 1; cpu++) {
|
||||
pcp_time_t total = 0, *single_cp_time = &cp_time[cpu * CPUSTATES];
|
||||
for (int state = 0; state < CPUSTATES; state++) {
|
||||
total += single_cp_time[state];
|
||||
}
|
||||
cpuinfo.emplace_back(single_cp_time[CP_IDLE], total);
|
||||
}
|
||||
free(cp_time);
|
||||
return cpuinfo;
|
||||
}
|
||||
|
||||
std::vector<float> waybar::modules::Cpu::parseCpuFrequencies() {
|
||||
static std::vector<float> frequencies;
|
||||
if (frequencies.empty()) {
|
||||
spdlog::warn("cpu/bsd: parseCpuFrequencies is not implemented, expect garbage in {*_frequency}");
|
||||
frequencies.push_back(NAN);
|
||||
}
|
||||
return frequencies;
|
||||
}
|
85
src/modules/cpu/common.cpp
Normal file
85
src/modules/cpu/common.cpp
Normal file
@ -0,0 +1,85 @@
|
||||
#include "modules/cpu.hpp"
|
||||
|
||||
waybar::modules::Cpu::Cpu(const std::string& id, const Json::Value& config)
|
||||
: ALabel(config, "cpu", id, "{usage}%", 10) {
|
||||
thread_ = [this] {
|
||||
dp.emit();
|
||||
thread_.sleep_for(interval_);
|
||||
};
|
||||
}
|
||||
|
||||
auto waybar::modules::Cpu::update() -> void {
|
||||
// TODO: as creating dynamic fmt::arg arrays is buggy we have to calc both
|
||||
auto cpu_load = getCpuLoad();
|
||||
auto [cpu_usage, tooltip] = getCpuUsage();
|
||||
auto [max_frequency, min_frequency, avg_frequency] = getCpuFrequency();
|
||||
if (tooltipEnabled()) {
|
||||
label_.set_tooltip_text(tooltip);
|
||||
}
|
||||
auto format = format_;
|
||||
auto state = getState(cpu_usage);
|
||||
if (!state.empty() && config_["format-" + state].isString()) {
|
||||
format = config_["format-" + state].asString();
|
||||
}
|
||||
|
||||
if (format.empty()) {
|
||||
event_box_.hide();
|
||||
} else {
|
||||
event_box_.show();
|
||||
label_.set_markup(fmt::format(format,
|
||||
fmt::arg("load", cpu_load),
|
||||
fmt::arg("usage", cpu_usage),
|
||||
fmt::arg("max_frequency", max_frequency),
|
||||
fmt::arg("min_frequency", min_frequency),
|
||||
fmt::arg("avg_frequency", avg_frequency)));
|
||||
}
|
||||
|
||||
// Call parent update
|
||||
ALabel::update();
|
||||
}
|
||||
|
||||
double waybar::modules::Cpu::getCpuLoad() {
|
||||
double load[1];
|
||||
if (getloadavg(load, 1) != -1) {
|
||||
return load[0];
|
||||
}
|
||||
throw std::runtime_error("Can't get Cpu load");
|
||||
}
|
||||
|
||||
std::tuple<uint16_t, std::string> waybar::modules::Cpu::getCpuUsage() {
|
||||
if (prev_times_.empty()) {
|
||||
prev_times_ = parseCpuinfo();
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
}
|
||||
std::vector<std::tuple<size_t, size_t>> curr_times = parseCpuinfo();
|
||||
std::string tooltip;
|
||||
uint16_t usage = 0;
|
||||
for (size_t i = 0; i < curr_times.size(); ++i) {
|
||||
auto [curr_idle, curr_total] = curr_times[i];
|
||||
auto [prev_idle, prev_total] = prev_times_[i];
|
||||
const float delta_idle = curr_idle - prev_idle;
|
||||
const float delta_total = curr_total - prev_total;
|
||||
uint16_t tmp = 100 * (1 - delta_idle / delta_total);
|
||||
if (i == 0) {
|
||||
usage = tmp;
|
||||
tooltip = fmt::format("Total: {}%", tmp);
|
||||
} else {
|
||||
tooltip = tooltip + fmt::format("\nCore{}: {}%", i - 1, tmp);
|
||||
}
|
||||
}
|
||||
prev_times_ = curr_times;
|
||||
return {usage, tooltip};
|
||||
}
|
||||
|
||||
std::tuple<float, float, float> waybar::modules::Cpu::getCpuFrequency() {
|
||||
std::vector<float> frequencies = parseCpuFrequencies();
|
||||
auto [min, max] = std::minmax_element(std::begin(frequencies), std::end(frequencies));
|
||||
float avg_frequency = std::accumulate(std::begin(frequencies), std::end(frequencies), 0.0) / frequencies.size();
|
||||
|
||||
// Round frequencies with double decimal precision to get GHz
|
||||
float max_frequency = std::ceil(*max / 10.0) / 100.0;
|
||||
float min_frequency = std::ceil(*min / 10.0) / 100.0;
|
||||
avg_frequency = std::ceil(avg_frequency / 10.0) / 100.0;
|
||||
|
||||
return { max_frequency, min_frequency, avg_frequency };
|
||||
}
|
77
src/modules/cpu/linux.cpp
Normal file
77
src/modules/cpu/linux.cpp
Normal file
@ -0,0 +1,77 @@
|
||||
#include <filesystem>
|
||||
#include "modules/cpu.hpp"
|
||||
|
||||
std::vector<std::tuple<size_t, size_t>> waybar::modules::Cpu::parseCpuinfo() {
|
||||
const std::string data_dir_ = "/proc/stat";
|
||||
std::ifstream info(data_dir_);
|
||||
if (!info.is_open()) {
|
||||
throw std::runtime_error("Can't open " + data_dir_);
|
||||
}
|
||||
std::vector<std::tuple<size_t, size_t>> cpuinfo;
|
||||
std::string line;
|
||||
while (getline(info, line)) {
|
||||
if (line.substr(0, 3).compare("cpu") != 0) {
|
||||
break;
|
||||
}
|
||||
std::stringstream sline(line.substr(5));
|
||||
std::vector<size_t> times;
|
||||
for (size_t time = 0; sline >> time; times.push_back(time))
|
||||
;
|
||||
|
||||
size_t idle_time = 0;
|
||||
size_t total_time = 0;
|
||||
if (times.size() >= 4) {
|
||||
idle_time = times[3];
|
||||
total_time = std::accumulate(times.begin(), times.end(), 0);
|
||||
}
|
||||
cpuinfo.emplace_back(idle_time, total_time);
|
||||
}
|
||||
return cpuinfo;
|
||||
}
|
||||
|
||||
std::vector<float> waybar::modules::Cpu::parseCpuFrequencies() {
|
||||
const std::string file_path_ = "/proc/cpuinfo";
|
||||
std::ifstream info(file_path_);
|
||||
if (!info.is_open()) {
|
||||
throw std::runtime_error("Can't open " + file_path_);
|
||||
}
|
||||
std::vector<float> frequencies;
|
||||
std::string line;
|
||||
while (getline(info, line)) {
|
||||
if (line.substr(0, 7).compare("cpu MHz") != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string frequency_str = line.substr(line.find(":") + 2);
|
||||
float frequency = std::strtol(frequency_str.c_str(), nullptr, 10);
|
||||
frequencies.push_back(frequency);
|
||||
}
|
||||
info.close();
|
||||
|
||||
if (frequencies.size() <= 0) {
|
||||
std::string cpufreq_dir = "/sys/devices/system/cpu/cpufreq";
|
||||
if (std::filesystem::exists(cpufreq_dir)) {
|
||||
std::vector<std::string> frequency_files = {
|
||||
"/cpuinfo_min_freq",
|
||||
"/cpuinfo_max_freq"
|
||||
};
|
||||
for (auto& p: std::filesystem::directory_iterator(cpufreq_dir)) {
|
||||
for (auto freq_file: frequency_files) {
|
||||
std::string freq_file_path = p.path().string() + freq_file;
|
||||
if (std::filesystem::exists(freq_file_path)) {
|
||||
std::string freq_value;
|
||||
std::ifstream freq(freq_file_path);
|
||||
if (freq.is_open()) {
|
||||
getline(freq, freq_value);
|
||||
float frequency = std::strtol(freq_value.c_str(), nullptr, 10);
|
||||
frequencies.push_back(frequency / 1000);
|
||||
freq.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return frequencies;
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user