Compare commits

..

404 Commits

Author SHA1 Message Date
fd417c0805 chore: 0.9.15 2022-11-03 09:43:05 +01:00
afa590f781 Merge pull request #1758 from Alexays/revert-1687-fix-custom-module-markup
Revert "Escape text in custom module"
2022-11-02 06:00:00 +01:00
df36ac3408 Revert "Escape text in custom module" 2022-11-02 05:59:50 +01:00
ebdf575d45 fix: lint 2022-10-28 14:44:48 +02:00
a4d27ea806 fix: checking router id in handleEvent function 2022-10-28 14:44:04 +02:00
a10266ceee fix: add power to tooltip format 2022-10-28 14:35:18 +02:00
c374c412d3 chore: remove unwanted file 2022-10-27 10:00:38 +02:00
2fec1d4907 fix: typo 2022-10-27 09:14:07 +02:00
be28ee3d7e fix(#1707): hide module when no controller found 2022-10-27 09:00:31 +02:00
2d7e21ed7d fix: lint 2022-10-26 17:26:15 +02:00
930a3e168b Merge pull request #1747 from bi4k8/taskbar-task-reorder 2022-10-26 17:25:55 +02:00
7948d03d25 Merge pull request #1744 from Quantenzitrone/master 2022-10-26 17:14:58 +02:00
ff61e7bf4e taskbar: implement drag-and-drop task reordering 2022-10-25 19:39:23 +00:00
64849f52c9 fixed memory module not rounding numbers 2022-10-22 02:31:14 +02:00
1374b0fce4 Merge pull request #1740 from ErikReider/gamemode-segfault-fix 2022-10-20 13:09:50 +02:00
1ceaff27c2 Fixed gamemode module segfaulting when disconnecting monitor 2022-10-20 12:38:52 +02:00
527017baca chore: update date wrap 2022-10-20 11:05:19 +02:00
f330e51472 fix: typo 2022-10-20 10:57:27 +02:00
411c6f4b4b chore: update catch 2022-10-20 10:56:47 +02:00
e8e8ccb6cf Merge pull request #1661 from asas1asas200/zeng-feat-improve_keyboard 2022-10-20 10:50:35 +02:00
a24f2d72a7 Merge pull request #1730 from herlev/hyprland-window-rewrite 2022-10-20 10:48:57 +02:00
ffa458223d Merge pull request #1724 from llyyr/fix-build-with-catch2 2022-10-20 10:47:52 +02:00
aa8bd51952 Merge pull request #1738 from pinselimo/fix-button-padding 2022-10-20 10:46:08 +02:00
05dbfe261a style: Revert set default minimal width of buttons to zero #1737 2022-10-20 10:34:20 +02:00
1f591e36f1 button: Hardcode min-width property set to zero
Buttons come with an intrinsic min-width but lack a method to alter this
property. Setting the requested size to zero has also no effect on it.
The only way found to work is to hard code the CSS into the button.
2022-10-20 10:31:11 +02:00
d0677c1801 Merge pull request #1737 from pinselimo/fix-button-padding 2022-10-19 14:59:49 +02:00
c18c6b080a Set default minimal width of buttons to zero
Even if all margins, padding and borders of buttons are removed the
label inside the buttons may still be padded if they are too short.
Setting the minimal width of buttons to zero fixes this issue.
2022-10-19 14:48:56 +02:00
7240611d87 Merge pull request #1736 from pinselimo/fix-battery-module 2022-10-19 13:39:20 +02:00
e1045381fe Fix linter 2022-10-19 13:30:28 +02:00
e660a3634d Fix linter 2022-10-19 13:29:05 +02:00
54e04b5a30 Refactor rewriteTitle 2022-10-19 13:25:08 +02:00
662a250705 Fix battery indicator crash on linux
A pre-processor flag was misspelled and is now corrected.
2022-10-19 13:15:21 +02:00
f72c1a54d3 Merge branch 'Alexays:master' into hyprland-window-rewrite 2022-10-19 12:18:22 +02:00
6b221133c2 Merge pull request #1703 from lbartoletti/freebsd_battery 2022-10-19 09:08:47 +02:00
d01fda6fae Merge pull request #1721 from herlev/sort-workspaces-by-number 2022-10-19 09:08:03 +02:00
692b90c995 fix build 2022-10-19 08:36:15 +02:00
dea2d721eb Merge pull request #1733 from ItsDrike/master 2022-10-18 19:45:42 +02:00
72a2ada82c remove clang-format lines 2022-10-18 19:30:43 +02:00
6156a62294 fix time_remaining. FreeBSD sysctl returns minutes and not hours 2022-10-18 19:30:43 +02:00
d4d35e2f89 apply clang-format 2022-10-18 19:30:43 +02:00
a58988ea9d Battery: replace #else by #elif defined(__linux__)
Cannot use #else here when inotify_init1() is hidden behind #if defined(__Linux__).

Co-authored-by: Jan Beich <jbeich@FreeBSD.org>
2022-10-18 19:30:43 +02:00
0ada5ac8b0 Battery::getAdapterStatus: better code format 2022-10-18 19:30:41 +02:00
1421163df3 remove useless include <sys/types.h> 2022-10-18 19:30:23 +02:00
9d5f0e45c0 Add test if there is battery 2022-10-18 19:30:23 +02:00
45e44e03bd Apply jbeich suggestion for if defined(__linux__) 2022-10-18 19:30:21 +02:00
830c5cd5d0 FreeBSD: Add support to battery
This commit aims to propose a FreeBSD to gain battery support using sysctl on hw.acpi.battery.*
2022-10-18 19:30:04 +02:00
90f206f92a Fix crash on quickly switching workspaces
The hyprland/window widget had an assertion ensuring that the output
from hyprctl matched the currently selected workspace id. However this
assertion fails if workspaces are switched too quickly, causing the
selected workspace to differ in id from the one in hyprctl, failing this
assertion which then crashes the entire program.

This fix simply changes this assertion into an if statement, and if a
mismatch is found, empty string is returned as the window name.
2022-10-18 18:36:00 +02:00
59e7f1974c Document hyprland/window rewrite option 2022-10-18 13:21:20 +02:00
97ae2ff343 Add rewrite option to hyprland/window 2022-10-18 13:18:43 +02:00
3d63080346 Document sort-by-number option in man page 2022-10-18 12:25:22 +02:00
cb842d9d50 Merge branch 'Alexays:master' into sort-workspaces-by-number 2022-10-18 12:19:00 +02:00
a7e6330078 Merge pull request #1729 from pinselimo/use_gtk_button_v2 2022-10-18 11:27:17 +02:00
93807b0b3e resources: Remove border effect on hover
Moves the ``border = none;`` attribute from workspace buttons to the
global scope. The hover effects on all buttons are now consistent in the
default stylesheet.
2022-10-18 11:25:20 +02:00
6e73c58e60 fix: lint 2022-10-18 09:01:45 +02:00
209225e381 Merge pull request #1701 from Dordovel/master 2022-10-18 09:01:00 +02:00
7746328daa Merge pull request #1667 from asas1asas200/zeng-feat-sway_scratchpad 2022-10-18 09:00:31 +02:00
c7d475ee86 Merge pull request #1728 from lilydjwg/fixpa 2022-10-18 08:45:45 +02:00
4ed13df092 Merge branch 'Alexays:master' into master 2022-10-17 19:00:21 +03:00
33c3ab35a8 Fix linter error (formatting) 2022-10-17 10:13:37 +02:00
4dfea72db0 Merge branch 'Alexays:master' into sort-workspaces-by-number 2022-10-17 10:01:12 +02:00
504132dc55 Merge pull request #1719 from herlev/master 2022-10-17 09:53:05 +02:00
debbfccf07 Merge pull request #1705 from lbartoletti/freebsd_temperature_use_thermal-zone_config 2022-10-17 09:52:54 +02:00
56ec72c31c Merge branch 'master' into master 2022-10-17 09:44:17 +02:00
27c6c96b37 Merge branch 'master' into freebsd_temperature_use_thermal-zone_config 2022-10-17 09:34:06 +02:00
8551c4bbe3 fix: lint 2022-10-17 09:19:00 +02:00
58362abfaf Merge pull request #1630 from duxovni/pow_format 2022-10-17 09:16:47 +02:00
2abeba2b52 Merge pull request #1679 from tomcharnock/master 2022-10-17 09:10:54 +02:00
bfa3adcfd6 Merge pull request #1120 from pinselimo/use_gtk_button_v2 2022-10-17 09:09:12 +02:00
2db6fc8b1b Merge pull request #1687 from sespiros/fix-custom-module-markup 2022-10-17 09:08:01 +02:00
c2dd296d31 Merge pull request #1704 from gunslingerfry/master 2022-10-17 09:07:26 +02:00
5b0c5ea9ce Merge pull request #1720 from IanManske/inhibitor-default-state 2022-10-17 09:06:26 +02:00
c7bb0ae0af Merge pull request #1636 from IsaacWoods/master 2022-10-17 09:05:03 +02:00
b2f90dffe1 Merge pull request #1710 from m-braunschweig/filename 2022-10-17 09:04:21 +02:00
f86dff60e6 utils: add sanitize_str to encode '&' etc.
gtk requires some chars (<>&"') to be encoded for them to render
properly. `sanitize_str` sanitizes raw strings that have such chars and
returns a properly encoded string
2022-10-17 00:31:19 +02:00
1db3c55b48 Fix build with catch2>=3.0.0 2022-10-16 19:21:43 +05:30
35254ee834 pulseaudio: disconnect on destruction 2022-10-16 15:24:17 +08:00
9a0013cb10 Add option to wlr/workspaces to sort workspaces by number 2022-10-15 01:44:58 +02:00
cca5227210 Add config value for inhibitor default state. 2022-10-13 21:47:57 -04:00
cf9d98a0be remove <optional> dependency 2022-10-13 23:49:41 +02:00
015409acaf Allow hyprland/window to show active window on a per monitor basis 2022-10-13 23:41:56 +02:00
2b735f44bc modules: Set tooltip on button
Mouse-over tooltips set on the label only appear once the mouse hovers
over exactly the label. Other apps (e.g. firefox) show the tooltip once
the pointer hovers the button. Not solely its label. With this commit we
get the same behaviour.
2022-10-12 10:25:30 +02:00
8fa5d9b838 modules: Set style-context on button
Fixes issue where the class parameters in style.css would have no
effect.

The CSS now references the GtkButton instead of the GtkLabel. Removing
all style-classes from the custom module GtkButton however removes
any properties set via style.css. Thus, the default classes 'flat' and
'text-button' are added on every update of these modules.
2022-10-12 10:25:30 +02:00
0012bcbd74 resources: Set button hover effects globally
Since now modules as well as workspaces are buttons, the fix for
the 'strange hover effects' has to be applied on a global level.
In return there is a nice hover effect also on the modules.
2022-10-12 10:25:30 +02:00
b8322c4b4b button: Add AButton class
The AButton class is designed as full a substitute to ALabel. The
GtkButton attribute 'button_' is initialized with a label. This
label can the be referenced by the subsequent inheritors of AButton
instead of the GtkLabel attribute 'label_' of ALabel.
For convenience a GtkLabel* 'label_' attribute is added to AButton.

If the button cannot be clicked it is disabled, effectively acting
like its label predecessor.

GtkButton seems to catch one-click mouse events regardless of the
flags set on it. Therefore, 'signal_pressed' is connected to a
function creating a fake GdkEventButton* and calling 'handleToggle'
(for details on this possible bug in GTK see:
https://stackoverflow.com/questions/45334911 )

In accordance with other GtkButtons (i.e. the sway/workspace ones)
set_relief(Gtk::RELIEF_NONE) is called on the 'button_' instance.
2022-10-12 10:25:29 +02:00
07050cf354 Merge branch 'Alexays:master' into master 2022-10-04 15:37:36 +03:00
ddf3e11240 remove clang-format lines 2022-10-04 11:28:32 +02:00
1ca660460a apply clang-format 2022-10-04 08:03:54 +02:00
0898236586 remove useless include <sys/types.h> 2022-10-04 07:37:05 +02:00
c3e91cd228 [FreeBSD] Use thermal-zone
The zone was hardcoded in #1702.
This commit allows to use the "thermal-zone"
variable.

Follow up #1702
2022-10-04 07:29:16 +02:00
c500c7d9a1 Fixed pulseaudio max-volume configuration. Fixed issue where volume stepping would cause the max volume to go above the max and never reach 0. 2022-09-30 15:25:12 -06:00
5da45ece9d Merge pull request #1702 from lbartoletti/freebsd_temperature 2022-09-30 21:24:05 +02:00
024777a5bc FreeBSD: Add support to temperature
This commit aims to propose a FreeBSD to gain temperature support using
sysctl on hw.acpi.thermal.tz0.temperature.
2022-09-30 21:12:28 +02:00
9758833027 added user module 2022-09-30 14:33:23 +03:00
9a958f6848 Merge branch 'master' of https://github.com/Alexays/Waybar 2022-09-22 09:52:45 +02:00
9e03bb61c7 Escape text in custom module 2022-09-16 01:19:44 +03:00
710f89599e Merge pull request #1686 from Alexays/revert-1685-master 2022-09-15 15:47:20 +02:00
d1700bf202 Revert "added checking router id in handleEvent function, because module does…" 2022-09-15 15:47:14 +02:00
e1b31db42b Merge pull request #1685 from Dordovel/master 2022-09-15 13:10:54 +02:00
52e9f624be added checking router id in handleEvent function, because module doesn't update state 2022-09-15 14:03:32 +03:00
e75eafcb34 Merge branch 'master' of https://github.com/tomcharnock/Waybar 2022-09-09 07:19:12 +00:00
6558a156b3 Add man entry for the ignored-sinks option 2022-09-09 00:54:32 +01:00
faf8954712 Add config option to ignore Pulseaudio Sinks
Fixes #1347
2022-09-09 00:51:25 +01:00
e58f1fd3e0 Merge pull request #1412 from eigenbrot/battery_zero_pad_minutes
Add battery format-time option for zero-padded minutes
2022-09-07 16:54:28 +02:00
6b83360e76 Add "{m}" battery format-time option for zero-pad minutes 2022-09-07 08:53:07 -06:00
03ca8de6d7 Update config.cpp 2022-09-07 10:33:57 +02:00
ac193ae669 Merge pull request #1646 from LukashonakV/ISSUE#1545
Issue#1545. Calendar scrolling opportunity
2022-09-07 09:16:59 +02:00
38d2815425 Merge pull request #1678 from asas1asas200/zeng-feat-idle_inhibitor_tooltip
feat(idle-inhibitor): add tooltip format
2022-09-05 17:52:27 +02:00
79f21c0d7b Merge pull request #1600 from leophys/master
Add support for reading the config path from env
2022-09-05 10:56:01 +02:00
0306c97173 Merge branch 'master' of https://github.com/Alexays/Waybar 2022-09-05 09:54:04 +02:00
8a82cdff16 Merge pull request #1659 from TheRealLorenz/master
Add 'max-volume' option to pulseaudio
2022-09-05 09:13:01 +02:00
29bdff5314 Merge pull request #1657 from vaxerski/hyprlandLanguage
Added a basic hyprland/language module
2022-09-05 09:12:17 +02:00
eb017347b8 Add support for reading the config path from env
This commit adds support to reading the config base path from the
environment variable `WAYBAR_CONFIG_DIR`. If it is set, but no
configuration is found there, it falls back to the previous mechanism
of using the default paths, without erroring.
2022-09-05 08:21:36 +02:00
912d7f8588 Making calculations uint64_t 2022-09-03 18:08:26 +02:00
5647146ac0 Added Discharging clause and corrected typo 2022-09-03 17:52:11 +02:00
af2a3f8bda Added alternative calculations for time remaining 2022-09-03 16:06:13 +02:00
55e83f90d1 feat(idle-inhibitor): add tooltip format 2022-09-03 19:21:32 +08:00
0d94853613 Added alternative variable calculations 2022-09-02 15:37:23 +02:00
120c68e014 Updated logic in battery module 2022-09-02 11:42:46 +02:00
4deb6d812d Merge pull request #1653 from kennypm/dsp
add JACK module
2022-09-02 08:12:57 +02:00
bc201fd0eb doc(sway/scratchpad): add man page 2022-08-31 16:27:25 +08:00
d2ff116c92 feat(sway/scratchpad): add some configs
Add some configs for displaying.
Remove draft codes.
2022-08-31 16:27:25 +08:00
e3342467fc feat(sway/scratchpad): add basic counter 2022-08-31 16:27:25 +08:00
ce10ce0d5e Merge pull request #1672 from asas1asas200/zeng-style-lint 2022-08-31 10:06:43 +02:00
4a929240df style(lint): fix some files lint 2022-08-31 15:51:50 +08:00
33d13af6d1 Merge pull request #1670 from akliuxingyuan/master 2022-08-30 20:43:51 +02:00
90878a5c98 Merge pull request #1669 from asas1asas200/zeng-fix-network 2022-08-30 20:43:03 +02:00
0d27949f0a scale icons for HiDPI monitor 2022-08-30 23:13:38 +08:00
f6322d2dd1 fix(network): dont escape essid in tooltip
Like #1256 , but escape by calling `set_tooltip_markup()`, because the
label text uses `set_markup()`.
2022-08-30 23:05:34 +08:00
330d166c82 Merge pull request #1668 from alex-courtis/1591-river-escape-window-and-mode 2022-08-29 08:26:40 +02:00
5f2dd99e6d #1591 river escape window and mode 2022-08-29 16:22:08 +10:00
8b03e38594 fix(keyboard): correct device-path config behavior 2022-08-24 14:08:34 +08:00
5944989a8a doc(keyboard): add deprecated warning 2022-08-24 02:41:12 +08:00
58a399b9af chore(ci, meson): add inotify dependency for BSD 2022-08-24 02:22:40 +08:00
dcd75b3b40 feat(keybaord): enable hotplug support
Use inotify listening devices path changes to implement hotplug support.
The new hotplug thread is also an event loop, so the interval value has
no effect.
The evdev is now open on demand.

Fix libinput_interface object life-time.
2022-08-23 23:30:16 +08:00
17f91391b6 Merge branch 'Alexays:master' into ISSUE#1545 2022-08-23 09:00:08 +00:00
061f4550f4 feat(keyboard): improve keyboard response time
Use libinput event for keyboard state updates.
The state will update when CAPS_LOCK, NUM_LOCK or SCROLL_LOCK has been
released,
`interval` will have no effect after this change.
2022-08-22 22:49:59 +08:00
fd24d7bcf6 Merge pull request #1660 from asas1asas200/master 2022-08-21 08:09:35 +02:00
51670f0506 Fix typo 2022-08-21 12:35:33 +08:00
4e930ba50a Add 'max-volume' option to pulseaudio. Fixes #1607 2022-08-20 22:21:57 +02:00
8839a86afe Merge branch 'Alexays:master' into ISSUE#1545 2022-08-19 13:52:52 +00:00
f4bfe777d9 oops 2022-08-18 20:56:26 -04:00
59e57ab9a0 man page and adjust default format 2022-08-18 17:05:04 -04:00
f00f30a5ae Merge pull request #5 from NotAShelf/hyprlandLanguage
Add man docs for Hyprland language module
2022-08-18 19:23:06 +02:00
40bc2e96db wording 2022-08-18 20:21:14 +03:00
9ac9dc368e Merge branch 'hyprlandLanguage' of https://github.com/vaxerski/Waybar into hyprlandLanguage 2022-08-18 20:16:42 +03:00
39c170bf10 remove one comment that I forgot to 2022-08-18 19:13:24 +02:00
5fea01300c Merge branch 'hyprlandLanguage' of github.com:NotAShelf/Waybar into hyprlandLanguage 2022-08-18 20:12:44 +03:00
b181cd04b6 update man docs for format-<lang> option 2022-08-18 20:11:44 +03:00
d786f9a0e6 Merge branch 'vaxerski:hyprlandLanguage' into hyprlandLanguage 2022-08-18 20:10:31 +03:00
c5910ae19a Merge branch 'hyprlandLanguage' of https://github.com/vaxerski/Waybar into hyprlandLanguage 2022-08-18 20:09:34 +03:00
ed6467e785 fix linter 2022-08-18 19:02:46 +02:00
43c3ca1d38 added the thing i was talking about 2022-08-18 18:59:34 +02:00
97f0d6fa42 remove redundant formatting 2022-08-18 19:35:40 +03:00
b8a68b8085 man documentation for hl language module 2022-08-18 19:32:26 +03:00
8881b9a6ef fix linter the most 2022-08-18 18:06:34 +02:00
e8942feefc fix linter more 2022-08-18 18:05:40 +02:00
a23d58e900 fix linter 2022-08-18 18:04:39 +02:00
16d5619f3b added a basic hyprland/language module 2022-08-18 18:00:27 +02:00
bcee4e15d3 fix: lint files 2022-08-18 15:22:25 +02:00
b7bd06ad8f Update window.cpp 2022-08-18 15:21:50 +02:00
e50c246601 Merge pull request #1651 from TheRealLorenz/master
Feature: sway/window can show 'shell' parameter
2022-08-18 15:21:09 +02:00
ee504b826d Update README.md 2022-08-18 15:16:28 +02:00
848ae1f818 Merge pull request #1656 from vaxerski/hyprland
Added a Hyprland backend and a Window module
2022-08-18 15:15:45 +02:00
406eb0ee9a Merge pull request #4 from NotAShelf/hyprland
Init man documentation
2022-08-18 15:10:42 +02:00
112d481ae7 Init man documentation 2022-08-18 15:59:00 +03:00
872cd6083d Merge pull request #3 from vaxerski/revert-2-master
Revert "init man documentation"
2022-08-18 14:54:30 +02:00
8dc78e4e40 Revert "init man documentation" 2022-08-18 14:54:20 +02:00
e662b8c624 Merge pull request #2 from NotAShelf/master
init man documentation
2022-08-18 14:53:15 +02:00
e0451816e2 init man documentation 2022-08-18 15:29:59 +03:00
e2e59a52df make the linter happy 2022-08-17 22:03:49 +02:00
123ed36739 remove workspaces module as its buggy and unnecessary 2022-08-17 21:58:33 +02:00
c64058c947 stabilize window module 2022-08-17 21:54:23 +02:00
56d46e62c1 add samplerate callback since pipewire supports dynamic samplerate changes 2022-08-12 11:30:12 -04:00
89a57f6722 simplify build option description 2022-08-11 18:35:33 -04:00
4336f10b29 Merge branch 'dsp' of https://github.com/kennypm/Waybar into dsp 2022-08-11 17:26:45 -04:00
a7979a3e56 add locks and refactor for clarity 2022-08-11 17:26:27 -04:00
bfed2114e4 jack_client_close working properly now 2022-08-11 15:49:24 -04:00
f65a372855 Merge branch 'Alexays:master' into dsp 2022-08-11 07:46:20 +00:00
6f3fe6d339 Update waybar-sway-window.5.scd 2022-08-11 08:41:10 +02:00
c287b0c82b Update manpage for sway/window 2022-08-10 22:24:48 +02:00
5b1cd65e20 Fix: better formatting 2022-08-10 10:41:18 +02:00
99ed2bb7fa Feature: sway/window can show 'shell' parameter 2022-08-10 10:34:51 +02:00
ddd5b4e157 refactor 2022-08-07 15:29:42 -04:00
e9e5780aae Calendar scrolling opportunity 2022-08-06 13:55:20 +03:00
061ad13082 Bug: tripple click uses wrong event type 2022-08-06 13:52:00 +03:00
77bea7c182 Merge pull request #1631 from m-braunschweig/filename
mpd: add filename formatter
2022-08-04 10:05:14 +02:00
c2ab2e6d19 Merge pull request #1627 from datMaffin/master
sni: Use the pixmap if for the given icon name an icon could not be found
2022-08-04 10:04:48 +02:00
11239a4900 mpd: add filename formatter 2022-08-03 20:52:18 +02:00
95b5348c24 sni: change missing icon in theme logging from info to trace 2022-08-03 17:34:34 +02:00
9616df58da Merge branch 'Alexays:master' into dsp 2022-08-01 03:30:45 +00:00
7b115913de Merge pull request #1638 from ErikReider/master 2022-07-31 21:27:05 +02:00
4029c5423f Added UPower to README 2022-07-31 10:56:42 +02:00
3996764880 Merge pull request #1637 from jbeich/ci 2022-07-30 09:09:26 +02:00
60821257ac chore(ci): adjust FreeBSD to follow upstream recommendations
- use macos-12 as macos-10.15 will be removed on 2022-08-30
- use major version to transparently pick up updates
2022-07-29 20:05:24 +00:00
e14005a6aa Fix binary pow formatting for values between 1000 and 1024 2022-07-21 16:37:43 -04:00
15dbe8965e fix Linter error 2022-07-19 22:36:59 -04:00
decc5bcd68 namespace cleanup 2022-07-19 22:34:35 -04:00
92870cab2a namespace cleanup 2022-07-19 22:30:42 -04:00
4cb2cc9f21 fix Linter errors 2022-07-19 21:54:36 -04:00
02df861829 fix Linter errors 2022-07-19 21:53:32 -04:00
23eaffc04b fix Linter errors 2022-07-19 21:49:56 -04:00
714451e4f9 cleanup 2022-07-19 19:40:23 -04:00
4cd6024f07 move issue from comment to Issues 2022-07-19 19:36:48 -04:00
8b5f42d934 remove unnecessary libprocps dependency 2022-07-19 19:27:39 -04:00
b65c976bc1 fix build type 2022-07-19 01:41:32 -04:00
5e7c9378df update fork 2022-07-19 01:40:05 -04:00
a9569e7d5c Merge branch 'dsp' of https://github.com/kennypm/Waybar into dsp 2022-07-19 01:39:19 -04:00
318a6e0969 fix segfault when stopping JACK2 server 2022-07-19 01:38:56 -04:00
a1d046b2e7 Update README.md 2022-07-19 01:38:56 -04:00
c7b09eea11 changed callbacks to use static_cast 2022-07-19 01:38:56 -04:00
bc8517fd08 fix callbacks 2022-07-19 01:38:56 -04:00
9439e4183c fix callbacks 2022-07-19 01:38:56 -04:00
8fc8bb40bf Initial commit for Waybar JACK monitoring module
-DSP load
  -xruns
  -connected/disconnected state
  -only tested with Pipewire so far but should work with JACK2 as well

 On branch dsp
 Changes to be committed:
	modified:   include/factory.hpp
	new file:   include/modules/jack.hpp
	modified:   meson.build
	modified:   meson_options.txt
	modified:   src/factory.cpp
	new file:   src/modules/jack.cpp
2022-07-19 01:38:35 -04:00
d906080f26 Merge pull request #1617 from alebastr/fmt-9
fix: adapt to fmt 9.0.0 breaking changes
2022-07-18 10:00:46 +02:00
04d66de866 sni: remove unnecesary parameter 2022-07-17 22:20:24 +02:00
699f732146 sni: Remove unnecessary getIconByName call 2022-07-17 22:15:14 +02:00
f437bf96e3 sni: Prefer system icons over pixmap 2022-07-17 22:15:12 +02:00
fc9a390977 sni: Use the given pixmap even if there is a name given 2022-07-17 22:14:57 +02:00
56a45e962b Merge pull request #1628 from carlosV2/master 2022-07-17 18:15:23 +02:00
48d2759df5 add layout as class to language module 2022-07-17 16:13:32 +01:00
1116ff0d67 Merge pull request #1624 from ersen0/fix-man
battery: fix wrong definition for "format"
2022-07-15 10:44:09 +02:00
0c04aea108 battery: fix wrong definition for "format" 2022-07-15 11:01:14 +03:00
a44622aa9f fix: fmt 9.x deprecation warning for implicit enum conversions 2022-07-13 22:36:37 -07:00
3117aefdf3 fix: drop conditionals for ancient fmt versions 2022-07-13 22:36:33 -07:00
24a8332b62 fix: adapt to fmt 9.0.0 breaking changes 2022-07-13 22:36:32 -07:00
84e7689521 Merge pull request #1621 from jbeich/ci 2022-07-14 07:33:06 +02:00
0708573fa4 chore(ci): upgrade FreeBSD to 13.1
FreeBSD doesn't support /latest and /quarterly package repos on EOL
versions. 13.0 reaches EOL on 2022-08-31, so avoid CI breakage.
2022-07-13 21:26:45 +00:00
08d472d1b1 Merge pull request #1612 from LukashonakV/Gentoo_CI
New Gentoo CI
2022-07-12 16:24:10 +02:00
c35f91ed7a Update linux.yml
New Gentoo CI container
2022-07-06 09:50:21 +00:00
9c3af1b6ad Gentoo docker file 2022-07-06 09:47:24 +00:00
17b60bc737 minor changes 2022-07-01 15:35:25 +02:00
c1f92d2a3c added workspaces 2022-07-01 15:16:54 +02:00
72f478c195 added backend and hyprland/window 2022-07-01 12:46:28 +02:00
5128a5d9f3 Merge pull request #1599 from LukashonakV/ISSUE#1565
Last weekday applies Unix fmt
2022-06-27 10:18:12 +02:00
36aa22189b Last weekday applies Unix fmt 2022-06-24 16:44:06 +03:00
d10d9b8202 Merge pull request #1590 from qubidt/pulseaudio-fix
pulseaudio: avoid retaining outdated form factor
2022-06-15 09:15:50 +02:00
e57899c0c5 pulseaudio: avoid retaining outdated form factor
when the module fails to get the pulseaudio device form factor, the
module persists the existing value, resulting in the incorrect
format-icon being used to format the label on device changes.

reset the form factor value so that the icon lookup properly falls back
to "default" when missing
2022-06-14 13:57:03 -05:00
249c0aad73 fix: lint 2022-06-14 09:17:40 +02:00
18a4f87a59 Merge pull request #1588 from qubidt/custom-module-class
Retain instance name css class for custom modules
2022-06-14 09:15:42 +02:00
458c03bf95 retain instance name css class for custom modules
When adding a custom module with a name, e.g.:

```jsonc
{
  ...,
  "custom/foo#bar": { },
  ...
}
```

The custom module does not retain the `bar` class as it should, because
all the classes are replaced with the runtime output:

1b4a7b02f4/src/modules/custom.cpp (L141-L147)

Avoid removing the module instance name class so css class behavior is
consistent between all modules.
2022-06-13 16:10:41 -05:00
1b4a7b02f4 Merge pull request #1575 from cosandr/bandwidth-update
Add total bandwidth formatting options
2022-06-11 11:45:18 +02:00
fb2ac8a765 Merge pull request #1580 from tiosgz/river-mode-readme
README.md: add river/mode to feature list
2022-06-02 16:48:46 +02:00
13100326b0 README.md: add river/mode to feature list 2022-06-02 14:36:18 +00:00
ca0d35286d Merge pull request #1579 from tiosgz/river-mode
river/mode: new module
2022-06-02 14:22:21 +02:00
f3a049c6df river/mode: new module
This module shows river's current mapping mode (e.g. normal, locked).
2022-06-01 15:35:08 +00:00
074b7c4b99 Merge pull request #1578 from NickHastings/readme-river
Advertise river modules
2022-06-01 10:18:03 +02:00
b24fd35add Advertise river modules 2022-06-01 09:10:26 +09:00
c27dab9379 Merge pull request #1576 from daangoossens22/fix_bluetooth 2022-05-28 15:28:20 +02:00
6857691679 style(bluetooth): apply project style 2022-05-28 12:58:37 +02:00
a475be7cf7 feat(bluetooth): add format-icons 2022-05-28 12:35:33 +02:00
00c11c64ca fix(bluetooth): tooltip-format-connected-battery 2022-05-28 12:33:47 +02:00
4e2305639b Add option for displaying total bandwidth 2022-05-28 10:54:10 +02:00
e0f29dbf71 Add bandwidth in bytes to 5 waybar-network 2022-05-28 10:39:43 +02:00
36d3d511d6 Merge pull request #1571 from daangoossens22/position_bar
fix: vertical bar not anchored when width is set
2022-05-25 16:42:20 +02:00
ae9fb57790 fix: vertical bar not anchored when width is set 2022-05-25 16:09:21 +02:00
b8ee448e71 Merge pull request #1567 from jbeich/freebsd 2022-05-23 20:47:45 +02:00
632058a4f6 chore(ci): test upower module on freebsd 2022-05-23 16:33:48 +00:00
d25278f710 fix(upower): add missing include for libc++
In file included from src/modules/upower/upower.cpp:1:
include/modules/upower/upower.hpp:25:16: error: no template named 'unordered_map' in namespace 'std'
  typedef std::unordered_map<std::string, UpDevice *> Devices;
          ~~~~~^
In file included from src/modules/upower/upower_tooltip.cpp:1:
include/modules/upower/upower_tooltip.hpp:13:16: error: no template named 'unordered_map' in namespace 'std'
  typedef std::unordered_map<std::string, UpDevice*> Devices;
          ~~~~~^
2022-05-23 16:27:32 +00:00
2dfd64e1c9 Merge pull request #1566 from ErikReider/master
Added gamemode man file to meson
2022-05-23 14:43:58 +02:00
3c182c9ca9 Added gamemode man file to meson 2022-05-23 14:13:30 +02:00
aa5f55bbe3 chore: v0.9.13 2022-05-23 13:54:24 +02:00
7ab9a560ae fix: lint 2022-05-23 13:47:14 +02:00
a5299af3c2 Merge pull request #1562 from trevnels/river-window
River Window Module
2022-05-23 13:43:28 +02:00
4d1aeb7eb8 Merge pull request #1525 from FlexW/feature/icon-heuristics
sway/window: Add heuristics for finding icons
2022-05-23 13:42:26 +02:00
38a846ae51 Merge pull request #1555 from LukashonakV/ISSUE#1552
Calendar module: localization issue #1552
2022-05-23 13:40:48 +02:00
03bbc9df64 Merge pull request #1554 from ErikReider/gamemode-module
Gamemode Module
2022-05-23 13:40:09 +02:00
1e4fe0bee8 Merge pull request #1557 from LukashonakV/ISSUE#1556
Issue#1556. Battery module: a lot of warnings when battery dissapears
2022-05-23 13:39:23 +02:00
5e2067d51f Merge pull request #1563 from groknull/crash-on-empty-cpuvec
Prevent segfault in getCpuFrequency
2022-05-23 13:38:53 +02:00
7ea0a2348b Man page example now uses default values 2022-05-21 12:08:05 +02:00
fd306e184a Added man page 2022-05-21 12:06:45 +02:00
f4f2989e85 Added tooltip-format 2022-05-21 12:02:45 +02:00
8d4c7176f8 Renamed not-running-bide to hide-not-running 2022-05-21 12:02:35 +02:00
7abcbe80e5 Prevent segfault in getCpuFrequency
When parseCpuFrequencies returns an empty vector, getCpuFrequency
would attempt to dereference an invalid iterator.

Return early from getCpuFrequency when parseCpuFrequencies returns an
empty vector.

Resolves a segfault when waybar is run within a VM on apple silicon.
2022-05-19 20:01:57 -04:00
165c5a861d manpage fixes 2022-05-19 16:41:05 -04:00
d84c0f13e6 forgot to commit meson build 2022-05-19 16:33:50 -04:00
01ffe2c290 add inherited ALabel options to river window manpage 2022-05-19 15:53:25 -04:00
b900c01381 add manpage and make format option work 2022-05-19 15:32:10 -04:00
e2b676b800 add river/window module 2022-05-19 15:20:04 -04:00
7f995507fe std::filesystem::path is a string representation 2022-05-14 17:10:44 +03:00
b39a8ede6c Issue#1556. Battery module: wrong string comparison
1. battery.hpp - added local bool variable. Force to print warnings the
only once in order to warn user about wrong battery configuraion. And
does not bring a mess when the battery is turned off (gamepads, etc.)
2. dir_name is an object which takes a part in comparison. So converted to the string.
2022-05-14 16:56:46 +03:00
315ea991bc Calendar module: localization issue #1552 Linter #60 2022-05-13 23:56:08 +03:00
bd0f6128d3 Revert "Waybar. Issue#1552. Calendar module, LC_TIME variable"
This reverts commit 7b7ee41e13.
2022-05-13 22:58:38 +03:00
5a014305ec Revert "Issue#1552. Calendar module, LC_TIME variable"
This reverts commit 448b413eca.
2022-05-13 22:58:00 +03:00
3411236697 Initial implementation 2022-05-13 21:30:45 +02:00
e615612bf4 Calendar module: localization issue #1552 2022-05-13 18:51:32 +03:00
448b413eca Issue#1552. Calendar module, LC_TIME variable 2022-05-13 12:54:18 +03:00
7b7ee41e13 Waybar. Issue#1552. Calendar module, LC_TIME variable 2022-05-12 19:04:45 +03:00
9bc821bdac Merge pull request #1551 from loserMcloser/keyboard-state-css-classes
Add classes to individual keyboard state labels
2022-05-12 13:55:32 +02:00
bfcb936d87 Add classes to individual keyboard state labels 2022-05-11 08:08:28 -06:00
3d023a0421 Merge pull request #1540 from daangoossens22/bluetooth
feat: extend bluetooth module
2022-05-11 09:26:38 +02:00
e235f48245 feat: hide module if empty 2022-05-07 13:42:27 +02:00
3043d42a89 style: apply projects clang-format 2022-05-06 17:01:43 +02:00
733fb8c62a docs: update + add experimental section 2022-05-06 16:43:53 +02:00
954bed3f5e refactor: adapter renamed to controller
Since it is also called controller in bluetoothctl
2022-05-06 16:37:48 +02:00
13df878bc3 refactor: logic for enumerating devices in tooltip 2022-05-06 16:37:40 +02:00
4592dd4a6c Merge pull request #1527 from siikamiika/network-current-iface-bandwidth
network: calculate bandwidth for current interface
2022-05-05 09:44:44 +02:00
794610a1ca feat: display all connected devices in tooltip 2022-05-04 19:27:39 +02:00
7bbf7c99a3 fix: lint 2022-05-04 17:29:08 +02:00
eec0a8255f Merge pull request #1454 from Psykar/idle_inhibitor_timeout
Add a config to set a timeout for the idle_inhibitor module
2022-05-04 17:27:21 +02:00
638b4e6573 feat: extend bluetooth module 2022-05-02 18:11:21 +02:00
caee2e611f Merge pull request #1530 from qubidt/backlight-fix
Backlight: avoid crash on getting brightness fails
2022-04-22 09:17:54 +02:00
96746142d2 Backlight: don't reset value when failing to read
Avoids the brightness percentage resetting to 0 on intermittent failures
2022-04-21 22:19:05 -05:00
1af7191740 Backlight: avoid crash on getting brightness fails
Reading brightness value for backlight device can fail intermittently
(particularly when using ddcci-driver-linux). Handle this more
gracefully rather than crashing
2022-04-21 22:02:45 -05:00
89be55b00b Merge pull request #1510 from towoe/sway-bar-show
Show hidden bar
2022-04-20 05:13:53 +02:00
23369aa14c Merge pull request #1500 from RobertMueller2/clock-thread-sleep
Replace sleep_until with sleep_for to prevent clock from getting stuck with system time adjustment
2022-04-20 05:11:49 +02:00
a16e54573e Merge pull request #1524 from berbiche/fix/gtk-layer-shell-anchors
bar: don't set layer-shell anchor for edges when width is not 'auto'
2022-04-20 05:09:36 +02:00
7231c47244 network: calculate bandwidth for current interface 2022-04-18 13:56:30 +03:00
6184e43c84 Merge pull request #1523 from FlexW/feature/icon-size
sway/window: Allow the user to change the size of the app icon
2022-04-18 08:59:36 +02:00
3f123d9c4e sway/window: Add heuristics for finding icons
This adds heuristics for finding the applications icon.
2022-04-18 03:09:25 +02:00
6851e26450 bar: don't set layer-shell anchor for edges
Don't set the anchor for certain edges when the width or the height
is not set to a value of 'auto' (1).

When the bar is vertical, the top and bottom edges are not anchored
otherwise the left and right edges are not anchored.

This resolves an issue wherein the width and height set for the
layer-shell were ignored because the layer was set to anchor to all
edges.
2022-04-17 18:19:36 -04:00
fc6f5741b1 sway/window: Allow the user to change the size of the app icon
Fixes #1461
2022-04-17 23:57:57 +02:00
264e2c3983 Merge pull request #1522 from FlexW/bugfix/app-icon 2022-04-17 23:32:59 +02:00
45988b3dbb Sway/window: Only update icon from main thread
If Gtk objects get updated from other threads than the main thread GTK
can get confused. This is a regression of bcadf64031.

Fixes #1464, #1474
2022-04-17 22:55:58 +02:00
4e3f91d237 Issue 1226/1497: align updates with times divisible by interval 2022-04-16 14:21:28 +02:00
e5d05baba3 Issue 1226/1497: Replace sleep_until with sleep_for to prevent clock from getting stuck with system time adjustment 2022-04-16 14:21:28 +02:00
7763d50691 Add reset behaviour of modifier key
Add an option to change the behaviour of the modifier key to reset the
visibility.
2022-04-15 20:04:58 +02:00
5a0e42cc76 Limit visibility updates
Prevent visibility updates to occur for inactive modules.
Check active modules and subscribe to only those events.
2022-04-15 20:04:56 +02:00
1dcd36b06c Show bar on sway mode
Display the bar if the sway mode is not the default mode.
2022-04-15 19:58:50 +02:00
93f9b3d213 Clear urgency hint with modifier press
If the modifier is pressed and release without another event, the
intended behaviour is to clear an urgency hint and hide the bar again.

Note that if multiple workspaces have the urgency hint set, the bar is
hidden again and an urgent workspace is focused, the bar does not stay
hidden anymore.
2022-04-15 19:55:06 +02:00
54b1df69a9 fix: lint clock 2022-04-15 14:39:13 +02:00
73cd156a7a Merge pull request #1492 from LukashonakV/master
#1315. Add option to display week number on calendar
2022-04-15 14:37:46 +02:00
e3700b924e Show bar if a workspace becomes urgent
Add a second reason to show the bar besides visible by modifier.
Update the visibility based on changes in the workspace urgency.
Check all workspaces for urgency and keep the bar visible if at least
one has an urgency hint.
2022-04-14 19:08:11 +02:00
d87cf8a8f2 Merge pull request #1518 from towoe/bluetooth-format
Add disabled bluetooth style
2022-04-12 10:35:54 +02:00
e8b022c096 Add disabled bluetooth style
Allow to set a different style if the bluetooth adapter is disabled.
2022-04-12 10:31:20 +02:00
503fe9a7ea Merge pull request #1516 from alebastr/ipc-enum-type
refactor: change `enum ipc_command_type` to uint32_t
2022-04-11 08:49:43 +02:00
b812596080 Update lint.yml 2022-04-11 08:49:20 +02:00
13fdbc13c3 refactor: change enum ipc_command_type to uint32_t
As we always use the enum to compare or initialize uint32_t values, it
would be better to declare it with the right type. This way we could
avoid `-Wnarrowing` warnings or unnecessary type casts.
2022-04-10 12:52:46 -07:00
1071b9f7c5 Add a config to set a timeout for the idle_inhibitor module 2022-04-10 22:47:52 +09:30
6ad1f6b853 Merge branch 'master' into master 2022-04-10 09:54:50 +00:00
a1129c4c87 fix: bsd 2022-04-06 14:55:08 +02:00
2e12ea6a81 fix: add missing include 2022-04-06 08:43:31 +02:00
f2fcadbf62 refactor: lint 2022-04-06 08:37:19 +02:00
168ba2ca5b Create lint.yml 2022-04-06 08:27:52 +02:00
46f07d24dd Merge branch 'master' into master 2022-04-05 15:28:55 +00:00
ed3e2ffdc3 Merge pull request #1499 from LukashonakV/ISSUE#1068
Waybar. Issue#1068. Double/Triple events
2022-04-05 16:40:52 +02:00
d5b76bd8b5 Merge pull request #1495 from 0cc4m/master
Battery module support for rk817
2022-04-05 16:39:08 +02:00
1d03034fbb Merge pull request #1493 from ErikReider/upower-fixes
Upower fixes
2022-04-05 16:37:36 +02:00
e094480684 Very basic hypr window title module 2022-04-02 21:08:43 +02:00
f4cc088d2f Waybar. Issue#1068. Double/Triple events. Removed unnecessary including 2022-03-29 13:47:38 +03:00
b086e2f995 Waybar. Issue#1068. Double/Triple events 2022-03-29 12:26:05 +03:00
4a457648f9 Waybar. Clock module. Calendar - custom output formats 2022-03-27 11:15:56 +03:00
3a95f8f599 Add battery module fallback for batteries without capacity or with _avg instead of _cur files 2022-03-26 19:42:06 +01:00
a7ed1ed570 Don't call dp.emit() when UPower service active status changes 2022-03-25 17:35:37 +01:00
e0f0931e2d Hide module if UPower service isn't running 2022-03-25 17:27:36 +01:00
0140606226 Fixed segfault on upower service restart 2022-03-25 16:57:25 +01:00
1d2a381b5f Waybar. Clock module - weeknum fix for the left side 2022-03-25 18:51:59 +03:00
d1d73b5003 Added missing "fulL" and "empty" CSS classes 2022-03-25 14:57:04 +01:00
9dc09d2702 Added upower man page into man_files meson variable 2022-03-25 14:53:46 +01:00
2ca4dcac49 Set box widget name to "upower" 2022-03-25 14:52:12 +01:00
2d87bcb1ab https://github.com/Alexays/Waybar/issues/1315. Option to display week number on calendar 2022-03-24 15:41:50 +03:00
d4a07483b2 Merge pull request #1484 from ErikReider/upower-module
Upower module
2022-03-22 10:00:28 +01:00
84dc82e1c1 Added tooltip-padding 2022-03-21 13:50:46 +01:00
e06316c80b Only set label text if string doesn't only contain spaces 2022-03-20 00:36:53 +01:00
7b071567ea Removed goto in update method 2022-03-20 00:36:13 +01:00
2633ff3fb9 Fixed time_left string not being set properly 2022-03-19 23:10:15 +01:00
0764e9ad6e Added format and format-alt config properties 2022-03-19 21:15:48 +01:00
c4282cfacc Made tooltip getDeviceIcon return const string 2022-03-19 19:22:21 +01:00
05effad18b Added CSS status classes 2022-03-19 19:22:00 +01:00
5f19a54deb Added man page 2022-03-19 17:25:43 +01:00
7fac2afb85 Added custom tooltip with device icon, device name and battery status 2022-03-19 17:09:55 +01:00
4196e0d5d1 Unref all devices on destruct 2022-03-19 11:35:13 +01:00
14a2a7027f Moved upower into its own directory 2022-03-19 11:34:34 +01:00
2b2ac311d5 Fixed not visible when only battery is plugged in 2022-03-19 11:19:39 +01:00
d7a030daf3 Lowered default icon size to 20 2022-03-19 11:19:08 +01:00
7345918f84 Added mutex locking to resetDevices 2022-03-19 11:18:51 +01:00
105f1cefe1 Fixed device unrefed 2022-03-19 10:52:05 +01:00
175d82858b Merge branch 'upower-module' of github.com:ErikReider/Waybar into upower-module 2022-03-19 10:48:43 +01:00
c8d785071f Merge branch 'master' into upower-module 2022-03-19 10:48:02 +01:00
8c6063d181 Merge pull request #1485 from LukashonakV/master
Hide/Unhide temperature module when "format*" is empty.
2022-03-19 10:24:59 +01:00
799125fb73 Merge pull request #1489 from momokrono/master
feat: added network speed in Bytes
2022-03-19 10:24:26 +01:00
fcf93a6c45 feat: added network speed in Bytes 2022-03-18 10:35:19 +01:00
6946288053 PR #1485 review 2022-03-17 11:31:06 +03:00
2a563f54e7 Change name to upower 2022-03-16 15:33:39 +01:00
9f337db2d2 Hide/Unhide module when "format*" is empty. 2022-03-16 15:50:00 +03:00
136b47ce0d Fixed percentage not getting rounded 2022-03-15 23:03:13 +01:00
6eb187a23e Moved upower.*pp out of the upower directories 2022-03-15 23:00:09 +01:00
9b9e42fc5f use device variable instead of getting the device from the map 2022-03-15 22:50:11 +01:00
d47073ef13 Reload all devices after wake from suspend 2022-03-15 22:49:40 +01:00
5396ffb71f Added "icon-size" and "hide-if-empty" config options 2022-03-15 20:22:32 +01:00
5e9faeb2d0 Now shows the percentage and the correct icon 2022-03-15 20:22:04 +01:00
4ee81c8dea Added all callbacks 2022-03-15 17:54:06 +01:00
a37ef74fb1 Merge pull request #1479 from dorgnarg/master
Use user-defined mode when toggling visibility rather than resetting to default
2022-03-15 09:06:08 +01:00
07034d561c Merge pull request #1481 from LukashonakV/master
Battery module. Gamepads support
2022-03-14 17:42:26 +01:00
37d87be3c1 Add supporting of the gamepads batteries 2022-03-14 17:53:19 +03:00
8aee7492d4 Plug/Unplug batteries on hot(useful for gamepads) 2022-03-14 17:12:05 +03:00
5c1c07a035 Merge pull request #1480 from avdv/xkb-load-exotic-rules
sway/language: Load exotic xkb rules too
2022-03-13 22:32:00 +01:00
caa24f0647 sway/language: Load exotic xkb rules too 2022-03-13 09:40:32 +01:00
f4c6dfcddc Uses user-defined mode when toggling visibility rather than resetting to default mode 2022-03-12 13:32:08 -07:00
2b3fc3acff Merge pull request #1478 from Artturin/moonemoji 2022-03-12 16:03:50 +01:00
25536f70a4 use moon phases for backlight format-icons 2022-03-12 16:05:06 +02:00
74ca1a42c6 Merge pull request #1476 from Psykar/fix-bsd-action
Fix freebsd action
2022-03-10 15:00:32 +01:00
8b6bc215cc Fix freebsd action 2022-03-10 14:48:40 +01:00
3c1ba0a240 chore: v0.9.12 2022-03-10 09:53:25 +01:00
6c7acf18b5 Update network.cpp 2022-03-10 09:53:02 +01:00
ead1b2f0dc Merge pull request #1467 from Pound-Hash/docs
Edited README
2022-03-10 09:51:12 +01:00
0e580236ce Fixed English mechanics: grammar, punctuation, and styling. 2022-03-08 15:52:20 -08:00
ccce2b700b fix segfault when stopping JACK2 server 2022-02-24 02:46:45 -05:00
65c3f0a132 Merge branch 'dsp' of https://github.com/kennypm/Waybar into dsp 2022-02-18 02:14:51 -05:00
e6262b870c changed callbacks to use static_cast 2022-02-18 02:13:43 -05:00
823ed887ab Update README.md 2022-02-12 05:53:32 -05:00
3bf815f6de fix callbacks 2022-02-12 01:52:51 -05:00
c1cda1553a fix callbacks 2022-02-12 01:51:11 -05:00
f6ee90e5ba Merge branch 'dsp' of https://github.com/kennypm/Waybar into dsp 2022-02-12 01:49:14 -05:00
d5c400c0cc Initial commit for Waybar JACK monitoring module
-DSP load
  -xruns
  -connected/disconnected state
  -only tested with Pipewire so far but should work with JACK2 as well

 On branch dsp
 Changes to be committed:
	modified:   include/factory.hpp
	new file:   include/modules/jack.hpp
	modified:   meson.build
	modified:   meson_options.txt
	modified:   src/factory.cpp
	new file:   src/modules/jack.cpp
2022-02-09 02:53:52 -05:00
161 changed files with 8492 additions and 3991 deletions

View File

@ -1,6 +1,5 @@
--- ---
BasedOnStyle: Google BasedOnStyle: Google
AlignConsecutiveDeclarations: true AlignConsecutiveDeclarations: false
BinPackArguments: false
ColumnLimit: 100 ColumnLimit: 100
... ...

View File

@ -4,14 +4,14 @@ on: [ push, pull_request ]
jobs: jobs:
clang: clang:
# Run actions in a FreeBSD vm on the macos-10.15 runner # Run actions in a FreeBSD VM on the macos-12 runner
# https://github.com/actions/runner/issues/385 - for FreeBSD runner support # https://github.com/actions/runner/issues/385 - for FreeBSD runner support
# https://github.com/actions/virtual-environments/issues/4060 - for lack of VirtualBox on MacOS 11 runners # https://github.com/actions/virtual-environments/issues/4060 - for lack of VirtualBox on MacOS 11 runners
runs-on: macos-10.15 runs-on: macos-12
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- name: Test in FreeBSD VM - name: Test in FreeBSD VM
uses: vmactions/freebsd-vm@v0.1.6 # aka FreeBSD 13.0 uses: vmactions/freebsd-vm@v0
with: with:
mem: 2048 mem: 2048
usesh: true usesh: true
@ -21,7 +21,8 @@ jobs:
pkg install -y git # subprojects/date pkg install -y git # subprojects/date
pkg install -y catch evdev-proto gtk-layer-shell gtkmm30 jsoncpp \ pkg install -y catch evdev-proto gtk-layer-shell gtkmm30 jsoncpp \
libdbusmenu libevdev libfmt libmpdclient libudev-devd meson \ libdbusmenu libevdev libfmt libmpdclient libudev-devd meson \
pkgconf pulseaudio scdoc sndio spdlog wayland-protocols pkgconf pulseaudio scdoc sndio spdlog wayland-protocols upower \
libinotify
run: | run: |
meson build -Dman-pages=enabled meson build -Dman-pages=enabled
ninja -C build ninja -C build

14
.github/workflows/lint.yml vendored Normal file
View File

@ -0,0 +1,14 @@
name: Linter
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: DoozyX/clang-format-lint-action@v0.13
with:
source: '.'
extensions: 'h,cpp,c'
clangFormatVersion: 12

View File

@ -12,6 +12,7 @@ jobs:
- debian - debian
- fedora - fedora
- opensuse - opensuse
- gentoo
runs-on: ubuntu-latest runs-on: ubuntu-latest
container: container:

11
Dockerfiles/gentoo Normal file
View File

@ -0,0 +1,11 @@
# vim: ft=Dockerfile
FROM gentoo/stage3:latest
RUN export FEATURES="-ipc-sandbox -network-sandbox -pid-sandbox -sandbox -usersandbox" && \
emerge --sync && \
eselect news read --quiet new 1>/dev/null 2>&1 && \
emerge --verbose --update --deep --with-bdeps=y --backtrack=30 --newuse @world && \
USE="wayland gtk3 gtk -doc X" emerge dev-vcs/git dev-libs/wayland dev-libs/wayland-protocols =dev-cpp/gtkmm-3.24.6 x11-libs/libxkbcommon \
x11-libs/gtk+:3 dev-libs/libdbusmenu dev-libs/libnl sys-power/upower media-libs/libpulse dev-libs/libevdev media-libs/libmpdclient \
media-sound/sndio gui-libs/gtk-layer-shell app-text/scdoc

View File

@ -2,14 +2,17 @@
> Highly customizable Wayland bar for Sway and Wlroots based compositors.<br> > 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 > Available in Arch [community](https://www.archlinux.org/packages/community/x86_64/waybar/) or
[AUR](https://aur.archlinux.org/packages/waybar-git/), [Gentoo](https://packages.gentoo.org/packages/gui-apps/waybar), [openSUSE](https://build.opensuse.org/package/show/X11:Wayland/waybar), and [Alpine Linux](https://pkgs.alpinelinux.org/packages?name=waybar)<br> [AUR](https://aur.archlinux.org/packages/waybar-git/), [Gentoo](https://packages.gentoo.org/packages/gui-apps/waybar), [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)* > *Waybar [examples](https://github.com/Alexays/Waybar/wiki/Examples)*
#### Current features #### Current features
- Sway (Workspaces, Binding mode, Focused window name) - Sway (Workspaces, Binding mode, Focused window name)
- River (Mapping mode, Tags, Focused window name)
- Hyprland (Focused window name)
- Tray [#21](https://github.com/Alexays/Waybar/issues/21) - Tray [#21](https://github.com/Alexays/Waybar/issues/21)
- Local time - Local time
- Battery - Battery
- UPower
- Network - Network
- Bluetooth - Bluetooth
- Pulseaudio - Pulseaudio
@ -20,7 +23,7 @@
- MPD - MPD
- Custom scripts - Custom scripts
- Multiple output configuration - Multiple output configuration
- And much more customizations - And many more customizations
#### Configuration and Styling #### Configuration and Styling
@ -70,6 +73,7 @@ libmpdclient [MPD module]
libsndio [sndio module] libsndio [sndio module]
libevdev [KeyboardState module] libevdev [KeyboardState module]
xkbregistry xkbregistry
upower [UPower battery module]
``` ```
**Build dependencies** **Build dependencies**
@ -81,7 +85,7 @@ scdoc
wayland-protocols wayland-protocols
``` ```
On Ubuntu you can install all the relevant dependencies using this command (tested with 19.10 and 20.04): On Ubuntu, you can install all the relevant dependencies using this command (tested with 19.10 and 20.04):
``` ```
sudo apt install \ sudo apt install \
@ -103,12 +107,14 @@ sudo apt install \
libspdlog-dev \ libspdlog-dev \
libwayland-dev \ libwayland-dev \
scdoc \ scdoc \
upower \
libxkbregistry-dev libxkbregistry-dev
``` ```
Contributions welcome! - have fun :)<br> Contributions welcome!<br>
The style guidelines is [Google's](https://google.github.io/styleguide/cppguide.html) Have fun :)<br>
The style guidelines are [Google's](https://google.github.io/styleguide/cppguide.html)
## License ## License

35
include/AButton.hpp Normal file
View File

@ -0,0 +1,35 @@
#pragma once
#include <glibmm/markup.h>
#include <gtkmm/button.h>
#include <gtkmm/cssprovider.h>
#include <gtkmm/label.h>
#include <json/json.h>
#include "AModule.hpp"
namespace waybar {
class AButton : public AModule {
public:
AButton(const Json::Value &, const std::string &, const std::string &, const std::string &format,
uint16_t interval = 0, bool ellipsize = false, bool enable_click = false,
bool enable_scroll = false);
virtual ~AButton() = 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::Button button_ = Gtk::Button(name_);
Gtk::Label *label_ = (Gtk::Label *)button_.get_child();
std::string format_;
const std::chrono::seconds interval_;
bool alt_ = false;
std::string default_format_;
virtual bool handleToggle(GdkEventButton *const &e);
virtual std::string getState(uint8_t value, bool lesser = false);
};
} // namespace waybar

View File

@ -3,6 +3,7 @@
#include <glibmm/markup.h> #include <glibmm/markup.h>
#include <gtkmm/label.h> #include <gtkmm/label.h>
#include <json/json.h> #include <json/json.h>
#include "AModule.hpp" #include "AModule.hpp"
namespace waybar { namespace waybar {
@ -10,7 +11,8 @@ namespace waybar {
class ALabel : public AModule { class ALabel : public AModule {
public: public:
ALabel(const Json::Value &, const std::string &, const std::string &, const std::string &format, ALabel(const Json::Value &, const std::string &, const std::string &, const std::string &format,
uint16_t interval = 0, bool ellipsize = false, bool enable_click = false, bool enable_scroll = false); uint16_t interval = 0, bool ellipsize = false, bool enable_click = false,
bool enable_scroll = false);
virtual ~ALabel() = default; virtual ~ALabel() = default;
virtual auto update() -> void; 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::string &alt = "", uint16_t max = 0);

View File

@ -36,6 +36,22 @@ class AModule : public IModule {
std::vector<int> pid_; std::vector<int> pid_;
gdouble distance_scrolled_y_; gdouble distance_scrolled_y_;
gdouble distance_scrolled_x_; gdouble distance_scrolled_x_;
static const inline std::map<std::pair<uint, GdkEventType>, std::string> eventMap_{
{std::make_pair(1, GdkEventType::GDK_BUTTON_PRESS), "on-click"},
{std::make_pair(1, GdkEventType::GDK_2BUTTON_PRESS), "on-double-click"},
{std::make_pair(1, GdkEventType::GDK_3BUTTON_PRESS), "on-triple-click"},
{std::make_pair(2, GdkEventType::GDK_BUTTON_PRESS), "on-click-middle"},
{std::make_pair(2, GdkEventType::GDK_2BUTTON_PRESS), "on-double-click-middle"},
{std::make_pair(2, GdkEventType::GDK_3BUTTON_PRESS), "on-triple-click-middle"},
{std::make_pair(3, GdkEventType::GDK_BUTTON_PRESS), "on-click-right"},
{std::make_pair(3, GdkEventType::GDK_2BUTTON_PRESS), "on-double-click-right"},
{std::make_pair(3, GdkEventType::GDK_3BUTTON_PRESS), "on-triple-click-right"},
{std::make_pair(8, GdkEventType::GDK_BUTTON_PRESS), "on-click-backward"},
{std::make_pair(8, GdkEventType::GDK_2BUTTON_PRESS), "on-double-click-backward"},
{std::make_pair(8, GdkEventType::GDK_3BUTTON_PRESS), "on-triple-click-backward"},
{std::make_pair(9, GdkEventType::GDK_BUTTON_PRESS), "on-click-forward"},
{std::make_pair(9, GdkEventType::GDK_2BUTTON_PRESS), "on-double-click-forward"},
{std::make_pair(9, GdkEventType::GDK_3BUTTON_PRESS), "on-triple-click-forward"}};
}; };
} // namespace waybar } // namespace waybar

View File

@ -14,6 +14,7 @@ namespace waybar {
class Config { class Config {
public: public:
static const std::vector<std::string> CONFIG_DIRS; static const std::vector<std::string> CONFIG_DIRS;
static const char *CONFIG_PATH_ENV;
/* Try to find any of provided names in the supported set of config directories */ /* Try to find any of provided names in the supported set of config directories */
static std::optional<std::string> findConfigPath( static std::optional<std::string> findConfigPath(

View File

@ -7,19 +7,27 @@
#include "modules/simpleclock.hpp" #include "modules/simpleclock.hpp"
#endif #endif
#ifdef HAVE_SWAY #ifdef HAVE_SWAY
#include "modules/sway/language.hpp"
#include "modules/sway/mode.hpp" #include "modules/sway/mode.hpp"
#include "modules/sway/scratchpad.hpp"
#include "modules/sway/window.hpp" #include "modules/sway/window.hpp"
#include "modules/sway/workspaces.hpp" #include "modules/sway/workspaces.hpp"
#include "modules/sway/language.hpp"
#endif #endif
#ifdef HAVE_WLR #ifdef HAVE_WLR
#include "modules/wlr/taskbar.hpp" #include "modules/wlr/taskbar.hpp"
#include "modules/wlr/workspace_manager.hpp" #include "modules/wlr/workspace_manager.hpp"
#endif #endif
#ifdef HAVE_RIVER #ifdef HAVE_RIVER
#include "modules/river/mode.hpp"
#include "modules/river/tags.hpp" #include "modules/river/tags.hpp"
#include "modules/river/window.hpp"
#endif #endif
#if defined(__linux__) && !defined(NO_FILESYSTEM) #ifdef HAVE_HYPRLAND
#include "modules/hyprland/backend.hpp"
#include "modules/hyprland/language.hpp"
#include "modules/hyprland/window.hpp"
#endif
#if defined(__FreeBSD__) || (defined(__linux__) && !defined(NO_FILESYSTEM))
#include "modules/battery.hpp" #include "modules/battery.hpp"
#endif #endif
#if defined(HAVE_CPU_LINUX) || defined(HAVE_CPU_BSD) #if defined(HAVE_CPU_LINUX) || defined(HAVE_CPU_BSD)
@ -42,6 +50,12 @@
#ifdef HAVE_LIBEVDEV #ifdef HAVE_LIBEVDEV
#include "modules/keyboard_state.hpp" #include "modules/keyboard_state.hpp"
#endif #endif
#ifdef HAVE_GAMEMODE
#include "modules/gamemode.hpp"
#endif
#ifdef HAVE_UPOWER
#include "modules/upower/upower.hpp"
#endif
#ifdef HAVE_LIBPULSE #ifdef HAVE_LIBPULSE
#include "modules/pulseaudio.hpp" #include "modules/pulseaudio.hpp"
#endif #endif
@ -52,16 +66,16 @@
#include "modules/sndio.hpp" #include "modules/sndio.hpp"
#endif #endif
#ifdef HAVE_GIO_UNIX #ifdef HAVE_GIO_UNIX
#include "modules/bluetooth.hpp"
#include "modules/inhibitor.hpp" #include "modules/inhibitor.hpp"
#endif #endif
#ifdef HAVE_LIBJACK
#include "modules/jack.hpp"
#endif
#include "bar.hpp" #include "bar.hpp"
#include "modules/custom.hpp" #include "modules/custom.hpp"
#include "modules/temperature.hpp" #include "modules/temperature.hpp"
#if defined(__linux__) #include "modules/user.hpp"
# ifdef WANT_RFKILL
# include "modules/bluetooth.hpp"
# endif
#endif
namespace waybar { namespace waybar {

View File

@ -1,8 +1,9 @@
#pragma once #pragma once
#include <gtkmm/widget.h>
#include <gtkmm/box.h> #include <gtkmm/box.h>
#include <gtkmm/widget.h>
#include <json/json.h> #include <json/json.h>
#include "AModule.hpp" #include "AModule.hpp"
#include "bar.hpp" #include "bar.hpp"
#include "factory.hpp" #include "factory.hpp"

View File

@ -5,7 +5,7 @@
#include <string_view> #include <string_view>
#include <vector> #include <vector>
#include "ALabel.hpp" #include "AButton.hpp"
#include "util/json.hpp" #include "util/json.hpp"
#include "util/sleeper_thread.hpp" #include "util/sleeper_thread.hpp"
@ -14,7 +14,7 @@ struct udev_device;
namespace waybar::modules { namespace waybar::modules {
class Backlight : public ALabel { class Backlight : public AButton {
class BacklightDev { class BacklightDev {
public: public:
BacklightDev() = default; BacklightDev() = default;

View File

@ -6,12 +6,16 @@
#include <filesystem> #include <filesystem>
#endif #endif
#include <fmt/format.h> #include <fmt/format.h>
#if defined(__linux__)
#include <sys/inotify.h> #include <sys/inotify.h>
#endif
#include <algorithm> #include <algorithm>
#include <fstream> #include <fstream>
#include <string> #include <string>
#include <vector> #include <vector>
#include "ALabel.hpp"
#include "AButton.hpp"
#include "util/sleeper_thread.hpp" #include "util/sleeper_thread.hpp"
namespace waybar::modules { namespace waybar::modules {
@ -22,7 +26,7 @@ namespace fs = std::experimental::filesystem;
namespace fs = std::filesystem; namespace fs = std::filesystem;
#endif #endif
class Battery : public ALabel { class Battery : public AButton {
public: public:
Battery(const std::string&, const Json::Value&); Battery(const std::string&, const Json::Value&);
~Battery(); ~Battery();
@ -44,6 +48,7 @@ class Battery : public ALabel {
int global_watch_fd_; int global_watch_fd_;
std::mutex battery_list_mutex_; std::mutex battery_list_mutex_;
std::string old_status_; std::string old_status_;
bool warnFirstTime_{true};
util::SleeperThread thread_; util::SleeperThread thread_;
util::SleeperThread thread_battery_update_; util::SleeperThread thread_battery_update_;

View File

@ -1,18 +1,79 @@
#pragma once #pragma once
#include "ALabel.hpp" #include "AButton.hpp"
#ifdef WANT_RFKILL
#include "util/rfkill.hpp" #include "util/rfkill.hpp"
#endif
#include <gio/gio.h>
#include <optional>
#include <string>
#include <vector>
namespace waybar::modules { namespace waybar::modules {
class Bluetooth : public ALabel { class Bluetooth : public AButton {
struct ControllerInfo {
std::string path;
std::string address;
std::string address_type;
// std::string name; // just use alias instead
std::string alias;
bool powered;
bool discoverable;
bool pairable;
bool discovering;
};
// NOTE: there are some properties that not all devices provide
struct DeviceInfo {
std::string path;
std::string paired_controller;
std::string address;
std::string address_type;
// std::optional<std::string> name; // just use alias instead
std::string alias;
std::optional<std::string> icon;
bool paired;
bool trusted;
bool blocked;
bool connected;
bool services_resolved;
// NOTE: experimental feature in bluez
std::optional<unsigned char> battery_percentage;
};
public: public:
Bluetooth(const std::string&, const Json::Value&); Bluetooth(const std::string&, const Json::Value&);
~Bluetooth() = default; ~Bluetooth() = default;
auto update() -> void; auto update() -> void;
private: private:
static auto onInterfaceAddedOrRemoved(GDBusObjectManager*, GDBusObject*, GDBusInterface*,
gpointer) -> void;
static auto onInterfaceProxyPropertiesChanged(GDBusObjectManagerClient*, GDBusObjectProxy*,
GDBusProxy*, GVariant*, const gchar* const*,
gpointer) -> void;
auto getDeviceBatteryPercentage(GDBusObject*) -> std::optional<unsigned char>;
auto getDeviceProperties(GDBusObject*, DeviceInfo&) -> bool;
auto getControllerProperties(GDBusObject*, ControllerInfo&) -> bool;
auto findCurController(ControllerInfo&) -> bool;
auto findConnectedDevices(const std::string&, std::vector<DeviceInfo>&) -> void;
#ifdef WANT_RFKILL
util::Rfkill rfkill_; util::Rfkill rfkill_;
#endif
const std::unique_ptr<GDBusObjectManager, void (*)(GDBusObjectManager*)> manager_;
std::string state_;
ControllerInfo cur_controller_;
std::vector<DeviceInfo> connected_devices_;
DeviceInfo cur_focussed_device_;
std::string device_enumerate_;
std::vector<std::string> device_preference_;
}; };
} // namespace waybar::modules } // namespace waybar::modules

View File

@ -1,7 +1,8 @@
#pragma once #pragma once
#include <date/tz.h> #include <date/tz.h>
#include "ALabel.hpp"
#include "AButton.hpp"
#include "util/sleeper_thread.hpp" #include "util/sleeper_thread.hpp"
namespace waybar { namespace waybar {
@ -13,7 +14,7 @@ namespace modules {
const std::string kCalendarPlaceholder = "calendar"; const std::string kCalendarPlaceholder = "calendar";
const std::string KTimezonedTimeListPlaceholder = "timezoned_time_list"; const std::string KTimezonedTimeListPlaceholder = "timezoned_time_list";
class Clock : public ALabel { class Clock : public AButton {
public: public:
Clock(const std::string&, const Json::Value&); Clock(const std::string&, const Json::Value&);
~Clock() = default; ~Clock() = default;
@ -24,8 +25,9 @@ class Clock : public ALabel {
std::locale locale_; std::locale locale_;
std::vector<const date::time_zone*> time_zones_; std::vector<const date::time_zone*> time_zones_;
int current_time_zone_idx_; int current_time_zone_idx_;
date::year_month_day cached_calendar_ymd_ = date::January/1/0; date::year_month_day calendar_cached_ymd_{date::January / 1 / 0};
std::string cached_calendar_text_; date::months calendar_shift_{0}, calendar_shift_init_{0};
std::string calendar_cached_text_;
bool is_calendar_in_tooltip_; bool is_calendar_in_tooltip_;
bool is_timezoned_list_in_tooltip_; bool is_timezoned_list_in_tooltip_;
@ -36,8 +38,7 @@ class Clock : public ALabel {
auto first_day_of_week() -> date::weekday; auto first_day_of_week() -> date::weekday;
const date::time_zone* current_timezone(); const date::time_zone* current_timezone();
bool is_timezone_fixed(); bool is_timezone_fixed();
auto timezones_text(std::chrono::_V2::system_clock::time_point *now) -> std::string; auto timezones_text(std::chrono::system_clock::time_point* now) -> std::string;
}; };
} // namespace modules } // namespace modules
} // namespace waybar } // namespace waybar

View File

@ -1,18 +1,20 @@
#pragma once #pragma once
#include <fmt/format.h> #include <fmt/format.h>
#include <cstdint> #include <cstdint>
#include <fstream> #include <fstream>
#include <numeric> #include <numeric>
#include <string> #include <string>
#include <utility> #include <utility>
#include <vector> #include <vector>
#include "ALabel.hpp"
#include "AButton.hpp"
#include "util/sleeper_thread.hpp" #include "util/sleeper_thread.hpp"
namespace waybar::modules { namespace waybar::modules {
class Cpu : public ALabel { class Cpu : public AButton {
public: public:
Cpu(const std::string&, const Json::Value&); Cpu(const std::string&, const Json::Value&);
~Cpu() = default; ~Cpu() = default;

View File

@ -1,16 +1,18 @@
#pragma once #pragma once
#include <fmt/format.h> #include <fmt/format.h>
#include <csignal> #include <csignal>
#include <string> #include <string>
#include "ALabel.hpp"
#include "AButton.hpp"
#include "util/command.hpp" #include "util/command.hpp"
#include "util/json.hpp" #include "util/json.hpp"
#include "util/sleeper_thread.hpp" #include "util/sleeper_thread.hpp"
namespace waybar::modules { namespace waybar::modules {
class Custom : public ALabel { class Custom : public AButton {
public: public:
Custom(const std::string&, const std::string&, const Json::Value&); Custom(const std::string&, const std::string&, const Json::Value&);
~Custom(); ~Custom();
@ -28,6 +30,7 @@ class Custom : public ALabel {
const std::string name_; const std::string name_;
std::string text_; std::string text_;
std::string id_;
std::string alt_; std::string alt_;
std::string tooltip_; std::string tooltip_;
std::vector<std::string> class_; std::vector<std::string> class_;

View File

@ -1,15 +1,17 @@
#pragma once #pragma once
#include <fmt/format.h> #include <fmt/format.h>
#include <fstream>
#include <sys/statvfs.h> #include <sys/statvfs.h>
#include "ALabel.hpp"
#include "util/sleeper_thread.hpp" #include <fstream>
#include "AButton.hpp"
#include "util/format.hpp" #include "util/format.hpp"
#include "util/sleeper_thread.hpp"
namespace waybar::modules { namespace waybar::modules {
class Disk : public ALabel { class Disk : public AButton {
public: public:
Disk(const std::string&, const Json::Value&); Disk(const std::string&, const Json::Value&);
~Disk() = default; ~Disk() = default;

View File

@ -0,0 +1,77 @@
#pragma once
#include <iostream>
#include <map>
#include <string>
#include "ALabel.hpp"
#include "giomm/dbusconnection.h"
#include "giomm/dbusproxy.h"
#include "glibconfig.h"
#include "gtkmm/box.h"
#include "gtkmm/image.h"
#include "gtkmm/label.h"
#include "gtkmm/overlay.h"
namespace waybar::modules {
class Gamemode : public AModule {
public:
Gamemode(const std::string &, const Json::Value &);
~Gamemode();
auto update() -> void;
private:
const std::string DEFAULT_ICON_NAME = "input-gaming-symbolic";
const std::string DEFAULT_FORMAT = "{glyph}";
const std::string DEFAULT_FORMAT_ALT = "{glyph} {count}";
const std::string DEFAULT_TOOLTIP_FORMAT = "Games running: {count}";
const std::string DEFAULT_GLYPH = "";
void appear(const Glib::RefPtr<Gio::DBus::Connection> &connection, const Glib::ustring &name,
const Glib::ustring &name_owner);
void disappear(const Glib::RefPtr<Gio::DBus::Connection> &connection, const Glib::ustring &name);
void prepareForSleep_cb(const Glib::RefPtr<Gio::DBus::Connection> &connection,
const Glib::ustring &sender_name, const Glib::ustring &object_path,
const Glib::ustring &interface_name, const Glib::ustring &signal_name,
const Glib::VariantContainerBase &parameters);
void notify_cb(const Glib::ustring &sender_name, const Glib::ustring &signal_name,
const Glib::VariantContainerBase &arguments);
void getData();
bool handleToggle(GdkEventButton *const &);
// Config
std::string format = DEFAULT_FORMAT;
std::string format_alt = DEFAULT_FORMAT_ALT;
std::string tooltip_format = DEFAULT_TOOLTIP_FORMAT;
std::string glyph = DEFAULT_GLYPH;
bool tooltip = true;
bool hideNotRunning = true;
bool useIcon = true;
uint iconSize = 20;
uint iconSpacing = 4;
std::string iconName = DEFAULT_ICON_NAME;
Gtk::Box box_;
Gtk::Image icon_;
Gtk::Label label_;
const std::string dbus_name = "com.feralinteractive.GameMode";
const std::string dbus_obj_path = "/com/feralinteractive/GameMode";
const std::string dbus_interface = "org.freedesktop.DBus.Properties";
const std::string dbus_get_interface = "com.feralinteractive.GameMode";
uint gameCount = 0;
std::string lastStatus;
bool showAltText = false;
guint login1_id;
Glib::RefPtr<Gio::DBus::Proxy> gamemode_proxy;
Glib::RefPtr<Gio::DBus::Connection> system_connection;
bool gamemodeRunning;
guint gamemodeWatcher_id;
};
} // namespace waybar::modules

View File

@ -0,0 +1,28 @@
#pragma once
#include <deque>
#include <functional>
#include <memory>
#include <mutex>
#include <string>
#include <thread>
namespace waybar::modules::hyprland {
class IPC {
public:
IPC() { startIPC(); }
void registerForIPC(const std::string&, std::function<void(const std::string&)>);
std::string getSocket1Reply(const std::string& rq);
private:
void startIPC();
void parseIPC(const std::string&);
std::mutex callbackMutex;
std::deque<std::pair<std::string, std::function<void(const std::string&)>>> callbacks;
};
inline std::unique_ptr<IPC> gIPC;
inline bool modulesReady = false;
}; // namespace waybar::modules::hyprland

View File

@ -0,0 +1,29 @@
#include <fmt/format.h>
#include "AButton.hpp"
#include "bar.hpp"
#include "modules/hyprland/backend.hpp"
#include "util/json.hpp"
namespace waybar::modules::hyprland {
class Language : public waybar::AButton {
public:
Language(const std::string&, const waybar::Bar&, const Json::Value&);
~Language() = default;
auto update() -> void;
private:
void onEvent(const std::string&);
void initLanguage();
std::string getShortFrom(const std::string&);
std::mutex mutex_;
const Bar& bar_;
util::JsonParser parser_;
std::string layoutName_;
};
} // namespace waybar::modules::hyprland

View File

@ -0,0 +1,31 @@
#include <fmt/format.h>
#include <tuple>
#include "ALabel.hpp"
#include "bar.hpp"
#include "modules/hyprland/backend.hpp"
#include "util/json.hpp"
namespace waybar::modules::hyprland {
class Window : public waybar::ALabel {
public:
Window(const std::string&, const waybar::Bar&, const Json::Value&);
~Window() = default;
auto update() -> void;
private:
uint getActiveWorkspaceID(std::string);
std::string getLastWindowTitle(uint);
void onEvent(const std::string&);
bool separate_outputs;
std::mutex mutex_;
const Bar& bar_;
util::JsonParser parser_;
std::string lastView;
};
} // namespace waybar::modules::hyprland

View File

@ -1,13 +1,16 @@
#pragma once #pragma once
#include <fmt/format.h> #include <fmt/format.h>
#include "ALabel.hpp"
#include "AButton.hpp"
#include "bar.hpp" #include "bar.hpp"
#include "client.hpp" #include "client.hpp"
namespace waybar::modules { namespace waybar::modules {
class IdleInhibitor : public ALabel { class IdleInhibitor : public AButton {
sigc::connection timeout_;
public: public:
IdleInhibitor(const std::string&, const waybar::Bar&, const Json::Value&); IdleInhibitor(const std::string&, const waybar::Bar&, const Json::Value&);
~IdleInhibitor(); ~IdleInhibitor();
@ -17,6 +20,7 @@ class IdleInhibitor : public ALabel {
private: private:
bool handleToggle(GdkEventButton* const& e); bool handleToggle(GdkEventButton* const& e);
void toggleStatus();
const Bar& bar_; const Bar& bar_;
struct zwp_idle_inhibitor_v1* idle_inhibitor_; struct zwp_idle_inhibitor_v1* idle_inhibitor_;

View File

@ -1,15 +1,15 @@
#pragma once #pragma once
#include <memory>
#include <gio/gio.h> #include <gio/gio.h>
#include "ALabel.hpp" #include <memory>
#include "AButton.hpp"
#include "bar.hpp" #include "bar.hpp"
namespace waybar::modules { namespace waybar::modules {
class Inhibitor : public ALabel { class Inhibitor : public AButton {
public: public:
Inhibitor(const std::string&, const waybar::Bar&, const Json::Value&); Inhibitor(const std::string&, const waybar::Bar&, const Json::Value&);
~Inhibitor() override; ~Inhibitor() override;

44
include/modules/jack.hpp Normal file
View File

@ -0,0 +1,44 @@
#pragma once
#include <fmt/format.h>
#include <jack/jack.h>
#include <jack/thread.h>
#include <fstream>
#include "ALabel.hpp"
#include "util/sleeper_thread.hpp"
namespace waybar::modules {
class JACK : public ALabel {
public:
JACK(const std::string &, const Json::Value &);
~JACK() = default;
auto update() -> void;
int bufSize(jack_nframes_t size);
int sampleRate(jack_nframes_t rate);
int xrun();
void shutdown();
private:
std::string JACKState();
jack_client_t *client_;
jack_nframes_t bufsize_;
jack_nframes_t samplerate_;
unsigned int xruns_;
float load_;
bool running_;
std::mutex mutex_;
std::string state_;
util::SleeperThread thread_;
};
} // namespace waybar::modules
int bufSizeCallback(jack_nframes_t size, void *obj);
int sampleRateCallback(jack_nframes_t rate, void *obj);
int xrunCallback(void *obj);
void shutdownCallback(void *obj);

View File

@ -1,18 +1,17 @@
#pragma once #pragma once
#include <fmt/format.h>
#if FMT_VERSION < 60000
#include <fmt/time.h>
#else
#include <fmt/chrono.h> #include <fmt/chrono.h>
#endif #include <gtkmm/label.h>
#include <unordered_map>
#include "AModule.hpp" #include "AModule.hpp"
#include "bar.hpp" #include "bar.hpp"
#include "util/sleeper_thread.hpp" #include "util/sleeper_thread.hpp"
#include <gtkmm/label.h>
extern "C" { extern "C" {
#include <libevdev/libevdev.h> #include <libevdev/libevdev.h>
#include <libinput.h>
} }
namespace waybar::modules { namespace waybar::modules {
@ -24,6 +23,8 @@ class KeyboardState : public AModule {
auto update() -> void; auto update() -> void;
private: private:
auto tryAddDevice(const std::string&) -> void;
Gtk::Box box_; Gtk::Box box_;
Gtk::Label numlock_label_; Gtk::Label numlock_label_;
Gtk::Label capslock_label_; Gtk::Label capslock_label_;
@ -35,11 +36,12 @@ class KeyboardState : public AModule {
const std::chrono::seconds interval_; const std::chrono::seconds interval_;
std::string icon_locked_; std::string icon_locked_;
std::string icon_unlocked_; std::string icon_unlocked_;
std::string devices_path_;
int fd_; struct libinput* libinput_;
libevdev* dev_; std::unordered_map<std::string, struct libinput_device*> libinput_devices_;
util::SleeperThread thread_; util::SleeperThread libinput_thread_, hotplug_thread_;
}; };
} // namespace waybar::modules } // namespace waybar::modules

View File

@ -1,14 +1,16 @@
#pragma once #pragma once
#include <fmt/format.h> #include <fmt/format.h>
#include <fstream> #include <fstream>
#include <unordered_map> #include <unordered_map>
#include "ALabel.hpp"
#include "AButton.hpp"
#include "util/sleeper_thread.hpp" #include "util/sleeper_thread.hpp"
namespace waybar::modules { namespace waybar::modules {
class Memory : public ALabel { class Memory : public AButton {
public: public:
Memory(const std::string&, const Json::Value&); Memory(const std::string&, const Json::Value&);
~Memory() = default; ~Memory() = default;

View File

@ -7,12 +7,12 @@
#include <condition_variable> #include <condition_variable>
#include <thread> #include <thread>
#include "ALabel.hpp" #include "AButton.hpp"
#include "modules/mpd/state.hpp" #include "modules/mpd/state.hpp"
namespace waybar::modules { namespace waybar::modules {
class MPD : public ALabel { class MPD : public AButton {
friend class detail::Context; friend class detail::Context;
// State machine // State machine
@ -41,6 +41,7 @@ class MPD : public ALabel {
private: private:
std::string getTag(mpd_tag_type type, unsigned idx = 0) const; std::string getTag(mpd_tag_type type, unsigned idx = 0) const;
std::string getFilename() const;
void setLabel(); void setLabel();
std::string getStateIcon() const; std::string getStateIcon() const;
std::string getOptionIcon(std::string optionName, bool activated) const; std::string getOptionIcon(std::string optionName, bool activated) const;

View File

@ -1,13 +1,13 @@
#pragma once #pragma once
#include <mpd/client.h>
#include <fmt/format.h> #include <fmt/format.h>
#include <mpd/client.h>
#include <spdlog/spdlog.h> #include <spdlog/spdlog.h>
#include <condition_variable> #include <condition_variable>
#include <thread> #include <thread>
#include "ALabel.hpp" #include "AButton.hpp"
namespace waybar::modules { namespace waybar::modules {
class MPD; class MPD;

View File

@ -12,9 +12,7 @@ inline void Context::tryConnect() const { mpd_module_->tryConne
inline unique_connection& Context::connection() { return mpd_module_->connection_; } inline unique_connection& Context::connection() { return mpd_module_->connection_; }
constexpr inline mpd_state Context::state() const { return mpd_module_->state_; } constexpr inline mpd_state Context::state() const { return mpd_module_->state_; }
inline void Context::do_update() { inline void Context::do_update() { mpd_module_->setLabel(); }
mpd_module_->setLabel();
}
inline void Context::checkErrors(mpd_connection* conn) const { mpd_module_->checkErrors(conn); } inline void Context::checkErrors(mpd_connection* conn) const { mpd_module_->checkErrors(conn); }
inline void Context::queryMPD() const { mpd_module_->queryMPD(); } inline void Context::queryMPD() const { mpd_module_->queryMPD(); }

View File

@ -7,7 +7,10 @@
#include <netlink/genl/genl.h> #include <netlink/genl/genl.h>
#include <netlink/netlink.h> #include <netlink/netlink.h>
#include <sys/epoll.h> #include <sys/epoll.h>
#include "ALabel.hpp"
#include <optional>
#include "AButton.hpp"
#include "util/sleeper_thread.hpp" #include "util/sleeper_thread.hpp"
#ifdef WANT_RFKILL #ifdef WANT_RFKILL
#include "util/rfkill.hpp" #include "util/rfkill.hpp"
@ -15,7 +18,7 @@
namespace waybar::modules { namespace waybar::modules {
class Network : public ALabel { class Network : public AButton {
public: public:
Network(const std::string&, const Json::Value&); Network(const std::string&, const Json::Value&);
~Network(); ~Network();

View File

@ -3,13 +3,15 @@
#include <fmt/format.h> #include <fmt/format.h>
#include <pulse/pulseaudio.h> #include <pulse/pulseaudio.h>
#include <pulse/volume.h> #include <pulse/volume.h>
#include <algorithm> #include <algorithm>
#include <array> #include <array>
#include "ALabel.hpp"
#include "AButton.hpp"
namespace waybar::modules { namespace waybar::modules {
class Pulseaudio : public ALabel { class Pulseaudio : public AButton {
public: public:
Pulseaudio(const std::string&, const Json::Value&); Pulseaudio(const std::string&, const Json::Value&);
~Pulseaudio(); ~Pulseaudio();

View File

@ -0,0 +1,28 @@
#pragma once
#include <wayland-client.h>
#include "ALabel.hpp"
#include "bar.hpp"
#include "river-status-unstable-v1-client-protocol.h"
namespace waybar::modules::river {
class Mode : public waybar::ALabel {
public:
Mode(const std::string &, const waybar::Bar &, const Json::Value &);
~Mode();
// Handlers for wayland events
void handle_mode(const char *mode);
struct zriver_status_manager_v1 *status_manager_;
struct wl_seat *seat_;
private:
const waybar::Bar &bar_;
std::string mode_;
struct zriver_seat_status_v1 *seat_status_;
};
} /* namespace waybar::modules::river */

View File

@ -5,8 +5,8 @@
#include "AModule.hpp" #include "AModule.hpp"
#include "bar.hpp" #include "bar.hpp"
#include "river-status-unstable-v1-client-protocol.h"
#include "river-control-unstable-v1-client-protocol.h" #include "river-control-unstable-v1-client-protocol.h"
#include "river-status-unstable-v1-client-protocol.h"
#include "xdg-output-unstable-v1-client-protocol.h" #include "xdg-output-unstable-v1-client-protocol.h"
namespace waybar::modules::river { namespace waybar::modules::river {

View File

@ -0,0 +1,33 @@
#pragma once
#include <gtkmm/button.h>
#include <wayland-client.h>
#include "ALabel.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 Window : public waybar::ALabel {
public:
Window(const std::string &, const waybar::Bar &, const Json::Value &);
~Window();
// Handlers for wayland events
void handle_focused_view(const char *title);
void handle_focused_output(struct wl_output *output);
void handle_unfocused_output(struct wl_output *output);
struct zriver_status_manager_v1 *status_manager_;
struct wl_seat *seat_;
private:
const waybar::Bar &bar_;
struct wl_output *output_; // stores the output this module belongs to
struct wl_output *focused_output_; // stores the currently focused output
struct zriver_seat_status_v1 *seat_status_;
};
} /* namespace waybar::modules::river */

View File

@ -1,17 +1,13 @@
#pragma once #pragma once
#include <fmt/format.h>
#if FMT_VERSION < 60000
#include <fmt/time.h>
#else
#include <fmt/chrono.h> #include <fmt/chrono.h>
#endif
#include "ALabel.hpp" #include "AButton.hpp"
#include "util/sleeper_thread.hpp" #include "util/sleeper_thread.hpp"
namespace waybar::modules { namespace waybar::modules {
class Clock : public ALabel { class Clock : public AButton {
public: public:
Clock(const std::string&, const Json::Value&); Clock(const std::string&, const Json::Value&);
~Clock() = default; ~Clock() = default;

View File

@ -1,13 +1,15 @@
#pragma once #pragma once
#include <sndio.h> #include <sndio.h>
#include <vector> #include <vector>
#include "ALabel.hpp"
#include "AButton.hpp"
#include "util/sleeper_thread.hpp" #include "util/sleeper_thread.hpp"
namespace waybar::modules { namespace waybar::modules {
class Sndio : public ALabel { class Sndio : public AButton {
public: public:
Sndio(const std::string &, const Json::Value &); Sndio(const std::string &, const Json::Value &);
~Sndio(); ~Sndio();

View File

@ -4,7 +4,9 @@
#include <giomm.h> #include <giomm.h>
#include <glibmm/refptr.h> #include <glibmm/refptr.h>
#include <json/json.h> #include <json/json.h>
#include <tuple> #include <tuple>
#include "bar.hpp" #include "bar.hpp"
#include "modules/sni/item.hpp" #include "modules/sni/item.hpp"

View File

@ -1,6 +1,7 @@
#pragma once #pragma once
#include <fmt/format.h> #include <fmt/format.h>
#include "AModule.hpp" #include "AModule.hpp"
#include "bar.hpp" #include "bar.hpp"
#include "modules/sni/host.hpp" #include "modules/sni/host.hpp"

View File

@ -1,4 +1,5 @@
#pragma once #pragma once
#include <atomic>
#include <string> #include <string>
#include "modules/sway/ipc/client.hpp" #include "modules/sway/ipc/client.hpp"
@ -30,18 +31,28 @@ class BarIpcClient {
private: private:
void onInitialConfig(const struct Ipc::ipc_response& res); void onInitialConfig(const struct Ipc::ipc_response& res);
void onIpcEvent(const struct Ipc::ipc_response&); void onIpcEvent(const struct Ipc::ipc_response&);
void onCmd(const struct Ipc::ipc_response&);
void onConfigUpdate(const swaybar_config& config); void onConfigUpdate(const swaybar_config& config);
void onVisibilityUpdate(bool visible_by_modifier); void onVisibilityUpdate(bool visible_by_modifier);
void onModeUpdate(bool visible_by_modifier);
void onUrgencyUpdate(bool visible_by_urgency);
void update(); void update();
bool isModuleEnabled(std::string name);
Bar& bar_; Bar& bar_;
util::JsonParser parser_; util::JsonParser parser_;
Ipc ipc_; Ipc ipc_;
swaybar_config bar_config_; swaybar_config bar_config_;
std::string modifier_reset_;
bool visible_by_mode_ = false;
bool visible_by_modifier_ = false; bool visible_by_modifier_ = false;
bool visible_by_urgency_ = false;
std::atomic<bool> modifier_no_action_ = false;
SafeSignal<bool> signal_mode_;
SafeSignal<bool> signal_visible_; SafeSignal<bool> signal_visible_;
SafeSignal<bool> signal_urgency_;
SafeSignal<swaybar_config> signal_config_; SafeSignal<swaybar_config> signal_config_;
}; };

View File

@ -4,9 +4,11 @@
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/un.h> #include <sys/un.h>
#include <unistd.h> #include <unistd.h>
#include <cstring> #include <cstring>
#include <memory> #include <memory>
#include <mutex> #include <mutex>
#include "ipc.hpp" #include "ipc.hpp"
#include "util/sleeper_thread.hpp" #include "util/sleeper_thread.hpp"

View File

@ -1,8 +1,10 @@
#pragma once #pragma once
#include <cstdint>
#define event_mask(ev) (1u << (ev & 0x7F)) #define event_mask(ev) (1u << (ev & 0x7F))
enum ipc_command_type { enum ipc_command_type : uint32_t {
// i3 command types - see i3's I3_REPLY_TYPE constants // i3 command types - see i3's I3_REPLY_TYPE constants
IPC_COMMAND = 0, IPC_COMMAND = 0,
IPC_GET_WORKSPACES = 1, IPC_GET_WORKSPACES = 1,
@ -21,16 +23,16 @@ enum ipc_command_type {
IPC_GET_SEATS = 101, IPC_GET_SEATS = 101,
// Events sent from sway to clients. Events have the highest bits set. // Events sent from sway to clients. Events have the highest bits set.
IPC_EVENT_WORKSPACE = ((1 << 31) | 0), IPC_EVENT_WORKSPACE = ((1U << 31) | 0),
IPC_EVENT_OUTPUT = ((1 << 31) | 1), IPC_EVENT_OUTPUT = ((1U << 31) | 1),
IPC_EVENT_MODE = ((1 << 31) | 2), IPC_EVENT_MODE = ((1U << 31) | 2),
IPC_EVENT_WINDOW = ((1 << 31) | 3), IPC_EVENT_WINDOW = ((1U << 31) | 3),
IPC_EVENT_BARCONFIG_UPDATE = ((1 << 31) | 4), IPC_EVENT_BARCONFIG_UPDATE = ((1U << 31) | 4),
IPC_EVENT_BINDING = ((1 << 31) | 5), IPC_EVENT_BINDING = ((1U << 31) | 5),
IPC_EVENT_SHUTDOWN = ((1 << 31) | 6), IPC_EVENT_SHUTDOWN = ((1U << 31) | 6),
IPC_EVENT_TICK = ((1 << 31) | 7), IPC_EVENT_TICK = ((1U << 31) | 7),
// sway-specific event types // sway-specific event types
IPC_EVENT_BAR_STATE_UPDATE = ((1<<31) | 20), IPC_EVENT_BAR_STATE_UPDATE = ((1U << 31) | 20),
IPC_EVENT_INPUT = ((1<<31) | 21), IPC_EVENT_INPUT = ((1U << 31) | 21),
}; };

View File

@ -6,7 +6,7 @@
#include <map> #include <map>
#include <string> #include <string>
#include "ALabel.hpp" #include "AButton.hpp"
#include "bar.hpp" #include "bar.hpp"
#include "client.hpp" #include "client.hpp"
#include "modules/sway/ipc/client.hpp" #include "modules/sway/ipc/client.hpp"
@ -14,18 +14,14 @@
namespace waybar::modules::sway { namespace waybar::modules::sway {
class Language : public ALabel, public sigc::trackable { class Language : public AButton, public sigc::trackable {
public: public:
Language(const std::string& id, const Json::Value& config); Language(const std::string& id, const Json::Value& config);
~Language() = default; ~Language() = default;
auto update() -> void; auto update() -> void;
private: private:
enum class DispayedShortFlag { enum class DispayedShortFlag { None = 0, ShortName = 1, ShortDescription = 1 << 1 };
None = 0,
ShortName = 1,
ShortDescription = 1 << 1
};
struct Layout { struct Layout {
std::string full_name; std::string full_name;
@ -40,6 +36,7 @@ class Language : public ALabel, public sigc::trackable {
XKBContext(); XKBContext();
~XKBContext(); ~XKBContext();
auto next_layout() -> Layout*; auto next_layout() -> Layout*;
private: private:
rxkb_context* context_ = nullptr; rxkb_context* context_ = nullptr;
rxkb_layout* xkb_layout_ = nullptr; rxkb_layout* xkb_layout_ = nullptr;

View File

@ -1,7 +1,8 @@
#pragma once #pragma once
#include <fmt/format.h> #include <fmt/format.h>
#include "ALabel.hpp"
#include "AButton.hpp"
#include "bar.hpp" #include "bar.hpp"
#include "client.hpp" #include "client.hpp"
#include "modules/sway/ipc/client.hpp" #include "modules/sway/ipc/client.hpp"
@ -9,7 +10,7 @@
namespace waybar::modules::sway { namespace waybar::modules::sway {
class Mode : public ALabel, public sigc::trackable { class Mode : public AButton, public sigc::trackable {
public: public:
Mode(const std::string&, const Json::Value&); Mode(const std::string&, const Json::Value&);
~Mode() = default; ~Mode() = default;

View File

@ -0,0 +1,35 @@
#pragma once
#include <gtkmm/label.h>
#include <mutex>
#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 Scratchpad : public ALabel {
public:
Scratchpad(const std::string&, const Json::Value&);
~Scratchpad() = default;
auto update() -> void;
private:
auto getTree() -> void;
auto onCmd(const struct Ipc::ipc_response&) -> void;
auto onEvent(const struct Ipc::ipc_response&) -> void;
std::string tooltip_format_;
bool show_empty_;
bool tooltip_enabled_;
std::string tooltip_text_;
int count_;
std::mutex mutex_;
Ipc ipc_;
util::JsonParser parser_;
};
} // namespace waybar::modules::sway

View File

@ -1,6 +1,7 @@
#pragma once #pragma once
#include <fmt/format.h> #include <fmt/format.h>
#include <tuple> #include <tuple>
#include "AIconLabel.hpp" #include "AIconLabel.hpp"
@ -20,18 +21,23 @@ class Window : public AIconLabel, public sigc::trackable {
private: private:
void onEvent(const struct Ipc::ipc_response&); void onEvent(const struct Ipc::ipc_response&);
void onCmd(const struct Ipc::ipc_response&); void onCmd(const struct Ipc::ipc_response&);
std::tuple<std::size_t, int, std::string, std::string> getFocusedNode(const Json::Value& nodes, std::tuple<std::size_t, int, std::string, std::string, std::string, std::string> getFocusedNode(
std::string& output); const Json::Value& nodes, std::string& output);
void getTree(); void getTree();
std::string rewriteTitle(const std::string& title); void updateAppIconName();
void updateAppIcon(); void updateAppIcon();
const Bar& bar_; const Bar& bar_;
std::string window_; std::string window_;
int windowId_; int windowId_;
std::string app_id_; std::string app_id_;
std::string app_class_;
std::string old_app_id_; std::string old_app_id_;
std::size_t app_nb_; std::size_t app_nb_;
std::string shell_;
unsigned app_icon_size_{24};
bool update_app_icon_{true};
std::string app_icon_name_;
util::JsonParser parser_; util::JsonParser parser_;
std::mutex mutex_; std::mutex mutex_;
Ipc ipc_; Ipc ipc_;

View File

@ -1,10 +1,11 @@
#pragma once #pragma once
#include <unordered_map>
#include <fmt/format.h> #include <fmt/format.h>
#include <gtkmm/button.h> #include <gtkmm/button.h>
#include <gtkmm/label.h> #include <gtkmm/label.h>
#include <unordered_map> #include <unordered_map>
#include "AModule.hpp" #include "AModule.hpp"
#include "bar.hpp" #include "bar.hpp"
#include "client.hpp" #include "client.hpp"

View File

@ -1,13 +1,15 @@
#pragma once #pragma once
#include <fmt/format.h> #include <fmt/format.h>
#include <fstream> #include <fstream>
#include "ALabel.hpp"
#include "AButton.hpp"
#include "util/sleeper_thread.hpp" #include "util/sleeper_thread.hpp"
namespace waybar::modules { namespace waybar::modules {
class Temperature : public ALabel { class Temperature : public AButton {
public: public:
Temperature(const std::string&, const Json::Value&); Temperature(const std::string&, const Json::Value&);
~Temperature() = default; ~Temperature() = default;

View File

@ -0,0 +1,79 @@
#pragma once
#include <libupower-glib/upower.h>
#include <iostream>
#include <map>
#include <string>
#include <unordered_map>
#include "ALabel.hpp"
#include "glibconfig.h"
#include "gtkmm/box.h"
#include "gtkmm/image.h"
#include "gtkmm/label.h"
#include "modules/upower/upower_tooltip.hpp"
namespace waybar::modules::upower {
class UPower : public AModule {
public:
UPower(const std::string &, const Json::Value &);
~UPower();
auto update() -> void;
private:
typedef std::unordered_map<std::string, UpDevice *> Devices;
const std::string DEFAULT_FORMAT = "{percentage}";
const std::string DEFAULT_FORMAT_ALT = "{percentage} {time}";
static void deviceAdded_cb(UpClient *client, UpDevice *device, gpointer data);
static void deviceRemoved_cb(UpClient *client, const gchar *objectPath, gpointer data);
static void deviceNotify_cb(UpDevice *device, GParamSpec *pspec, gpointer user_data);
static void prepareForSleep_cb(GDBusConnection *system_bus, const gchar *sender_name,
const gchar *object_path, const gchar *interface_name,
const gchar *signal_name, GVariant *parameters,
gpointer user_data);
static void upowerAppear(GDBusConnection *conn, const gchar *name, const gchar *name_owner,
gpointer data);
static void upowerDisappear(GDBusConnection *connection, const gchar *name, gpointer user_data);
void removeDevice(const gchar *objectPath);
void addDevice(UpDevice *device);
void setDisplayDevice();
void resetDevices();
void removeDevices();
bool show_tooltip_callback(int, int, bool, const Glib::RefPtr<Gtk::Tooltip> &tooltip);
bool handleToggle(GdkEventButton *const &);
std::string timeToString(gint64 time);
const std::string getDeviceStatus(UpDeviceState &state);
Gtk::Box box_;
Gtk::Image icon_;
Gtk::Label label_;
// Config
bool hideIfEmpty = true;
bool tooltip_enabled = true;
uint tooltip_spacing = 4;
uint tooltip_padding = 4;
uint iconSize = 20;
std::string format = DEFAULT_FORMAT;
std::string format_alt = DEFAULT_FORMAT_ALT;
Devices devices;
std::mutex m_Mutex;
UpClient *client;
UpDevice *displayDevice;
guint login1_id;
GDBusConnection *login1_connection;
UPowerTooltip *upower_tooltip;
std::string lastStatus;
bool showAltText;
bool upowerRunning;
guint upowerWatcher_id;
};
} // namespace waybar::modules::upower

View File

@ -0,0 +1,32 @@
#pragma once
#include <libupower-glib/upower.h>
#include <unordered_map>
#include "gtkmm/box.h"
#include "gtkmm/label.h"
#include "gtkmm/window.h"
namespace waybar::modules::upower {
class UPowerTooltip : public Gtk::Window {
private:
typedef std::unordered_map<std::string, UpDevice*> Devices;
const std::string getDeviceIcon(UpDeviceKind& kind);
Gtk::Box* contentBox;
uint iconSize;
uint tooltipSpacing;
uint tooltipPadding;
public:
UPowerTooltip(uint iconSize, uint tooltipSpacing, uint tooltipPadding);
~UPowerTooltip();
uint updateTooltip(Devices& devices);
};
} // namespace waybar::modules::upower

34
include/modules/user.hpp Normal file
View File

@ -0,0 +1,34 @@
#pragma once
#include <fmt/chrono.h>
#include <gdkmm/pixbuf.h>
#include <glibmm/refptr.h>
#include "AIconLabel.hpp"
#include "util/sleeper_thread.hpp"
namespace waybar::modules {
class User : public AIconLabel {
public:
User(const std::string&, const Json::Value&);
~User() = default;
auto update() -> void;
private:
util::SleeperThread thread_;
Glib::RefPtr<Gdk::Pixbuf> pixbuf_;
static constexpr inline int defaultUserImageWidth_ = 20;
static constexpr inline int defaultUserImageHeight_ = 20;
long uptime_as_seconds();
std::string get_user_login();
std::string get_user_home_dir();
std::string get_default_user_avatar_path();
void init_default_user_avatar(int width, int height);
void init_user_avatar(const std::string& path, int width, int height);
void init_avatar(const Json::Value& config);
void init_update_worker();
};
} // namespace waybar::modules

View File

@ -1,37 +1,32 @@
#pragma once #pragma once
#include <gdk/gdk.h>
#include <glibmm/refptr.h>
#include <gtkmm/box.h>
#include <gtkmm/button.h>
#include <gtkmm/icontheme.h>
#include <gtkmm/image.h>
#include <gtkmm/label.h>
#include <wayland-client.h>
#include <map>
#include <memory>
#include <string>
#include <unordered_set>
#include <vector>
#include "AModule.hpp" #include "AModule.hpp"
#include "bar.hpp" #include "bar.hpp"
#include "client.hpp" #include "client.hpp"
#include "giomm/desktopappinfo.h" #include "giomm/desktopappinfo.h"
#include "util/json.hpp" #include "util/json.hpp"
#include <memory>
#include <string>
#include <vector>
#include <map>
#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" #include "wlr-foreign-toplevel-management-unstable-v1-client-protocol.h"
namespace waybar::modules::wlr { namespace waybar::modules::wlr {
class Taskbar; class Taskbar;
class Task class Task {
{
public: public:
Task(const waybar::Bar &, const Json::Value &, Taskbar *, Task(const waybar::Bar &, const Json::Value &, Taskbar *,
struct zwlr_foreign_toplevel_handle_v1 *, struct wl_seat *); struct zwlr_foreign_toplevel_handle_v1 *, struct wl_seat *);
@ -79,11 +74,16 @@ class Task
std::string app_id_; std::string app_id_;
uint32_t state_ = 0; uint32_t state_ = 0;
int32_t drag_start_x;
int32_t drag_start_y;
int32_t drag_start_button = -1;
private: private:
std::string repr() const; std::string repr() const;
std::string state_string(bool = false) const; std::string state_string(bool = false) const;
void set_app_info_from_app_id_list(const std::string &app_id_list); void set_app_info_from_app_id_list(const std::string &app_id_list);
bool image_load_icon(Gtk::Image& image, const Glib::RefPtr<Gtk::IconTheme>& icon_theme, Glib::RefPtr<Gio::DesktopAppInfo> app_info, int size); bool image_load_icon(Gtk::Image &image, const Glib::RefPtr<Gtk::IconTheme> &icon_theme,
Glib::RefPtr<Gio::DesktopAppInfo> app_info, int size);
void hide_if_ignored(); void hide_if_ignored();
public: public:
@ -109,6 +109,12 @@ class Task
/* Callbacks for Gtk events */ /* Callbacks for Gtk events */
bool handle_clicked(GdkEventButton *); bool handle_clicked(GdkEventButton *);
bool handle_button_release(GdkEventButton *);
bool handle_motion_notify(GdkEventMotion *);
void handle_drag_data_get(const Glib::RefPtr<Gdk::DragContext> &context,
Gtk::SelectionData &selection_data, guint info, guint time);
void handle_drag_data_received(const Glib::RefPtr<Gdk::DragContext> &context, int x, int y,
Gtk::SelectionData selection_data, guint info, guint time);
public: public:
bool operator==(const Task &) const; bool operator==(const Task &) const;
@ -128,9 +134,7 @@ class Task
using TaskPtr = std::unique_ptr<Task>; using TaskPtr = std::unique_ptr<Task>;
class Taskbar : public waybar::AModule {
class Taskbar : public waybar::AModule
{
public: public:
Taskbar(const std::string &, const waybar::Bar &, const Json::Value &); Taskbar(const std::string &, const waybar::Bar &, const Json::Value &);
~Taskbar(); ~Taskbar();

View File

@ -152,6 +152,7 @@ class WorkspaceManager : public AModule {
bool sort_by_name_ = true; bool sort_by_name_ = true;
bool sort_by_coordinates_ = true; bool sort_by_coordinates_ = true;
bool sort_by_number_ = false;
bool all_outputs_ = false; bool all_outputs_ = false;
bool active_only_ = false; bool active_only_ = false;
bool creation_delayed_ = false; bool creation_delayed_ = false;

View File

@ -3,6 +3,8 @@
namespace waybar::modules::wlr { namespace waybar::modules::wlr {
void add_registry_listener(void *data); void add_registry_listener(void *data);
void add_workspace_listener(zext_workspace_handle_v1 *workspace_handle, void *data); void add_workspace_listener(zext_workspace_handle_v1 *workspace_handle, void *data);
void add_workspace_group_listener(zext_workspace_group_handle_v1 *workspace_group_handle, void *data); void add_workspace_group_listener(zext_workspace_group_handle_v1 *workspace_group_handle,
zext_workspace_manager_v1* workspace_manager_bind(wl_registry *registry, uint32_t name, uint32_t version, void *data); void *data);
} zext_workspace_manager_v1 *workspace_manager_bind(wl_registry *registry, uint32_t name,
uint32_t version, void *data);
} // namespace waybar::modules::wlr

View File

@ -27,7 +27,6 @@
#endif #endif
#endif #endif
// ----------- #included from clara_textflow.hpp ----------- // ----------- #included from clara_textflow.hpp -----------
// TextFlowCpp // TextFlowCpp
@ -51,8 +50,8 @@
#define CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH 80 #define CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH 80
#endif #endif
namespace clara {
namespace clara { namespace TextFlow { namespace TextFlow {
inline auto isWhitespace(char c) -> bool { inline auto isWhitespace(char c) -> bool {
static std::string chars = " \t\n\r"; static std::string chars = " \t\n\r";
@ -88,9 +87,7 @@ namespace clara { namespace TextFlow {
bool m_suffix = false; bool m_suffix = false;
iterator(Column const &column, size_t stringIndex) iterator(Column const &column, size_t stringIndex)
: m_column( column ), : m_column(column), m_stringIndex(stringIndex) {}
m_stringIndex( stringIndex )
{}
auto line() const -> std::string const & { return m_column.m_strings[m_stringIndex]; } auto line() const -> std::string const & { return m_column.m_strings[m_stringIndex]; }
@ -98,10 +95,8 @@ namespace clara { namespace TextFlow {
assert(at > 0); assert(at > 0);
assert(at <= line().size()); assert(at <= line().size());
return at == line().size() || return at == line().size() || (isWhitespace(line()[at]) && !isWhitespace(line()[at - 1])) ||
( isWhitespace( line()[at] ) && !isWhitespace( line()[at-1] ) ) || isBreakableBefore(line()[at]) || isBreakableAfter(line()[at - 1]);
isBreakableBefore( line()[at] ) ||
isBreakableAfter( line()[at-1] );
} }
void calcLength() { void calcLength() {
@ -110,18 +105,14 @@ namespace clara { namespace TextFlow {
m_suffix = false; m_suffix = false;
auto width = m_column.m_width - indent(); auto width = m_column.m_width - indent();
m_end = m_pos; m_end = m_pos;
while( m_end < line().size() && line()[m_end] != '\n' ) while (m_end < line().size() && line()[m_end] != '\n') ++m_end;
++m_end;
if (m_end < m_pos + width) { if (m_end < m_pos + width) {
m_len = m_end - m_pos; m_len = m_end - m_pos;
} } else {
else {
size_t len = width; size_t len = width;
while (len > 0 && !isBoundary(m_pos + len)) while (len > 0 && !isBoundary(m_pos + len)) --len;
--len; while (len > 0 && isWhitespace(line()[m_pos + len - 1])) --len;
while (len > 0 && isWhitespace( line()[m_pos + len - 1] ))
--len;
if (len > 0) { if (len > 0) {
m_len = len; m_len = len;
@ -133,7 +124,8 @@ namespace clara { namespace TextFlow {
} }
auto indent() const -> size_t { auto indent() const -> size_t {
auto initial = m_pos == 0 && m_stringIndex == 0 ? m_column.m_initialIndent : std::string::npos; auto initial =
m_pos == 0 && m_stringIndex == 0 ? m_column.m_initialIndent : std::string::npos;
return initial == std::string::npos ? m_column.m_indent : initial; return initial == std::string::npos ? m_column.m_indent : initial;
} }
@ -150,10 +142,10 @@ namespace clara { namespace TextFlow {
explicit iterator(Column const &column) : m_column(column) { explicit iterator(Column const &column) : m_column(column) {
assert(m_column.m_width > m_column.m_indent); assert(m_column.m_width > m_column.m_indent);
assert( m_column.m_initialIndent == std::string::npos || m_column.m_width > m_column.m_initialIndent ); assert(m_column.m_initialIndent == std::string::npos ||
m_column.m_width > m_column.m_initialIndent);
calcLength(); calcLength();
if( m_len == 0 ) if (m_len == 0) m_stringIndex++; // Empty string
m_stringIndex++; // Empty string
} }
auto operator*() const -> std::string { auto operator*() const -> std::string {
@ -167,15 +159,13 @@ namespace clara { namespace TextFlow {
if (m_pos < line().size() && line()[m_pos] == '\n') if (m_pos < line().size() && line()[m_pos] == '\n')
m_pos += 1; m_pos += 1;
else else
while( m_pos < line().size() && isWhitespace( line()[m_pos] ) ) while (m_pos < line().size() && isWhitespace(line()[m_pos])) ++m_pos;
++m_pos;
if (m_pos == line().size()) { if (m_pos == line().size()) {
m_pos = 0; m_pos = 0;
++m_stringIndex; ++m_stringIndex;
} }
if( m_stringIndex < m_column.m_strings.size() ) if (m_stringIndex < m_column.m_strings.size()) calcLength();
calcLength();
return *this; return *this;
} }
auto operator++(int) -> iterator { auto operator++(int) -> iterator {
@ -185,14 +175,10 @@ namespace clara { namespace TextFlow {
} }
auto operator==(iterator const &other) const -> bool { auto operator==(iterator const &other) const -> bool {
return return m_pos == other.m_pos && m_stringIndex == other.m_stringIndex &&
m_pos == other.m_pos &&
m_stringIndex == other.m_stringIndex &&
&m_column == &other.m_column; &m_column == &other.m_column;
} }
auto operator !=( iterator const& other ) const -> bool { auto operator!=(iterator const &other) const -> bool { return !operator==(other); }
return !operator==( other );
}
}; };
using const_iterator = iterator; using const_iterator = iterator;
@ -238,18 +224,14 @@ namespace clara { namespace TextFlow {
}; };
class Spacer : public Column { class Spacer : public Column {
public: public:
explicit Spacer( size_t spaceWidth ) : Column( "" ) { explicit Spacer(size_t spaceWidth) : Column("") { width(spaceWidth); }
width( spaceWidth );
}
}; };
class Columns { class Columns {
std::vector<Column> m_columns; std::vector<Column> m_columns;
public: public:
class iterator { class iterator {
friend Columns; friend Columns;
struct EndTag {}; struct EndTag {};
@ -258,14 +240,10 @@ namespace clara { namespace TextFlow {
std::vector<Column::iterator> m_iterators; std::vector<Column::iterator> m_iterators;
size_t m_activeIterators; size_t m_activeIterators;
iterator( Columns const& columns, EndTag ) iterator(Columns const &columns, EndTag) : m_columns(columns.m_columns), m_activeIterators(0) {
: m_columns( columns.m_columns ),
m_activeIterators( 0 )
{
m_iterators.reserve(m_columns.size()); m_iterators.reserve(m_columns.size());
for( auto const& col : m_columns ) for (auto const &col : m_columns) m_iterators.push_back(col.end());
m_iterators.push_back( col.end() );
} }
public: public:
@ -276,13 +254,10 @@ namespace clara { namespace TextFlow {
using iterator_category = std::forward_iterator_tag; using iterator_category = std::forward_iterator_tag;
explicit iterator(Columns const &columns) explicit iterator(Columns const &columns)
: m_columns( columns.m_columns ), : m_columns(columns.m_columns), m_activeIterators(m_columns.size()) {
m_activeIterators( m_columns.size() )
{
m_iterators.reserve(m_columns.size()); m_iterators.reserve(m_columns.size());
for( auto const& col : m_columns ) for (auto const &col : m_columns) m_iterators.push_back(col.begin());
m_iterators.push_back( col.begin() );
} }
auto operator==(iterator const &other) const -> bool { auto operator==(iterator const &other) const -> bool {
@ -303,8 +278,7 @@ namespace clara { namespace TextFlow {
padding = std::string(width - col.size(), ' '); padding = std::string(width - col.size(), ' ');
else else
padding = ""; padding = "";
} } else {
else {
padding += std::string(width, ' '); padding += std::string(width, ' ');
} }
} }
@ -312,8 +286,7 @@ namespace clara { namespace TextFlow {
} }
auto operator++() -> iterator & { auto operator++() -> iterator & {
for (size_t i = 0; i < m_columns.size(); ++i) { for (size_t i = 0; i < m_columns.size(); ++i) {
if (m_iterators[i] != m_columns[i].end()) if (m_iterators[i] != m_columns[i].end()) ++m_iterators[i];
++m_iterators[i];
} }
return *this; return *this;
} }
@ -339,7 +312,6 @@ namespace clara { namespace TextFlow {
} }
inline friend std::ostream &operator<<(std::ostream &os, Columns const &cols) { inline friend std::ostream &operator<<(std::ostream &os, Columns const &cols) {
bool first = true; bool first = true;
for (auto line : cols) { for (auto line : cols) {
if (first) if (first)
@ -364,19 +336,20 @@ namespace clara { namespace TextFlow {
cols += other; cols += other;
return cols; return cols;
} }
}} } // namespace TextFlow
} // namespace clara
#endif // CLARA_TEXTFLOW_HPP_INCLUDED #endif // CLARA_TEXTFLOW_HPP_INCLUDED
// ----------- end of #include from clara_textflow.hpp ----------- // ----------- end of #include from clara_textflow.hpp -----------
// ........... back in clara.hpp // ........... back in clara.hpp
#include <algorithm>
#include <memory> #include <memory>
#include <set> #include <set>
#include <algorithm>
#if !defined(CLARA_PLATFORM_WINDOWS) && ( defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) ) #if !defined(CLARA_PLATFORM_WINDOWS) && \
(defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER))
#define CLARA_PLATFORM_WINDOWS #define CLARA_PLATFORM_WINDOWS
#endif #endif
@ -408,25 +381,17 @@ namespace detail {
std::vector<std::string> m_args; std::vector<std::string> m_args;
public: public:
Args( int argc, char const* const* argv ) Args(int argc, char const *const *argv) : m_exeName(argv[0]), m_args(argv + 1, argv + argc) {}
: m_exeName(argv[0]),
m_args(argv + 1, argv + argc) {}
Args(std::initializer_list<std::string> args) Args(std::initializer_list<std::string> args)
: m_exeName( *args.begin() ), : m_exeName(*args.begin()), m_args(args.begin() + 1, args.end()) {}
m_args( args.begin()+1, args.end() )
{}
auto exeName() const -> std::string { auto exeName() const -> std::string { return m_exeName; }
return m_exeName;
}
}; };
// Wraps a token coming from a token stream. These may not directly correspond to strings as a single string // Wraps a token coming from a token stream. These may not directly correspond to strings as a
// may encode an option + its argument if the : or = form is used // single string may encode an option + its argument if the : or = form is used
enum class TokenType { enum class TokenType { Option, Argument };
Option, Argument
};
struct Token { struct Token {
TokenType type; TokenType type;
std::string token; std::string token;
@ -451,8 +416,7 @@ namespace detail {
m_tokenBuffer.resize(0); m_tokenBuffer.resize(0);
// Skip any empty strings // Skip any empty strings
while( it != itEnd && it->empty() ) while (it != itEnd && it->empty()) ++it;
++it;
if (it != itEnd) { if (it != itEnd) {
auto const &next = *it; auto const &next = *it;
@ -481,13 +445,9 @@ namespace detail {
public: public:
explicit TokenStream(Args const &args) : TokenStream(args.m_args.begin(), args.m_args.end()) {} explicit TokenStream(Args const &args) : TokenStream(args.m_args.begin(), args.m_args.end()) {}
TokenStream( Iterator it, Iterator itEnd ) : it( it ), itEnd( itEnd ) { TokenStream(Iterator it, Iterator itEnd) : it(it), itEnd(itEnd) { loadBuffer(); }
loadBuffer();
}
explicit operator bool() const { explicit operator bool() const { return !m_tokenBuffer.empty() || it != itEnd; }
return !m_tokenBuffer.empty() || it != itEnd;
}
auto count() const -> size_t { return m_tokenBuffer.size() + (itEnd - it); } auto count() const -> size_t { return m_tokenBuffer.size() + (itEnd - it); }
@ -505,20 +465,16 @@ namespace detail {
if (m_tokenBuffer.size() >= 2) { if (m_tokenBuffer.size() >= 2) {
m_tokenBuffer.erase(m_tokenBuffer.begin()); m_tokenBuffer.erase(m_tokenBuffer.begin());
} else { } else {
if( it != itEnd ) if (it != itEnd) ++it;
++it;
loadBuffer(); loadBuffer();
} }
return *this; return *this;
} }
}; };
class ResultBase { class ResultBase {
public: public:
enum Type { enum Type { Ok, LogicError, RuntimeError };
Ok, LogicError, RuntimeError
};
protected: protected:
ResultBase(Type type) : m_type(type) {} ResultBase(Type type) : m_type(type) {}
@ -541,26 +497,20 @@ namespace detail {
ResultValueBase(Type type) : ResultBase(type) {} ResultValueBase(Type type) : ResultBase(type) {}
ResultValueBase(ResultValueBase const &other) : ResultBase(other) { ResultValueBase(ResultValueBase const &other) : ResultBase(other) {
if( m_type == ResultBase::Ok ) if (m_type == ResultBase::Ok) new (&m_value) T(other.m_value);
new( &m_value ) T( other.m_value );
} }
ResultValueBase( Type, T const &value ) : ResultBase( Ok ) { ResultValueBase(Type, T const &value) : ResultBase(Ok) { new (&m_value) T(value); }
new( &m_value ) T( value );
}
auto operator=(ResultValueBase const &other) -> ResultValueBase & { auto operator=(ResultValueBase const &other) -> ResultValueBase & {
if( m_type == ResultBase::Ok ) if (m_type == ResultBase::Ok) m_value.~T();
m_value.~T();
ResultBase::operator=(other); ResultBase::operator=(other);
if( m_type == ResultBase::Ok ) if (m_type == ResultBase::Ok) new (&m_value) T(other.m_value);
new( &m_value ) T( other.m_value );
return *this; return *this;
} }
~ResultValueBase() override { ~ResultValueBase() override {
if( m_type == Ok ) if (m_type == Ok) m_value.~T();
m_value.~T();
} }
union { union {
@ -579,17 +529,21 @@ namespace detail {
public: public:
template <typename U> template <typename U>
explicit BasicResult(BasicResult<U> const &other) explicit BasicResult(BasicResult<U> const &other)
: ResultValueBase<T>( other.type() ), : ResultValueBase<T>(other.type()), m_errorMessage(other.errorMessage()) {
m_errorMessage( other.errorMessage() )
{
assert(type() != ResultBase::Ok); assert(type() != ResultBase::Ok);
} }
template <typename U> template <typename U>
static auto ok( U const &value ) -> BasicResult { return { ResultBase::Ok, value }; } static auto ok(U const &value) -> BasicResult {
return {ResultBase::Ok, value};
}
static auto ok() -> BasicResult { return {ResultBase::Ok}; } static auto ok() -> BasicResult { return {ResultBase::Ok}; }
static auto logicError( std::string const &message ) -> BasicResult { return { ResultBase::LogicError, message }; } static auto logicError(std::string const &message) -> BasicResult {
static auto runtimeError( std::string const &message ) -> BasicResult { return { ResultBase::RuntimeError, message }; } return {ResultBase::LogicError, message};
}
static auto runtimeError(std::string const &message) -> BasicResult {
return {ResultBase::RuntimeError, message};
}
explicit operator bool() const { return m_type == ResultBase::Ok; } explicit operator bool() const { return m_type == ResultBase::Ok; }
auto type() const -> ResultBase::Type { return m_type; } auto type() const -> ResultBase::Type { return m_type; }
@ -597,21 +551,17 @@ namespace detail {
protected: protected:
void enforceOk() const override { void enforceOk() const override {
// Errors shouldn't reach this point, but if they do // Errors shouldn't reach this point, but if they do
// the actual error message will be in m_errorMessage // the actual error message will be in m_errorMessage
assert(m_type != ResultBase::LogicError); assert(m_type != ResultBase::LogicError);
assert(m_type != ResultBase::RuntimeError); assert(m_type != ResultBase::RuntimeError);
if( m_type != ResultBase::Ok ) if (m_type != ResultBase::Ok) std::abort();
std::abort();
} }
std::string m_errorMessage; // Only populated if resultType is an error std::string m_errorMessage; // Only populated if resultType is an error
BasicResult(ResultBase::Type type, std::string const &message) BasicResult(ResultBase::Type type, std::string const &message)
: ResultValueBase<T>(type), : ResultValueBase<T>(type), m_errorMessage(message) {
m_errorMessage(message)
{
assert(m_type != ResultBase::Ok); assert(m_type != ResultBase::Ok);
} }
@ -619,17 +569,12 @@ namespace detail {
using ResultBase::m_type; using ResultBase::m_type;
}; };
enum class ParseResultType { enum class ParseResultType { Matched, NoMatch, ShortCircuitAll, ShortCircuitSame };
Matched, NoMatch, ShortCircuitAll, ShortCircuitSame
};
class ParseState { class ParseState {
public: public:
ParseState(ParseResultType type, TokenStream const &remainingTokens) ParseState(ParseResultType type, TokenStream const &remainingTokens)
: m_type(type), : m_type(type), m_remainingTokens(remainingTokens) {}
m_remainingTokens( remainingTokens )
{}
auto type() const -> ParseResultType { return m_type; } auto type() const -> ParseResultType { return m_type; }
auto remainingTokens() const -> TokenStream { return m_remainingTokens; } auto remainingTokens() const -> TokenStream { return m_remainingTokens; }
@ -664,22 +609,24 @@ namespace detail {
} }
inline auto convertInto(std::string const &source, bool &target) -> ParserResult { inline auto convertInto(std::string const &source, bool &target) -> ParserResult {
std::string srcLC = source; std::string srcLC = source;
std::transform( srcLC.begin(), srcLC.end(), srcLC.begin(), []( char c ) { return static_cast<char>( ::tolower(c) ); } ); std::transform(srcLC.begin(), srcLC.end(), srcLC.begin(),
[](char c) { return static_cast<char>(::tolower(c)); });
if (srcLC == "y" || srcLC == "1" || srcLC == "true" || srcLC == "yes" || srcLC == "on") if (srcLC == "y" || srcLC == "1" || srcLC == "true" || srcLC == "yes" || srcLC == "on")
target = true; target = true;
else if (srcLC == "n" || srcLC == "0" || srcLC == "false" || srcLC == "no" || srcLC == "off") else if (srcLC == "n" || srcLC == "0" || srcLC == "false" || srcLC == "no" || srcLC == "off")
target = false; target = false;
else else
return ParserResult::runtimeError( "Expected a boolean value but did not recognise: '" + source + "'" ); return ParserResult::runtimeError("Expected a boolean value but did not recognise: '" + source +
"'");
return ParserResult::ok(ParseResultType::Matched); return ParserResult::ok(ParseResultType::Matched);
} }
#ifdef CLARA_CONFIG_OPTIONAL_TYPE #ifdef CLARA_CONFIG_OPTIONAL_TYPE
template <typename T> template <typename T>
inline auto convertInto( std::string const &source, CLARA_CONFIG_OPTIONAL_TYPE<T>& target ) -> ParserResult { inline auto convertInto(std::string const &source, CLARA_CONFIG_OPTIONAL_TYPE<T> &target)
-> ParserResult {
T temp; T temp;
auto result = convertInto(source, temp); auto result = convertInto(source, temp);
if( result ) if (result) target = std::move(temp);
target = std::move(temp);
return result; return result;
} }
#endif // CLARA_CONFIG_OPTIONAL_TYPE #endif // CLARA_CONFIG_OPTIONAL_TYPE
@ -711,9 +658,7 @@ namespace detail {
explicit BoundValueRef(T &ref) : m_ref(ref) {} explicit BoundValueRef(T &ref) : m_ref(ref) {}
auto setValue( std::string const &arg ) -> ParserResult override { auto setValue(std::string const &arg) -> ParserResult override { return convertInto(arg, m_ref); }
return convertInto( arg, m_ref );
}
}; };
template <typename T> template <typename T>
@ -727,8 +672,7 @@ namespace detail {
auto setValue(std::string const &arg) -> ParserResult override { auto setValue(std::string const &arg) -> ParserResult override {
T temp; T temp;
auto result = convertInto(arg, temp); auto result = convertInto(arg, temp);
if( result ) if (result) m_ref.push_back(temp);
m_ref.push_back( temp );
return result; return result;
} }
}; };
@ -746,7 +690,8 @@ namespace detail {
template <typename ReturnType> template <typename ReturnType>
struct LambdaInvoker { struct LambdaInvoker {
static_assert( std::is_same<ReturnType, ParserResult>::value, "Lambda must return void or clara::ParserResult" ); static_assert(std::is_same<ReturnType, ParserResult>::value,
"Lambda must return void or clara::ParserResult");
template <typename L, typename ArgType> template <typename L, typename ArgType>
static auto invoke(L const &lambda, ArgType const &arg) -> ParserResult { static auto invoke(L const &lambda, ArgType const &arg) -> ParserResult {
@ -767,12 +712,10 @@ namespace detail {
inline auto invokeLambda(L const &lambda, std::string const &arg) -> ParserResult { inline auto invokeLambda(L const &lambda, std::string const &arg) -> ParserResult {
ArgType temp{}; ArgType temp{};
auto result = convertInto(arg, temp); auto result = convertInto(arg, temp);
return !result return !result ? result
? result
: LambdaInvoker<typename UnaryLambdaTraits<L>::ReturnType>::invoke(lambda, temp); : LambdaInvoker<typename UnaryLambdaTraits<L>::ReturnType>::invoke(lambda, temp);
} }
template <typename L> template <typename L>
struct BoundLambda : BoundValueRefBase { struct BoundLambda : BoundValueRefBase {
L m_lambda; L m_lambda;
@ -790,7 +733,8 @@ namespace detail {
L m_lambda; L m_lambda;
static_assert(UnaryLambdaTraits<L>::isValid, "Supplied lambda must take exactly one argument"); static_assert(UnaryLambdaTraits<L>::isValid, "Supplied lambda must take exactly one argument");
static_assert( std::is_same<typename UnaryLambdaTraits<L>::ArgType, bool>::value, "flags must be boolean" ); static_assert(std::is_same<typename UnaryLambdaTraits<L>::ArgType, bool>::value,
"flags must be boolean");
explicit BoundFlagLambda(L const &lambda) : m_lambda(lambda) {} explicit BoundFlagLambda(L const &lambda) : m_lambda(lambda) {}
@ -807,7 +751,8 @@ namespace detail {
public: public:
virtual ~ParserBase() = default; virtual ~ParserBase() = default;
virtual auto validate() const -> Result { return Result::ok(); } virtual auto validate() const -> Result { return Result::ok(); }
virtual auto parse( std::string const& exeName, TokenStream const &tokens) const -> InternalParseResult = 0; virtual auto parse(std::string const &exeName, TokenStream const &tokens) const
-> InternalParseResult = 0;
virtual auto cardinality() const -> size_t { return 1; } virtual auto cardinality() const -> size_t { return 1; }
auto parse(Args const &args) const -> InternalParseResult { auto parse(Args const &args) const -> InternalParseResult {
@ -839,15 +784,11 @@ namespace detail {
public: public:
template <typename T> template <typename T>
ParserRefImpl(T &ref, std::string const &hint) ParserRefImpl(T &ref, std::string const &hint)
: m_ref( std::make_shared<BoundValueRef<T>>( ref ) ), : m_ref(std::make_shared<BoundValueRef<T>>(ref)), m_hint(hint) {}
m_hint( hint )
{}
template <typename LambdaT> template <typename LambdaT>
ParserRefImpl(LambdaT const &ref, std::string const &hint) ParserRefImpl(LambdaT const &ref, std::string const &hint)
: m_ref( std::make_shared<BoundLambda<LambdaT>>( ref ) ), : m_ref(std::make_shared<BoundLambda<LambdaT>>(ref)), m_hint(hint) {}
m_hint(hint)
{}
auto operator()(std::string const &description) -> DerivedT & { auto operator()(std::string const &description) -> DerivedT & {
m_description = description; m_description = description;
@ -864,9 +805,7 @@ namespace detail {
return static_cast<DerivedT &>(*this); return static_cast<DerivedT &>(*this);
}; };
auto isOptional() const -> bool { auto isOptional() const -> bool { return m_optionality == Optionality::Optional; }
return m_optionality == Optionality::Optional;
}
auto cardinality() const -> size_t override { auto cardinality() const -> size_t override {
if (m_ref->isContainer()) if (m_ref->isContainer())
@ -906,11 +845,8 @@ namespace detail {
auto name() const -> std::string { return *m_name; } auto name() const -> std::string { return *m_name; }
auto set(std::string const &newName) -> ParserResult { auto set(std::string const &newName) -> ParserResult {
auto lastSlash = newName.find_last_of("\\/"); auto lastSlash = newName.find_last_of("\\/");
auto filename = ( lastSlash == std::string::npos ) auto filename = (lastSlash == std::string::npos) ? newName : newName.substr(lastSlash + 1);
? newName
: newName.substr( lastSlash+1 );
*m_name = filename; *m_name = filename;
if (m_ref) if (m_ref)
@ -926,8 +862,7 @@ namespace detail {
auto parse(std::string const &, TokenStream const &tokens) const -> InternalParseResult override { auto parse(std::string const &, TokenStream const &tokens) const -> InternalParseResult override {
auto validationResult = validate(); auto validationResult = validate();
if( !validationResult ) if (!validationResult) return InternalParseResult(validationResult);
return InternalParseResult( validationResult );
auto remainingTokens = tokens; auto remainingTokens = tokens;
auto const &token = *remainingTokens; auto const &token = *remainingTokens;
@ -960,7 +895,8 @@ namespace detail {
public: public:
template <typename LambdaT> template <typename LambdaT>
explicit Opt( LambdaT const &ref ) : ParserRefImpl( std::make_shared<BoundFlagLambda<LambdaT>>( ref ) ) {} explicit Opt(LambdaT const &ref)
: ParserRefImpl(std::make_shared<BoundFlagLambda<LambdaT>>(ref)) {}
explicit Opt(bool &ref) : ParserRefImpl(std::make_shared<BoundFlagRef>(ref)) {} explicit Opt(bool &ref) : ParserRefImpl(std::make_shared<BoundFlagRef>(ref)) {}
@ -985,16 +921,14 @@ namespace detail {
oss << ", "; oss << ", ";
oss << opt; oss << opt;
} }
if( !m_hint.empty() ) if (!m_hint.empty()) oss << " <" << m_hint << ">";
oss << " <" << m_hint << ">";
return {{oss.str(), m_description}}; return {{oss.str(), m_description}};
} }
auto isMatch(std::string const &optToken) const -> bool { auto isMatch(std::string const &optToken) const -> bool {
auto normalisedToken = normaliseOpt(optToken); auto normalisedToken = normaliseOpt(optToken);
for (auto const &name : m_optNames) { for (auto const &name : m_optNames) {
if( normaliseOpt( name ) == normalisedToken ) if (normaliseOpt(name) == normalisedToken) return true;
return true;
} }
return false; return false;
} }
@ -1003,8 +937,7 @@ namespace detail {
auto parse(std::string const &, TokenStream const &tokens) const -> InternalParseResult override { auto parse(std::string const &, TokenStream const &tokens) const -> InternalParseResult override {
auto validationResult = validate(); auto validationResult = validate();
if( !validationResult ) if (!validationResult) return InternalParseResult(validationResult);
return InternalParseResult( validationResult );
auto remainingTokens = tokens; auto remainingTokens = tokens;
if (remainingTokens && remainingTokens->type == TokenType::Option) { if (remainingTokens && remainingTokens->type == TokenType::Option) {
@ -1013,8 +946,7 @@ namespace detail {
if (m_ref->isFlag()) { if (m_ref->isFlag()) {
auto flagRef = static_cast<detail::BoundFlagRefBase *>(m_ref.get()); auto flagRef = static_cast<detail::BoundFlagRefBase *>(m_ref.get());
auto result = flagRef->setFlag(true); auto result = flagRef->setFlag(true);
if( !result ) if (!result) return InternalParseResult(result);
return InternalParseResult( result );
if (result.value() == ParseResultType::ShortCircuitAll) if (result.value() == ParseResultType::ShortCircuitAll)
return InternalParseResult::ok(ParseState(result.value(), remainingTokens)); return InternalParseResult::ok(ParseState(result.value(), remainingTokens));
} else { } else {
@ -1026,8 +958,7 @@ namespace detail {
if (argToken.type != TokenType::Argument) if (argToken.type != TokenType::Argument)
return InternalParseResult::runtimeError("Expected argument following " + token.token); return InternalParseResult::runtimeError("Expected argument following " + token.token);
auto result = valueRef->setValue(argToken.token); auto result = valueRef->setValue(argToken.token);
if( !result ) if (!result) return InternalParseResult(result);
return InternalParseResult( result );
if (result.value() == ParseResultType::ShortCircuitAll) if (result.value() == ParseResultType::ShortCircuitAll)
return InternalParseResult::ok(ParseState(result.value(), remainingTokens)); return InternalParseResult::ok(ParseState(result.value(), remainingTokens));
} }
@ -1038,17 +969,14 @@ namespace detail {
} }
auto validate() const -> Result override { auto validate() const -> Result override {
if( m_optNames.empty() ) if (m_optNames.empty()) return Result::logicError("No options supplied to Opt");
return Result::logicError( "No options supplied to Opt" );
for (auto const &name : m_optNames) { for (auto const &name : m_optNames) {
if( name.empty() ) if (name.empty()) return Result::logicError("Option name cannot be empty");
return Result::logicError( "Option name cannot be empty" );
#ifdef CLARA_PLATFORM_WINDOWS #ifdef CLARA_PLATFORM_WINDOWS
if (name[0] != '-' && name[0] != '/') if (name[0] != '-' && name[0] != '/')
return Result::logicError("Option name must begin with '-' or '/'"); return Result::logicError("Option name must begin with '-' or '/'");
#else #else
if( name[0] != '-' ) if (name[0] != '-') return Result::logicError("Option name must begin with '-'");
return Result::logicError( "Option name must begin with '-'" );
#endif #endif
} }
return ParserRefImpl::validate(); return ParserRefImpl::validate();
@ -1060,18 +988,12 @@ namespace detail {
: Opt([&](bool flag) { : Opt([&](bool flag) {
showHelpFlag = flag; showHelpFlag = flag;
return ParserResult::ok(ParseResultType::ShortCircuitAll); return ParserResult::ok(ParseResultType::ShortCircuitAll);
}) }) {
{ static_cast<Opt &> (*this)("display usage information")["-?"]["-h"]["--help"].optional();
static_cast<Opt &>( *this )
("display usage information")
["-?"]["-h"]["--help"]
.optional();
} }
}; };
struct Parser : ParserBase { struct Parser : ParserBase {
mutable ExeName m_exeName; mutable ExeName m_exeName;
std::vector<Opt> m_options; std::vector<Opt> m_options;
std::vector<Arg> m_args; std::vector<Arg> m_args;
@ -1104,9 +1026,13 @@ namespace detail {
// Forward deprecated interface with '+' instead of '|' // Forward deprecated interface with '+' instead of '|'
template <typename T> template <typename T>
auto operator+=( T const &other ) -> Parser & { return operator|=( other ); } auto operator+=(T const &other) -> Parser & {
return operator|=(other);
}
template <typename T> template <typename T>
auto operator+( T const &other ) const -> Parser { return operator|( other ); } auto operator+(T const &other) const -> Parser {
return operator|(other);
}
auto getHelpColumns() const -> std::vector<HelpColumns> { auto getHelpColumns() const -> std::vector<HelpColumns> {
std::vector<HelpColumns> cols; std::vector<HelpColumns> cols;
@ -1119,7 +1045,8 @@ namespace detail {
void writeToStream(std::ostream &os) const { void writeToStream(std::ostream &os) const {
if (!m_exeName.name().empty()) { if (!m_exeName.name().empty()) {
os << "usage:\n" << " " << m_exeName.name() << " "; os << "usage:\n"
<< " " << m_exeName.name() << " ";
bool required = true, first = true; bool required = true, first = true;
for (auto const &arg : m_args) { for (auto const &arg : m_args) {
if (first) if (first)
@ -1131,28 +1058,22 @@ namespace detail {
required = false; required = false;
} }
os << "<" << arg.hint() << ">"; os << "<" << arg.hint() << ">";
if( arg.cardinality() == 0 ) if (arg.cardinality() == 0) os << " ... ";
os << " ... ";
} }
if( !required ) if (!required) os << "]";
os << "]"; if (!m_options.empty()) os << " options";
if( !m_options.empty() )
os << " options";
os << "\n\nwhere options are:" << std::endl; os << "\n\nwhere options are:" << std::endl;
} }
auto rows = getHelpColumns(); auto rows = getHelpColumns();
size_t consoleWidth = CLARA_CONFIG_CONSOLE_WIDTH; size_t consoleWidth = CLARA_CONFIG_CONSOLE_WIDTH;
size_t optWidth = 0; size_t optWidth = 0;
for( auto const &cols : rows ) for (auto const &cols : rows) optWidth = (std::max)(optWidth, cols.left.size() + 2);
optWidth = (std::max)(optWidth, cols.left.size() + 2);
optWidth = (std::min)(optWidth, consoleWidth / 2); optWidth = (std::min)(optWidth, consoleWidth / 2);
for (auto const &cols : rows) { for (auto const &cols : rows) {
auto row = auto row = TextFlow::Column(cols.left).width(optWidth).indent(2) + TextFlow::Spacer(4) +
TextFlow::Column( cols.left ).width( optWidth ).indent( 2 ) +
TextFlow::Spacer(4) +
TextFlow::Column(cols.right).width(consoleWidth - 7 - optWidth); TextFlow::Column(cols.right).width(consoleWidth - 7 - optWidth);
os << row << std::endl; os << row << std::endl;
} }
@ -1166,21 +1087,19 @@ namespace detail {
auto validate() const -> Result override { auto validate() const -> Result override {
for (auto const &opt : m_options) { for (auto const &opt : m_options) {
auto result = opt.validate(); auto result = opt.validate();
if( !result ) if (!result) return result;
return result;
} }
for (auto const &arg : m_args) { for (auto const &arg : m_args) {
auto result = arg.validate(); auto result = arg.validate();
if( !result ) if (!result) return result;
return result;
} }
return Result::ok(); return Result::ok();
} }
using ParserBase::parse; using ParserBase::parse;
auto parse( std::string const& exeName, TokenStream const &tokens ) const -> InternalParseResult override { auto parse(std::string const &exeName, TokenStream const &tokens) const
-> InternalParseResult override {
struct ParserInfo { struct ParserInfo {
ParserBase const *parser = nullptr; ParserBase const *parser = nullptr;
size_t count = 0; size_t count = 0;
@ -1204,10 +1123,10 @@ namespace detail {
for (size_t i = 0; i < totalParsers; ++i) { for (size_t i = 0; i < totalParsers; ++i) {
auto &parseInfo = parseInfos[i]; auto &parseInfo = parseInfos[i];
if( parseInfo.parser->cardinality() == 0 || parseInfo.count < parseInfo.parser->cardinality() ) { if (parseInfo.parser->cardinality() == 0 ||
parseInfo.count < parseInfo.parser->cardinality()) {
result = parseInfo.parser->parse(exeName, result.value().remainingTokens()); result = parseInfo.parser->parse(exeName, result.value().remainingTokens());
if (!result) if (!result) return result;
return result;
if (result.value().type() != ParseResultType::NoMatch) { if (result.value().type() != ParseResultType::NoMatch) {
tokenParsed = true; tokenParsed = true;
++parseInfo.count; ++parseInfo.count;
@ -1216,10 +1135,10 @@ namespace detail {
} }
} }
if( result.value().type() == ParseResultType::ShortCircuitAll ) if (result.value().type() == ParseResultType::ShortCircuitAll) return result;
return result;
if (!tokenParsed) if (!tokenParsed)
return InternalParseResult::runtimeError( "Unrecognised token: " + result.value().remainingTokens()->token ); return InternalParseResult::runtimeError("Unrecognised token: " +
result.value().remainingTokens()->token);
} }
// !TBD Check missing required options // !TBD Check missing required options
return result; return result;
@ -1233,7 +1152,6 @@ namespace detail {
} }
} // namespace detail } // namespace detail
// A Combined parser // A Combined parser
using detail::Parser; using detail::Parser;
@ -1258,7 +1176,6 @@ using detail::ParseResultType;
// Result type for parser operation // Result type for parser operation
using detail::ParserResult; using detail::ParserResult;
} // namespace clara } // namespace clara
#endif // CLARA_HPP_INCLUDED #endif // CLARA_HPP_INCLUDED

View File

@ -5,15 +5,14 @@
class pow_format { class pow_format {
public: public:
pow_format(long long val, std::string&& unit, bool binary = false): pow_format(long long val, std::string&& unit, bool binary = false)
val_(val), unit_(unit), binary_(binary) { }; : val_(val), unit_(unit), binary_(binary){};
long long val_; long long val_;
std::string unit_; std::string unit_;
bool binary_; bool binary_;
}; };
namespace fmt { namespace fmt {
template <> template <>
struct formatter<pow_format> { struct formatter<pow_format> {
@ -57,8 +56,9 @@ namespace fmt {
fraction /= base; fraction /= base;
} }
auto max_width = 4 // coeff in {:.3g} format auto number_width = 5 // coeff in {:.1f} format
+ 1 // prefix from units array + s.binary_; // potential 4th digit before the decimal point
auto max_width = number_width + 1 // prefix from units array
+ s.binary_ // for the 'i' in GiB. + s.binary_ // for the 'i' in GiB.
+ s.unit_.length(); + s.unit_.length();
@ -70,23 +70,24 @@ namespace fmt {
case '<': case '<':
return format_to(ctx.out(), "{:<{}}", fmt::format("{}", s), max_width); return format_to(ctx.out(), "{:<{}}", fmt::format("{}", s), max_width);
case '=': case '=':
format = "{coefficient:<4.3g}{padding}{prefix}{unit}"; format = "{coefficient:<{number_width}.1f}{padding}{prefix}{unit}";
break; break;
case 0: case 0:
default: default:
format = "{coefficient:.3g}{prefix}{unit}"; format = "{coefficient:.1f}{prefix}{unit}";
break; break;
} }
return format_to(ctx.out(), format return format_to(
, fmt::arg("coefficient", fraction) ctx.out(), format, fmt::arg("coefficient", fraction),
, fmt::arg("prefix", std::string() + units[pow] + ((s.binary_ && pow) ? "i" : "")) fmt::arg("number_width", number_width),
, fmt::arg("unit", s.unit_) fmt::arg("prefix", std::string() + units[pow] + ((s.binary_ && pow) ? "i" : "")),
, fmt::arg("padding", pow ? "" : s.binary_ ? " " : " ") fmt::arg("unit", s.unit_),
); fmt::arg("padding", pow ? ""
: s.binary_ ? " "
: " "));
} }
}; };
// Glib ustirng support // Glib ustirng support
template <> template <>
struct formatter<Glib::ustring> : formatter<std::string> { struct formatter<Glib::ustring> : formatter<std::string> {
@ -95,5 +96,4 @@ namespace fmt {
return formatter<std::string>::format(value, ctx); return formatter<std::string>::format(value, ctx);
} }
}; };
} } // namespace fmt

View File

@ -1,7 +1,15 @@
#pragma once #pragma once
#include <fmt/ostream.h>
#include <json/json.h> #include <json/json.h>
#if (FMT_VERSION >= 90000)
template <>
struct fmt::formatter<Json::Value> : ostream_formatter {};
#endif
namespace waybar::util { namespace waybar::util {
struct JsonParser { struct JsonParser {

View File

@ -0,0 +1,8 @@
#pragma once
#include <json/json.h>
#include <string>
namespace waybar::util {
std::string rewriteTitle(const std::string&, const Json::Value&);
}

View File

@ -0,0 +1,6 @@
#pragma once
#include <string>
namespace waybar::util {
std::string sanitize_string(std::string str);
} // namespace waybar::util

View File

@ -17,6 +17,7 @@ namespace waybar::util {
*/ */
class CancellationGuard { class CancellationGuard {
int oldstate; int oldstate;
public: public:
CancellationGuard() { pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate); } CancellationGuard() { pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate); }
~CancellationGuard() { pthread_setcancelstate(oldstate, &oldstate); } ~CancellationGuard() { pthread_setcancelstate(oldstate, &oldstate); }

View File

@ -39,7 +39,7 @@ The *battery* module displays the current capacity and state (eg. charging) of y
*format*: ++ *format*: ++
typeof: string ++ typeof: string ++
default: {capacity}% ++ default: {capacity}% ++
The format, how the time should be displayed. The format, how information should be displayed.
*format-time*: ++ *format-time*: ++
typeof: string ++ typeof: string ++
@ -114,9 +114,10 @@ The *battery* module displays the current capacity and state (eg. charging) of y
The *battery* module allows you to define how time should be formatted via *format-time*. The *battery* module allows you to define how time should be formatted via *format-time*.
The two arguments are: The three arguments are:
*{H}*: Hours *{H}*: Hours
*{M}*: Minutes *{M}*: Minutes
*{m}*: Zero-padded minutes
# CUSTOM FORMATS # CUSTOM FORMATS

View File

@ -6,21 +6,47 @@ waybar - bluetooth module
# DESCRIPTION # DESCRIPTION
The *bluetooth* module displays information about the status of the device's bluetooth device. The *bluetooth* module displays information about a bluetooth controller and its connections.
# CONFIGURATION # CONFIGURATION
Addressed by *bluetooth* Addressed by *bluetooth*
*controller*: ++
typeof: string ++
Use the controller with the defined alias. Otherwise a random controller is used. Recommended to define when there is more than 1 controller available to the system.
*format-device-preference*: ++
typeof: array ++
A ranking of bluetooth devices, addressed by their alias. The order is from *first displayed* to *last displayed*. ++
If this config option is not defined or none of the devices in the list are connected, it will fall back to showing the last connected device.
*format*: ++ *format*: ++
typeof: string ++ typeof: string ++
default: *{icon}* ++ default: * {status}* ++
The format, how information should be displayed. This format is used when other formats aren't specified. The format, how information should be displayed. This format is used when other formats aren't specified.
*format-disabled*: ++
typeof: string ++
This format is used when the displayed controller is disabled.
*format-off*: ++
typeof: string ++
This format is used when the displayed controller is turned off.
*format-on*: ++
typeof: string ++
This format is used when the displayed controller is turned on with no devices connected.
*format-connected*: ++
typeof: string ++
This format is used when the displayed controller is connected to at least 1 device.
*format-icons*: ++ *format-icons*: ++
typeof: array/object ++ typeof: array/object ++
Based on the device status, the corresponding icon gets selected. ++ Based on the current battery percentage (see section *EXPERIMENTAL BATTERY PERCENTAGE FEATURE*), the corresponding icon gets selected. ++
The order is *low* to *high*. Or by the state if it is an object. The order is *low* to *high*. Will only show the current battery percentage icon in the *\*-connected-battery* config options. ++
Or by the state if it is an object. It will fall back to the enabled state if its derivatives are not defined (on, off, connected).
*rotate*: ++ *rotate*: ++
typeof: integer ++ typeof: integer ++
@ -71,26 +97,106 @@ Addressed by *bluetooth*
typeof: string ++ typeof: string ++
The format, how information should be displayed in the tooltip. This format is used when other formats aren't specified. The format, how information should be displayed in the tooltip. This format is used when other formats aren't specified.
*tooltip-format-disabled*: ++
typeof: string ++
This format is used when the displayed controller is disabled.
*tooltip-format-off*: ++
typeof: string ++
This format is used when the displayed controller is turned off.
*tooltip-format-on*: ++
typeof: string ++
This format is used when the displayed controller is turned on with no devices connected.
*tooltip-format-connected*: ++
typeof: string ++
This format is used when the displayed controller is connected to at least 1 device.
*tooltip-format-enumerate-connected*: ++
typeof: string ++
This format is used to define how each connected device should be displayed within the *device_enumerate* format replacement in the tooltip menu.
# FORMAT REPLACEMENTS # FORMAT REPLACEMENTS
*{status}*: Status of the bluetooth device. *{status}*: Status of the bluetooth device.
*{icon}*: Icon, as defined in *format-icons*. *{icon}*: Icon, as defined in *format-icons*.
*{num_connections}*: Number of connections the displayed controller has.
*{controller_address}*: Address of the displayed controller.
*{controller_address_type}*: Address type of the displayed controller.
*{controller_alias}*: Alias of the displayed controller.
*{device_address}*: Address of the displayed device.
*{device_address_type}*: Address type of the displayed device.
*{device_alias}*: Alias of the displayed device.
*{device_enumerate}*: Show a list of all connected devices, each on a seperate line. Define the format of each device with the *tooltip-format-enumerate-connected* ++
and/or *tooltip-format-enumerate-connected-battery* config options. Can only be used in the tooltip related format options.
# EXPERIMENTAL BATTERY PERCENTAGE FEATURE
At the time of writing, the experimental features of BlueZ need to be turned on, for the battery percentage options listed below to work.
## FORMAT REPLACEMENT
*{device_battery_percentage}*: Battery percentage of the displayed device if available. Use only in the config options defined below.
## CONFIGURATION
*format-connected-battery*: ++
typeof: string ++
This format is used when the displayed device provides its battery percentage.
*tooltip-format-connected-battery*: ++
typeof: string ++
This format is used when the displayed device provides its battery percentage.
*tooltip-format-enumerate-connected-battery*: ++
typeof: string ++
This format is used to define how each connected device with a battery should be displayed within the *device_enumerate* format replacement option. ++
When this config option is not defined, it will fall back on the *tooltip-format-enumerate-connected* config option.
# EXAMPLES # EXAMPLES
``` ```
"bluetooth": { "bluetooth": {
"format": "{icon}", // "controller": "controller1", // specify the alias of the controller if there are more than 1 on the system
"format-alt": "bluetooth: {status}", "format": " {status}",
"format-icons": { "format-disabled": "", // an empty format will hide the module
"enabled": "", "format-connected": " {num_connections} connected",
"disabled": "" "tooltip-format": "{controller_alias}\\t{controller_address}",
}, "tooltip-format-connected": "{controller_alias}\\t{controller_address}\\n\\n{device_enumerate}",
"tooltip-format": "{}" "tooltip-format-enumerate-connected": "{device_alias}\\t{device_address}"
}
```
```
"bluetooth": {
"format": " {status}",
"format-connected": " {device_alias}",
"format-connected-battery": " {device_alias} {device_battery_percentage}%",
// "format-device-preference": [ "device1", "device2" ], // preference list deciding the displayed device
"tooltip-format": "{controller_alias}\\t{controller_address}\\n\\n{num_connections} connected",
"tooltip-format-connected": "{controller_alias}\\t{controller_address}\\n\\n{num_connections} connected\\n\\n{device_enumerate}",
"tooltip-format-enumerate-connected": "{device_alias}\\t{device_address}",
"tooltip-format-enumerate-connected-battery": "{device_alias}\\t{device_address}\\t{device_battery_percentage}%"
} }
``` ```
# STYLE # STYLE
- *#bluetooth* - *#bluetooth*
- *#bluetooth.disabled*
- *#bluetooth.off*
- *#bluetooth.on*
- *#bluetooth.connected*
- *#bluetooth.discoverable*
- *#bluetooth.discovering*
- *#bluetooth.pairable*

95
man/waybar-gamemode.5.scd Normal file
View File

@ -0,0 +1,95 @@
waybar-gamemode(5)
# NAME
waybar - gamemode module
# DESCRIPTION
The *gamemode* module displays if any game or application is running with ++
Feral Gamemode optimizations.
# CONFIGURATION
*format*: ++
typeof: string ++
default: {glyph} ++
The text format.
*format-alt*: ++
typeof: string ++
default: {glyph} {count} ++
The text format when toggled.
*tooltip*: ++
typeof: bool ++
defualt: true ++
Option to disable tooltip on hover.
*tooltip-format*: ++
typeof: string ++
default: Games running: {glyph} ++
The text format of the tooltip.
*hide-not-running*: ++
typeof: bool ++
default: true ++
Defines if the module should be hidden if no games are running.
*use-icon*: ++
typeof: bool ++
default: true ++
Defines if the module should display a GTK icon instead of the specified *glyph*
*glyph*: ++
typeof: string ++
default:  ++
The string icon to display. Only visible if *use-icon* is set to false.
*icon-name*: ++
typeof: string ++
default: input-gaming-symbolic ++
The GTK icon to display. Only visible if *use-icon* is set to true.
*icon-size*: ++
typeof: unsigned integer ++
default: 20 ++
Defines the size of the icons.
*icon-spacing*: ++
typeof: unsigned integer ++
default: 4 ++
Defines the spacing between the icon and the text.
# FORMAT REPLACEMENTS
*{glyph}*: The string icon glyph to use instead.
*{count}*: The amount of games running with gamemode optimizations.
# TOOLTIP FORMAT REPLACEMENTS
*{count}*: The amount of games running with gamemode optimizations.
# EXAMPLES
```
"gamemode": {
"format": "{glyph}",
"format-alt": "{glyph} {count}",
"glyph": "",
"hide-not-running": true,
"use-icon": true,
"icon-name": "input-gaming-symbolic",
"icon-spacing": 4,
"icon-size": 20,
"tooltip": true,
"tooltip-format": "Games running: {count}"
}
```
# STYLE
- *#gamemode*
- *#gamemode.running*

View File

@ -0,0 +1,43 @@
waybar-hyprland-language(5)
# NAME
waybar - hyprland language module
# DESCRIPTION
The *language* module displays the currently selected language.
# CONFIGURATION
Addressed by *hyprland/language*
*format*: ++
typeof: string ++
default: {} ++
The format, how information should be displayed. On {} the currently selected language is displayed.
*format-<lang>* ++
typeof: string++
Provide an alternative name to display per language where <lang> is the language of your choosing. Can be passed multiple times with multiple languages as shown by the example below.
*keyboard-name*: ++
typeof: string ++
Specifies which keyboard to use from hyprctl devices output. Using the option that begins with "AT Translated set..." is recommended.
# EXAMPLES
```
"hyprland/language": {
"format": "Lang: {}"
"format-us": "AMERICA, HELL YEAH!" // For American English
"format-tr": "As bayrakları" // For Turkish
"keyboard-name": "AT Translated Set 2 keyboard"
}
```
# STYLE
- *#language*

View File

@ -0,0 +1,50 @@
waybar-hyprland-window(5)
# NAME
waybar - hyprland window module
# DESCRIPTION
The *window* module displays the title of the currently focused window in Hyprland.
# CONFIGURATION
Addressed by *hyprland/window*
*format*: ++
typeof: string ++
default: {} ++
The format, how information should be displayed. On {} the current window title is displayed.
*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
```
"hyprland/window": {
"format": "{}",
"rewrite": {
"(.*) - Mozilla Firefox": "🌎 $1",
"(.*) - zsh": "> [$1]"
}
}
```
# STYLE
- *#window*

View File

@ -63,11 +63,28 @@ screensaving, also known as "presentation mode".
typeof: double ++ typeof: double ++
Threshold to be used when scrolling. Threshold to be used when scrolling.
*start-activated*: ++
typeof: bool ++
default: *false* ++
Whether the inhibit should be activated when starting waybar.
*timeout*: ++
typeof: double ++
The number of minutes the inhibit should last.
*tooltip*: ++ *tooltip*: ++
typeof: bool ++ typeof: bool ++
default: true ++ default: true ++
Option to disable tooltip on hover. Option to disable tooltip on hover.
*tooltip-format-activated*: ++
typeof: string ++
This format is used when the inhibit is activated.
*tooltip-format-deactivated*: ++
typeof: string ++
This format is used when the inhibit is deactivated.
# FORMAT REPLACEMENTS # FORMAT REPLACEMENTS
*{status}*: status (*activated* or *deactivated*) *{status}*: status (*activated* or *deactivated*)
@ -82,6 +99,7 @@ screensaving, also known as "presentation mode".
"format-icons": { "format-icons": {
"activated": "", "activated": "",
"deactivated": "" "deactivated": ""
} },
"timeout": 30.5
} }
``` ```

112
man/waybar-jack.5.scd Normal file
View File

@ -0,0 +1,112 @@
waybar-jack(5)
# NAME
waybar - JACK module
# DESCRIPTION
The *jack* module displays the current state of the JACK server.
# CONFIGURATION
Addressed by *jack*
*format*: ++
typeof: string ++
default: *{load}%* ++
The format, how information should be displayed. This format is used when other formats aren't specified.
*format-connected*: ++
typeof: string ++
This format is used when the module is connected to the JACK server.
*format-disconnected*: ++
typeof: string ++
This format is used when the module is not connected to the JACK server.
*format-xrun*: ++
typeof: string ++
This format is used for one polling interval, when the JACK server reports an xrun.
*realtime*: ++
typeof: bool ++
default: *true* ++
Option to drop real-time privileges for the JACK client opened by Waybar.
*tooltip*: ++
typeof: bool ++
default: *true* ++
Option to disable tooltip on hover.
*tooltip-format*: ++
typeof: string ++
default: *{bufsize}/{samplerate} {latency}ms* ++
The format of information displayed in the tooltip.
*interval*: ++
typeof: integer ++
default: 1 ++
The interval in which the information gets polled.
*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.
# FORMAT REPLACEMENTS
*{load}*: The current CPU load estimated by JACK.
*{bufsize}*: The size of the JACK buffer.
*{samplerate}*: The samplerate at which the JACK server is running.
*{latency}*: The duration, in ms, of the current buffer size.
*{xruns}*: The number of xruns reported by the JACK server since starting Waybar.
# EXAMPLES
```
"jack": {
"format": "DSP {}%",
"format-xrun": "{xruns} xruns",
"format-disconnected": "DSP off",
"realtime": true
}
```
# STYLE
- *#jack*
- *#jack.connected*
- *#jack.disconnected*
- *#jack.xrun*

View File

@ -13,6 +13,7 @@ You must be a member of the input group to use this module.
# CONFIGURATION # CONFIGURATION
*interval*: ++ *interval*: ++
Deprecated, this module use event loop now, the interval has no effect.
typeof: integer ++ typeof: integer ++
default: 1 ++ default: 1 ++
The interval, in seconds, to poll the keyboard state. The interval, in seconds, to poll the keyboard state.
@ -79,4 +80,9 @@ The following *format-icons* can be set.
- *#keyboard-state* - *#keyboard-state*
- *#keyboard-state label* - *#keyboard-state label*
- *#keyboard-state label.locked* - *#keyboard-state label.locked*
- *#keyboard-state label.numlock*
- *#keyboard-state label.numlock.locked*
- *#keyboard-state label.capslock*
- *#keyboard-state label.capslock.locked*
- *#keyboard-state label.scrolllock*
- *#keyboard-state label.scrolllock.locked*

View File

@ -149,10 +149,20 @@ Addressed by *network*
*{bandwidthDownBits}*: Instant down speed in bits/seconds. *{bandwidthDownBits}*: Instant down speed in bits/seconds.
*{bandwidthTotalBits}*: Instant total speed in bits/seconds.
*{bandwidthUpOctets}*: Instant up speed in octets/seconds. *{bandwidthUpOctets}*: Instant up speed in octets/seconds.
*{bandwidthDownOctets}*: Instant down speed in octets/seconds. *{bandwidthDownOctets}*: Instant down speed in octets/seconds.
*{bandwidthTotalOctets}*: Instant total speed in octets/seconds.
*{bandwidthUpBytes}*: Instant up speed in bytes/seconds.
*{bandwidthDownBytes}*: Instant down speed in bytes/seconds.
*{bandwidthTotalBytes}*: Instant total speed in bytes/seconds.
*{icon}*: Icon, as defined in *format-icons*. *{icon}*: Icon, as defined in *format-icons*.
# EXAMPLES # EXAMPLES

View File

@ -96,6 +96,15 @@ Additionally you can control the volume by scrolling *up* or *down* while the cu
default: true ++ default: true ++
Option to disable tooltip on hover. Option to disable tooltip on hover.
*max-volume*: ++
typeof: integer ++
default: 100 ++
The maximum volume that can be set, in percentage.
*ignored-sinks*: ++
typeof: array ++
Sinks in this list will not be shown as the active sink by Waybar. Entries should be the sink's description field.
# FORMAT REPLACEMENTS # FORMAT REPLACEMENTS
*{desc}*: Pulseaudio port's description, for bluetooth it'll be the device name. *{desc}*: Pulseaudio port's description, for bluetooth it'll be the device name.

View File

@ -0,0 +1,75 @@
waybar-river-mode(5)
# NAME
waybar - river mode module
# DESCRIPTION
The *mode* module displays the current mapping mode of river.
# CONFIGURATION
Addressed by *river/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.
# EXAMPLES
```
"river/mode": {
"format": " {}"
}
```
# STYLE
- *#mode*
- *#mode.<mode>*

View File

@ -0,0 +1,59 @@
waybar-river-window(5)
# NAME
waybar - river window module
# DESCRIPTION
The *window* module displays the title of the currently focused window in river
# CONFIGURATION
Addressed by *river/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.
# EXAMPLES
```
"river/window": {
"format": "{}"
}
```
# STYLE
- *#window*
- *#window.focused* Applied when the output this module's bar belongs to is focused.

View File

@ -0,0 +1,64 @@
waybar-sway-scratchpad(5)
# NAME
waybar - sway scratchpad module
# DESCRIPTION
The *scratchpad* module displays the scratchpad status in Sway
# CONFIGURATION
Addressed by *sway/scratchpad*
*format*: ++
typeof: string ++
default: {icon} {count} ++
The format, how information should be displayed.
*show-empty*: ++
typeof: bool ++
default: false ++
Option to show module when scratchpad is empty.
*format-icons*: ++
typeof: array/object ++
Based on the current scratchpad window counts, the corresponding icon gets selected.
*tooltip*: ++
typeof: bool ++
default: true ++
Option to disable tooltip on hover.
*tooltip-format*: ++
typeof: string ++
default: {app}: {title} ++
The format, how information in the tooltip should be displayed.
# FORMAT REPLACEMENTS
*{icon}*: Icon, as defined in *format-icons*.
*{count}*: Number of windows in the scratchpad.
*{app}*: Name of the application in the scratchpad.
*{title}*: Title of the application in the scratchpad.
# EXAMPLES
```
"sway/scratchpad": {
"format": "{icon} {count}",
"show-empty": false,
"format-icons": ["", ""],
"tooltip": true,
"tooltip-format": "{app}: {title}"
}
```
# STYLE
- *#scratchpad*
- *#scratchpad.empty*

View File

@ -14,8 +14,8 @@ Addressed by *sway/window*
*format*: ++ *format*: ++
typeof: string ++ typeof: string ++
default: {} ++ default: {title} ++
The format, how information should be displayed. On {} data gets inserted. The format, how information should be displayed.
*rotate*: ++ *rotate*: ++
typeof: integer ++ typeof: integer ++
@ -75,6 +75,20 @@ Addressed by *sway/window*
default: false ++ default: false ++
Option to hide the application icon. Option to hide the application icon.
*icon-size*: ++
typeof: integer ++
default: 24 ++
Option to change the size of the application icon.
# FORMAT REPLACEMENTS
*{title}*: The title of the focused window.
*{app_id}*: The app_id of the focused window.
*{shell}*: The shell of the focused window. It's 'xwayland' when the window is
running through xwayland, otherwise it's 'xdg-shell'.
# REWRITE RULES # REWRITE RULES
*rewrite* is an object where keys are regular expressions and values are *rewrite* is an object where keys are regular expressions and values are

76
man/waybar-upower.5.scd Normal file
View File

@ -0,0 +1,76 @@
waybar-upower(5)
# NAME
waybar - upower module
# DESCRIPTION
The *upower* module displays the main battery capacity with all other upower
compatible devices in the tooltip.
# CONFIGURATION
*icon-size*: ++
typeof: integer ++
default: 20 ++
Defines the size of the icons.
*format*: ++
typeof: string ++
default: {percentage} ++
The text format.
*format-alt*: ++
typeof: string ++
default: {percentage} {time} ++
The text format when toggled.
*hide-if-empty*: ++
typeof: bool ++
default: true ++
Defines visibility of the module if no devices can be found.
*tooltip*: ++
typeof: bool ++
defualt: true ++
Option to disable tooltip on hover.
*tooltip-spacing*: ++
typeof: integer ++
default: 4 ++
Defines the spacing between the tooltip device name and device battery ++
status.
*tooltip-padding*: ++
typeof: integer ++
default: 4 ++
Defines the spacing between the tooltip window edge and the tooltip content.
# FORMAT REPLACEMENTS
*{percentage}*: The battery capacity in percentage
*{time}*: An estimated time either until empty or until fully charged ++
depending on the charging state.
# EXAMPLES
```
"upower": {
"icon-size": 20,
"hide-if-empty": true,
"tooltip": true,
"tooltip-spacing": 20
}
```
# STYLE
- *#upower*
- *#upower.charging*
- *#upower.discharging*
- *#upower.full*
- *#upower.empty*
- *#upower.unknown-status*

View File

@ -33,6 +33,11 @@ Addressed by *wlr/workspaces*
Note that if both *sort-by-name* and *sort-by-coordinates* are true sort by name will be first. Note that if both *sort-by-name* and *sort-by-coordinates* are true sort by name will be first.
If both are false - sort by id will be performed. If both are false - sort by id will be performed.
*sort-by-number*: ++
typeof: bool ++
default: false ++
If set to true, workspace names will be sorted numerically. Takes presedence over any other sort-by option.
*all-outputs*: ++ *all-outputs*: ++
typeof: bool ++ typeof: bool ++
default: false ++ default: false ++
@ -75,7 +80,8 @@ Additional to workspace name matching, the following *format-icons* can be set.
"5": "", "5": "",
"focused": "", "focused": "",
"default": "" "default": ""
} },
"sort-by-number": true
} }
``` ```

View File

@ -77,6 +77,13 @@ Also a minimal example configuration can be found on the at the bottom of this m
Selects one of the preconfigured display modes. This is an equivalent of the sway-bar(5) *mode* command and supports the same values: *dock*, *hide*, *invisible*, *overlay*. ++ Selects one of the preconfigured display modes. This is an equivalent of the sway-bar(5) *mode* command and supports the same values: *dock*, *hide*, *invisible*, *overlay*. ++
Note: *hide* and *invisible* modes may be not as useful without Sway IPC. Note: *hide* and *invisible* modes may be not as useful without Sway IPC.
modifier-reset ++
typeof: string ++
default: *press*
Defines the timing of modifier key to reset the bar visibility.
To reset the visibility of the bar with the press of the modifier key use *press*.
Use *release* to reset the visibility upon the release of the modifier key and only if no other action happened while the key was pressed. This prevents hiding the bar when the modifier is used to switch a workspace, change binding mode or start a keybinding.
*exclusive* ++ *exclusive* ++
typeof: bool ++ typeof: bool ++
default: *true* ++ default: *true* ++
@ -261,9 +268,12 @@ A module group is defined by specifying a module named "group/some-group-name".
- *waybar-mpd(5)* - *waybar-mpd(5)*
- *waybar-network(5)* - *waybar-network(5)*
- *waybar-pulseaudio(5)* - *waybar-pulseaudio(5)*
- *waybar-river-mode(5)*
- *waybar-river-tags(5)* - *waybar-river-tags(5)*
- *waybar-river-window(5)*
- *waybar-states(5)* - *waybar-states(5)*
- *waybar-sway-mode(5)* - *waybar-sway-mode(5)*
- *waybar-sway-scratchpad(5)*
- *waybar-sway-window(5)* - *waybar-sway-window(5)*
- *waybar-sway-workspaces(5)* - *waybar-sway-workspaces(5)*
- *waybar-wlr-taskbar(5)* - *waybar-wlr-taskbar(5)*

View File

@ -1,6 +1,6 @@
project( project(
'waybar', 'cpp', 'c', 'waybar', 'cpp', 'c',
version: '0.9.11', version: '0.9.15',
license: 'MIT', license: 'MIT',
meson_version: '>= 0.49.0', meson_version: '>= 0.49.0',
default_options : [ default_options : [
@ -79,24 +79,28 @@ is_netbsd = host_machine.system() == 'netbsd'
is_openbsd = host_machine.system() == 'openbsd' is_openbsd = host_machine.system() == 'openbsd'
thread_dep = dependency('threads') thread_dep = dependency('threads')
fmt = dependency('fmt', version : ['>=7.0.0'], fallback : ['fmt', 'fmt_dep']) fmt = dependency('fmt', version : ['>=8.1.1'], fallback : ['fmt', 'fmt_dep'])
spdlog = dependency('spdlog', version : ['>=1.8.5'], fallback : ['spdlog', 'spdlog_dep'], default_options : ['external_fmt=true']) spdlog = dependency('spdlog', version : ['>=1.10.0'], fallback : ['spdlog', 'spdlog_dep'], default_options : ['external_fmt=enabled'])
wayland_client = dependency('wayland-client') wayland_client = dependency('wayland-client')
wayland_cursor = dependency('wayland-cursor') wayland_cursor = dependency('wayland-cursor')
wayland_protos = dependency('wayland-protocols') wayland_protos = dependency('wayland-protocols')
gtkmm = dependency('gtkmm-3.0', version : ['>=3.22.0']) gtkmm = dependency('gtkmm-3.0', version : ['>=3.22.0'])
dbusmenu_gtk = dependency('dbusmenu-gtk3-0.4', required: get_option('dbusmenu-gtk')) dbusmenu_gtk = dependency('dbusmenu-gtk3-0.4', required: get_option('dbusmenu-gtk'))
giounix = dependency('gio-unix-2.0', required: (get_option('dbusmenu-gtk').enabled() or get_option('logind').enabled())) giounix = dependency('gio-unix-2.0', required: (get_option('dbusmenu-gtk').enabled() or get_option('logind').enabled() or get_option('upower_glib').enabled()))
jsoncpp = dependency('jsoncpp') jsoncpp = dependency('jsoncpp')
sigcpp = dependency('sigc++-2.0') sigcpp = dependency('sigc++-2.0')
libinotify = dependency('libinotify', required: false)
libepoll = dependency('epoll-shim', required: false) libepoll = dependency('epoll-shim', required: false)
libinput = dependency('libinput', required: get_option('libinput'))
libnl = dependency('libnl-3.0', required: get_option('libnl')) libnl = dependency('libnl-3.0', required: get_option('libnl'))
libnlgen = dependency('libnl-genl-3.0', required: get_option('libnl')) libnlgen = dependency('libnl-genl-3.0', required: get_option('libnl'))
upower_glib = dependency('upower-glib', required: get_option('upower_glib'))
libpulse = dependency('libpulse', required: get_option('pulseaudio')) libpulse = dependency('libpulse', required: get_option('pulseaudio'))
libudev = dependency('libudev', required: get_option('libudev')) libudev = dependency('libudev', required: get_option('libudev'))
libevdev = dependency('libevdev', required: get_option('libevdev')) libevdev = dependency('libevdev', required: get_option('libevdev'))
libmpdclient = dependency('libmpdclient', required: get_option('mpd')) libmpdclient = dependency('libmpdclient', required: get_option('mpd'))
xkbregistry = dependency('xkbregistry') xkbregistry = dependency('xkbregistry')
libjack = dependency('jack', required: get_option('jack'))
libsndio = compiler.find_library('sndio', required: get_option('sndio')) libsndio = compiler.find_library('sndio', required: get_option('sndio'))
if libsndio.found() if libsndio.found()
@ -141,18 +145,22 @@ endif
src_files = files( src_files = files(
'src/factory.cpp', 'src/factory.cpp',
'src/AModule.cpp', 'src/AModule.cpp',
'src/AButton.cpp',
'src/ALabel.cpp', 'src/ALabel.cpp',
'src/AIconLabel.cpp', 'src/AIconLabel.cpp',
'src/modules/custom.cpp', 'src/modules/custom.cpp',
'src/modules/disk.cpp', 'src/modules/disk.cpp',
'src/modules/idle_inhibitor.cpp', 'src/modules/idle_inhibitor.cpp',
'src/modules/temperature.cpp', 'src/modules/temperature.cpp',
'src/modules/user.cpp',
'src/main.cpp', 'src/main.cpp',
'src/bar.cpp', 'src/bar.cpp',
'src/client.cpp', 'src/client.cpp',
'src/config.cpp', 'src/config.cpp',
'src/group.cpp', 'src/group.cpp',
'src/util/ustring_clen.cpp' 'src/util/ustring_clen.cpp',
'src/util/sanitize_str.cpp',
'src/util/rewrite_title.cpp'
) )
if is_linux if is_linux
@ -174,6 +182,11 @@ elif is_dragonfly or is_freebsd or is_netbsd or is_openbsd
'src/modules/memory/bsd.cpp', 'src/modules/memory/bsd.cpp',
'src/modules/memory/common.cpp', 'src/modules/memory/common.cpp',
) )
if is_freebsd
src_files += files(
'src/modules/battery.cpp',
)
endif
endif endif
add_project_arguments('-DHAVE_SWAY', language: 'cpp') add_project_arguments('-DHAVE_SWAY', language: 'cpp')
@ -183,7 +196,8 @@ src_files += [
'src/modules/sway/mode.cpp', 'src/modules/sway/mode.cpp',
'src/modules/sway/language.cpp', 'src/modules/sway/language.cpp',
'src/modules/sway/window.cpp', 'src/modules/sway/window.cpp',
'src/modules/sway/workspaces.cpp' 'src/modules/sway/workspaces.cpp',
'src/modules/sway/scratchpad.cpp'
] ]
if true if true
@ -195,7 +209,16 @@ endif
if true if true
add_project_arguments('-DHAVE_RIVER', language: 'cpp') add_project_arguments('-DHAVE_RIVER', language: 'cpp')
src_files += 'src/modules/river/mode.cpp'
src_files += 'src/modules/river/tags.cpp' src_files += 'src/modules/river/tags.cpp'
src_files += 'src/modules/river/window.cpp'
endif
if true
add_project_arguments('-DHAVE_HYPRLAND', language: 'cpp')
src_files += 'src/modules/hyprland/backend.cpp'
src_files += 'src/modules/hyprland/window.cpp'
src_files += 'src/modules/hyprland/language.cpp'
endif endif
if libnl.found() and libnlgen.found() if libnl.found() and libnlgen.found()
@ -203,11 +226,27 @@ if libnl.found() and libnlgen.found()
src_files += 'src/modules/network.cpp' src_files += 'src/modules/network.cpp'
endif endif
if (giounix.found() and not get_option('logind').disabled())
add_project_arguments('-DHAVE_GAMEMODE', language: 'cpp')
src_files += 'src/modules/gamemode.cpp'
endif
if (upower_glib.found() and giounix.found() and not get_option('logind').disabled())
add_project_arguments('-DHAVE_UPOWER', language: 'cpp')
src_files += 'src/modules/upower/upower.cpp'
src_files += 'src/modules/upower/upower_tooltip.cpp'
endif
if libpulse.found() if libpulse.found()
add_project_arguments('-DHAVE_LIBPULSE', language: 'cpp') add_project_arguments('-DHAVE_LIBPULSE', language: 'cpp')
src_files += 'src/modules/pulseaudio.cpp' src_files += 'src/modules/pulseaudio.cpp'
endif endif
if libjack.found()
add_project_arguments('-DHAVE_LIBJACK', language: 'cpp')
src_files += 'src/modules/jack.cpp'
endif
if dbusmenu_gtk.found() if dbusmenu_gtk.found()
add_project_arguments('-DHAVE_DBUSMENU', language: 'cpp') add_project_arguments('-DHAVE_DBUSMENU', language: 'cpp')
src_files += files( src_files += files(
@ -223,8 +262,9 @@ if libudev.found() and (is_linux or libepoll.found())
src_files += 'src/modules/backlight.cpp' src_files += 'src/modules/backlight.cpp'
endif endif
if libevdev.found() and (is_linux or libepoll.found()) if libevdev.found() and (is_linux or libepoll.found()) and libinput.found() and (is_linux or libinotify.found())
add_project_arguments('-DHAVE_LIBEVDEV', language: 'cpp') add_project_arguments('-DHAVE_LIBEVDEV', language: 'cpp')
add_project_arguments('-DHAVE_LIBINPUT', language: 'cpp')
src_files += 'src/modules/keyboard_state.cpp' src_files += 'src/modules/keyboard_state.cpp'
endif endif
@ -246,17 +286,15 @@ endif
if (giounix.found() and not get_option('logind').disabled()) if (giounix.found() and not get_option('logind').disabled())
add_project_arguments('-DHAVE_GIO_UNIX', language: 'cpp') add_project_arguments('-DHAVE_GIO_UNIX', language: 'cpp')
src_files += 'src/modules/inhibitor.cpp' src_files += 'src/modules/inhibitor.cpp'
src_files += 'src/modules/bluetooth.cpp'
endif endif
if get_option('rfkill').enabled() if get_option('rfkill').enabled() and is_linux
if is_linux
add_project_arguments('-DWANT_RFKILL', language: 'cpp') add_project_arguments('-DWANT_RFKILL', language: 'cpp')
src_files += files( src_files += files(
'src/modules/bluetooth.cpp',
'src/util/rfkill.cpp' 'src/util/rfkill.cpp'
) )
endif endif
endif
if tz_dep.found() if tz_dep.found()
add_project_arguments('-DHAVE_LIBDATE', language: 'cpp') add_project_arguments('-DHAVE_LIBDATE', language: 'cpp')
@ -286,10 +324,14 @@ executable(
gtkmm, gtkmm,
dbusmenu_gtk, dbusmenu_gtk,
giounix, giounix,
libinput,
libnl, libnl,
libnlgen, libnlgen,
upower_glib,
libpulse, libpulse,
libjack,
libudev, libudev,
libinotify,
libepoll, libepoll,
libmpdclient, libmpdclient,
libevdev, libevdev,
@ -333,15 +375,19 @@ if scdoc.found()
'waybar-cpu.5.scd', 'waybar-cpu.5.scd',
'waybar-custom.5.scd', 'waybar-custom.5.scd',
'waybar-disk.5.scd', 'waybar-disk.5.scd',
'waybar-gamemode.5.scd',
'waybar-idle-inhibitor.5.scd', 'waybar-idle-inhibitor.5.scd',
'waybar-keyboard-state.5.scd', 'waybar-keyboard-state.5.scd',
'waybar-memory.5.scd', 'waybar-memory.5.scd',
'waybar-mpd.5.scd', 'waybar-mpd.5.scd',
'waybar-network.5.scd', 'waybar-network.5.scd',
'waybar-pulseaudio.5.scd', 'waybar-pulseaudio.5.scd',
'waybar-river-mode.5.scd',
'waybar-river-tags.5.scd', 'waybar-river-tags.5.scd',
'waybar-river-window.5.scd',
'waybar-sway-language.5.scd', 'waybar-sway-language.5.scd',
'waybar-sway-mode.5.scd', 'waybar-sway-mode.5.scd',
'waybar-sway-scratchpad.5.scd',
'waybar-sway-window.5.scd', 'waybar-sway-window.5.scd',
'waybar-sway-workspaces.5.scd', 'waybar-sway-workspaces.5.scd',
'waybar-temperature.5.scd', 'waybar-temperature.5.scd',
@ -351,6 +397,7 @@ if scdoc.found()
'waybar-wlr-workspaces.5.scd', 'waybar-wlr-workspaces.5.scd',
'waybar-bluetooth.5.scd', 'waybar-bluetooth.5.scd',
'waybar-sndio.5.scd', 'waybar-sndio.5.scd',
'waybar-upower.5.scd',
] ]
if (giounix.found() and not get_option('logind').disabled()) if (giounix.found() and not get_option('logind').disabled())
@ -381,6 +428,7 @@ endif
catch2 = dependency( catch2 = dependency(
'catch2', 'catch2',
version: '>=3.0.0',
fallback: ['catch2', 'catch2_dep'], fallback: ['catch2', 'catch2_dep'],
required: get_option('tests'), required: get_option('tests'),
) )

View File

@ -1,8 +1,10 @@
option('libcxx', type : 'boolean', value : false, description : 'Build with Clang\'s libc++ instead of libstdc++ on Linux.') option('libcxx', type : 'boolean', value : false, description : 'Build with Clang\'s libc++ instead of libstdc++ on Linux.')
option('libinput', type: 'feature', value: 'auto', description: 'Enable libinput support for libinput related features')
option('libnl', type: 'feature', value: 'auto', description: 'Enable libnl support for network related features') 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('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('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('pulseaudio', type: 'feature', value: 'auto', description: 'Enable support for pulseaudio')
option('upower_glib', type: 'feature', value: 'auto', description: 'Enable support for upower')
option('systemd', type: 'feature', value: 'auto', description: 'Install systemd user service unit') 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('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('man-pages', type: 'feature', value: 'auto', description: 'Generate and install man pages')
@ -13,3 +15,4 @@ option('sndio', type: 'feature', value: 'auto', description: 'Enable support for
option('logind', type: 'feature', value: 'auto', description: 'Enable support for logind') option('logind', type: 'feature', value: 'auto', description: 'Enable support for logind')
option('tests', type: 'feature', value: 'auto', description: 'Enable tests') option('tests', type: 'feature', value: 'auto', description: 'Enable tests')
option('experimental', type : 'boolean', value : false, description: 'Enable experimental features') option('experimental', type : 'boolean', value : false, description: 'Enable experimental features')
option('jack', type: 'feature', value: 'auto', description: 'Enable support for JACK')

View File

@ -16,7 +16,7 @@
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
</copyright> </copyright>
<interface name="zriver_status_manager_v1" version="2"> <interface name="zriver_status_manager_v1" version="3">
<description summary="manage river status objects"> <description summary="manage river status objects">
A global factory for objects that receive status information specific A global factory for objects that receive status information specific
to river. It could be used to implement, for example, a status bar. to river. It could be used to implement, for example, a status bar.
@ -85,7 +85,7 @@
</event> </event>
</interface> </interface>
<interface name="zriver_seat_status_v1" version="1"> <interface name="zriver_seat_status_v1" version="3">
<description summary="track seat focus"> <description summary="track seat focus">
This interface allows clients to receive information about the current This interface allows clients to receive information about the current
focus of a seat. Note that (un)focused_output events will only be sent focus of a seat. Note that (un)focused_output events will only be sent
@ -121,5 +121,13 @@
</description> </description>
<arg name="title" type="string" summary="title of the focused view"/> <arg name="title" type="string" summary="title of the focused view"/>
</event> </event>
<event name="mode" since="3">
<description summary="the active mode changed">
Sent once on binding the interface and again whenever a new mode
is entered (e.g. with riverctl enter-mode foobar).
</description>
<arg name="name" type="string" summary="name of the mode"/>
</event>
</interface> </interface>
</protocol> </protocol>

View File

@ -5,7 +5,7 @@
// "width": 1280, // Waybar width // "width": 1280, // Waybar width
"spacing": 4, // Gaps between modules (4px) "spacing": 4, // Gaps between modules (4px)
// Choose the order of the modules // Choose the order of the modules
"modules-left": ["sway/workspaces", "sway/mode", "custom/media"], "modules-left": ["sway/workspaces", "sway/mode", "sway/scratchpad", "custom/media"],
"modules-center": ["sway/window"], "modules-center": ["sway/window"],
"modules-right": ["mpd", "idle_inhibitor", "pulseaudio", "network", "cpu", "memory", "temperature", "backlight", "keyboard-state", "sway/language", "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 // Modules configuration
@ -36,6 +36,13 @@
"sway/mode": { "sway/mode": {
"format": "<span style=\"italic\">{}</span>" "format": "<span style=\"italic\">{}</span>"
}, },
"sway/scratchpad": {
"format": "{icon} {count}",
"show-empty": false,
"format-icons": ["", ""],
"tooltip": true,
"tooltip-format": "{app}: {title}"
},
"mpd": { "mpd": {
"format": "{stateIcon} {consumeIcon}{randomIcon}{repeatIcon}{singleIcon}{artist} - {album} - {title} ({elapsedTime:%M:%S}/{totalTime:%M:%S}) ⸨{songPosition}|{queueLength}⸩ {volume}% ", "format": "{stateIcon} {consumeIcon}{randomIcon}{repeatIcon}{singleIcon}{artist} - {album} - {title} ({elapsedTime:%M:%S}/{totalTime:%M:%S}) ⸨{songPosition}|{queueLength}⸩ {volume}% ",
"format-disconnected": "Disconnected ", "format-disconnected": "Disconnected ",
@ -96,7 +103,7 @@
"backlight": { "backlight": {
// "device": "acpi_video1", // "device": "acpi_video1",
"format": "{percent}% {icon}", "format": "{percent}% {icon}",
"format-icons": ["", ""] "format-icons": ["", "", "", "", "", "", "", "", ""]
}, },
"battery": { "battery": {
"states": { "states": {

View File

@ -34,21 +34,28 @@ window#waybar.chromium {
border: none; border: none;
} }
#workspaces button { button {
padding: 0 5px;
background-color: transparent;
color: #ffffff;
/* Use box-shadow instead of border so the text isn't offset */ /* Use box-shadow instead of border so the text isn't offset */
box-shadow: inset 0 -3px transparent; box-shadow: inset 0 -3px transparent;
/* Avoid rounded borders under each workspace name */ /* Avoid rounded borders under each button name */
border: none; border: none;
border-radius: 0; border-radius: 0;
} }
/* https://github.com/Alexays/Waybar/wiki/FAQ#the-workspace-buttons-have-a-strange-hover-effect */ /* https://github.com/Alexays/Waybar/wiki/FAQ#the-workspace-buttons-have-a-strange-hover-effect */
button:hover {
background: inherit;
box-shadow: inset 0 -3px #ffffff;
}
#workspaces button {
padding: 0 5px;
background-color: transparent;
color: #ffffff;
}
#workspaces button:hover { #workspaces button:hover {
background: rgba(0, 0, 0, 0.2); background: rgba(0, 0, 0, 0.2);
box-shadow: inset 0 -3px #ffffff;
} }
#workspaces button.focused { #workspaces button.focused {
@ -78,6 +85,7 @@ window#waybar.chromium {
#tray, #tray,
#mode, #mode,
#idle_inhibitor, #idle_inhibitor,
#scratchpad,
#mpd { #mpd {
padding: 0 10px; padding: 0 10px;
color: #ffffff; color: #ffffff;
@ -252,3 +260,11 @@ label:focus {
#keyboard-state > label.locked { #keyboard-state > label.locked {
background: rgba(0, 0, 0, 0.2); background: rgba(0, 0, 0, 0.2);
} }
#scratchpad {
background: rgba(0, 0, 0, 0.2);
}
#scratchpad.empty {
background-color: transparent;
}

160
src/AButton.cpp Normal file
View File

@ -0,0 +1,160 @@
#include "AButton.hpp"
#include <fmt/format.h>
#include <util/command.hpp>
namespace waybar {
AButton::AButton(const Json::Value& config, const std::string& name, const std::string& id,
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)
: std::chrono::seconds(
config_["interval"].isUInt() ? config_["interval"].asUInt() : interval)),
default_format_(format_) {
button_.set_name(name);
button_.set_relief(Gtk::RELIEF_NONE);
/* https://github.com/Alexays/Waybar/issues/1731 */
auto css = Gtk::CssProvider::create();
css->load_from_data("button { min-width: 0; }");
button_.get_style_context()->add_provider(css, GTK_STYLE_PROVIDER_PRIORITY_USER);
if (!id.empty()) {
button_.get_style_context()->add_class(id);
}
event_box_.add(button_);
if (config_["max-length"].isUInt()) {
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_["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);
}
}
if (!(config_["on-click"].isString() || config_["on-click-middle"].isString() ||
config_["on-click-backward"].isString() || config_["on-click-forward"].isString() ||
config_["on-click-right"].isString() || config_["format-alt"].isString() || enable_click)) {
button_.set_sensitive(false);
} else {
button_.signal_pressed().connect([this] {
GdkEventButton* e = (GdkEventButton*)gdk_event_new(GDK_BUTTON_PRESS);
e->button = 1;
handleToggle(e);
});
}
}
auto AButton::update() -> void { AModule::update(); }
std::string AButton::getIcon(uint16_t percentage, const std::string& alt, uint16_t max) {
auto format_icons = config_["format-icons"];
if (format_icons.isObject()) {
if (!alt.empty() && (format_icons[alt].isString() || format_icons[alt].isArray())) {
format_icons = format_icons[alt];
} else {
format_icons = format_icons["default"];
}
}
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 "";
}
std::string AButton::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::AButton::handleToggle(GdkEventButton* const& e) {
if (config_["format-alt-click"].isUInt() && e->button == config_["format-alt-click"].asUInt()) {
alt_ = !alt_;
if (alt_ && config_["format-alt"].isString()) {
format_ = config_["format-alt"].asString();
} else {
format_ = default_format_;
}
}
return AModule::handleToggle(e);
}
std::string AButton::getState(uint8_t value, bool lesser) {
if (!config_["states"].isObject()) {
return "";
}
// Get current state
std::vector<std::pair<std::string, uint8_t>> states;
if (config_["states"].isObject()) {
for (auto it = config_["states"].begin(); it != config_["states"].end(); ++it) {
if (it->isUInt() && it.key().isString()) {
states.emplace_back(it.key().asString(), it->asUInt());
}
}
}
// Sort states
std::sort(states.begin(), states.end(), [&lesser](auto& a, auto& b) {
return lesser ? a.second < b.second : a.second > b.second;
});
std::string valid_state;
for (auto const& state : states) {
if ((lesser ? value <= state.second : value >= state.second) && valid_state.empty()) {
button_.get_style_context()->add_class(state.first);
valid_state = state.first;
} else {
button_.get_style_context()->remove_class(state.first);
}
}
return valid_state;
}
} // namespace waybar

View File

@ -1,5 +1,7 @@
#include "ALabel.hpp" #include "ALabel.hpp"
#include <fmt/format.h> #include <fmt/format.h>
#include <util/command.hpp> #include <util/command.hpp>
namespace waybar { namespace waybar {
@ -46,15 +48,10 @@ ALabel::ALabel(const Json::Value& config, const std::string& name, const std::st
} else { } else {
label_.set_xalign(align); label_.set_xalign(align);
} }
}
} }
auto ALabel::update() -> void { AModule::update(); }
}
auto ALabel::update() -> void {
AModule::update();
}
std::string ALabel::getIcon(uint16_t percentage, const std::string& alt, uint16_t max) { std::string ALabel::getIcon(uint16_t percentage, const std::string& alt, uint16_t max) {
auto format_icons = config_["format-icons"]; auto format_icons = config_["format-icons"];
@ -78,7 +75,8 @@ std::string ALabel::getIcon(uint16_t percentage, const std::string& alt, uint16_
return ""; return "";
} }
std::string ALabel::getIcon(uint16_t percentage, const std::vector<std::string>& alts, uint16_t max) { std::string ALabel::getIcon(uint16_t percentage, const std::vector<std::string>& alts,
uint16_t max) {
auto format_icons = config_["format-icons"]; auto format_icons = config_["format-icons"];
if (format_icons.isObject()) { if (format_icons.isObject()) {
std::string _alt = "default"; std::string _alt = "default";

View File

@ -1,20 +1,32 @@
#include "AModule.hpp" #include "AModule.hpp"
#include <fmt/format.h> #include <fmt/format.h>
#include <util/command.hpp> #include <util/command.hpp>
namespace waybar { namespace waybar {
AModule::AModule(const Json::Value& config, const std::string& name, const std::string& id, AModule::AModule(const Json::Value& config, const std::string& name, const std::string& id,
bool enable_click, bool enable_scroll) bool enable_click, bool enable_scroll)
: name_(std::move(name)), config_(std::move(config)) : name_(std::move(name)),
, distance_scrolled_y_(0.0) config_(std::move(config)),
, distance_scrolled_x_(0.0) { distance_scrolled_y_(0.0),
distance_scrolled_x_(0.0) {
// configure events' user commands // configure events' user commands
if (config_["on-click"].isString() || config_["on-click-middle"].isString() || if (enable_click) {
config_["on-click-backward"].isString() || config_["on-click-forward"].isString() ||
config_["on-click-right"].isString() || enable_click) {
event_box_.add_events(Gdk::BUTTON_PRESS_MASK); event_box_.add_events(Gdk::BUTTON_PRESS_MASK);
event_box_.signal_button_press_event().connect(sigc::mem_fun(*this, &AModule::handleToggle)); event_box_.signal_button_press_event().connect(sigc::mem_fun(*this, &AModule::handleToggle));
} else {
std::map<std::pair<uint, GdkEventType>, std::string>::const_iterator it{eventMap_.cbegin()};
while (it != eventMap_.cend()) {
if (config_[it->second].isString()) {
event_box_.add_events(Gdk::BUTTON_PRESS_MASK);
event_box_.signal_button_press_event().connect(
sigc::mem_fun(*this, &AModule::handleToggle));
break;
}
++it;
}
} }
if (config_["on-scroll-up"].isString() || config_["on-scroll-down"].isString() || enable_scroll) { if (config_["on-scroll-up"].isString() || config_["on-scroll-down"].isString() || enable_scroll) {
event_box_.add_events(Gdk::SCROLL_MASK | Gdk::SMOOTH_SCROLL_MASK); event_box_.add_events(Gdk::SCROLL_MASK | Gdk::SMOOTH_SCROLL_MASK);
@ -30,7 +42,6 @@ AModule::~AModule() {
} }
} }
auto AModule::update() -> void { auto AModule::update() -> void {
// Run user-provided update handler if configured // Run user-provided update handler if configured
if (config_["on-update"].isString()) { if (config_["on-update"].isString()) {
@ -39,18 +50,17 @@ auto AModule::update() -> void {
} }
bool AModule::handleToggle(GdkEventButton* const& e) { bool AModule::handleToggle(GdkEventButton* const& e) {
std::string format; const std::map<std::pair<uint, GdkEventType>, std::string>::const_iterator& rec{
if (config_["on-click"].isString() && e->button == 1) { eventMap_.find(std::pair(e->button, e->type))};
format = config_["on-click"].asString(); std::string format{(rec != eventMap_.cend()) ? rec->second : std::string{""}};
} else if (config_["on-click-middle"].isString() && e->button == 2) {
format = config_["on-click-middle"].asString(); if (!format.empty()) {
} else if (config_["on-click-right"].isString() && e->button == 3) { if (config_[format].isString())
format = config_["on-click-right"].asString(); format = config_[format].asString();
} else if (config_["on-click-backward"].isString() && e->button == 8) { else
format = config_["on-click-backward"].asString(); format.clear();
} else if (config_["on-click-forward"].isString() && e->button == 9) {
format = config_["on-click-forward"].asString();
} }
if (!format.empty()) { if (!format.empty()) {
pid_.push_back(util::command::forkExec(format)); pid_.push_back(util::command::forkExec(format));
} }
@ -60,10 +70,14 @@ bool AModule::handleToggle(GdkEventButton* const& e) {
AModule::SCROLL_DIR AModule::getScrollDir(GdkEventScroll* e) { AModule::SCROLL_DIR AModule::getScrollDir(GdkEventScroll* e) {
switch (e->direction) { switch (e->direction) {
case GDK_SCROLL_UP: return SCROLL_DIR::UP; case GDK_SCROLL_UP:
case GDK_SCROLL_DOWN: return SCROLL_DIR::DOWN; return SCROLL_DIR::UP;
case GDK_SCROLL_LEFT: return SCROLL_DIR::LEFT; case GDK_SCROLL_DOWN:
case GDK_SCROLL_RIGHT: return SCROLL_DIR::RIGHT; return SCROLL_DIR::DOWN;
case GDK_SCROLL_LEFT:
return SCROLL_DIR::LEFT;
case GDK_SCROLL_RIGHT:
return SCROLL_DIR::RIGHT;
case GDK_SCROLL_SMOOTH: { case GDK_SCROLL_SMOOTH: {
SCROLL_DIR dir{SCROLL_DIR::NONE}; SCROLL_DIR dir{SCROLL_DIR::NONE};
@ -101,7 +115,8 @@ AModule::SCROLL_DIR AModule::getScrollDir(GdkEventScroll* e) {
return dir; return dir;
} }
// Silence -Wreturn-type: // Silence -Wreturn-type:
default: return SCROLL_DIR::NONE; default:
return SCROLL_DIR::NONE;
} }
} }

View File

@ -170,12 +170,21 @@ struct GLSSurfaceImpl : public BarSurface, public sigc::trackable {
vertical_ = true; vertical_ = true;
unanchored = GTK_LAYER_SHELL_EDGE_LEFT; unanchored = GTK_LAYER_SHELL_EDGE_LEFT;
} }
for (auto edge : {GTK_LAYER_SHELL_EDGE_LEFT, for (auto edge : {GTK_LAYER_SHELL_EDGE_LEFT, GTK_LAYER_SHELL_EDGE_RIGHT,
GTK_LAYER_SHELL_EDGE_RIGHT, GTK_LAYER_SHELL_EDGE_TOP, GTK_LAYER_SHELL_EDGE_BOTTOM}) {
GTK_LAYER_SHELL_EDGE_TOP,
GTK_LAYER_SHELL_EDGE_BOTTOM}) {
gtk_layer_set_anchor(window_.gobj(), edge, unanchored != edge); gtk_layer_set_anchor(window_.gobj(), edge, unanchored != edge);
} }
// Disable anchoring for other edges too if the width
// or the height has been set to a value other than 'auto'
// otherwise the bar will use all space
if (vertical_ && height_ > 1) {
gtk_layer_set_anchor(window_.gobj(), GTK_LAYER_SHELL_EDGE_BOTTOM, false);
gtk_layer_set_anchor(window_.gobj(), GTK_LAYER_SHELL_EDGE_TOP, false);
} else if (!vertical_ && width_ > 1) {
gtk_layer_set_anchor(window_.gobj(), GTK_LAYER_SHELL_EDGE_LEFT, false);
gtk_layer_set_anchor(window_.gobj(), GTK_LAYER_SHELL_EDGE_RIGHT, false);
}
} }
void setSize(uint32_t width, uint32_t height) override { void setSize(uint32_t width, uint32_t height) override {
@ -276,8 +285,8 @@ struct RawSurfaceImpl : public BarSurface, public sigc::trackable {
margins_ = margins; margins_ = margins;
// updating already mapped window // updating already mapped window
if (layer_surface_) { if (layer_surface_) {
zwlr_layer_surface_v1_set_margin( zwlr_layer_surface_v1_set_margin(layer_surface_.get(), margins_.top, margins_.right,
layer_surface_.get(), margins_.top, margins_.right, margins_.bottom, margins_.left); margins_.bottom, margins_.left);
} }
} }
@ -365,14 +374,14 @@ struct RawSurfaceImpl : public BarSurface, public sigc::trackable {
auto gdk_window = window_.get_window()->gobj(); auto gdk_window = window_.get_window()->gobj();
surface_ = gdk_wayland_window_get_wl_surface(gdk_window); surface_ = gdk_wayland_window_get_wl_surface(gdk_window);
layer_surface_.reset(zwlr_layer_shell_v1_get_layer_surface( layer_surface_.reset(zwlr_layer_shell_v1_get_layer_surface(client->layer_shell, surface_,
client->layer_shell, surface_, output_, layer_, "waybar")); output_, layer_, "waybar"));
zwlr_layer_surface_v1_add_listener(layer_surface_.get(), &layer_surface_listener, this); 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_keyboard_interactivity(layer_surface_.get(), false);
zwlr_layer_surface_v1_set_anchor(layer_surface_.get(), anchor_); zwlr_layer_surface_v1_set_anchor(layer_surface_.get(), anchor_);
zwlr_layer_surface_v1_set_margin( zwlr_layer_surface_v1_set_margin(layer_surface_.get(), margins_.top, margins_.right,
layer_surface_.get(), margins_.top, margins_.right, margins_.bottom, margins_.left); margins_.bottom, margins_.left);
setSurfaceSize(width_, height_); setSurfaceSize(width_, height_);
setExclusiveZone(exclusive_zone_); setExclusiveZone(exclusive_zone_);
@ -453,10 +462,8 @@ struct RawSurfaceImpl : public BarSurface, public sigc::trackable {
o->window_.set_size_request(o->width_, o->height_); o->window_.set_size_request(o->width_, o->height_);
o->window_.resize(o->width_, o->height_); o->window_.resize(o->width_, o->height_);
o->setExclusiveZone(o->exclusive_zone_); o->setExclusiveZone(o->exclusive_zone_);
spdlog::info(BAR_SIZE_MSG, spdlog::info(BAR_SIZE_MSG, o->width_ == 1 ? "auto" : std::to_string(o->width_),
o->width_ == 1 ? "auto" : std::to_string(o->width_), o->height_ == 1 ? "auto" : std::to_string(o->height_), o->output_name_);
o->height_ == 1 ? "auto" : std::to_string(o->height_),
o->output_name_);
o->commit(); o->commit();
} }
zwlr_layer_surface_v1_ack_configure(surface, serial); zwlr_layer_surface_v1_ack_configure(surface, serial);
@ -567,8 +574,10 @@ waybar::Bar::Bar(struct waybar_output* w_output, const Json::Value& w_config)
} }
surface_impl_->setMargins(margins_); surface_impl_->setMargins(margins_);
surface_impl_->setPosition(position);
surface_impl_->setSize(width, height); surface_impl_->setSize(width, height);
// Position needs to be set after calculating the height due to the
// GTK layer shell anchors logic relying on the dimensions of the bar.
surface_impl_->setPosition(position);
/* Read custom modes if available */ /* Read custom modes if available */
if (auto modes = config.get("modes", {}); modes.isObject()) { if (auto modes = config.get("modes", {}); modes.isObject()) {
@ -665,8 +674,12 @@ void waybar::Bar::onMap(GdkEventAny*) {
void waybar::Bar::setVisible(bool value) { void waybar::Bar::setVisible(bool value) {
visible = value; visible = value;
if (auto mode = config.get("mode", {}); mode.isString()) {
setMode(visible ? config["mode"].asString() : MODE_INVISIBLE);
} else {
setMode(visible ? MODE_DEFAULT : MODE_INVISIBLE); setMode(visible ? MODE_DEFAULT : MODE_INVISIBLE);
} }
}
void waybar::Bar::toggle() { setVisible(!visible); } void waybar::Bar::toggle() { setVisible(!visible); }
@ -719,7 +732,8 @@ void waybar::Bar::handleSignal(int signal) {
} }
} }
void waybar::Bar::getModules(const Factory& factory, const std::string& pos, Gtk::Box* group = nullptr) { void waybar::Bar::getModules(const Factory& factory, const std::string& pos,
Gtk::Box* group = nullptr) {
auto module_list = group ? config[pos]["modules"] : config[pos]; auto module_list = group ? config[pos]["modules"] : config[pos];
if (module_list.isArray()) { if (module_list.isArray()) {
for (const auto& name : module_list) { for (const auto& name : module_list) {

View File

@ -1,12 +1,12 @@
#include "client.hpp" #include "client.hpp"
#include <fmt/ostream.h>
#include <spdlog/spdlog.h> #include <spdlog/spdlog.h>
#include <iostream> #include <iostream>
#include "idle-inhibit-unstable-v1-client-protocol.h" #include "idle-inhibit-unstable-v1-client-protocol.h"
#include "util/clara.hpp" #include "util/clara.hpp"
#include "util/format.hpp"
#include "wlr-layer-shell-unstable-v1-client-protocol.h" #include "wlr-layer-shell-unstable-v1-client-protocol.h"
waybar::Client *waybar::Client::inst() { waybar::Client *waybar::Client::inst() {
@ -52,8 +52,8 @@ void waybar::Client::handleOutput(struct waybar_output &output) {
} }
struct waybar::waybar_output &waybar::Client::getOutput(void *addr) { struct waybar::waybar_output &waybar::Client::getOutput(void *addr) {
auto it = std::find_if( auto it = std::find_if(outputs_.begin(), outputs_.end(),
outputs_.begin(), outputs_.end(), [&addr](const auto &output) { return &output == addr; }); [&addr](const auto &output) { return &output == addr; });
if (it == outputs_.end()) { if (it == outputs_.end()) {
throw std::runtime_error("Unable to find valid output"); throw std::runtime_error("Unable to find valid output");
} }
@ -169,8 +169,8 @@ auto waybar::Client::setupCss(const std::string &css_file) -> void {
throw std::runtime_error("Can't open style file"); throw std::runtime_error("Can't open style file");
} }
// there's always only one screen // there's always only one screen
style_context_->add_provider_for_screen( style_context_->add_provider_for_screen(Gdk::Screen::get_default(), css_provider_,
Gdk::Screen::get_default(), css_provider_, GTK_STYLE_PROVIDER_PRIORITY_USER); GTK_STYLE_PROVIDER_PRIORITY_USER);
} }
void waybar::Client::bindInterfaces() { void waybar::Client::bindInterfaces() {
@ -224,8 +224,8 @@ int waybar::Client::main(int argc, char *argv[]) {
if (!log_level.empty()) { if (!log_level.empty()) {
spdlog::set_level(spdlog::level::from_str(log_level)); spdlog::set_level(spdlog::level::from_str(log_level));
} }
gtk_app = Gtk::Application::create( gtk_app = Gtk::Application::create(argc, argv, "fr.arouillard.waybar",
argc, argv, "fr.arouillard.waybar", Gio::APPLICATION_HANDLES_COMMAND_LINE); Gio::APPLICATION_HANDLES_COMMAND_LINE);
gdk_display = Gdk::Display::get_default(); gdk_display = Gdk::Display::get_default();
if (!gdk_display) { if (!gdk_display) {
throw std::runtime_error("Can't find display"); throw std::runtime_error("Can't find display");
@ -244,6 +244,4 @@ int waybar::Client::main(int argc, char *argv[]) {
return 0; return 0;
} }
void waybar::Client::reset() { void waybar::Client::reset() { gtk_app->quit(); }
gtk_app->quit();
}

View File

@ -1,32 +1,43 @@
#include "config.hpp" #include "config.hpp"
#include <fmt/ostream.h>
#include <spdlog/spdlog.h> #include <spdlog/spdlog.h>
#include <unistd.h> #include <unistd.h>
#include <wordexp.h> #include <wordexp.h>
#include <filesystem>
#include <fstream> #include <fstream>
#include <stdexcept> #include <stdexcept>
#include "util/json.hpp" #include "util/json.hpp"
namespace fs = std::filesystem;
namespace waybar { namespace waybar {
const std::vector<std::string> Config::CONFIG_DIRS = { const std::vector<std::string> Config::CONFIG_DIRS = {
"$XDG_CONFIG_HOME/waybar/", "$XDG_CONFIG_HOME/waybar/", "$HOME/.config/waybar/", "$HOME/waybar/",
"$HOME/.config/waybar/", "/etc/xdg/waybar/", SYSCONFDIR "/xdg/waybar/", "./resources/",
"$HOME/waybar/",
"/etc/xdg/waybar/",
SYSCONFDIR "/xdg/waybar/",
"./resources/",
}; };
std::optional<std::string> tryExpandPath(const std::string &path) { const char *Config::CONFIG_PATH_ENV = "WAYBAR_CONFIG_DIR";
std::optional<std::string> tryExpandPath(const std::string base, const std::string filename) {
fs::path path;
if (filename != "") {
path = fs::path(base) / fs::path(filename);
} else {
path = fs::path(base);
}
spdlog::debug("Try expanding: {}", path.string());
wordexp_t p; wordexp_t p;
if (wordexp(path.c_str(), &p, 0) == 0) { if (wordexp(path.c_str(), &p, 0) == 0) {
if (access(*p.we_wordv, F_OK) == 0) { if (access(*p.we_wordv, F_OK) == 0) {
std::string result = *p.we_wordv; std::string result = *p.we_wordv;
wordfree(&p); wordfree(&p);
spdlog::debug("Found config file: {}", path.string());
return result; return result;
} }
wordfree(&p); wordfree(&p);
@ -36,10 +47,17 @@ std::optional<std::string> tryExpandPath(const std::string &path) {
std::optional<std::string> Config::findConfigPath(const std::vector<std::string> &names, std::optional<std::string> Config::findConfigPath(const std::vector<std::string> &names,
const std::vector<std::string> &dirs) { const std::vector<std::string> &dirs) {
std::vector<std::string> paths; if (const char *dir = std::getenv(Config::CONFIG_PATH_ENV)) {
for (const auto &name : names) {
if (auto res = tryExpandPath(dir, name); res) {
return res;
}
}
}
for (const auto &dir : dirs) { for (const auto &dir : dirs) {
for (const auto &name : names) { for (const auto &name : names) {
if (auto res = tryExpandPath(dir + name); res) { if (auto res = tryExpandPath(dir, name); res) {
return res; return res;
} }
} }
@ -73,11 +91,11 @@ void Config::resolveConfigIncludes(Json::Value &config, int depth) {
if (includes.isArray()) { if (includes.isArray()) {
for (const auto &include : includes) { for (const auto &include : includes) {
spdlog::info("Including resource file: {}", include.asString()); spdlog::info("Including resource file: {}", include.asString());
setupConfig(config, tryExpandPath(include.asString()).value_or(""), ++depth); setupConfig(config, tryExpandPath(include.asString(), "").value_or(""), ++depth);
} }
} else if (includes.isString()) { } else if (includes.isString()) {
spdlog::info("Including resource file: {}", includes.asString()); spdlog::info("Including resource file: {}", includes.asString());
setupConfig(config, tryExpandPath(includes.asString()).value_or(""), ++depth); setupConfig(config, tryExpandPath(includes.asString(), "").value_or(""), ++depth);
} }
} }

View File

@ -7,11 +7,21 @@ waybar::AModule* waybar::Factory::makeModule(const std::string& name) const {
auto hash_pos = name.find('#'); auto hash_pos = name.find('#');
auto ref = name.substr(0, hash_pos); auto ref = name.substr(0, hash_pos);
auto id = hash_pos != std::string::npos ? name.substr(hash_pos + 1) : ""; auto id = hash_pos != std::string::npos ? name.substr(hash_pos + 1) : "";
#if defined(__linux__) && !defined(NO_FILESYSTEM) #if defined(__FreeBSD__) || (defined(__linux__) && !defined(NO_FILESYSTEM))
if (ref == "battery") { if (ref == "battery") {
return new waybar::modules::Battery(id, config_[name]); return new waybar::modules::Battery(id, config_[name]);
} }
#endif #endif
#ifdef HAVE_GAMEMODE
if (ref == "gamemode") {
return new waybar::modules::Gamemode(id, config_[name]);
}
#endif
#ifdef HAVE_UPOWER
if (ref == "upower") {
return new waybar::modules::upower::UPower(id, config_[name]);
}
#endif
#ifdef HAVE_SWAY #ifdef HAVE_SWAY
if (ref == "sway/mode") { if (ref == "sway/mode") {
return new waybar::modules::sway::Mode(id, config_[name]); return new waybar::modules::sway::Mode(id, config_[name]);
@ -25,6 +35,9 @@ waybar::AModule* waybar::Factory::makeModule(const std::string& name) const {
if (ref == "sway/language") { if (ref == "sway/language") {
return new waybar::modules::sway::Language(id, config_[name]); return new waybar::modules::sway::Language(id, config_[name]);
} }
if (ref == "sway/scratchpad") {
return new waybar::modules::sway::Scratchpad(id, config_[name]);
}
#endif #endif
#ifdef HAVE_WLR #ifdef HAVE_WLR
if (ref == "wlr/taskbar") { if (ref == "wlr/taskbar") {
@ -37,9 +50,23 @@ waybar::AModule* waybar::Factory::makeModule(const std::string& name) const {
#endif #endif
#endif #endif
#ifdef HAVE_RIVER #ifdef HAVE_RIVER
if (ref == "river/mode") {
return new waybar::modules::river::Mode(id, bar_, config_[name]);
}
if (ref == "river/tags") { if (ref == "river/tags") {
return new waybar::modules::river::Tags(id, bar_, config_[name]); return new waybar::modules::river::Tags(id, bar_, config_[name]);
} }
if (ref == "river/window") {
return new waybar::modules::river::Window(id, bar_, config_[name]);
}
#endif
#ifdef HAVE_HYPRLAND
if (ref == "hyprland/window") {
return new waybar::modules::hyprland::Window(id, bar_, config_[name]);
}
if (ref == "hyprland/language") {
return new waybar::modules::hyprland::Language(id, bar_, config_[name]);
}
#endif #endif
if (ref == "idle_inhibitor") { if (ref == "idle_inhibitor") {
return new waybar::modules::IdleInhibitor(id, bar_, config_[name]); return new waybar::modules::IdleInhibitor(id, bar_, config_[name]);
@ -57,6 +84,9 @@ waybar::AModule* waybar::Factory::makeModule(const std::string& name) const {
if (ref == "clock") { if (ref == "clock") {
return new waybar::modules::Clock(id, config_[name]); return new waybar::modules::Clock(id, config_[name]);
} }
if (ref == "user") {
return new waybar::modules::User(id, config_[name]);
}
if (ref == "disk") { if (ref == "disk") {
return new waybar::modules::Disk(id, config_[name]); return new waybar::modules::Disk(id, config_[name]);
} }
@ -96,20 +126,21 @@ waybar::AModule* waybar::Factory::makeModule(const std::string& name) const {
} }
#endif #endif
#ifdef HAVE_GIO_UNIX #ifdef HAVE_GIO_UNIX
if (ref == "bluetooth") {
return new waybar::modules::Bluetooth(id, config_[name]);
}
if (ref == "inhibitor") { if (ref == "inhibitor") {
return new waybar::modules::Inhibitor(id, bar_, config_[name]); return new waybar::modules::Inhibitor(id, bar_, config_[name]);
} }
#endif
#ifdef HAVE_LIBJACK
if (ref == "jack") {
return new waybar::modules::JACK(id, config_[name]);
}
#endif #endif
if (ref == "temperature") { if (ref == "temperature") {
return new waybar::modules::Temperature(id, config_[name]); 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) { if (ref.compare(0, 7, "custom/") == 0 && ref.size() > 7) {
return new waybar::modules::Custom(ref.substr(7), id, config_[name]); return new waybar::modules::Custom(ref.substr(7), id, config_[name]);
} }

View File

@ -1,14 +1,14 @@
#include "group.hpp" #include "group.hpp"
#include <fmt/format.h> #include <fmt/format.h>
#include <util/command.hpp> #include <util/command.hpp>
namespace waybar { namespace waybar {
Group::Group(const std::string& name, const Bar& bar, const Json::Value& config) Group::Group(const std::string& name, const Bar& bar, const Json::Value& config)
: AModule(config, name, "", false, false), : AModule(config, name, "", false, false),
box{bar.vertical ? Gtk::ORIENTATION_HORIZONTAL : Gtk::ORIENTATION_VERTICAL, 0} box{bar.vertical ? Gtk::ORIENTATION_HORIZONTAL : Gtk::ORIENTATION_VERTICAL, 0} {}
{
}
auto Group::update() -> void { auto Group::update() -> void {
// noop // noop

View File

@ -1,9 +1,11 @@
#include <spdlog/spdlog.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <csignal> #include <csignal>
#include <list> #include <list>
#include <mutex> #include <mutex>
#include <sys/types.h>
#include <sys/wait.h>
#include <spdlog/spdlog.h>
#include "client.hpp" #include "client.hpp"
std::mutex reap_mtx; std::mutex reap_mtx;
@ -38,8 +40,7 @@ void* signalThread(void* args) {
} }
break; break;
default: default:
spdlog::debug("Received signal with number {}, but not handling", spdlog::debug("Received signal with number {}, but not handling", signum);
signum);
break; break;
} }
} }

View File

@ -87,14 +87,14 @@ int waybar::modules::Backlight::BacklightDev::get_max() const { return max_; }
void waybar::modules::Backlight::BacklightDev::set_max(int max) { max_ = max; } void waybar::modules::Backlight::BacklightDev::set_max(int max) { max_ = max; }
waybar::modules::Backlight::Backlight(const std::string &id, const Json::Value &config) waybar::modules::Backlight::Backlight(const std::string &id, const Json::Value &config)
: ALabel(config, "backlight", id, "{percent}%", 2), : AButton(config, "backlight", id, "{percent}%", 2),
preferred_device_(config["device"].isString() ? config["device"].asString() : "") { preferred_device_(config["device"].isString() ? config["device"].asString() : "") {
// Get initial state // Get initial state
{ {
std::unique_ptr<udev, UdevDeleter> udev_check{udev_new()}; std::unique_ptr<udev, UdevDeleter> udev_check{udev_new()};
check_nn(udev_check.get(), "Udev check new failed"); check_nn(udev_check.get(), "Udev check new failed");
enumerate_devices( enumerate_devices(devices_.begin(), devices_.end(), std::back_inserter(devices_),
devices_.begin(), devices_.end(), std::back_inserter(devices_), udev_check.get()); udev_check.get());
if (devices_.empty()) { if (devices_.empty()) {
throw std::runtime_error("No backlight found"); throw std::runtime_error("No backlight found");
} }
@ -108,8 +108,7 @@ waybar::modules::Backlight::Backlight(const std::string &id, const Json::Value &
std::unique_ptr<udev_monitor, UdevMonitorDeleter> mon{ std::unique_ptr<udev_monitor, UdevMonitorDeleter> mon{
udev_monitor_new_from_netlink(udev.get(), "udev")}; udev_monitor_new_from_netlink(udev.get(), "udev")};
check_nn(mon.get(), "udev monitor new failed"); check_nn(mon.get(), "udev monitor new failed");
check_gte(udev_monitor_filter_add_match_subsystem_devtype(mon.get(), "backlight", nullptr), check_gte(udev_monitor_filter_add_match_subsystem_devtype(mon.get(), "backlight", nullptr), 0,
0,
"udev failed to add monitor filter: "); "udev failed to add monitor filter: ");
udev_monitor_enable_receiving(mon.get()); udev_monitor_enable_receiving(mon.get());
@ -126,8 +125,8 @@ waybar::modules::Backlight::Backlight(const std::string &id, const Json::Value &
epoll_event events[EPOLL_MAX_EVENTS]; epoll_event events[EPOLL_MAX_EVENTS];
while (udev_thread_.isRunning()) { while (udev_thread_.isRunning()) {
const int event_count = epoll_wait( const int event_count = epoll_wait(epoll_fd.get(), events, EPOLL_MAX_EVENTS,
epoll_fd.get(), events, EPOLL_MAX_EVENTS, std::chrono::milliseconds{interval_}.count()); std::chrono::milliseconds{interval_}.count());
if (!udev_thread_.isRunning()) { if (!udev_thread_.isRunning()) {
break; break;
} }
@ -173,20 +172,21 @@ auto waybar::modules::Backlight::update() -> void {
return; return;
} }
const uint8_t percent = best->get_max() == 0 ? 100 : round(best->get_actual() * 100.0f / best->get_max()); const uint8_t percent =
label_.set_markup(fmt::format( best->get_max() == 0 ? 100 : round(best->get_actual() * 100.0f / best->get_max());
format_, fmt::arg("percent", std::to_string(percent)), fmt::arg("icon", getIcon(percent)))); label_->set_markup(fmt::format(format_, fmt::arg("percent", std::to_string(percent)),
fmt::arg("icon", getIcon(percent))));
getState(percent); getState(percent);
} else { } else {
if (!previous_best_.has_value()) { if (!previous_best_.has_value()) {
return; return;
} }
label_.set_markup(""); label_->set_markup("");
} }
previous_best_ = best == nullptr ? std::nullopt : std::optional{*best}; previous_best_ = best == nullptr ? std::nullopt : std::optional{*best};
previous_format_ = format_; previous_format_ = format_;
// Call parent update // Call parent update
ALabel::update(); AButton::update();
} }
template <class ForwardIt> template <class ForwardIt>
@ -214,19 +214,20 @@ void waybar::modules::Backlight::upsert_device(ForwardIt first, ForwardIt last,
strncmp(name, "amdgpu_bl", 9) == 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); const char *actual = udev_device_get_sysattr_value(dev, actual_brightness_attr);
check_nn(actual);
const int actual_int = std::stoi(actual);
const char *max = udev_device_get_sysattr_value(dev, "max_brightness"); const char *max = udev_device_get_sysattr_value(dev, "max_brightness");
check_nn(max);
const int max_int = std::stoi(max);
auto found = auto found =
std::find_if(first, last, [name](const auto &device) { return device.name() == name; }); std::find_if(first, last, [name](const auto &device) { return device.name() == name; });
if (found != last) { if (found != last) {
found->set_actual(actual_int); if (actual != nullptr) {
found->set_max(max_int); found->set_actual(std::stoi(actual));
}
if (max != nullptr) {
found->set_max(std::stoi(max));
}
} else { } else {
const int actual_int = actual == nullptr ? 0 : std::stoi(actual);
const int max_int = max == nullptr ? 0 : std::stoi(max);
*inserter = BacklightDev{name, actual_int, max_int}; *inserter = BacklightDev{name, actual_int, max_int};
++inserter; ++inserter;
} }

View File

@ -1,9 +1,13 @@
#include "modules/battery.hpp" #include "modules/battery.hpp"
#if defined(__FreeBSD__)
#include <sys/sysctl.h>
#endif
#include <spdlog/spdlog.h> #include <spdlog/spdlog.h>
#include <iostream>
waybar::modules::Battery::Battery(const std::string& id, const Json::Value& config) waybar::modules::Battery::Battery(const std::string& id, const Json::Value& config)
: ALabel(config, "battery", id, "{capacity}%", 60) { : AButton(config, "battery", id, "{capacity}%", 60) {
#if defined(__linux__)
battery_watch_fd_ = inotify_init1(IN_CLOEXEC); battery_watch_fd_ = inotify_init1(IN_CLOEXEC);
if (battery_watch_fd_ == -1) { if (battery_watch_fd_ == -1) {
throw std::runtime_error("Unable to listen batteries."); throw std::runtime_error("Unable to listen batteries.");
@ -19,12 +23,12 @@ waybar::modules::Battery::Battery(const std::string& id, const Json::Value& conf
if (global_watch < 0) { if (global_watch < 0) {
throw std::runtime_error("Could not watch for battery plug/unplug"); throw std::runtime_error("Could not watch for battery plug/unplug");
} }
#endif
refreshBatteries();
worker(); worker();
} }
waybar::modules::Battery::~Battery() { waybar::modules::Battery::~Battery() {
#if defined(__linux__)
std::lock_guard<std::mutex> guard(battery_list_mutex_); std::lock_guard<std::mutex> guard(battery_list_mutex_);
if (global_watch >= 0) { if (global_watch >= 0) {
@ -40,9 +44,16 @@ waybar::modules::Battery::~Battery() {
batteries_.erase(it); batteries_.erase(it);
} }
close(battery_watch_fd_); close(battery_watch_fd_);
#endif
} }
void waybar::modules::Battery::worker() { void waybar::modules::Battery::worker() {
#if defined(__FreeBSD__)
thread_timer_ = [this] {
dp.emit();
thread_timer_.sleep_for(interval_);
};
#else
thread_timer_ = [this] { thread_timer_ = [this] {
// Make sure we eventually update the list of batteries even if we miss an // Make sure we eventually update the list of batteries even if we miss an
// inotify event for some reason // inotify event for some reason
@ -69,11 +80,12 @@ void waybar::modules::Battery::worker() {
refreshBatteries(); refreshBatteries();
dp.emit(); dp.emit();
}; };
#endif
} }
void waybar::modules::Battery::refreshBatteries() { void waybar::modules::Battery::refreshBatteries() {
#if defined(__linux__)
std::lock_guard<std::mutex> guard(battery_list_mutex_); std::lock_guard<std::mutex> guard(battery_list_mutex_);
// Mark existing list of batteries as not necessarily found // Mark existing list of batteries as not necessarily found
std::map<fs::path, bool> check_map; std::map<fs::path, bool> check_map;
for (auto const& bat : batteries_) { for (auto const& bat : batteries_) {
@ -88,8 +100,9 @@ void waybar::modules::Battery::refreshBatteries() {
auto dir_name = node.path().filename(); auto dir_name = node.path().filename();
auto bat_defined = config_["bat"].isString(); auto bat_defined = config_["bat"].isString();
if (((bat_defined && dir_name == config_["bat"].asString()) || !bat_defined) && if (((bat_defined && dir_name == config_["bat"].asString()) || !bat_defined) &&
fs::exists(node.path() / "capacity") && fs::exists(node.path() / "uevent") && (fs::exists(node.path() / "capacity") || fs::exists(node.path() / "charge_now")) &&
fs::exists(node.path() / "status") && fs::exists(node.path() / "type")) { fs::exists(node.path() / "uevent") && fs::exists(node.path() / "status") &&
fs::exists(node.path() / "type")) {
std::string type; std::string type;
std::ifstream(node.path() / "type") >> type; std::ifstream(node.path() / "type") >> type;
@ -109,18 +122,21 @@ void waybar::modules::Battery::refreshBatteries() {
} }
auto adap_defined = config_["adapter"].isString(); auto adap_defined = config_["adapter"].isString();
if (((adap_defined && dir_name == config_["adapter"].asString()) || !adap_defined) && if (((adap_defined && dir_name == config_["adapter"].asString()) || !adap_defined) &&
fs::exists(node.path() / "online")) { (fs::exists(node.path() / "online") || fs::exists(node.path() / "status"))) {
adapter_ = node.path(); adapter_ = node.path();
} }
} }
} catch (fs::filesystem_error& e) { } catch (fs::filesystem_error& e) {
throw std::runtime_error(e.what()); throw std::runtime_error(e.what());
} }
if (batteries_.empty()) { if (warnFirstTime_ && batteries_.empty()) {
if (config_["bat"].isString()) { if (config_["bat"].isString()) {
throw std::runtime_error("No battery named " + config_["bat"].asString()); spdlog::warn("No battery named {0}", config_["bat"].asString());
} else {
spdlog::warn("No batteries.");
} }
throw std::runtime_error("No batteries.");
warnFirstTime_ = false;
} }
// Remove any batteries that are no longer present and unwatch them // Remove any batteries that are no longer present and unwatch them
@ -133,15 +149,21 @@ void waybar::modules::Battery::refreshBatteries() {
batteries_.erase(check.first); batteries_.erase(check.first);
} }
} }
#endif
} }
// Unknown > Full > Not charging > Discharging > Charging // Unknown > Full > Not charging > Discharging > Charging
static bool status_gt(const std::string& a, const std::string& b) { static bool status_gt(const std::string& a, const std::string& b) {
if (a == b) return false; if (a == b)
else if (a == "Unknown") return true; return false;
else if (a == "Full" && b != "Unknown") return true; else if (a == "Unknown")
else if (a == "Not charging" && b != "Unknown" && b != "Full") return true; return true;
else if (a == "Discharging" && b != "Unknown" && b != "Full" && b != "Not charging") 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; return false;
} }
@ -149,83 +171,35 @@ const std::tuple<uint8_t, float, std::string, float> waybar::modules::Battery::g
std::lock_guard<std::mutex> guard(battery_list_mutex_); std::lock_guard<std::mutex> guard(battery_list_mutex_);
try { try {
uint32_t total_power = 0; // μW #if defined(__FreeBSD__)
uint32_t total_energy = 0; // μWh /* Allocate state of battery units reported via ACPI. */
uint32_t total_energy_full = 0; int battery_units = 0;
uint32_t total_energy_full_design = 0; size_t battery_units_size = sizeof battery_units;
std::string status = "Unknown"; if (sysctlbyname("hw.acpi.battery.units", &battery_units, &battery_units_size, NULL, 0) != 0) {
for (auto const& item : batteries_) { throw std::runtime_error("sysctl hw.acpi.battery.units failed");
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::getline(std::ifstream(bat / "status"), _status);
// 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 (battery_units < 0) {
if (status_gt(status, _status)) { throw std::runtime_error("No battery units");
status = _status;
} }
total_power += power_now;
total_energy += energy_now; int capacity;
total_energy_full += energy_full; size_t size_capacity = sizeof capacity;
total_energy_full_design += energy_full_design; if (sysctlbyname("hw.acpi.battery.life", &capacity, &size_capacity, NULL, 0) != 0) {
throw std::runtime_error("sysctl hw.acpi.battery.life failed");
} }
if (!adapter_.empty() && status == "Discharging") { int time;
bool online; size_t size_time = sizeof time;
std::ifstream(adapter_ / "online") >> online; if (sysctlbyname("hw.acpi.battery.time", &time, &size_time, NULL, 0) != 0) {
if (online) { throw std::runtime_error("sysctl hw.acpi.battery.time failed");
status = "Plugged";
} }
int rate;
size_t size_rate = sizeof rate;
if (sysctlbyname("hw.acpi.battery.rate", &rate, &size_rate, NULL, 0) != 0) {
throw std::runtime_error("sysctl hw.acpi.battery.rate failed");
} }
float time_remaining = 0;
if (status == "Discharging" && total_power != 0) { auto status = getAdapterStatus(capacity);
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;
}
}
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 // Handle full-at
if (config_["full-at"].isUInt()) { if (config_["full-at"].isUInt()) {
auto full_at = config_["full-at"].asUInt(); auto full_at = config_["full-at"].asUInt();
@ -239,13 +213,317 @@ const std::tuple<uint8_t, float, std::string, float> waybar::modules::Battery::g
capacity = 100.f; capacity = 100.f;
} }
uint8_t cap = round(capacity); uint8_t cap = round(capacity);
if (cap == 100 && status == "Charging") { if (cap == 100 && status == "Plugged") {
// If we've reached 100% just mark as full as some batteries can stay // If we've reached 100% just mark as full as some batteries can stay
// stuck reporting they're still charging but not yet done // stuck reporting they're still charging but not yet done
status = "Full"; status = "Full";
} }
// spdlog::info("{} {} {} {}", capacity,time,status,rate);
return {capacity, time / 60.0, status, rate};
#elif defined(__linux__)
uint32_t total_power = 0; // μW
bool total_power_exists = false;
uint32_t total_energy = 0; // μWh
bool total_energy_exists = false;
uint32_t total_energy_full = 0;
bool total_energy_full_exists = false;
uint32_t total_energy_full_design = 0;
bool total_energy_full_design_exists = false;
uint32_t total_capacity = 0;
bool total_capacity_exists = false;
std::string status = "Unknown";
for (auto const& item : batteries_) {
auto bat = item.first;
std::string _status;
std::getline(std::ifstream(bat / "status"), _status);
// Some battery will report current and charge in μA/μAh.
// Scale these by the voltage to get μW/μWh.
uint32_t capacity = 0;
bool capacity_exists = false;
if (fs::exists(bat / "capacity")) {
capacity_exists = true;
std::ifstream(bat / "capacity") >> capacity;
}
uint32_t current_now = 0;
bool current_now_exists = false;
if (fs::exists(bat / "current_now")) {
current_now_exists = true;
std::ifstream(bat / "current_now") >> current_now;
} else if (fs::exists(bat / "current_avg")) {
current_now_exists = true;
std::ifstream(bat / "current_avg") >> current_now;
}
uint32_t voltage_now = 0;
bool voltage_now_exists = false;
if (fs::exists(bat / "voltage_now")) {
voltage_now_exists = true;
std::ifstream(bat / "voltage_now") >> voltage_now;
} else if (fs::exists(bat / "voltage_avg")) {
voltage_now_exists = true;
std::ifstream(bat / "voltage_avg") >> voltage_now;
}
uint32_t charge_full = 0;
bool charge_full_exists = false;
if (fs::exists(bat / "charge_full")) {
charge_full_exists = true;
std::ifstream(bat / "charge_full") >> charge_full;
}
uint32_t charge_full_design = 0;
bool charge_full_design_exists = false;
if (fs::exists(bat / "charge_full_design")) {
charge_full_design_exists = true;
std::ifstream(bat / "charge_full_design") >> charge_full_design;
}
uint32_t charge_now = 0;
bool charge_now_exists = false;
if (fs::exists(bat / "charge_now")) {
charge_now_exists = true;
std::ifstream(bat / "charge_now") >> charge_now;
}
uint32_t power_now = 0;
bool power_now_exists = false;
if (fs::exists(bat / "power_now")) {
power_now_exists = true;
std::ifstream(bat / "power_now") >> power_now;
}
uint32_t energy_now = 0;
bool energy_now_exists = false;
if (fs::exists(bat / "energy_now")) {
energy_now_exists = true;
std::ifstream(bat / "energy_now") >> energy_now;
}
uint32_t energy_full = 0;
bool energy_full_exists = false;
if (fs::exists(bat / "energy_full")) {
energy_full_exists = true;
std::ifstream(bat / "energy_full") >> energy_full;
}
uint32_t energy_full_design = 0;
bool energy_full_design_exists = false;
if (fs::exists(bat / "energy_full_design")) {
energy_full_design_exists = true;
std::ifstream(bat / "energy_full_design") >> energy_full_design;
}
if (!voltage_now_exists) {
if (power_now_exists && current_now_exists && current_now != 0) {
voltage_now_exists = true;
voltage_now = 1000000 * (uint64_t)power_now / (uint64_t)current_now;
} else if (energy_full_design_exists && charge_full_design_exists &&
charge_full_design != 0) {
voltage_now_exists = true;
voltage_now = 1000000 * (uint64_t)energy_full_design / (uint64_t)charge_full_design;
} else if (energy_now_exists) {
if (charge_now_exists && charge_now != 0) {
voltage_now_exists = true;
voltage_now = 1000000 * (uint64_t)energy_now / (uint64_t)charge_now;
} else if (capacity_exists && charge_full_exists) {
charge_now_exists = true;
charge_now = (uint64_t)charge_full * (uint64_t)capacity / 100;
if (charge_full != 0 && capacity != 0) {
voltage_now_exists = true;
voltage_now =
1000000 * (uint64_t)energy_now * 100 / (uint64_t)charge_full / (uint64_t)capacity;
}
}
} else if (energy_full_exists) {
if (charge_full_exists && charge_full != 0) {
voltage_now_exists = true;
voltage_now = 1000000 * (uint64_t)energy_full / (uint64_t)charge_full;
} else if (charge_now_exists && capacity_exists) {
if (capacity != 0) {
charge_full_exists = true;
charge_full = 100 * (uint64_t)charge_now / (uint64_t)capacity;
}
if (charge_now != 0) {
voltage_now_exists = true;
voltage_now =
10000 * (uint64_t)energy_full * (uint64_t)capacity / (uint64_t)charge_now;
}
}
}
}
if (!capacity_exists) {
if (charge_now_exists && charge_full_exists && charge_full != 0) {
capacity_exists = true;
capacity = 100 * (uint64_t)charge_now / (uint64_t)charge_full;
} else if (energy_now_exists && energy_full_exists && energy_full != 0) {
capacity_exists = true;
capacity = 100 * (uint64_t)energy_now / (uint64_t)energy_full;
} else if (charge_now_exists && energy_full_exists && voltage_now_exists) {
if (!charge_full_exists && voltage_now != 0) {
charge_full_exists = true;
charge_full = 1000000 * (uint64_t)energy_full / (uint64_t)voltage_now;
}
if (energy_full != 0) {
capacity_exists = true;
capacity = (uint64_t)charge_now * (uint64_t)voltage_now / 10000 / (uint64_t)energy_full;
}
} else if (charge_full_exists && energy_now_exists && voltage_now_exists) {
if (!charge_now_exists && voltage_now != 0) {
charge_now_exists = true;
charge_now = 1000000 * (uint64_t)energy_now / (uint64_t)voltage_now;
}
if (voltage_now != 0 && charge_full != 0) {
capacity_exists = true;
capacity = 100 * 1000000 * (uint64_t)energy_now / (uint64_t)voltage_now /
(uint64_t)charge_full;
}
}
}
if (!energy_now_exists && voltage_now_exists) {
if (charge_now_exists) {
energy_now_exists = true;
energy_now = (uint64_t)charge_now * (uint64_t)voltage_now / 1000000;
} else if (capacity_exists && charge_full_exists) {
charge_now_exists = true;
charge_now = (uint64_t)capacity * (uint64_t)charge_full / 100;
energy_now_exists = true;
energy_now =
(uint64_t)voltage_now * (uint64_t)capacity * (uint64_t)charge_full / 1000000 / 100;
} else if (capacity_exists && energy_full) {
if (voltage_now != 0) {
charge_full_exists = true;
charge_full = 1000000 * (uint64_t)energy_full / (uint64_t)voltage_now;
charge_now_exists = true;
charge_now = (uint64_t)capacity * 10000 * (uint64_t)energy_full / (uint64_t)voltage_now;
}
energy_now_exists = true;
energy_now = (uint64_t)capacity * (uint64_t)energy_full / 100;
}
}
if (!energy_full_exists && voltage_now_exists) {
if (charge_full_exists) {
energy_full_exists = true;
energy_full = (uint64_t)charge_full * (uint64_t)voltage_now / 1000000;
} else if (charge_now_exists && capacity_exists && capacity != 0) {
charge_full_exists = true;
charge_full = 100 * (uint64_t)charge_now / (uint64_t)capacity;
energy_full_exists = true;
energy_full = (uint64_t)charge_now * (uint64_t)voltage_now / (uint64_t)capacity / 10000;
} else if (capacity_exists && energy_now) {
if (voltage_now != 0) {
charge_now_exists = true;
charge_now = 1000000 * (uint64_t)energy_now / (uint64_t)voltage_now;
}
if (capacity != 0) {
energy_full_exists = true;
energy_full = 100 * (uint64_t)energy_now / (uint64_t)capacity;
if (voltage_now != 0) {
charge_full_exists = true;
charge_full =
100 * 1000000 * (uint64_t)energy_now / (uint64_t)voltage_now / (uint64_t)capacity;
}
}
}
}
if (!power_now_exists && voltage_now_exists && current_now_exists) {
power_now_exists = true;
power_now = (uint64_t)voltage_now * (uint64_t)current_now / 1000000;
}
if (!energy_full_design_exists && voltage_now_exists && charge_full_design_exists) {
energy_full_design_exists = true;
energy_full_design = (uint64_t)voltage_now * (uint64_t)charge_full_design / 1000000;
}
// Show the "smallest" status among all batteries
if (status_gt(status, _status)) status = _status;
if (power_now_exists) {
total_power_exists = true;
total_power += power_now;
}
if (energy_now_exists) {
total_energy_exists = true;
total_energy += energy_now;
}
if (energy_full_exists) {
total_energy_full_exists = true;
total_energy_full += energy_full;
}
if (energy_full_design_exists) {
total_energy_full_design_exists = true;
total_energy_full_design += energy_full_design;
}
if (capacity_exists) {
total_capacity_exists = true;
total_capacity += capacity;
}
}
if (!adapter_.empty() && status == "Discharging") {
bool online;
std::string current_status;
std::ifstream(adapter_ / "online") >> online;
std::getline(std::ifstream(adapter_ / "status"), current_status);
if (online && current_status != "Discharging") status = "Plugged";
}
float time_remaining{0.0f};
if (status == "Discharging" && total_power_exists && total_energy_exists) {
if (total_power != 0) time_remaining = (float)total_energy / total_power;
} else if (status == "Charging" && total_energy_exists && total_energy_full_exists &&
total_power_exists) {
if (total_power != 0)
time_remaining = -(float)(total_energy_full - total_energy) / total_power;
// If we've turned positive it means the battery is past 100% and so just report that as no
// time remaining
if (time_remaining > 0.0f) time_remaining = 0.0f;
}
float calculated_capacity{0.0f};
if (total_capacity_exists) {
if (total_capacity > 0.0f)
calculated_capacity = (float)total_capacity;
else if (total_energy_full_exists && total_energy_exists) {
if (total_energy_full > 0.0f)
calculated_capacity = ((float)total_energy * 100.0f / (float)total_energy_full);
}
}
// Handle design-capacity
if ((config_["design-capacity"].isBool() ? config_["design-capacity"].asBool() : false) &&
total_energy_exists && total_energy_full_design_exists) {
if (total_energy_full_design > 0.0f)
calculated_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) calculated_capacity = 100.f * calculated_capacity / full_at;
}
// Handle it gracefully by clamping at 100%
// This can happen when the battery is calibrating and goes above 100%
if (calculated_capacity > 100.f) calculated_capacity = 100.f;
uint8_t cap = round(calculated_capacity);
// If we've reached 100% just mark as full as some batteries can stay stuck reporting they're
// still charging but not yet done
if (cap == 100 && status == "Charging") status = "Full";
return {cap, time_remaining, status, total_power / 1e6}; return {cap, time_remaining, status, total_power / 1e6};
#endif
} catch (const std::exception& e) { } catch (const std::exception& e) {
spdlog::error("Battery: {}", e.what()); spdlog::error("Battery: {}", e.what());
return {0, 0, "Unknown", 0}; return {0, 0, "Unknown", 0};
@ -253,13 +531,26 @@ const std::tuple<uint8_t, float, std::string, float> waybar::modules::Battery::g
} }
const std::string waybar::modules::Battery::getAdapterStatus(uint8_t capacity) const { const std::string waybar::modules::Battery::getAdapterStatus(uint8_t capacity) const {
#if defined(__FreeBSD__)
int state;
size_t size_state = sizeof state;
if (sysctlbyname("hw.acpi.battery.state", &state, &size_state, NULL, 0) != 0) {
throw std::runtime_error("sysctl hw.acpi.battery.state failed");
}
bool online = state == 2;
std::string status{"Unknown"}; // TODO: add status in FreeBSD
{
#else
if (!adapter_.empty()) { if (!adapter_.empty()) {
bool online; bool online;
std::string status;
std::ifstream(adapter_ / "online") >> online; std::ifstream(adapter_ / "online") >> online;
std::getline(std::ifstream(adapter_ / "status"), status);
#endif
if (capacity == 100) { if (capacity == 100) {
return "Full"; return "Full";
} }
if (online) { if (online && status != "Discharging") {
return "Plugged"; return "Plugged";
} }
return "Discharging"; return "Discharging";
@ -279,19 +570,26 @@ const std::string waybar::modules::Battery::formatTimeRemaining(float hoursRemai
if (config_["format-time"].isString()) { if (config_["format-time"].isString()) {
format = config_["format-time"].asString(); format = config_["format-time"].asString();
} }
return fmt::format(format, fmt::arg("H", full_hours), fmt::arg("M", minutes)); std::string zero_pad_minutes = fmt::format("{:02d}", minutes);
return fmt::format(format, fmt::arg("H", full_hours), fmt::arg("M", minutes),
fmt::arg("m", zero_pad_minutes));
} }
auto waybar::modules::Battery::update() -> void { auto waybar::modules::Battery::update() -> void {
#if defined(__linux__)
if (batteries_.empty()) {
event_box_.hide();
return;
}
#endif
auto [capacity, time_remaining, status, power] = getInfos(); auto [capacity, time_remaining, status, power] = getInfos();
if (status == "Unknown") { if (status == "Unknown") {
status = getAdapterStatus(capacity); status = getAdapterStatus(capacity);
} }
auto status_pretty = status; auto status_pretty = status;
// Transform to lowercase and replace space with dash // Transform to lowercase and replace space with dash
std::transform(status.begin(), status.end(), status.begin(), [](char ch) { std::transform(status.begin(), status.end(), status.begin(),
return ch == ' ' ? '-' : std::tolower(ch); [](char ch) { return ch == ' ' ? '-' : std::tolower(ch); });
});
auto format = format_; auto format = format_;
auto state = getState(capacity, true); auto state = getState(capacity, true);
auto time_remaining_formatted = formatTimeRemaining(time_remaining); auto time_remaining_formatted = formatTimeRemaining(time_remaining);
@ -313,15 +611,14 @@ auto waybar::modules::Battery::update() -> void {
} else if (config_["tooltip-format"].isString()) { } else if (config_["tooltip-format"].isString()) {
tooltip_format = config_["tooltip-format"].asString(); tooltip_format = config_["tooltip-format"].asString();
} }
label_.set_tooltip_text(fmt::format(tooltip_format, button_.set_tooltip_text(fmt::format(tooltip_format, fmt::arg("timeTo", tooltip_text_default),
fmt::arg("timeTo", tooltip_text_default), fmt::arg("power", power), fmt::arg("capacity", capacity),
fmt::arg("capacity", capacity),
fmt::arg("time", time_remaining_formatted))); fmt::arg("time", time_remaining_formatted)));
} }
if (!old_status_.empty()) { if (!old_status_.empty()) {
label_.get_style_context()->remove_class(old_status_); button_.get_style_context()->remove_class(old_status_);
} }
label_.get_style_context()->add_class(status); button_.get_style_context()->add_class(status);
old_status_ = status; old_status_ = status;
if (!state.empty() && config_["format-" + status + "-" + state].isString()) { if (!state.empty() && config_["format-" + status + "-" + state].isString()) {
format = config_["format-" + status + "-" + state].asString(); format = config_["format-" + status + "-" + state].asString();
@ -335,12 +632,10 @@ auto waybar::modules::Battery::update() -> void {
} else { } else {
event_box_.show(); event_box_.show();
auto icons = std::vector<std::string>{status + "-" + state, status, state}; auto icons = std::vector<std::string>{status + "-" + state, status, state};
label_.set_markup(fmt::format(format, label_->set_markup(fmt::format(format, fmt::arg("capacity", capacity), fmt::arg("power", power),
fmt::arg("capacity", capacity),
fmt::arg("power", power),
fmt::arg("icon", getIcon(capacity, icons)), fmt::arg("icon", getIcon(capacity, icons)),
fmt::arg("time", time_remaining_formatted))); fmt::arg("time", time_remaining_formatted)));
} }
// Call parent update // Call parent update
ALabel::update(); AButton::update();
} }

View File

@ -1,25 +1,411 @@
#include "modules/bluetooth.hpp" #include "modules/bluetooth.hpp"
#include <fmt/format.h> #include <fmt/format.h>
#include <spdlog/spdlog.h>
#include <algorithm>
#include <sstream>
namespace {
using GDBusManager = std::unique_ptr<GDBusObjectManager, void (*)(GDBusObjectManager*)>;
auto generateManager() -> GDBusManager {
GError* error = nullptr;
GDBusObjectManager* manager = g_dbus_object_manager_client_new_for_bus_sync(
G_BUS_TYPE_SYSTEM,
GDBusObjectManagerClientFlags::G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_DO_NOT_AUTO_START,
"org.bluez", "/", NULL, NULL, NULL, NULL, &error);
if (error) {
spdlog::error("g_dbus_object_manager_client_new_for_bus_sync() failed: {}", error->message);
g_error_free(error);
}
auto destructor = [](GDBusObjectManager* manager) {
if (manager) {
g_object_unref(manager);
}
};
return GDBusManager{manager, destructor};
}
auto getBoolProperty(GDBusProxy* proxy, const char* property_name) -> bool {
auto gvar = g_dbus_proxy_get_cached_property(proxy, property_name);
if (gvar) {
bool property_value = g_variant_get_boolean(gvar);
g_variant_unref(gvar);
return property_value;
}
spdlog::error("getBoolProperty() failed: doesn't have property {}", property_name);
return false;
}
auto getOptionalStringProperty(GDBusProxy* proxy, const char* property_name)
-> std::optional<std::string> {
auto gvar = g_dbus_proxy_get_cached_property(proxy, property_name);
if (gvar) {
std::string property_value = g_variant_get_string(gvar, NULL);
g_variant_unref(gvar);
return property_value;
}
return std::nullopt;
}
auto getStringProperty(GDBusProxy* proxy, const char* property_name) -> std::string {
auto property_value = getOptionalStringProperty(proxy, property_name);
if (!property_value.has_value()) {
spdlog::error("getStringProperty() failed: doesn't have property {}", property_name);
}
return property_value.value_or("");
}
auto getUcharProperty(GDBusProxy* proxy, const char* property_name) -> unsigned char {
auto gvar = g_dbus_proxy_get_cached_property(proxy, property_name);
if (gvar) {
unsigned char property_value;
g_variant_get(gvar, "y", &property_value);
g_variant_unref(gvar);
return property_value;
}
spdlog::error("getUcharProperty() failed: doesn't have property {}", property_name);
return 0;
}
} // namespace
waybar::modules::Bluetooth::Bluetooth(const std::string& id, const Json::Value& config) waybar::modules::Bluetooth::Bluetooth(const std::string& id, const Json::Value& config)
: ALabel(config, "bluetooth", id, "{icon}", 10), rfkill_{RFKILL_TYPE_BLUETOOTH} { : AButton(config, "bluetooth", id, " {status}", 10),
#ifdef WANT_RFKILL
rfkill_{RFKILL_TYPE_BLUETOOTH},
#endif
manager_(generateManager()) {
if (config_["format-device-preference"].isArray()) {
std::transform(config_["format-device-preference"].begin(),
config_["format-device-preference"].end(),
std::back_inserter(device_preference_), [](auto x) { return x.asString(); });
}
// NOTE: assumption made that the controller that is selcected stays unchanged
// for duration of the module
if (!findCurController(cur_controller_)) {
if (config_["controller-alias"].isString()) {
spdlog::error("findCurController() failed: no bluetooth controller found with alias '{}'",
config_["controller-alias"].asString());
} else {
spdlog::error("findCurController() failed: no bluetooth controller found");
}
event_box_.hide();
return;
}
findConnectedDevices(cur_controller_.path, connected_devices_);
g_signal_connect(manager_.get(), "interface-proxy-properties-changed",
G_CALLBACK(onInterfaceProxyPropertiesChanged), this);
g_signal_connect(manager_.get(), "interface-added", G_CALLBACK(onInterfaceAddedOrRemoved), this);
g_signal_connect(manager_.get(), "interface-removed", G_CALLBACK(onInterfaceAddedOrRemoved),
this);
#ifdef WANT_RFKILL
rfkill_.on_update.connect(sigc::hide(sigc::mem_fun(*this, &Bluetooth::update))); rfkill_.on_update.connect(sigc::hide(sigc::mem_fun(*this, &Bluetooth::update)));
#endif
dp.emit();
} }
auto waybar::modules::Bluetooth::update() -> void { auto waybar::modules::Bluetooth::update() -> void {
std::string status = rfkill_.getState() ? "disabled" : "enabled"; // focussed device is either:
// - the first device in the device_preference_ list that is connected to the
// current controller (if none fallback to last connected device)
// - it is the last device that connected to the current controller
if (!connected_devices_.empty()) {
bool preferred_device_connected = false;
if (!device_preference_.empty()) {
for (const std::string& device_alias : device_preference_) {
auto it =
std::find_if(connected_devices_.begin(), connected_devices_.end(),
[device_alias](auto device) { return device_alias == device.alias; });
if (it != connected_devices_.end()) {
preferred_device_connected = true;
cur_focussed_device_ = *it;
break;
}
}
}
if (!preferred_device_connected) {
cur_focussed_device_ = connected_devices_.back();
}
}
label_.set_markup( std::string state;
fmt::format(format_, fmt::arg("status", status), fmt::arg("icon", getIcon(0, status)))); std::string tooltip_format;
if (!cur_controller_.powered)
state = "off";
else if (!connected_devices_.empty())
state = "connected";
else
state = "on";
#ifdef WANT_RFKILL
if (rfkill_.getState()) state = "disabled";
#endif
bool battery_available =
state == "connected" && cur_focussed_device_.battery_percentage.has_value();
#ifdef WANT_RFKILL
// also adds enabled icon if icon for state is not defined
std::vector<std::string> states = {state, rfkill_.getState() ? "disabled" : "enabled"};
std::string icon = getIcon(0, states);
#else
std::string icon = getIcon(0, state);
#endif
std::string icon_label = icon;
std::string icon_tooltip = icon;
if (!alt_) {
if (battery_available && config_["format-connected-battery"].isString()) {
format_ = config_["format-connected-battery"].asString();
icon_label = getIcon(cur_focussed_device_.battery_percentage.value_or(0));
} else if (config_["format-" + state].isString()) {
format_ = config_["format-" + state].asString();
} else if (config_["format"].isString()) {
format_ = config_["format"].asString();
} else {
format_ = default_format_;
}
}
if (battery_available && config_["tooltip-format-connected-battery"].isString()) {
tooltip_format = config_["tooltip-format-connected-battery"].asString();
icon_tooltip = getIcon(cur_focussed_device_.battery_percentage.value_or(0));
} else if (config_["tooltip-format-" + state].isString()) {
tooltip_format = config_["tooltip-format-" + state].asString();
} else if (config_["tooltip-format"].isString()) {
tooltip_format = config_["tooltip-format"].asString();
}
format_.empty() ? event_box_.hide() : event_box_.show();
auto update_style_context = [this](const std::string& style_class, bool in_next_state) {
if (in_next_state && !button_.get_style_context()->has_class(style_class)) {
button_.get_style_context()->add_class(style_class);
} else if (!in_next_state && button_.get_style_context()->has_class(style_class)) {
button_.get_style_context()->remove_class(style_class);
}
};
update_style_context("discoverable", cur_controller_.discoverable);
update_style_context("discovering", cur_controller_.discovering);
update_style_context("pairable", cur_controller_.pairable);
if (!state_.empty()) {
update_style_context(state_, false);
}
update_style_context(state, true);
state_ = state;
label_->set_markup(fmt::format(
format_, fmt::arg("status", state_), fmt::arg("num_connections", connected_devices_.size()),
fmt::arg("controller_address", cur_controller_.address),
fmt::arg("controller_address_type", cur_controller_.address_type),
fmt::arg("controller_alias", cur_controller_.alias),
fmt::arg("device_address", cur_focussed_device_.address),
fmt::arg("device_address_type", cur_focussed_device_.address_type),
fmt::arg("device_alias", cur_focussed_device_.alias), fmt::arg("icon", icon_label),
fmt::arg("device_battery_percentage", cur_focussed_device_.battery_percentage.value_or(0))));
if (tooltipEnabled()) { if (tooltipEnabled()) {
if (config_["tooltip-format"].isString()) { bool tooltip_enumerate_connections_ = config_["tooltip-format-enumerate-connected"].isString();
auto tooltip_format = config_["tooltip-format"].asString(); bool tooltip_enumerate_connections_battery_ =
auto tooltip_text = fmt::format(tooltip_format, status, fmt::arg("status", status)); config_["tooltip-format-enumerate-connected-battery"].isString();
label_.set_tooltip_text(tooltip_text); if (tooltip_enumerate_connections_ || tooltip_enumerate_connections_battery_) {
std::stringstream ss;
for (DeviceInfo dev : connected_devices_) {
if ((tooltip_enumerate_connections_battery_ && dev.battery_percentage.has_value()) ||
tooltip_enumerate_connections_) {
ss << "\n";
std::string enumerate_format;
std::string enumerate_icon;
if (tooltip_enumerate_connections_battery_ && dev.battery_percentage.has_value()) {
enumerate_format = config_["tooltip-format-enumerate-connected-battery"].asString();
enumerate_icon = getIcon(dev.battery_percentage.value_or(0));
} else { } else {
label_.set_tooltip_text(status); enumerate_format = config_["tooltip-format-enumerate-connected"].asString();
}
ss << fmt::format(
enumerate_format, fmt::arg("device_address", dev.address),
fmt::arg("device_address_type", dev.address_type),
fmt::arg("device_alias", dev.alias), fmt::arg("icon", enumerate_icon),
fmt::arg("device_battery_percentage", dev.battery_percentage.value_or(0)));
}
}
device_enumerate_ = ss.str();
// don't start the connected devices text with a new line
if (!device_enumerate_.empty()) {
device_enumerate_.erase(0, 1);
}
}
button_.set_tooltip_text(fmt::format(
tooltip_format, fmt::arg("status", state_),
fmt::arg("num_connections", connected_devices_.size()),
fmt::arg("controller_address", cur_controller_.address),
fmt::arg("controller_address_type", cur_controller_.address_type),
fmt::arg("controller_alias", cur_controller_.alias),
fmt::arg("device_address", cur_focussed_device_.address),
fmt::arg("device_address_type", cur_focussed_device_.address_type),
fmt::arg("device_alias", cur_focussed_device_.alias), fmt::arg("icon", icon_tooltip),
fmt::arg("device_battery_percentage", cur_focussed_device_.battery_percentage.value_or(0)),
fmt::arg("device_enumerate", device_enumerate_)));
}
// Call parent update
AButton::update();
}
// NOTE: only for when the org.bluez.Battery1 interface is added/removed after/before a device is
// connected/disconnected
auto waybar::modules::Bluetooth::onInterfaceAddedOrRemoved(GDBusObjectManager* manager,
GDBusObject* object,
GDBusInterface* interface,
gpointer user_data) -> void {
std::string interface_name = g_dbus_proxy_get_interface_name(G_DBUS_PROXY(interface));
std::string object_path = g_dbus_proxy_get_object_path(G_DBUS_PROXY(interface));
if (interface_name == "org.bluez.Battery1") {
Bluetooth* bt = static_cast<Bluetooth*>(user_data);
auto device = std::find_if(bt->connected_devices_.begin(), bt->connected_devices_.end(),
[object_path](auto d) { return d.path == object_path; });
if (device != bt->connected_devices_.end()) {
device->battery_percentage = bt->getDeviceBatteryPercentage(object);
bt->dp.emit();
} }
} }
} }
auto waybar::modules::Bluetooth::onInterfaceProxyPropertiesChanged(
GDBusObjectManagerClient* manager, GDBusObjectProxy* object_proxy, GDBusProxy* interface_proxy,
GVariant* changed_properties, const gchar* const* invalidated_properties, gpointer user_data)
-> void {
std::string interface_name = g_dbus_proxy_get_interface_name(interface_proxy);
std::string object_path = g_dbus_object_get_object_path(G_DBUS_OBJECT(object_proxy));
Bluetooth* bt = static_cast<Bluetooth*>(user_data);
if (interface_name == "org.bluez.Adapter1") {
if (object_path == bt->cur_controller_.path) {
bt->getControllerProperties(G_DBUS_OBJECT(object_proxy), bt->cur_controller_);
bt->dp.emit();
}
} else if (interface_name == "org.bluez.Device1" || interface_name == "org.bluez.Battery1") {
DeviceInfo device;
bt->getDeviceProperties(G_DBUS_OBJECT(object_proxy), device);
auto cur_device = std::find_if(bt->connected_devices_.begin(), bt->connected_devices_.end(),
[device](auto d) { return d.path == device.path; });
if (cur_device == bt->connected_devices_.end()) {
if (device.connected) {
bt->connected_devices_.push_back(device);
bt->dp.emit();
}
} else {
if (!device.connected) {
bt->connected_devices_.erase(cur_device);
} else {
*cur_device = device;
}
bt->dp.emit();
}
}
}
auto waybar::modules::Bluetooth::getDeviceBatteryPercentage(GDBusObject* object)
-> std::optional<unsigned char> {
GDBusProxy* proxy_device_bat =
G_DBUS_PROXY(g_dbus_object_get_interface(object, "org.bluez.Battery1"));
if (proxy_device_bat != NULL) {
unsigned char battery_percentage = getUcharProperty(proxy_device_bat, "Percentage");
g_object_unref(proxy_device_bat);
return battery_percentage;
}
return std::nullopt;
}
auto waybar::modules::Bluetooth::getDeviceProperties(GDBusObject* object, DeviceInfo& device_info)
-> bool {
GDBusProxy* proxy_device = G_DBUS_PROXY(g_dbus_object_get_interface(object, "org.bluez.Device1"));
if (proxy_device != NULL) {
device_info.path = g_dbus_object_get_object_path(object);
device_info.paired_controller = getStringProperty(proxy_device, "Adapter");
device_info.address = getStringProperty(proxy_device, "Address");
device_info.address_type = getStringProperty(proxy_device, "AddressType");
device_info.alias = getStringProperty(proxy_device, "Alias");
device_info.icon = getOptionalStringProperty(proxy_device, "Icon");
device_info.paired = getBoolProperty(proxy_device, "Paired");
device_info.trusted = getBoolProperty(proxy_device, "Trusted");
device_info.blocked = getBoolProperty(proxy_device, "Blocked");
device_info.connected = getBoolProperty(proxy_device, "Connected");
device_info.services_resolved = getBoolProperty(proxy_device, "ServicesResolved");
g_object_unref(proxy_device);
device_info.battery_percentage = getDeviceBatteryPercentage(object);
return true;
}
return false;
}
auto waybar::modules::Bluetooth::getControllerProperties(GDBusObject* object,
ControllerInfo& controller_info) -> bool {
GDBusProxy* proxy_controller =
G_DBUS_PROXY(g_dbus_object_get_interface(object, "org.bluez.Adapter1"));
if (proxy_controller != NULL) {
controller_info.path = g_dbus_object_get_object_path(object);
controller_info.address = getStringProperty(proxy_controller, "Address");
controller_info.address_type = getStringProperty(proxy_controller, "AddressType");
controller_info.alias = getStringProperty(proxy_controller, "Alias");
controller_info.powered = getBoolProperty(proxy_controller, "Powered");
controller_info.discoverable = getBoolProperty(proxy_controller, "Discoverable");
controller_info.pairable = getBoolProperty(proxy_controller, "Pairable");
controller_info.discovering = getBoolProperty(proxy_controller, "Discovering");
g_object_unref(proxy_controller);
return true;
}
return false;
}
auto waybar::modules::Bluetooth::findCurController(ControllerInfo& controller_info) -> bool {
bool found_controller = false;
GList* objects = g_dbus_object_manager_get_objects(manager_.get());
for (GList* l = objects; l != NULL; l = l->next) {
GDBusObject* object = G_DBUS_OBJECT(l->data);
if (getControllerProperties(object, controller_info) &&
(!config_["controller-alias"].isString() ||
config_["controller-alias"].asString() == controller_info.alias)) {
found_controller = true;
break;
}
}
g_list_free_full(objects, g_object_unref);
return found_controller;
}
auto waybar::modules::Bluetooth::findConnectedDevices(const std::string& cur_controller_path,
std::vector<DeviceInfo>& connected_devices)
-> void {
GList* objects = g_dbus_object_manager_get_objects(manager_.get());
for (GList* l = objects; l != NULL; l = l->next) {
GDBusObject* object = G_DBUS_OBJECT(l->data);
DeviceInfo device;
if (getDeviceProperties(object, device) && device.connected &&
device.paired_controller == cur_controller_.path) {
connected_devices.push_back(device);
}
}
g_list_free_full(objects, g_object_unref);
}

View File

@ -1,13 +1,10 @@
#include "modules/clock.hpp" #include "modules/clock.hpp"
#include <spdlog/spdlog.h>
#if FMT_VERSION < 60000
#include <fmt/time.h>
#else
#include <fmt/chrono.h> #include <fmt/chrono.h>
#endif #include <spdlog/spdlog.h>
#include <ctime> #include <ctime>
#include <iomanip>
#include <sstream> #include <sstream>
#include <type_traits> #include <type_traits>
@ -21,45 +18,39 @@
using waybar::waybar_time; using waybar::waybar_time;
waybar::modules::Clock::Clock(const std::string& id, const Json::Value& config) waybar::modules::Clock::Clock(const std::string& id, const Json::Value& config)
: ALabel(config, "clock", id, "{:%H:%M}", 60, false, false, true), : AButton(config, "clock", id, "{:%H:%M}", 60, false, false, true),
current_time_zone_idx_(0), current_time_zone_idx_(0),
is_calendar_in_tooltip_(false), is_calendar_in_tooltip_(false),
is_timezoned_list_in_tooltip_(false) is_timezoned_list_in_tooltip_(false) {
{
if (config_["timezones"].isArray() && !config_["timezones"].empty()) { if (config_["timezones"].isArray() && !config_["timezones"].empty()) {
for (const auto& zone_name : config_["timezones"]) { for (const auto& zone_name : config_["timezones"]) {
if (!zone_name.isString() || zone_name.asString().empty()) { if (!zone_name.isString() || zone_name.asString().empty()) {
time_zones_.push_back(nullptr); time_zones_.push_back(nullptr);
continue; continue;
} }
time_zones_.push_back( time_zones_.push_back(date::locate_zone(zone_name.asString()));
date::locate_zone(
zone_name.asString()
)
);
} }
} else if (config_["timezone"].isString() && !config_["timezone"].asString().empty()) { } else if (config_["timezone"].isString() && !config_["timezone"].asString().empty()) {
time_zones_.push_back( time_zones_.push_back(date::locate_zone(config_["timezone"].asString()));
date::locate_zone(
config_["timezone"].asString()
)
);
} }
// If all timezones are parsed and no one is good, add nullptr to the timezones vector, to mark that local time should be shown. // If all timezones are parsed and no one is good, add nullptr to the timezones vector, to mark
// that local time should be shown.
if (!time_zones_.size()) { if (!time_zones_.size()) {
time_zones_.push_back(nullptr); time_zones_.push_back(nullptr);
} }
if (!is_timezone_fixed()) { if (!is_timezone_fixed()) {
spdlog::warn("As using a timezone, some format args may be missing as the date library haven't got a release since 2018."); spdlog::warn(
"As using a timezone, some format args may be missing as the date library haven't got a "
"release since 2018.");
} }
// Check if a particular placeholder is present in the tooltip format, to know what to calculate on update. // Check if a particular placeholder is present in the tooltip format, to know what to calculate
// on update.
if (config_["tooltip-format"].isString()) { if (config_["tooltip-format"].isString()) {
std::string trimmed_format = config_["tooltip-format"].asString(); std::string trimmed_format = config_["tooltip-format"].asString();
trimmed_format.erase(std::remove_if(trimmed_format.begin(), trimmed_format.erase(std::remove_if(trimmed_format.begin(), trimmed_format.end(),
trimmed_format.end(),
[](unsigned char x) { return std::isspace(x); }), [](unsigned char x) { return std::isspace(x); }),
trimmed_format.end()); trimmed_format.end());
if (trimmed_format.find("{" + kCalendarPlaceholder + "}") != std::string::npos) { if (trimmed_format.find("{" + kCalendarPlaceholder + "}") != std::string::npos) {
@ -70,6 +61,13 @@ waybar::modules::Clock::Clock(const std::string& id, const Json::Value& config)
} }
} }
if (is_calendar_in_tooltip_) {
if (config_["on-scroll"][kCalendarPlaceholder].isInt()) {
calendar_shift_init_ =
date::months{config_["on-scroll"].get(kCalendarPlaceholder, 0).asInt()};
}
}
if (config_["locale"].isString()) { if (config_["locale"].isString()) {
locale_ = std::locale(config_["locale"].asString()); locale_ = std::locale(config_["locale"].asString());
} else { } else {
@ -79,14 +77,16 @@ waybar::modules::Clock::Clock(const std::string& id, const Json::Value& config)
thread_ = [this] { thread_ = [this] {
dp.emit(); dp.emit();
auto now = std::chrono::system_clock::now(); auto now = std::chrono::system_clock::now();
auto timeout = std::chrono::floor<std::chrono::seconds>(now + interval_); /* difference with projected wakeup time */
auto diff = std::chrono::seconds(timeout.time_since_epoch().count() % interval_.count()); auto diff = now.time_since_epoch() % interval_;
thread_.sleep_until(timeout - diff); /* sleep until the next projected time */
thread_.sleep_for(interval_ - diff);
}; };
} }
const date::time_zone* waybar::modules::Clock::current_timezone() { const date::time_zone* waybar::modules::Clock::current_timezone() {
return time_zones_[current_time_zone_idx_] ? time_zones_[current_time_zone_idx_] : date::current_zone(); return time_zones_[current_time_zone_idx_] ? time_zones_[current_time_zone_idx_]
: date::current_zone();
} }
bool waybar::modules::Clock::is_timezone_fixed() { bool waybar::modules::Clock::is_timezone_fixed() {
@ -96,8 +96,8 @@ bool waybar::modules::Clock::is_timezone_fixed() {
auto waybar::modules::Clock::update() -> void { auto waybar::modules::Clock::update() -> void {
auto time_zone = current_timezone(); auto time_zone = current_timezone();
auto now = std::chrono::system_clock::now(); auto now = std::chrono::system_clock::now();
waybar_time wtime = {locale_, waybar_time wtime = {locale_, date::make_zoned(time_zone, date::floor<std::chrono::seconds>(now) +
date::make_zoned(time_zone, date::floor<std::chrono::seconds>(now))}; calendar_shift_)};
std::string text = ""; std::string text = "";
if (!is_timezone_fixed()) { if (!is_timezone_fixed()) {
// As date dep is not fully compatible, prefer fmt // As date dep is not fully compatible, prefer fmt
@ -107,26 +107,24 @@ auto waybar::modules::Clock::update() -> void {
} else { } else {
text = fmt::format(format_, wtime); text = fmt::format(format_, wtime);
} }
label_.set_markup(text); label_->set_markup(text);
if (tooltipEnabled()) { if (tooltipEnabled()) {
if (config_["tooltip-format"].isString()) { if (config_["tooltip-format"].isString()) {
std::string calendar_lines = ""; std::string calendar_lines{""};
std::string timezoned_time_lines = ""; std::string timezoned_time_lines{""};
if (is_calendar_in_tooltip_) { if (is_calendar_in_tooltip_) calendar_lines = calendar_text(wtime);
calendar_lines = calendar_text(wtime); if (is_timezoned_list_in_tooltip_) timezoned_time_lines = timezones_text(&now);
}
if (is_timezoned_list_in_tooltip_) {
timezoned_time_lines = timezones_text(&now);
}
auto tooltip_format = config_["tooltip-format"].asString(); auto tooltip_format = config_["tooltip-format"].asString();
text = fmt::format(tooltip_format, wtime, fmt::arg(kCalendarPlaceholder.c_str(), calendar_lines), fmt::arg(KTimezonedTimeListPlaceholder.c_str(), timezoned_time_lines)); text =
label_.set_tooltip_markup(text); fmt::format(tooltip_format, wtime, fmt::arg(kCalendarPlaceholder.c_str(), calendar_lines),
fmt::arg(KTimezonedTimeListPlaceholder.c_str(), timezoned_time_lines));
button_.set_tooltip_markup(text);
} }
} }
// Call parent update // Call parent update
ALabel::update(); AButton::update();
} }
bool waybar::modules::Clock::handleScroll(GdkEventScroll* e) { bool waybar::modules::Clock::handleScroll(GdkEventScroll* e) {
@ -136,6 +134,15 @@ bool waybar::modules::Clock::handleScroll(GdkEventScroll *e) {
} }
auto dir = AModule::getScrollDir(e); auto dir = AModule::getScrollDir(e);
// Shift calendar date
if (calendar_shift_init_.count() > 0) {
if (dir == SCROLL_DIR::UP)
calendar_shift_ += calendar_shift_init_;
else
calendar_shift_ -= calendar_shift_init_;
} else {
// Change time zone
if (dir != SCROLL_DIR::UP && dir != SCROLL_DIR::DOWN) { if (dir != SCROLL_DIR::UP && dir != SCROLL_DIR::DOWN) {
return true; return true;
} }
@ -148,7 +155,9 @@ bool waybar::modules::Clock::handleScroll(GdkEventScroll *e) {
size_t new_idx = current_time_zone_idx_ + 1; size_t new_idx = current_time_zone_idx_ + 1;
current_time_zone_idx_ = new_idx == nr_zones ? 0 : new_idx; current_time_zone_idx_ = new_idx == nr_zones ? 0 : new_idx;
} else { } else {
current_time_zone_idx_ = current_time_zone_idx_ == 0 ? nr_zones - 1 : current_time_zone_idx_ - 1; current_time_zone_idx_ =
current_time_zone_idx_ == 0 ? nr_zones - 1 : current_time_zone_idx_ - 1;
}
} }
update(); update();
@ -157,21 +166,53 @@ bool waybar::modules::Clock::handleScroll(GdkEventScroll *e) {
auto waybar::modules::Clock::calendar_text(const waybar_time& wtime) -> std::string { 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 daypoint = date::floor<date::days>(wtime.ztime.get_local_time());
const auto ymd = date::year_month_day(daypoint); 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()); if (calendar_cached_ymd_ == ymd) return calendar_cached_text_;
const auto curr_day = ymd.day();
const auto curr_day{(calendar_shift_init_.count() > 0 && calendar_shift_.count() != 0)
? date::day{0}
: ymd.day()};
const date::year_month ym{ymd.year(), ymd.month()};
const auto week_format{config_["format-calendar-weekdays"].isString()
? config_["format-calendar-weekdays"].asString()
: ""};
const auto wn_format{config_["format-calendar-weeks"].isString()
? config_["format-calendar-weeks"].asString()
: ""};
std::stringstream os; std::stringstream os;
const auto first_dow = first_day_of_week(); const auto first_dow = first_day_of_week();
int ws{0}; // weeks-pos: side(1 - left, 2 - right)
if (config_["calendar-weeks-pos"].isString()) {
if (config_["calendar-weeks-pos"].asString() == "left") {
ws = 1;
// Add paddings before the header
os << std::string(4, ' ');
} else if (config_["calendar-weeks-pos"].asString() == "right") {
ws = 2;
}
}
weekdays_header(first_dow, os); weekdays_header(first_dow, os);
// First week prefixed with spaces if needed. // First week prefixed with spaces if needed.
auto wd = date::weekday(ym / 1); auto wd = date::weekday(ym / 1);
auto empty_days = (wd - first_dow).count(); auto empty_days = (wd - first_dow).count();
date::sys_days lwd{static_cast<date::sys_days>(ym / 1) + date::days{7 - empty_days}};
if (first_dow == date::Monday) {
lwd -= date::days{1};
}
/* Print weeknumber on the left for the first row*/
if (ws == 1) {
os << fmt::format(wn_format, lwd);
os << ' ';
lwd += date::weeks{1};
}
if (empty_days > 0) { if (empty_days > 0) {
os << std::string(empty_days * 3 - 1, ' '); os << std::string(empty_days * 3 - 1, ' ');
} }
@ -180,7 +221,19 @@ auto waybar::modules::Clock::calendar_text(const waybar_time& wtime) -> std::str
if (wd != first_dow) { if (wd != first_dow) {
os << ' '; os << ' ';
} else if (unsigned(d) != 1) { } else if (unsigned(d) != 1) {
if (ws == 2) {
os << ' ';
os << fmt::format(wn_format, lwd);
lwd += date::weeks{1};
}
os << '\n'; os << '\n';
if (ws == 1) {
os << fmt::format(wn_format, lwd);
os << ' ';
lwd += date::weeks{1};
}
} }
if (d == curr_day) { if (d == curr_day) {
if (config_["today-format"].isString()) { if (config_["today-format"].isString()) {
@ -189,22 +242,32 @@ auto waybar::modules::Clock::calendar_text(const waybar_time& wtime) -> std::str
} else { } else {
os << "<b><u>" << date::format("%e", d) << "</u></b>"; os << "<b><u>" << date::format("%e", d) << "</u></b>";
} }
} else { } else if (config_["format-calendar"].isString()) {
os << fmt::format(config_["format-calendar"].asString(), date::format("%e", d));
} else
os << date::format("%e", d); os << date::format("%e", d);
/*Print weeks on the right when the endings with spaces*/
if (ws == 2 && d == last_day) {
empty_days = 6 - (wd.c_encoding() - first_dow.c_encoding());
if (empty_days > 0) {
os << std::string(empty_days * 3 + 1, ' ');
os << fmt::format(wn_format, lwd);
}
} }
} }
auto result = os.str(); auto result = os.str();
cached_calendar_ymd_ = ymd; calendar_cached_ymd_ = ymd;
cached_calendar_text_ = result; calendar_cached_text_ = result;
return result; return result;
} }
auto waybar::modules::Clock::weekdays_header(const date::weekday& first_dow, std::ostream& os) auto waybar::modules::Clock::weekdays_header(const date::weekday& first_dow, std::ostream& os)
-> void { -> void {
std::stringstream res;
auto wd = first_dow; auto wd = first_dow;
do { do {
if (wd != first_dow) os << ' '; if (wd != first_dow) res << ' ';
Glib::ustring wd_ustring(date::format(locale_, "%a", wd)); Glib::ustring wd_ustring(date::format(locale_, "%a", wd));
auto clen = ustring_clen(wd_ustring); auto clen = ustring_clen(wd_ustring);
auto wd_len = wd_ustring.length(); auto wd_len = wd_ustring.length();
@ -214,12 +277,18 @@ auto waybar::modules::Clock::weekdays_header(const date::weekday& first_dow, std
clen = ustring_clen(wd_ustring); clen = ustring_clen(wd_ustring);
} }
const std::string pad(2 - clen, ' '); const std::string pad(2 - clen, ' ');
os << pad << wd_ustring; res << pad << wd_ustring;
} while (++wd != first_dow); } while (++wd != first_dow);
os << "\n"; res << "\n";
if (config_["format-calendar-weekdays"].isString()) {
os << fmt::format(config_["format-calendar-weekdays"].asString(), res.str());
} else
os << res.str();
} }
auto waybar::modules::Clock::timezones_text(std::chrono::_V2::system_clock::time_point *now) -> std::string { auto waybar::modules::Clock::timezones_text(std::chrono::system_clock::time_point* now)
-> std::string {
if (time_zones_.size() == 1) { if (time_zones_.size() == 1) {
return ""; return "";
} }

View File

@ -1,11 +1,14 @@
#include "modules/cpu.hpp" #include <spdlog/spdlog.h>
// clang-format off
#include <sys/types.h> #include <sys/types.h>
#include <sys/sysctl.h> #include <sys/sysctl.h>
#include <spdlog/spdlog.h> // clang-format on
#include <cstdlib> // malloc
#include <unistd.h> // sysconf #include <unistd.h> // sysconf
#include <cmath> // NAN #include <cmath> // NAN
#include <cstdlib> // malloc
#include "modules/cpu.hpp"
#if defined(__NetBSD__) || defined(__OpenBSD__) #if defined(__NetBSD__) || defined(__OpenBSD__)
#include <sys/sched.h> #include <sys/sched.h>
@ -101,7 +104,8 @@ std::vector<std::tuple<size_t, size_t>> waybar::modules::Cpu::parseCpuinfo() {
std::vector<float> waybar::modules::Cpu::parseCpuFrequencies() { std::vector<float> waybar::modules::Cpu::parseCpuFrequencies() {
static std::vector<float> frequencies; static std::vector<float> frequencies;
if (frequencies.empty()) { if (frequencies.empty()) {
spdlog::warn("cpu/bsd: parseCpuFrequencies is not implemented, expect garbage in {*_frequency}"); spdlog::warn(
"cpu/bsd: parseCpuFrequencies is not implemented, expect garbage in {*_frequency}");
frequencies.push_back(NAN); frequencies.push_back(NAN);
} }
return frequencies; return frequencies;

View File

@ -10,7 +10,7 @@
#endif #endif
waybar::modules::Cpu::Cpu(const std::string& id, const Json::Value& config) waybar::modules::Cpu::Cpu(const std::string& id, const Json::Value& config)
: ALabel(config, "cpu", id, "{usage}%", 10) { : AButton(config, "cpu", id, "{usage}%", 10) {
thread_ = [this] { thread_ = [this] {
dp.emit(); dp.emit();
thread_.sleep_for(interval_); thread_.sleep_for(interval_);
@ -23,7 +23,7 @@ auto waybar::modules::Cpu::update() -> void {
auto [cpu_usage, tooltip] = getCpuUsage(); auto [cpu_usage, tooltip] = getCpuUsage();
auto [max_frequency, min_frequency, avg_frequency] = getCpuFrequency(); auto [max_frequency, min_frequency, avg_frequency] = getCpuFrequency();
if (tooltipEnabled()) { if (tooltipEnabled()) {
label_.set_tooltip_text(tooltip); button_.set_tooltip_text(tooltip);
} }
auto format = format_; auto format = format_;
auto total_usage = cpu_usage.empty() ? 0 : cpu_usage[0]; auto total_usage = cpu_usage.empty() ? 0 : cpu_usage[0];
@ -52,11 +52,11 @@ auto waybar::modules::Cpu::update() -> void {
auto icon_format = fmt::format("icon{}", core_i); auto icon_format = fmt::format("icon{}", core_i);
store.push_back(fmt::arg(icon_format.c_str(), getIcon(cpu_usage[i], icons))); store.push_back(fmt::arg(icon_format.c_str(), getIcon(cpu_usage[i], icons)));
} }
label_.set_markup(fmt::vformat(format, store)); label_->set_markup(fmt::vformat(format, store));
} }
// Call parent update // Call parent update
ALabel::update(); AButton::update();
} }
double waybar::modules::Cpu::getCpuLoad() { double waybar::modules::Cpu::getCpuLoad() {
@ -94,8 +94,12 @@ std::tuple<std::vector<uint16_t>, std::string> waybar::modules::Cpu::getCpuUsage
std::tuple<float, float, float> waybar::modules::Cpu::getCpuFrequency() { std::tuple<float, float, float> waybar::modules::Cpu::getCpuFrequency() {
std::vector<float> frequencies = parseCpuFrequencies(); std::vector<float> frequencies = parseCpuFrequencies();
if (frequencies.empty()) {
return {0.f, 0.f, 0.f};
}
auto [min, max] = std::minmax_element(std::begin(frequencies), std::end(frequencies)); 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(); float avg_frequency =
std::accumulate(std::begin(frequencies), std::end(frequencies), 0.0) / frequencies.size();
// Round frequencies with double decimal precision to get GHz // Round frequencies with double decimal precision to get GHz
float max_frequency = std::ceil(*max / 10.0) / 100.0; float max_frequency = std::ceil(*max / 10.0) / 100.0;

View File

@ -1,4 +1,5 @@
#include <filesystem> #include <filesystem>
#include "modules/cpu.hpp" #include "modules/cpu.hpp"
std::vector<std::tuple<size_t, size_t>> waybar::modules::Cpu::parseCpuinfo() { std::vector<std::tuple<size_t, size_t>> waybar::modules::Cpu::parseCpuinfo() {
@ -51,10 +52,7 @@ std::vector<float> waybar::modules::Cpu::parseCpuFrequencies() {
if (frequencies.size() <= 0) { if (frequencies.size() <= 0) {
std::string cpufreq_dir = "/sys/devices/system/cpu/cpufreq"; std::string cpufreq_dir = "/sys/devices/system/cpu/cpufreq";
if (std::filesystem::exists(cpufreq_dir)) { if (std::filesystem::exists(cpufreq_dir)) {
std::vector<std::string> frequency_files = { std::vector<std::string> frequency_files = {"/cpuinfo_min_freq", "/cpuinfo_max_freq"};
"/cpuinfo_min_freq",
"/cpuinfo_max_freq"
};
for (auto& p : std::filesystem::directory_iterator(cpufreq_dir)) { for (auto& p : std::filesystem::directory_iterator(cpufreq_dir)) {
for (auto freq_file : frequency_files) { for (auto freq_file : frequency_files) {
std::string freq_file_path = p.path().string() + freq_file; std::string freq_file_path = p.path().string() + freq_file;

View File

@ -4,7 +4,12 @@
waybar::modules::Custom::Custom(const std::string& name, const std::string& id, waybar::modules::Custom::Custom(const std::string& name, const std::string& id,
const Json::Value& config) const Json::Value& config)
: ALabel(config, "custom-" + name, id, "{}"), name_(name), fp_(nullptr), pid_(-1) { : AButton(config, "custom-" + name, id, "{}"),
name_(name),
id_(id),
percentage_(0),
fp_(nullptr),
pid_(-1) {
dp.emit(); dp.emit();
if (interval_.count() > 0) { if (interval_.count() > 0) {
delayWorker(); delayWorker();
@ -98,13 +103,13 @@ void waybar::modules::Custom::handleEvent() {
} }
bool waybar::modules::Custom::handleScroll(GdkEventScroll* e) { bool waybar::modules::Custom::handleScroll(GdkEventScroll* e) {
auto ret = ALabel::handleScroll(e); auto ret = AButton::handleScroll(e);
handleEvent(); handleEvent();
return ret; return ret;
} }
bool waybar::modules::Custom::handleToggle(GdkEventButton* const& e) { bool waybar::modules::Custom::handleToggle(GdkEventButton* const& e) {
auto ret = ALabel::handleToggle(e); auto ret = AButton::handleToggle(e);
handleEvent(); handleEvent();
return ret; return ret;
} }
@ -120,38 +125,39 @@ auto waybar::modules::Custom::update() -> void {
} else { } else {
parseOutputRaw(); parseOutputRaw();
} }
auto str = fmt::format(format_, auto str = fmt::format(format_, text_, fmt::arg("alt", alt_),
text_,
fmt::arg("alt", alt_),
fmt::arg("icon", getIcon(percentage_, alt_)), fmt::arg("icon", getIcon(percentage_, alt_)),
fmt::arg("percentage", percentage_)); fmt::arg("percentage", percentage_));
if (str.empty()) { if (str.empty()) {
event_box_.hide(); event_box_.hide();
} else { } else {
label_.set_markup(str); label_->set_markup(str);
if (tooltipEnabled()) { if (tooltipEnabled()) {
if (text_ == tooltip_) { if (text_ == tooltip_) {
if (label_.get_tooltip_markup() != str) { if (button_.get_tooltip_markup() != str) {
label_.set_tooltip_markup(str); button_.set_tooltip_markup(str);
} }
} else { } else {
if (label_.get_tooltip_markup() != tooltip_) { if (button_.get_tooltip_markup() != tooltip_) {
label_.set_tooltip_markup(tooltip_); button_.set_tooltip_markup(tooltip_);
} }
} }
} }
auto classes = label_.get_style_context()->list_classes(); auto classes = button_.get_style_context()->list_classes();
for (auto const& c : classes) { for (auto const& c : classes) {
label_.get_style_context()->remove_class(c); if (c == id_) continue;
button_.get_style_context()->remove_class(c);
} }
for (auto const& c : class_) { for (auto const& c : class_) {
label_.get_style_context()->add_class(c); button_.get_style_context()->add_class(c);
} }
button_.get_style_context()->add_class("flat");
button_.get_style_context()->add_class("text-button");
event_box_.show(); event_box_.show();
} }
} }
// Call parent update // Call parent update
ALabel::update(); AButton::update();
} }
void waybar::modules::Custom::parseOutputRaw() { void waybar::modules::Custom::parseOutputRaw() {

Some files were not shown because too many files have changed in this diff Show More