Compare commits

...

222 Commits

Author SHA1 Message Date
Alex
c6a9b63189 chore: 0.9.23 2023-11-02 14:16:55 +01:00
Alexis Rouillard
7dfc72003f Merge pull request #2629 from andresilva/custom-fix-zombie-processes
custom: reap zombie processes on termination
2023-11-02 10:12:21 +01:00
André Silva
1c1a39f597 custom: reap zombie processes on termination 2023-11-02 01:57:55 +00:00
Alexis Rouillard
121dcc645f Merge pull request #2628 from andresilva/fix-hyprland-workspaces-init
hyprland/workspaces: fix crash on monitor off/on
2023-11-01 23:12:32 +01:00
André Silva
8555456050 hyprland/workspaces: fix crash on monitor off/on 2023-11-01 22:04:19 +00:00
Alexis Rouillard
22dc87934a Merge pull request #2626 from akliuxingyuan/master 2023-11-01 17:35:42 +01:00
akliuxingyuan
335a736eed tray: load_icon use request_size directly 2023-11-01 22:26:52 +08:00
Alexis Rouillard
1149e51f72 Merge pull request #2625 from LukashonakV/happyLinter 2023-11-01 08:27:13 +01:00
Viktar Lukashonak
9012cebbf2 Happy Linter
Signed-off-by: Viktar Lukashonak <myxabeer@gmail.com>
2023-10-31 23:31:58 +03:00
Alexis Rouillard
6425bd2fe0 Merge pull request #2623 from LukashonakV/cavaBump 2023-10-31 21:13:52 +01:00
Alexis Rouillard
241938a86d Merge pull request #2624 from sahib/master 2023-10-31 21:13:18 +01:00
Chris Pahl
f511e61832 fix: custom: do not crash if input text is not valid utf-8 2023-10-31 19:41:42 +01:00
Viktar Lukashonak
b9b89cce7e Happy linter
Signed-off-by: Viktar Lukashonak <myxabeer@gmail.com>
2023-10-31 20:47:56 +03:00
Viktar Lukashonak
e9a66d68b7 Fix debug mode. cava issue
Signed-off-by: Viktar Lukashonak <myxabeer@gmail.com>
2023-10-31 20:27:00 +03:00
Alexis Rouillard
b37d0df89b Merge pull request #2622 from nomads-land/master 2023-10-31 07:44:29 +01:00
cvhere
67422eea36 Skips logging NoActivePlayer error msgs 2023-10-31 11:14:23 +05:30
Alexis Rouillard
e46f66b468 Merge pull request #2613 from DreamMaoMao/master
Fixed variable synchronization exception caused by the "hyprland/workspace" module
2023-10-27 17:27:37 +02:00
DreamMaoMao
1f0ce1a5d9 Fixed variable synchronization exception caused by the "hyprland/workspace" module receiving create or delete IPC requests too quickly 2023-10-27 14:17:43 +08:00
Alexis Rouillard
95b0647c91 chore: increase freebsd timeout 2023-10-26 22:17:20 +02:00
Alexis Rouillard
9ef8faf9b1 Merge pull request #2611 from taminob/bugfix/increase-freebsd-ci-timeout 2023-10-26 17:45:48 +02:00
Tamino Bauknecht
7d8c1494d7 cpu_usage: Fix ScopeGuard renaming in bsd-only file 2023-10-26 17:30:48 +02:00
Tamino Bauknecht
33f8a02fb5 ci: Increase freebsd timeout to 2h
After switching to a new FreeBSD action, the job seems to take longer
than 30 minutes.
Therefore, an increase in the timeout is necessary.
2023-10-26 17:19:26 +02:00
Alexis Rouillard
1618ee78b7 Merge pull request #2601 from taminob/bugfix/2598/fix-max-duration-sleep-for-bug
Fix sleep_for for max duration
2023-10-26 10:07:27 +02:00
Alex
efab1daa7e chore: switch freebsd action 2023-10-25 18:35:58 +02:00
Alexis Rouillard
9a305b2d73 Merge pull request #2609 from taminob/feature/reduce-freebsd-ci-timeout
Reduce freebsd ci timeout
2023-10-25 18:28:10 +02:00
Tamino Bauknecht
799fce0dc6 ci: Set freebsd to timeout after 30min
The job runs very unreliably and often times out after 6h of being stuck
in a boot loop.
This commit reduces the timeout to 30min.
2023-10-24 19:01:40 +02:00
Tamino Bauknecht
68dfd6aa3a scope_guard/modules: Rename scope_guard to ScopeGuard
Using pascal case for the class name keeps it more consistent with the
majority of the other class names.
2023-10-24 17:51:38 +02:00
Tamino Bauknecht
dd1de3efbf Revert "Revert "Fix potential memory leaks""
This reverts commit 2d33c20231 and
reapplies various patches for memory leaks.
The reason for the revert was a bug for a maximum duration interval
which caused sleep_for() to cause unpredictable behavior.
2023-10-24 17:51:38 +02:00
Tamino Bauknecht
521dac8086 sleeper_thread: Make sleep_for more robust
In the previous fix for a passed max duration, the assumption was made
that at maximum one second will pass between the duration assignment and
the std::condition_variable::sleep_for() call.
This implementation makes the behavior more predictable by using
sleep_until() instead to emulate the sleep_for() behavior.
2023-10-24 17:51:34 +02:00
Tamino Bauknecht
ad7d4eb07d sleeper_thread: Allow sleep_for with max duration
The standard library has the implicit requirement that for
std::condition_variable::sleep_for() the duration must not cause an
overflow if added to the current time.
This commit will reduce the duration accordingly to fit into the
duration type.
2023-10-24 17:44:35 +02:00
Alexis Rouillard
a459d8a9b3 Merge pull request #2605 from Syndelis/fix/hyprland-persistent-workspaces-disappear-when-empty 2023-10-24 08:31:11 +02:00
Brenno Lemos
4aee5977d6 fix: set workspace as persistent on create_workspace 2023-10-23 21:07:37 -03:00
Alexis Rouillard
f2085fcd92 Merge pull request #2592 from zjeffer/hyprland/workspaces
General cleanup in hyprland/workspaces
2023-10-23 08:45:52 +02:00
Alexis Rouillard
c47d75ceda Merge pull request #2593 from x0rzavi/typo-fixes
docs: fix typos and improve language coherence
2023-10-23 08:45:08 +02:00
Alexis Rouillard
9ecdbcc7bc Merge pull request #2596 from rehanzo/master 2023-10-22 09:46:35 +02:00
Alexis Rouillard
dafe49d28c Merge pull request #2599 from Alexays/revert-2586-bugfix/fix-potential-memory-leaks
Revert "Fix potential memory leaks"
2023-10-22 09:44:57 +02:00
Alexis Rouillard
2d33c20231 Revert "Fix potential memory leaks" 2023-10-22 09:44:46 +02:00
Rehan
5963bf6ace modules/mpris: change default interval value to 0 2023-10-21 18:14:46 -04:00
zjeffer
dab1493644 cleanup onEvent, dont use try/catch for flow control 2023-10-21 19:33:55 +02:00
zjeffer
acc911737d update window count inside the on_window_* functions 2023-10-21 18:53:53 +02:00
zjeffer
2d614c68f5 code review 2023-10-21 18:15:22 +02:00
Avishek Sen
d0cab2a367 docs: fix typos and improve language coherence 2023-10-21 21:15:25 +05:30
zjeffer
7576611782 formatting 2023-10-21 17:06:02 +02:00
zjeffer
ed65d9cdbd General cleanup in hyprland/workspaces 2023-10-21 16:52:23 +02:00
Alexis Rouillard
dbb887b4a9 Merge pull request #2585 from davxy/master
Show the network interface with highest priority (aka lower metric)
2023-10-21 14:10:21 +02:00
Alexis Rouillard
06f4028697 Merge pull request #2588 from taminob/bugfix/fix-custom-module-signal-without-interval
Custom module: Allow signal without interrupt
2023-10-21 14:09:12 +02:00
Alexis Rouillard
3413b70413 Merge pull request #2586 from taminob/bugfix/fix-potential-memory-leaks
Fix potential memory leaks
2023-10-21 14:08:58 +02:00
Alexis Rouillard
6a8b510db8 Merge pull request #2589 from taminob/bugfix/lint-check-hpp-header-files 2023-10-21 12:56:57 +02:00
Tamino Bauknecht
f598e348c4 ci: Update Linter job 2023-10-21 12:50:56 +02:00
Tamino Bauknecht
6dd2cfba34 ci: Lint header files with hpp file ending 2023-10-21 11:57:11 +02:00
Tamino Bauknecht
ae748b2644 modules+util: fix actual (potential) memory leaks 2023-10-21 11:51:33 +02:00
Tamino Bauknecht
a0b63d6b1e modules: use scope_exit for deletion to make code more robust 2023-10-21 11:51:18 +02:00
Tamino Bauknecht
89e85db790 ALabel: make use of std::chrono::max() instead of magic number 2023-10-21 11:50:38 +02:00
Tamino Bauknecht
a73669be6a modules/upower: use smart pointer to avoid memory leak 2023-10-21 11:50:28 +02:00
Tamino Bauknecht
8c57756556 util: add scope_guard
This custom small implementation avoids adding an extra dependency like
Boost.ScopeExit
2023-10-21 11:50:06 +02:00
Tamino Bauknecht
b8afde043c sleeper_thread: allow interrupting sleep()
This keeps the function consistent with sleep_until() and sleep_for()
which both can be interrupted.
This is relevant to allow an update via a "signal" without an "interval"
in a custom module.
2023-10-20 23:57:54 +02:00
Alexis Rouillard
eefd6e8336 Merge pull request #2578 from Syndelis/fix/hyprland-windows-disappearing 2023-10-20 10:24:56 +02:00
Davide Galassi
6829ed1bb4 Different interfaces have different index 2023-10-20 08:25:28 +02:00
Brenno Lemos
7d5577a2ed feat: create persistent workspaces after regular ones at init
feat: avoid recreating duplicate workspaces
2023-10-19 21:29:38 -03:00
Brenno Lemos
a41225c4e0 Revert "fix: fill persistent workspaces' windows at init"
This reverts commit e14a3b8687.
2023-10-19 21:23:00 -03:00
Brenno Lemos
a0d2d95b41 chore: remove unused function 2023-10-19 21:21:55 -03:00
Brenno Lemos
e14a3b8687 fix: fill persistent workspaces' windows at init 2023-10-19 21:19:08 -03:00
Brenno Lemos
846842be80 feat: emit dispatcher when any window is created during update 2023-10-19 10:45:00 -03:00
Brenno Lemos
e845db84ad feat: avoid recreating workspaces 2023-10-18 19:11:49 -03:00
Brenno Lemos
193040c41e feat: attempt to move windows out of the create window payload before taking them from workspaces 2023-10-18 19:11:49 -03:00
Alex
871f9a1269 fix: revert clock 2023-10-18 08:45:56 +02:00
Alex
5319cb6e10 fix: upower hidded on start 2023-10-17 20:12:24 +02:00
Alex
208928ded5 fix: lint 2023-10-17 19:29:06 +02:00
Alexis Rouillard
4d7eb3bd15 Merge pull request #2515 from chrisjshore/clock_fix
fix clock to work with fmt 10.x
2023-10-17 19:25:58 +02:00
Alexis Rouillard
6b73e2aa58 Merge pull request #2114 from mmhat/split-cpu-module
Split cpu module
2023-10-17 19:25:29 +02:00
Brenno Lemos
6ddd283d0f fix: special workspaces weren't registering windows because of the special qualifier prefix 2023-10-16 20:48:52 -03:00
Brenno Lemos
e70a67d958 chore: lint
chore: swap push_back to emplace_back
2023-10-16 19:14:50 -03:00
Brenno Lemos
67c0c9a66c fix: delay window creation to await for hyprland to create a workspace 2023-10-16 19:07:00 -03:00
Alexis Rouillard
42741c963e Merge pull request #2575 from Syndelis/feat/slider 2023-10-16 08:08:37 +02:00
Brenno Lemos
9d316de15a fix: avoid compiling audio_backend if pulse is not available 2023-10-15 18:12:31 -03:00
Brenno Lemos
ecbcf242d5 feat: allow unmuting by moving the pulseaudio slider 2023-10-15 17:52:12 -03:00
Brenno Lemos
fd3710d869 chore: suppress compiler warning 2023-10-15 17:52:12 -03:00
Brenno Lemos
11d7ca1d73 feat: backlight slider 2023-10-15 17:52:12 -03:00
Brenno Lemos
c3779dd16e refactor: move backlight backend out of backlight module 2023-10-15 17:52:12 -03:00
Brenno Lemos
442a4b0da0 feat: pulseaudio slider module 2023-10-15 17:52:12 -03:00
Brenno Lemos
c9e129cda2 feat: allow setting volume directly 2023-10-15 17:52:12 -03:00
Brenno Lemos
64d7fae03a refactor: move pulseaudio handling to separate class 2023-10-15 17:52:12 -03:00
Alexis Rouillard
44d8245605 Merge pull request #2560 from akshettrj/mpris-click-fix 2023-10-15 21:26:33 +02:00
Alexis Rouillard
93daf089b5 Merge pull request #2574 from Syndelis/feat/group-drawers 2023-10-15 21:26:04 +02:00
Alexis Rouillard
7645ae1907 Merge pull request #2563 from Syndelis/feat/hyprland-window-rename-by-title 2023-10-15 21:21:32 +02:00
Alexis Rouillard
3d496c2200 Merge pull request #2554 from mutoroglin/cava-hide-on-silence 2023-10-15 21:19:17 +02:00
Brenno Lemos
ff9b6c9469 docs: fix weird man limitation 2023-10-14 22:14:13 -03:00
Brenno Lemos
05b97e9ec2 fix: add hover handler to every element in the group drawer 2023-10-14 22:13:01 -03:00
Brenno Lemos
8f32d102ae docs: include group drawer documentation 2023-10-14 18:50:45 -03:00
Brenno Lemos
5a380da3bb chore: remove redundant else statement 2023-10-14 18:39:42 -03:00
Brenno Lemos
5e44cb6ba2 refactor: move signal handler adding into separate method
fix: typo in handleMouseHover method name
2023-10-14 18:30:27 -03:00
Brenno Lemos
fad858782c feat: improve drawer configuration 2023-10-14 18:24:50 -03:00
Brenno Lemos
5246ab15cb feat: add drawer bool option to group 2023-10-14 17:17:52 -03:00
Brenno Lemos
bbb7fb0c82 refactor: don't use a group's box directly in bar 2023-10-14 13:23:11 -03:00
Brenno Lemos
c59264d6b4 fix: clang < 16 can't emplace back struct with no constructor 2023-10-12 17:30:32 -03:00
Alexis Rouillard
a3774dc586 Merge pull request #2568 from Syndelis/feat/hyprland-ignore-workspaces 2023-10-12 07:32:56 +02:00
Brenno Lemos
ee652677a6 feat: ignore windows with empty classes or titles (if any rule uses title) 2023-10-11 11:40:49 -03:00
Brenno Lemos
ceeb5bf8bd docs: include new ignore-workspaces example and documentation 2023-10-11 11:03:18 -03:00
Brenno Lemos
c995bafa7a feat: add option to ignore workspaces based on regex 2023-10-11 10:59:33 -03:00
Brenno Lemos
f8340d88be chore: lint unrelated file
this file was edited in #2558 but not linted
2023-10-09 15:26:07 -03:00
Brenno Lemos
592d5645a5 docs: include new feature in manual 2023-10-09 14:58:21 -03:00
Brenno Lemos
f9a7ecf3a9 feat: optimize cache usage when window titles aren't involved 2023-10-09 14:49:38 -03:00
Brenno Lemos
387e54498e docs: document new regex collection class 2023-10-09 14:46:57 -03:00
Brenno Lemos
fad43d4b16 feat: listen to windowtitle IPC event condiationally to update window rules 2023-10-09 14:42:53 -03:00
Brenno Lemos
8d057e6f96 refactor: separate regex rule matching and caching in separate class 2023-10-09 13:53:00 -03:00
Joerg Weislogel
b2e88347b3 added description for configuration option hide-on-silence in man file 2023-10-09 17:05:12 +02:00
Akshett Rai Jindal
1af02e0a67 fix(modules/mpris): fix on-*-click typos
In all other places, the norm is to use `on-click-(middle|right)` but in
the mpris module, `on-(middle|right)-click` was being used which caused
clicks to malfunction if set to some custom commands
2023-10-09 11:48:49 +05:30
Alexis Rouillard
30cc88a4c5 Merge pull request #2558 from SWarrener/master 2023-10-08 22:37:46 +02:00
SWarrener
32d326ca4a Some missing backticks 2023-10-08 16:34:27 +01:00
SWarrener
ae92d7d186 Updating man page with details of options to force specific units in disk size output 2023-10-08 16:26:06 +01:00
SWarrener
c16e791cdc Adding options to allow disk outputs to always be in a specific unit 2023-10-08 16:24:50 +01:00
Christopher Shore
fbd62e0071 Merge branch 'Alexays:master' into clock_fix 2023-10-07 18:39:56 -04:00
Joerg Weislogel
1eb0777799 add function to cava module to hide on silence 2023-10-07 12:50:24 +02:00
Alexis Rouillard
58e506a675 Merge pull request #2529 from Syndelis/feat/hyprland-window-workspaces
Feature: Hyprland dynamic window names on workspaces
2023-10-02 19:17:42 +02:00
Brenno Lemos
1b98a04c93 chore: lint unrelated files so the CI passes 2023-10-02 12:33:28 -03:00
Alexis Rouillard
4c0347d9f2 Merge pull request #2540 from Syndelis/fix/hyprland-special-workspaces 2023-09-25 22:33:36 +02:00
Brenno Lemos
9a3238c20b chore: avoid the creation and deletion of doubled-special workspaces
see hyprwm/Hyprland#3424 for more info

Co-authored-by: Gabriel Fox <Inbox@GabrielFox.Dev>
2023-09-25 17:13:26 -03:00
Brenno Lemos
6e48b236a1 fix: workspace special wasn't removed
fixes  #2505

Co-authored-by: Gabriel Fox <Inbox@GabrielFox.Dev>
2023-09-25 17:12:51 -03:00
Alexis Rouillard
16f6d9dfa0 Merge pull request #2534 from woojiq/fix-hyprland-default-icon 2023-09-24 09:25:37 +02:00
woojiq
d37954322a fix(hyprland): use workspace name as default icon
Wlr and Sway modules use the workspace `name` as the default icon if no icon is provided. This adds the same behavior for the `hyprland/workspace` module.

Closes https://github.com/Alexays/Waybar/issues/2533
2023-09-23 21:55:18 +03:00
Brenno Lemos
258ab8b147 refactor: take window representation directly from old workspace on movewindow event 2023-09-22 21:12:42 -03:00
Brenno Lemos
6663ca3d75 chore: document new properties 2023-09-22 20:41:38 -03:00
Brenno Lemos
adbc9d95de feat: optional default icon for 0-match classes
Co-authored-by: Gabriel Fox <Inbox@GabrielFox.Dev>
2023-09-22 19:16:59 -03:00
Brenno Lemos
fbe544984c fix: ipc vs json window addr format mismatch
feat: ignore empty windows

Co-authored-by: Gabriel Fox <Inbox@GabrielFox.Dev>
2023-09-22 19:16:56 -03:00
Brenno Lemos
b9d5912a4f feat: rewrite window classes
feat: cache window class rewrite resolution

Co-authored-by: Gabriel Fox <Inbox@GabrielFox.Dev>
2023-09-22 19:16:53 -03:00
Brenno Lemos
3e2761e81f feat: dynamically assign windows to workspaces
Co-authored-by: Gabriel Fox <Inbox@GabrielFox.Dev>
2023-09-22 19:12:50 -03:00
Alexis Rouillard
6997b34a81 Merge pull request #2517 from an-prata/master
Lighter Weight Signal-Based Custom Modules
2023-09-21 23:48:22 +02:00
Alexis Rouillard
5960e8f1ee Merge pull request #2518 from idm1try/fix-bl-asahi
fix(backlight): wrong percentage numbers for device apple-panel-bl
2023-09-21 23:47:23 +02:00
idm1try
81ffeebfb1 fix: style
Co-authored-by: Alexis Rouillard <alexisr245@gmail.com>
2023-09-21 09:03:13 +05:00
Evan Overman
f14fe96e19 add info to interval and signal in manpage for custom modules 2023-09-19 14:52:48 -07:00
idm1try
954bea36f4 chore: remove result dir by nix 2023-09-19 18:52:00 +05:00
idm1try
388c024298 fix(backlight): wrong percentage numbers for device apple-panel-bl 2023-09-19 18:50:39 +05:00
Alexis Rouillard
9b8adc1951 Merge pull request #2494 from KanuX-14/battery_fix
Fix battery not showing for some devices
2023-09-19 13:33:35 +02:00
Evan Overman
bf371f70d1 add waitingWorker() to Custom 2023-09-18 14:56:14 -07:00
Evan Overman
7c28ffc856 add indefinite sleep() function to SleeperThread 2023-09-18 14:55:50 -07:00
Christopher Shore
14820e5d18 fix clock to work with fmt 10.x 2023-09-17 16:32:19 -04:00
Mann mit Hut
80a34eec81 Fixed formatting again 2023-09-13 23:25:39 +02:00
Mann mit Hut
d5203e5b37 Fixed cpu module: Provide stub implementation for parseCpuFrequencies 2023-09-13 23:12:35 +02:00
Mann mit Hut
91b6629103 Fixed format errors 2023-09-13 21:59:42 +02:00
Mann mit Hut
93d66a9258 Moved cpu/common.cpp to cpu.cpp 2023-09-13 21:56:37 +02:00
Mann mit Hut
8d7341da6e cpu module: Reuse getLoad of load module 2023-09-13 21:56:37 +02:00
Mann mit Hut
d1602e383c cpu module: Reuse getCpuUsage of cpu_usage module 2023-09-13 21:56:36 +02:00
Mann mit Hut
c45f6681b3 cpu module: Reuse getCpuFrequency of cpu_frequency module 2023-09-13 21:56:35 +02:00
Mann mit Hut
dce6a98f38 Added changes made to the cpu module 2023-09-13 21:56:34 +02:00
Mann mit Hut
982ffde002 Use labels instead of buttons 2023-09-13 21:56:33 +02:00
Mann mit Hut
888adb57ec Introduce cpu_usage module 2023-09-13 21:56:32 +02:00
Mann mit Hut
c36fe3a004 Introduce cpu_frequency module 2023-09-13 21:56:31 +02:00
Mann mit Hut
729564cc27 Introduced separate load module
The module provides the three system load averages. This is an
improvement compared what you can do with the cpu module: cpu
only provides the one minute sample and the state of the cpu module is
derived from the cpu usage which messes up the formating of the load
average. Also, at least on modern Linux systems, the load of a system
takes much more than the cpu utilization into account and it should
therefore live in a separate module.
2023-09-13 21:56:30 +02:00
Alexis Rouillard
4d32991bee Merge pull request #2507 from hariseldon78/patch-1
Update workspaces.cpp
2023-09-13 18:21:22 +02:00
Roberto Previdi
69736d68aa Update workspaces.cpp
Fix unchecked string to int conversion of workspace name (which can be a string)
Closes #2501
2023-09-13 18:20:13 +02:00
KanuX-14
28a2d15fef Update 'bat-compatibility' option to manual 2023-09-12 13:39:09 -03:00
Alexis Rouillard
a90e275d5e Merge pull request #2470 from 4e554c4c/darkmode
search for dark or light mode stylesheet
2023-09-11 09:36:05 +02:00
Alexis Rouillard
fc67558717 Merge branch 'master' into darkmode 2023-09-11 09:25:45 +02:00
Alexis Rouillard
196b400abf Merge pull request #2468 from khaneliman/persistent-rename
deprecate persistent_workspaces in favor of persistent-workspaces
2023-09-11 09:22:07 +02:00
Alexis Rouillard
05a2af2d7c Merge pull request #2486 from khaneliman/workspace-sorting
feat: hyprland workspaces add sort-by
2023-09-11 09:21:35 +02:00
KanuX-14
1ff4464b2f Use adapter status if battery status is inexistent 2023-09-10 15:16:43 -03:00
KanuX-14
60611e9c2b Fix battery not showing for some devices
Adds 'bat-compatibility' boolean checking from configuration file.
2023-09-10 14:41:40 -03:00
Austin Horstman
79cf33b9f1 refactor: enumparser create implementation file 2023-09-09 17:59:40 -05:00
Austin Horstman
b8630968b2 refactor: move capitalize string helper 2023-09-09 13:23:17 -05:00
Austin Horstman
2fee12d930 fix: enumparser capitalize everything to avoid issues 2023-09-09 12:14:52 -05:00
Austin Horstman
3ae2fe3272 refactor: PR review cleanup 2023-09-09 12:08:30 -05:00
Austin Horstman
2b8c92e8fd refactor: enum utility allow overriding 2023-09-09 11:18:12 -05:00
Austin Horstman
8ce64ea784 refactor: make parsing sort-by more lenient 2023-09-09 10:04:49 -05:00
Austin Horstman
8ea2626de8 refactor: sort-by enum hyprland 2023-09-09 10:04:48 -05:00
Austin Horstman
65ba449460 chore: update man page index 2023-09-08 23:17:21 -05:00
Austin Horstman
cbc12e5443 feat: hyprland workspaces add sort-by 2023-09-08 22:49:15 -05:00
Austin Horstman
587bd0cd62 refactor: cleanup hyprland workspaces constructor 2023-09-08 22:24:05 -05:00
Alexis Rouillard
309edd0585 Merge pull request #2485 from khaneliman/active-rename 2023-09-08 23:11:58 +02:00
Austin Horstman
2837b72064 fix: rename workspace active fix 2023-09-08 14:11:02 -05:00
Alexis Rouillard
38ef38b72f Merge pull request #2477 from zjeffer/fix/urgent-icon 2023-09-07 20:33:22 +02:00
zjeffer
6c3565c520 Add urgent icon
Fixes #2476
2023-09-07 19:33:56 +02:00
Calvin Lee
9bb2c01a44 clean up client.cpp 2023-09-07 13:43:59 +00:00
Calvin Lee
09873f0ed9 search for dark or light mode stylesheet
summary:
-------
This commit adds xdg-desktop-portal support to waybar. If a portal
supporting `org.freedesktop.portal.Settings` exists, then it will be
queried for the current colorscheme. This colorscheme will then be used
to prefer a `style-light.css` or `style-dark.css` over the basic
`style.css`.

technical details:
-----------------
Appearance is provided by several libraries, such as libhandy (mobile)
and libadwaita. However, waybar links to neither of these libraries. As
the amount of code required to communicate with xdg-desktop portal as a
client is rather minimal, I believe doing so is better than linking to
an additional library.

The Gio library for communicating with dbus is rather messy, Instead of
the `Portal` class containing a `Gio::Dbus::Proxy`, it extends it which
simplifies signal handling.

`Portal` then exposes its own signal, which can be listened to by waybar
to update CSS.

For a reference implementation, please see another one of my projects:
https://github.com/4e554c4c/darkman.nvim/blob/main/portal.go

test plan:
---------
If no desktop portal which provides `Settings` exists, then waybar
continues with the log line
```
[2023-09-06 14:14:37.754] [info] Unable to receive desktop appearance: GDBus.Error:org.freedesktop.DBus.Error.UnknownMethod: No such interface “org.freedesktop.portal.Settings” on object at path /org/freedesktop/portal/desktop
```

Furthermore, if `style-light.css` or `style-dark.css` do not exist, then
`style.css` will still be searched for.

Waybar has been tested with both light and dark startup. E.g. if the
appearance is dark on startup the log lines
```
[2023-09-06 14:27:45.379] [info] Discovered appearance 'dark'
[2023-09-06 14:27:45.379] [debug] Try expanding: $XDG_CONFIG_HOME/waybar/style-dark.css
[2023-09-06 14:27:45.379] [debug] Found config file: $XDG_CONFIG_HOME/waybar/style-dark.css
[2023-09-06 14:27:45.379] [info] Using CSS file /home/pounce/.config/waybar/style-dark.css
```
will be observed.
If the color then changes to light during the operation of waybar, it
will change css files:
```
[2023-09-06 14:28:17.173] [info] Received new appearance 'dark'
[2023-09-06 14:28:17.173] [debug] Try expanding: $XDG_CONFIG_HOME/waybar/style-light.css
[2023-09-06 14:28:17.173] [debug] Found config file: $XDG_CONFIG_HOME/waybar/style-light.css
[2023-09-06 14:28:17.173] [info] Using CSS file /home/pounce/.config/waybar/style-light.css
```

Finally, tested resetting waybar and toggling style (works, and style is
only changed once).

fixes: Alexays/Waybar#1973
2023-09-06 15:19:56 +00:00
khaneliman
c9e1899594 refactor: deprecate instead of remove persistent_workspaces 2023-09-05 16:02:45 -05:00
khaneliman
b405dc436c refactor!: wlr persistent workspaces config rename 2023-09-05 16:02:22 -05:00
khaneliman
4a6c1269fb refactor!: sway persistent workspaces config name rename 2023-09-05 16:02:21 -05:00
khaneliman
44ac6b8044 refactor!: hyprland persistent workspaces config option name standardization 2023-09-05 16:02:19 -05:00
Alexis Rouillard
80de22a159 Merge pull request #2408 from zjeffer/hyprland/workspaces_active-only
Implement 'active_only' option and 'visible' class in hyprland/workspaces
2023-09-05 22:59:49 +02:00
zjeffer
04b39ea64e hyprland/workspaces: implement 'active_only' option and visible class 2023-09-05 18:22:54 +02:00
Alexis Rouillard
116aa5cdbd Merge pull request #2466 from maximbaz/hyprland-support-workspace-rename
hyprland/workspaces: react on renameworkspace event
2023-09-05 17:23:06 +02:00
Maxim Baz
9c49f46b01 hyprland/workspaces: react on renameworkspace event 2023-09-05 17:13:25 +02:00
Alexis Rouillard
f7ff005dd5 Merge pull request #2460 from xercesblue/set_urgent_segfault
modules/hyprland: Fix segfault when attempting to set_urgent on a missing workspace
2023-09-05 08:42:39 +02:00
xercesblue
d40ccd0da8 modules/hyprland: Fix segfault when attempting to set_urgent on a missing workspace 2023-09-04 16:57:00 -07:00
Alexis Rouillard
6f66af9ab9 Merge pull request #2134 from bruceblore/battery-weighted-percentage
Display battery percentage as weighted average of battery levels
2023-09-04 22:01:40 +02:00
Alexis Rouillard
2d27e484c7 Merge pull request #2417 from Cherser-s/sni-click-coordinate-fix
sni: fix passing relative coordinates to dbus methods
2023-09-04 22:01:04 +02:00
Alexis Rouillard
a77ccf4bd1 Merge pull request #2457 from khaneliman/hyprland-cleanup
Hyprland linting cleanup
2023-09-04 22:00:44 +02:00
Austin Horstman
4cb8efbecc chore: cpplint fixes hyprland classes 2023-09-03 00:18:31 -05:00
Austin Horstman
8fc4187713 refactor: replace strcpy with snprintf 2023-09-02 23:56:06 -05:00
Austin Horstman
ce076927f3 chore: cpplint fixes hyprland headers 2023-09-02 23:56:04 -05:00
Alexis Rouillard
8eb614f69e Merge pull request #2438 from khaneliman/hyprland-workspace-array
hyprland persistent workspace support new config declaration
2023-09-01 09:10:23 +02:00
Alexis Rouillard
347dd1c799 Merge pull request #2431 from zjeffer/fix/persistent-workspace-icon
hyprland/workspaces: Add "empty" icon and class
2023-09-01 09:09:32 +02:00
Alexis Rouillard
82b7e4ea01 Merge pull request #2414 from KosmX/add_release_v2
Release button event second attempt
2023-09-01 09:08:23 +02:00
Alexis Rouillard
d7d4a6c632 Merge pull request #2442 from PucklaJ/hyprland_persistent
Show workspaces on all outputs if persistent_workspaces value is empty
2023-09-01 09:06:41 +02:00
PucklaJ
a18b41911d hyprland/workspaces: Show workspace on all outputs if an empty array is given
This behaviour is consistent with sway/workspaces and wlr/workspaces
2023-08-30 13:35:19 +02:00
Austin Horstman
52309615c1 hyprland new persistent_workspace configuration style 2023-08-29 00:11:25 -05:00
Cherser-s
65dfabc430 sni: fix passing relative coordinates to dbus methods
Doesn't correctly handle the case with both margin and width/height being set at the same time.
2023-08-25 20:37:16 +03:00
Cherser-s
936937ec78 store margins and global window offset in the bar object 2023-08-25 20:37:14 +03:00
zjeffer
e163dd8216 hyprland/workspaces: update manpage 2023-08-24 22:51:06 +02:00
zjeffer
06a9f98878 hyprland/workspaces: Add "empty" icon and class 2023-08-24 21:19:20 +02:00
Alexis Rouillard
b665843085 Merge pull request #2429 from khaneliman/hyprland-urgent
Hyprland urgent class support
2023-08-24 17:00:40 +02:00
Austin Horstman
ee4fbc58f7 hyprland add urgent ipc support 2023-08-23 12:52:29 -05:00
Austin Horstman
3081b0c576 flake lock update 2023-08-23 12:14:35 -05:00
Alexis Rouillard
b7a527b122 Merge pull request #2424 from asas1asas200/feat-keyboard-bindingkey 2023-08-20 09:40:36 +02:00
asas1asas200
54a6668846 feat(keyboard-state): add binding-keys options 2023-08-20 08:33:34 +08:00
Alexis Rouillard
ed0f7453c9 Merge pull request #2420 from Alexays/chore-subprojects
chore: update subprojects
2023-08-18 10:39:15 +02:00
Alex
19fe929d1f chore: update subprojects 2023-08-18 09:48:03 +02:00
KosmX
392e863e6d Apply formatting 2023-08-16 17:33:36 +02:00
KosmX
2ff347f9a8 Add handleRelease method to release events
This commit shouldn't change the handleToggle behaviour,
it shouldn't break anything.
2023-08-16 17:14:49 +02:00
KosmX
1d8331d0c5 Add release events to event map 2023-08-16 17:12:32 +02:00
KosmX
718db71638 Refactor enable click condition
This shouldn't change behaviour.
2023-08-16 17:11:44 +02:00
Alexis Rouillard
0a28b50a8c Merge pull request #2413 from PucklaJ/bluetooth-no-controller
Add format-no-controller to bluetooth module and fix it still being visible if the format string is empty
2023-08-16 17:08:48 +02:00
PucklaJ
70bc318a01 Fix bluetooth module still being visible if format is empty 2023-08-16 16:30:59 +02:00
PucklaJ
22817089db Add no-controller format to bluetooth module 2023-08-16 15:34:06 +02:00
Alexis Rouillard
aecd80702e Merge pull request #2412 from jpalus/simpleclock-fmt-compile-fix
Fix simpleclock module compilation with recent fmt
2023-08-16 14:35:39 +02:00
Jan Palus
abd7a0cf25 Fix simpleclock module compilation with recent fmt
both `format_` and `tooltip_format` are dynamically provided formats so
wrap them in `fmt::runtime()`
2023-08-16 14:32:48 +02:00
Alex
e30fba0b8f chore: 0.9.22 2023-08-16 13:34:05 +02:00
Alex
b5ea14c896 revert: release event 2023-08-16 13:31:24 +02:00
Alexis Rouillard
5b33a5917c Merge pull request #2404 from eltociear/master-1
fix: typo in taskbar.cpp
2023-08-16 08:55:33 +02:00
Alexis Rouillard
66b71cc857 Merge pull request #2409 from jpalus/fmt-cast-ustring-to-string 2023-08-15 22:35:46 +02:00
Jan Palus
c8237437d2 Explicitly cast ustring to string when passing to fmt
don't rely on implicit conversion which is no longer present in fmt
10.1.0

Fixes #2403
2023-08-15 20:57:07 +02:00
Ikko Eltociear Ashimine
57544fe694 fix: typo in taskbar.cpp
ocurred -> occurred
2023-08-15 00:45:09 +09:00
Bruce Blore
bad6cfae6f Added option to calculate battery percentage as total_energy * 100 / total_energy_full 2023-04-22 23:43:04 -07:00
133 changed files with 3789 additions and 1185 deletions

View File

@@ -1,6 +1,6 @@
name: freebsd
on: [ push, pull_request ]
on: [push, pull_request]
jobs:
clang:
@@ -9,21 +9,21 @@ jobs:
# https://github.com/actions/virtual-environments/issues/4060 - for lack of VirtualBox on MacOS 11 runners
runs-on: macos-12
steps:
- uses: actions/checkout@v3
- name: Test in FreeBSD VM
uses: vmactions/freebsd-vm@v0
with:
mem: 2048
usesh: true
prepare: |
export CPPFLAGS=-isystem/usr/local/include LDFLAGS=-L/usr/local/lib # sndio
sed -i '' 's/quarterly/latest/' /etc/pkg/FreeBSD.conf
pkg install -y git # subprojects/date
pkg install -y catch evdev-proto gtk-layer-shell gtkmm30 jsoncpp \
libdbusmenu libevdev libfmt libmpdclient libudev-devd meson \
pkgconf pulseaudio scdoc sndio spdlog wayland-protocols upower \
libinotify
run: |
meson build -Dman-pages=enabled
ninja -C build
meson test -C build --no-rebuild --print-errorlogs --suite waybar
- uses: actions/checkout@v3
- name: Test in FreeBSD VM
uses: cross-platform-actions/action@v0.19.1
timeout-minutes: 180
with:
operating_system: freebsd
version: "13.2"
environment_variables: CPPFLAGS=-isystem/usr/local/include LDFLAGS=-L/usr/local/lib
run: |
sudo sed -i '' 's/quarterly/latest/' /etc/pkg/FreeBSD.conf
sudo pkg install -y git # subprojects/date
sudo pkg install -y catch evdev-proto gtk-layer-shell gtkmm30 jsoncpp \
libdbusmenu libevdev libfmt libmpdclient libudev-devd meson \
pkgconf pulseaudio scdoc sndio spdlog wayland-protocols upower \
libinotify
meson build -Dman-pages=enabled
ninja -C build
meson test -C build --no-rebuild --print-errorlogs --suite waybar

View File

@@ -7,8 +7,8 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: DoozyX/clang-format-lint-action@v0.13
- uses: DoozyX/clang-format-lint-action@v0.16.2
with:
source: '.'
extensions: 'h,cpp,c'
clangFormatVersion: 12
extensions: 'hpp,h,cpp,c'
clangFormatVersion: 16

76
flake.lock generated
View File

@@ -2,15 +2,15 @@
"nodes": {
"devshell": {
"inputs": {
"flake-utils": "flake-utils",
"nixpkgs": "nixpkgs"
"nixpkgs": "nixpkgs",
"systems": "systems"
},
"locked": {
"lastModified": 1676293499,
"narHash": "sha256-uIOTlTxvrXxpKeTvwBI1JGDGtCxMXE3BI0LFwoQMhiQ=",
"lastModified": 1692523566,
"narHash": "sha256-VDJDihK6jNebVw9y3qKCVD6+6QaC/x8kxZzL4MaIPPY=",
"owner": "numtide",
"repo": "devshell",
"rev": "71e3022e3ab20bbf1342640547ef5bc14fb43bf4",
"rev": "d208c58e2f7afef838add5f18a9936b12a71d695",
"type": "github"
},
"original": {
@@ -36,27 +36,15 @@
}
},
"flake-utils": {
"locked": {
"lastModified": 1642700792,
"narHash": "sha256-XqHrk7hFb+zBvRg6Ghl+AZDq03ov6OshJLiSWOoX5es=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "846b2ae0fc4cc943637d3d1def4454213e203cba",
"type": "github"
"inputs": {
"systems": "systems_2"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"flake-utils_2": {
"locked": {
"lastModified": 1676283394,
"narHash": "sha256-XX2f9c3iySLCw54rJ/CZs+ZK6IQy7GXNY4nSOyu2QG4=",
"lastModified": 1689068808,
"narHash": "sha256-6ixXo3wt24N/melDWjq70UuHQLxGV8jZvooRanIHXw0=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "3db36a8b464d0c4532ba1c7dda728f4576d6d073",
"rev": "919d646de7be200f3bf08cb76ae1f09402b6f9b4",
"type": "github"
},
"original": {
@@ -67,11 +55,11 @@
},
"nixpkgs": {
"locked": {
"lastModified": 1643381941,
"narHash": "sha256-pHTwvnN4tTsEKkWlXQ8JMY423epos8wUOhthpwJjtpc=",
"lastModified": 1677383253,
"narHash": "sha256-UfpzWfSxkfXHnb4boXZNaKsAcUrZT9Hw+tao1oZxd08=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "5efc8ca954272c4376ac929f4c5ffefcc20551d5",
"rev": "9952d6bc395f5841262b006fbace8dd7e143b634",
"type": "github"
},
"original": {
@@ -83,11 +71,11 @@
},
"nixpkgs_2": {
"locked": {
"lastModified": 1676300157,
"narHash": "sha256-1HjRzfp6LOLfcj/HJHdVKWAkX9QRAouoh6AjzJiIerU=",
"lastModified": 1692638711,
"narHash": "sha256-J0LgSFgJVGCC1+j5R2QndadWI1oumusg6hCtYAzLID4=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "545c7a31e5dedea4a6d372712a18e00ce097d462",
"rev": "91a22f76cd1716f9d0149e8a5c68424bb691de15",
"type": "github"
},
"original": {
@@ -101,9 +89,39 @@
"inputs": {
"devshell": "devshell",
"flake-compat": "flake-compat",
"flake-utils": "flake-utils_2",
"flake-utils": "flake-utils",
"nixpkgs": "nixpkgs_2"
}
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
},
"systems_2": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
}
},
"root": "root",

View File

@@ -16,6 +16,7 @@
inherit (nixpkgs) lib;
genSystems = lib.genAttrs [
"x86_64-linux"
"aarch64-linux"
];
pkgsFor = genSystems (system:
@@ -47,17 +48,12 @@
let pkgs = import nixpkgs {
inherit system;
overlays = [ devshell.overlay ];
overlays = [ devshell.overlays.default ];
};
in
pkgs.devshell.mkShell {
imports = [ "${pkgs.devshell.extraModulesDir}/language/c.nix" ];
commands = [
{
package = pkgs.devshell.cli;
help = "Per project developer environments";
}
];
devshell.packages = with pkgs; [
clang-tools
gdb
@@ -79,6 +75,7 @@
at-spi2-atk atkmm cairo cairomm catch2 fmt_8 fontconfig
gdk-pixbuf glibmm gtk3 harfbuzz pango pangomm wayland-protocols
]);
env = with pkgs; [
{ name = "CPLUS_INCLUDE_PATH"; prefix = "$DEVSHELL_DIR/include"; }
{ name = "PKG_CONFIG_PATH"; prefix = "$DEVSHELL_DIR/lib/pkgconfig"; }

View File

@@ -36,8 +36,11 @@ class AModule : public IModule {
virtual bool handleToggle(GdkEventButton *const &ev);
virtual bool handleScroll(GdkEventScroll *);
virtual bool handleRelease(GdkEventButton *const &ev);
private:
bool handleUserEvent(GdkEventButton *const &ev);
std::vector<int> pid_;
gdouble distance_scrolled_y_;
gdouble distance_scrolled_x_;

19
include/ASlider.hpp Normal file
View File

@@ -0,0 +1,19 @@
#pragma once
#include "AModule.hpp"
#include "gtkmm/scale.h"
namespace waybar {
class ASlider : public AModule {
public:
ASlider(const Json::Value& config, const std::string& name, const std::string& id);
virtual void onValueChanged();
protected:
bool vertical_ = false;
int min_ = 0, max_ = 100, curr_ = 50;
Gtk::Scale scale_;
};
} // namespace waybar

View File

@@ -12,6 +12,7 @@
#include <vector>
#include "AModule.hpp"
#include "group.hpp"
#include "xdg-output-unstable-v1-client-protocol.h"
namespace waybar {
@@ -91,6 +92,9 @@ class Bar {
bool vertical = false;
Gtk::Window window;
int x_global;
int y_global;
#ifdef HAVE_SWAY
std::string bar_id;
#endif
@@ -98,15 +102,20 @@ class Bar {
private:
void onMap(GdkEventAny *);
auto setupWidgets() -> void;
void getModules(const Factory &, const std::string &, Gtk::Box *);
void getModules(const Factory &, const std::string &, waybar::Group *);
void setupAltFormatKeyForModule(const std::string &module_name);
void setupAltFormatKeyForModuleList(const char *module_list_name);
void setMode(const bar_mode &);
void onConfigure(GdkEventConfigure *ev);
void configureGlobalOffset(int width, int height);
void onOutputGeometryChanged();
/* Copy initial set of modes to allow customization */
bar_mode_map configured_modes = PRESET_MODES;
std::string last_mode_{MODE_DEFAULT};
struct bar_margins margins_;
std::unique_ptr<BarSurface> surface_impl_;
Gtk::Box left_;
Gtk::Box center_;

View File

@@ -7,6 +7,7 @@
#include "bar.hpp"
#include "config.hpp"
#include "util/portal.hpp"
struct zwlr_layer_shell_v1;
struct zwp_idle_inhibitor_v1;
@@ -33,7 +34,7 @@ class Client {
private:
Client() = default;
const std::string getStyle(const std::string &style);
const std::string getStyle(const std::string &style, std::optional<Appearance> appearance);
void bindInterfaces();
void handleOutput(struct waybar_output &output);
auto setupCss(const std::string &css_file) -> void;
@@ -52,6 +53,7 @@ class Client {
Glib::RefPtr<Gtk::StyleContext> style_context_;
Glib::RefPtr<Gtk::CssProvider> css_provider_;
std::unique_ptr<Portal> portal;
std::list<struct waybar_output> outputs_;
};

View File

@@ -38,6 +38,9 @@
#endif
#if defined(HAVE_CPU_LINUX) || defined(HAVE_CPU_BSD)
#include "modules/cpu.hpp"
#include "modules/cpu_frequency.hpp"
#include "modules/cpu_usage.hpp"
#include "modules/load.hpp"
#endif
#include "modules/idle_inhibitor.hpp"
#if defined(HAVE_MEMORY_LINUX) || defined(HAVE_MEMORY_BSD)

View File

@@ -5,18 +5,31 @@
#include <json/json.h>
#include "AModule.hpp"
#include "bar.hpp"
#include "factory.hpp"
#include "gtkmm/revealer.h"
namespace waybar {
class Group : public AModule {
public:
Group(const std::string&, const std::string&, const Json::Value&, bool);
~Group() = default;
virtual ~Group() = default;
auto update() -> void override;
operator Gtk::Widget&() override;
virtual Gtk::Box& getBox();
void addWidget(Gtk::Widget& widget);
bool handleMouseHover(GdkEventCrossing* const& e);
protected:
Gtk::Box box;
Gtk::Box revealer_box;
Gtk::Revealer revealer;
bool is_first_widget = true;
bool is_drawer = false;
std::string add_class_to_drawer_children;
void addHoverHandlerTo(Gtk::Widget& widget);
};
} // namespace waybar

View File

@@ -1,14 +1,14 @@
#pragma once
#include <memory>
#include <optional>
#include <string>
#include <string_view>
#include <vector>
#include "ALabel.hpp"
#include "giomm/dbusproxy.h"
#include "util/backlight_backend.hpp"
#include "util/json.hpp"
#include "util/sleeper_thread.hpp"
struct udev;
struct udev_device;
@@ -16,54 +16,17 @@ struct udev_device;
namespace waybar::modules {
class Backlight : public ALabel {
class BacklightDev {
public:
BacklightDev() = default;
BacklightDev(std::string name, int actual, int max, bool powered);
std::string_view name() const;
int get_actual() const;
void set_actual(int actual);
int get_max() const;
void set_max(int max);
bool get_powered() const;
void set_powered(bool powered);
friend inline bool operator==(const BacklightDev &lhs, const BacklightDev &rhs) {
return lhs.name_ == rhs.name_ && lhs.actual_ == rhs.actual_ && lhs.max_ == rhs.max_;
}
private:
std::string name_;
int actual_ = 1;
int max_ = 1;
bool powered_ = true;
};
public:
Backlight(const std::string &, const Json::Value &);
virtual ~Backlight();
virtual ~Backlight() = default;
auto update() -> void override;
private:
template <class ForwardIt>
static const BacklightDev *best_device(ForwardIt first, ForwardIt last, std::string_view);
template <class ForwardIt, class Inserter>
static void upsert_device(ForwardIt first, ForwardIt last, Inserter inserter, udev_device *dev);
template <class ForwardIt, class Inserter>
static void enumerate_devices(ForwardIt first, ForwardIt last, Inserter inserter, udev *udev);
bool handleScroll(GdkEventScroll *e) override;
const std::string preferred_device_;
static constexpr int EPOLL_MAX_EVENTS = 16;
std::optional<BacklightDev> previous_best_;
std::string previous_format_;
std::mutex udev_thread_mutex_;
std::vector<BacklightDev> devices_;
// thread must destruct before shared data
util::SleeperThread udev_thread_;
Glib::RefPtr<Gio::DBus::Proxy> login_proxy_;
util::BacklightBackend backend;
};
} // namespace waybar::modules

View File

@@ -0,0 +1,24 @@
#pragma once
#include <chrono>
#include "ASlider.hpp"
#include "util/backlight_backend.hpp"
namespace waybar::modules {
class BacklightSlider : public ASlider {
public:
BacklightSlider(const std::string&, const Json::Value&);
virtual ~BacklightSlider() = default;
void update() override;
void onValueChanged() override;
private:
std::chrono::milliseconds interval_;
std::string preferred_device_;
util::BacklightBackend backend;
};
} // namespace waybar::modules

View File

@@ -59,7 +59,8 @@ class Bluetooth : public ALabel {
auto getDeviceProperties(GDBusObject*, DeviceInfo&) -> bool;
auto getControllerProperties(GDBusObject*, ControllerInfo&) -> bool;
auto findCurController(ControllerInfo&) -> bool;
// Returns std::nullopt if no controller could be found
auto findCurController() -> std::optional<ControllerInfo>;
auto findConnectedDevices(const std::string&, std::vector<DeviceInfo>&) -> void;
#ifdef WANT_RFKILL
@@ -68,7 +69,7 @@ class Bluetooth : public ALabel {
const std::unique_ptr<GDBusObjectManager, void (*)(GDBusObjectManager*)> manager_;
std::string state_;
ControllerInfo cur_controller_;
std::optional<ControllerInfo> cur_controller_;
std::vector<DeviceInfo> connected_devices_;
DeviceInfo cur_focussed_device_;
std::string device_enumerate_;

View File

@@ -3,9 +3,11 @@
#include "ALabel.hpp"
#include "util/sleeper_thread.hpp"
namespace cava {
extern "C" {
#include <cava/common.h>
}
} // namespace cava
namespace waybar::modules {
using namespace std::literals::chrono_literals;
@@ -21,13 +23,13 @@ class Cava final : public ALabel {
util::SleeperThread thread_;
util::SleeperThread thread_fetch_input_;
struct error_s error_ {}; // cava errors
struct config_params prm_ {}; // cava parameters
struct audio_raw audio_raw_ {}; // cava handled raw audio data(is based on audio_data)
struct audio_data audio_data_ {}; // cava audio data
struct cava_plan* plan_; //{new cava_plan{}};
struct cava::error_s error_ {}; // cava errors
struct cava::config_params prm_ {}; // cava parameters
struct cava::audio_raw audio_raw_ {}; // cava handled raw audio data(is based on audio_data)
struct cava::audio_data audio_data_ {}; // cava audio data
struct cava::cava_plan* plan_; //{new cava_plan{}};
// Cava API to read audio source
ptr input_source_;
cava::ptr input_source_;
// Delay to handle audio source
std::chrono::milliseconds frame_time_milsec_{1s};
// Text to display
@@ -36,6 +38,7 @@ class Cava final : public ALabel {
std::chrono::seconds fetch_input_delay_{4};
std::chrono::seconds suspend_silence_delay_{0};
bool silence_{false};
bool hide_on_silence_{false};
int sleep_counter_{0};
// Cava method
void pause_resume();

View File

@@ -21,12 +21,6 @@ class Cpu : public ALabel {
auto update() -> void override;
private:
double getCpuLoad();
std::tuple<std::vector<uint16_t>, std::string> getCpuUsage();
std::tuple<float, float, float> getCpuFrequency();
std::vector<std::tuple<size_t, size_t>> parseCpuinfo();
std::vector<float> parseCpuFrequencies();
std::vector<std::tuple<size_t, size_t>> prev_times_;
util::SleeperThread thread_;

View File

@@ -0,0 +1,32 @@
#pragma once
#include <fmt/format.h>
#include <cstdint>
#include <fstream>
#include <numeric>
#include <string>
#include <utility>
#include <vector>
#include "ALabel.hpp"
#include "util/sleeper_thread.hpp"
namespace waybar::modules {
class CpuFrequency : public ALabel {
public:
CpuFrequency(const std::string&, const Json::Value&);
virtual ~CpuFrequency() = default;
auto update() -> void override;
// This is a static member because it is also used by the cpu module.
static std::tuple<float, float, float> getCpuFrequency();
private:
static std::vector<float> parseCpuFrequencies();
util::SleeperThread thread_;
};
} // namespace waybar::modules

View File

@@ -0,0 +1,35 @@
#pragma once
#include <fmt/format.h>
#include <cstdint>
#include <fstream>
#include <numeric>
#include <string>
#include <utility>
#include <vector>
#include "ALabel.hpp"
#include "util/sleeper_thread.hpp"
namespace waybar::modules {
class CpuUsage : public ALabel {
public:
CpuUsage(const std::string&, const Json::Value&);
virtual ~CpuUsage() = default;
auto update() -> void override;
// This is a static member because it is also used by the cpu module.
static std::tuple<std::vector<uint16_t>, std::string> getCpuUsage(
std::vector<std::tuple<size_t, size_t>>&);
private:
static std::vector<std::tuple<size_t, size_t>> parseCpuinfo();
std::vector<std::tuple<size_t, size_t>> prev_times_;
util::SleeperThread thread_;
};
} // namespace waybar::modules

View File

@@ -22,6 +22,7 @@ class Custom : public ALabel {
private:
void delayWorker();
void continuousWorker();
void waitingWorker();
void parseOutputRaw();
void parseOutputJson();
void handleEvent();

View File

@@ -20,6 +20,9 @@ class Disk : public ALabel {
private:
util::SleeperThread thread_;
std::string path_;
std::string unit_;
float calc_specific_divisor(const std::string divisor);
};
} // namespace waybar::modules

View File

@@ -1,10 +1,12 @@
#pragma once
#include <functional>
#include <list>
#include <memory>
#include <mutex>
#include <string>
#include <thread>
#include <utility>
#include "util/json.hpp"

View File

@@ -1,5 +1,9 @@
#pragma once
#include <fmt/format.h>
#include <string>
#include "ALabel.hpp"
#include "bar.hpp"
#include "modules/hyprland/backend.hpp"

View File

@@ -1,5 +1,9 @@
#pragma once
#include <fmt/format.h>
#include <string>
#include "ALabel.hpp"
#include "bar.hpp"
#include "modules/hyprland/backend.hpp"

View File

@@ -1,5 +1,9 @@
#pragma once
#include <fmt/format.h>
#include <string>
#include "AAppIconLabel.hpp"
#include "bar.hpp"
#include "modules/hyprland/backend.hpp"
@@ -10,7 +14,7 @@ namespace waybar::modules::hyprland {
class Window : public waybar::AAppIconLabel, public EventHandler {
public:
Window(const std::string&, const waybar::Bar&, const Json::Value&);
virtual ~Window();
~Window() override;
auto update() -> void override;

View File

@@ -1,17 +1,67 @@
#pragma once
#include <gtkmm/button.h>
#include <gtkmm/label.h>
#include <json/value.h>
#include <cstddef>
#include <cstdint>
#include <map>
#include <memory>
#include <optional>
#include <regex>
#include <string>
#include <variant>
#include <vector>
#include "AModule.hpp"
#include "bar.hpp"
#include "modules/hyprland/backend.hpp"
#include "util/enum.hpp"
#include "util/regex_collection.hpp"
using WindowAddress = std::string;
namespace waybar::modules::hyprland {
class Workspaces;
class WindowCreationPayload {
public:
WindowCreationPayload(std::string workspace_name, WindowAddress window_address,
std::string window_repr);
WindowCreationPayload(std::string workspace_name, WindowAddress window_address,
std::string window_class, std::string window_title);
WindowCreationPayload(Json::Value const& client_data);
int increment_time_spent_uncreated();
bool is_empty(Workspaces& workspace_manager);
bool repr_is_ready() const { return std::holds_alternative<Repr>(window_); }
std::string repr(Workspaces& workspace_manager);
std::string workspace_name() const { return workspace_name_; }
WindowAddress addr() const { return window_address_; }
void move_to_worksace(std::string& new_workspace_name);
private:
void clear_addr();
void clear_workspace_name();
using Repr = std::string;
using ClassAndTitle = std::pair<std::string, std::string>;
std::variant<Repr, ClassAndTitle> window_;
WindowAddress window_address_;
std::string workspace_name_;
int time_spent_uncreated_ = 0;
};
class Workspace {
public:
Workspace(const Json::Value& workspace_data);
explicit Workspace(const Json::Value& workspace_data, Workspaces& workspace_manager,
const Json::Value& clients_data = Json::Value::nullRef);
std::string& select_icon(std::map<std::string, std::string>& icons_map);
Gtk::Button& button() { return button_; };
@@ -21,16 +71,30 @@ class Workspace {
bool active() const { return active_; };
bool is_special() const { return is_special_; };
bool is_persistent() const { return is_persistent_; };
bool is_visible() const { return is_visible_; };
bool is_empty() const { return windows_ == 0; };
bool is_urgent() const { return is_urgent_; };
auto handle_clicked(GdkEventButton* bt) -> bool;
bool handle_clicked(GdkEventButton* bt) const;
void set_active(bool value = true) { active_ = value; };
void set_persistent(bool value = true) { is_persistent_ = value; };
void set_urgent(bool value = true) { is_urgent_ = value; };
void set_visible(bool value = true) { is_visible_ = value; };
void set_windows(uint value) { windows_ = value; };
void set_name(std::string const& value) { name_ = value; };
bool contains_window(WindowAddress const& addr) const { return window_map_.contains(addr); }
void insert_window(WindowCreationPayload create_window_paylod);
std::string remove_window(WindowAddress const& addr);
void initialize_window_map(const Json::Value& clients_data);
bool on_window_opened(WindowCreationPayload const& create_window_paylod);
std::optional<std::string> close_window(WindowAddress const& addr);
void update(const std::string& format, const std::string& icon);
private:
Workspaces& workspace_manager_;
int id_;
std::string name_;
std::string output_;
@@ -38,6 +102,10 @@ class Workspace {
bool active_ = false;
bool is_special_ = false;
bool is_persistent_ = false;
bool is_urgent_ = false;
bool is_visible_ = false;
std::map<WindowAddress, std::string> window_map_;
Gtk::Button button_;
Gtk::Box content_;
@@ -53,18 +121,57 @@ class Workspaces : public AModule, public EventHandler {
auto all_outputs() const -> bool { return all_outputs_; }
auto show_special() const -> bool { return show_special_; }
auto active_only() const -> bool { return active_only_; }
auto get_bar_output() const -> std::string { return bar_.output->name; }
std::string get_rewrite(std::string window_class, std::string window_title);
std::string& get_window_separator() { return format_window_separator_; }
bool is_workspace_ignored(std::string const& workspace_name);
bool window_rewrite_config_uses_title() const { return any_window_rewrite_rule_uses_title_; }
private:
void onEvent(const std::string&) override;
void onEvent(const std::string& e) override;
void update_window_count();
void sort_workspaces();
void create_workspace(Json::Value& value);
void remove_workspace(std::string name);
void create_workspace(Json::Value const& workspace_data,
Json::Value const& clients_data = Json::Value::nullRef);
void remove_workspace(std::string const& name);
void set_urgent_workspace(std::string const& windowaddress);
void parse_config(const Json::Value& config);
void register_ipc();
// workspace events
void on_workspace_activated(std::string const& payload);
void on_workspace_destroyed(std::string const& payload);
void on_workspace_created(std::string const& payload);
void on_workspace_moved(std::string const& payload);
void on_workspace_renamed(std::string const& payload);
// monitor events
void on_monitor_focused(std::string const& payload);
// window events
void on_window_opened(std::string const& payload);
void on_window_closed(std::string const& payload);
void on_window_moved(std::string const& payload);
void on_window_title_event(std::string const& payload);
int window_rewrite_priority_function(std::string const& window_rule);
bool all_outputs_ = false;
bool show_special_ = false;
bool active_only_ = false;
enum class SORT_METHOD { ID, NAME, NUMBER, DEFAULT };
util::EnumParser<SORT_METHOD> enum_parser_;
SORT_METHOD sort_by_ = SORT_METHOD::DEFAULT;
std::map<std::string, SORT_METHOD> sort_map_ = {{"ID", SORT_METHOD::ID},
{"NAME", SORT_METHOD::NAME},
{"NUMBER", SORT_METHOD::NUMBER},
{"DEFAULT", SORT_METHOD::DEFAULT}};
void fill_persistent_workspaces();
void create_persistent_workspaces();
@@ -72,13 +179,22 @@ class Workspaces : public AModule, public EventHandler {
bool persistent_created_ = false;
std::string format_;
std::map<std::string, std::string> icons_map_;
util::RegexCollection window_rewrite_rules_;
bool any_window_rewrite_rule_uses_title_ = false;
std::string format_window_separator_;
bool with_icon_;
uint64_t monitor_id_;
std::string active_workspace_name_;
std::vector<std::unique_ptr<Workspace>> workspaces_;
std::vector<Json::Value> workspaces_to_create_;
std::vector<std::string> workspaces_to_remove_;
std::vector<WindowCreationPayload> windows_to_create_;
std::vector<std::regex> ignore_workspaces_;
std::mutex mutex_;
const Bar& bar_;
Gtk::Box box_;

View File

@@ -3,6 +3,7 @@
#include <fmt/chrono.h>
#include <gtkmm/label.h>
#include <set>
#include <unordered_map>
#include "AModule.hpp"
@@ -40,6 +41,7 @@ class KeyboardState : public AModule {
struct libinput* libinput_;
std::unordered_map<std::string, struct libinput_device*> libinput_devices_;
std::set<int> binding_keys;
util::SleeperThread libinput_thread_, hotplug_thread_;
};

30
include/modules/load.hpp Normal file
View File

@@ -0,0 +1,30 @@
#pragma once
#include <fmt/format.h>
#include <cstdint>
#include <fstream>
#include <numeric>
#include <string>
#include <utility>
#include <vector>
#include "ALabel.hpp"
#include "util/sleeper_thread.hpp"
namespace waybar::modules {
class Load : public ALabel {
public:
Load(const std::string&, const Json::Value&);
virtual ~Load() = default;
auto update() -> void override;
// This is a static member because it is also used by the cpu module.
static std::tuple<double, double, double> getLoad();
private:
util::SleeperThread thread_;
};
} // namespace waybar::modules

View File

@@ -1,54 +1,27 @@
#pragma once
#include <fmt/format.h>
#include <pulse/pulseaudio.h>
#include <pulse/volume.h>
#include <algorithm>
#include <array>
#include <memory>
#include "ALabel.hpp"
#include "util/audio_backend.hpp"
namespace waybar::modules {
class Pulseaudio : public ALabel {
public:
Pulseaudio(const std::string&, const Json::Value&);
virtual ~Pulseaudio();
virtual ~Pulseaudio() = default;
auto update() -> void override;
private:
static void subscribeCb(pa_context*, pa_subscription_event_type_t, uint32_t, void*);
static void contextStateCb(pa_context*, void*);
static void sinkInfoCb(pa_context*, const pa_sink_info*, int, void*);
static void sourceInfoCb(pa_context*, const pa_source_info* i, int, void* data);
static void serverInfoCb(pa_context*, const pa_server_info*, void*);
static void volumeModifyCb(pa_context*, int, void*);
bool handleScroll(GdkEventScroll* e) override;
const std::vector<std::string> getPulseIcon() const;
pa_threaded_mainloop* mainloop_;
pa_mainloop_api* mainloop_api_;
pa_context* context_;
// SINK
uint32_t sink_idx_{0};
uint16_t volume_;
pa_cvolume pa_volume_;
bool muted_;
std::string port_name_;
std::string form_factor_;
std::string desc_;
std::string monitor_;
std::string current_sink_name_;
bool current_sink_running_;
// SOURCE
uint32_t source_idx_{0};
uint16_t source_volume_;
bool source_muted_;
std::string source_port_name_;
std::string source_desc_;
std::string default_source_name_;
std::shared_ptr<util::AudioBackend> backend = nullptr;
};
} // namespace waybar::modules

View File

@@ -0,0 +1,27 @@
#pragma once
#include <memory>
#include "ASlider.hpp"
#include "util/audio_backend.hpp"
namespace waybar::modules {
enum class PulseaudioSliderTarget {
Sink,
Source,
};
class PulseaudioSlider : public ASlider {
public:
PulseaudioSlider(const std::string&, const Json::Value&);
virtual ~PulseaudioSlider() = default;
void update() override;
void onValueChanged() override;
private:
std::shared_ptr<util::AudioBackend> backend = nullptr;
PulseaudioSliderTarget target = PulseaudioSliderTarget::Sink;
};
} // namespace waybar::modules

View File

@@ -84,6 +84,8 @@ class Item : public sigc::trackable {
// visibility of items with Status == Passive
bool show_passive_ = false;
const Bar& bar_;
Glib::RefPtr<Gio::DBus::Proxy> proxy_;
Glib::RefPtr<Gio::Cancellable> cancellable_;
std::set<std::string_view> update_pending_;

View File

@@ -69,7 +69,7 @@ class UPower : public AModule {
UpDevice *displayDevice;
guint login1_id;
GDBusConnection *login1_connection;
UPowerTooltip *upower_tooltip;
std::unique_ptr<UPowerTooltip> upower_tooltip;
std::string lastStatus;
bool showAltText;
bool upowerRunning;

View File

@@ -2,6 +2,7 @@
#include <libupower-glib/upower.h>
#include <memory>
#include <unordered_map>
#include "gtkmm/box.h"
@@ -16,7 +17,7 @@ class UPowerTooltip : public Gtk::Window {
const std::string getDeviceIcon(UpDeviceKind& kind);
Gtk::Box* contentBox;
std::unique_ptr<Gtk::Box> contentBox;
uint iconSize;
uint tooltipSpacing;

View File

@@ -0,0 +1,95 @@
#pragma once
#include <json/value.h>
#include <pulse/context.h>
#include <pulse/introspect.h>
#include <pulse/thread-mainloop.h>
#include <pulse/volume.h>
#include <functional>
#include <memory>
#include <string>
#include "util/backend_common.hpp"
namespace waybar::util {
class AudioBackend {
private:
static void subscribeCb(pa_context*, pa_subscription_event_type_t, uint32_t, void*);
static void contextStateCb(pa_context*, void*);
static void sinkInfoCb(pa_context*, const pa_sink_info*, int, void*);
static void sourceInfoCb(pa_context*, const pa_source_info* i, int, void* data);
static void serverInfoCb(pa_context*, const pa_server_info*, void*);
static void volumeModifyCb(pa_context*, int, void*);
pa_threaded_mainloop* mainloop_;
pa_mainloop_api* mainloop_api_;
pa_context* context_;
pa_cvolume pa_volume_;
// SINK
uint32_t sink_idx_{0};
uint16_t volume_;
bool muted_;
std::string port_name_;
std::string form_factor_;
std::string desc_;
std::string monitor_;
std::string current_sink_name_;
bool current_sink_running_;
// SOURCE
uint32_t source_idx_{0};
uint16_t source_volume_;
bool source_muted_;
std::string source_port_name_;
std::string source_desc_;
std::string default_source_name_;
std::vector<std::string> ignored_sinks_;
std::function<void()> on_updated_cb_ = NOOP;
/* Hack to keep constructor inaccessible but still public.
* This is required to be able to use std::make_shared.
* It is important to keep this class only accessible via a reference-counted
* pointer because the destructor will manually free memory, and this could be
* a problem with C++20's copy and move semantics.
*/
struct private_constructor_tag {};
public:
static std::shared_ptr<AudioBackend> getInstance(std::function<void()> on_updated_cb = NOOP);
AudioBackend(std::function<void()> on_updated_cb, private_constructor_tag tag);
~AudioBackend();
void changeVolume(uint16_t volume, uint16_t min_volume = 0, uint16_t max_volume = 100);
void changeVolume(ChangeType change_type, double step = 1, uint16_t max_volume = 100);
void setIgnoredSinks(const Json::Value& config);
std::string getSinkPortName() const { return port_name_; }
std::string getFormFactor() const { return form_factor_; }
std::string getSinkDesc() const { return desc_; }
std::string getMonitor() const { return monitor_; }
std::string getCurrentSinkName() const { return current_sink_name_; }
bool getCurrentSinkRunning() const { return current_sink_running_; }
uint16_t getSinkVolume() const { return volume_; }
bool getSinkMuted() const { return muted_; }
uint16_t getSourceVolume() const { return source_volume_; }
bool getSourceMuted() const { return source_muted_; }
std::string getSourcePortName() const { return source_port_name_; }
std::string getSourceDesc() const { return source_desc_; }
std::string getDefaultSourceName() const { return default_source_name_; }
void toggleSinkMute();
void toggleSinkMute(bool);
void toggleSourceMute();
void toggleSourceMute(bool);
bool isBluetooth();
};
} // namespace waybar::util

View File

@@ -0,0 +1,10 @@
#pragma once
#include "AModule.hpp"
namespace waybar::util {
const static auto NOOP = []() {};
enum class ChangeType : char { Increase, Decrease };
} // namespace waybar::util

View File

@@ -0,0 +1,93 @@
#pragma once
#include <libudev.h>
#include <spdlog/spdlog.h>
#include <chrono>
#include <mutex>
#include <optional>
#include <string>
#include <string_view>
#include <vector>
#include "giomm/dbusproxy.h"
#include "util/backend_common.hpp"
#include "util/sleeper_thread.hpp"
#define GET_BEST_DEVICE(varname, backend, preferred_device) \
decltype((backend).devices_) __devices; \
{ \
std::scoped_lock<std::mutex> lock((backend).udev_thread_mutex_); \
__devices = (backend).devices_; \
} \
auto varname = (backend).best_device(__devices.cbegin(), __devices.cend(), preferred_device);
namespace waybar::util {
class BacklightDevice {
public:
BacklightDevice() = default;
BacklightDevice(std::string name, int actual, int max, bool powered);
std::string name() const;
int get_actual() const;
void set_actual(int actual);
int get_max() const;
void set_max(int max);
bool get_powered() const;
void set_powered(bool powered);
friend inline bool operator==(const BacklightDevice &lhs, const BacklightDevice &rhs) {
return lhs.name_ == rhs.name_ && lhs.actual_ == rhs.actual_ && lhs.max_ == rhs.max_;
}
private:
std::string name_;
int actual_ = 1;
int max_ = 1;
bool powered_ = true;
};
class BacklightBackend {
public:
BacklightBackend(std::chrono::milliseconds interval, std::function<void()> on_updated_cb = NOOP);
// const inline BacklightDevice *get_best_device(std::string_view preferred_device);
const BacklightDevice *get_previous_best_device();
void set_previous_best_device(const BacklightDevice *device);
void set_brightness(std::string preferred_device, ChangeType change_type, double step);
void set_scaled_brightness(std::string preferred_device, int brightness);
int get_scaled_brightness(std::string preferred_device);
template <class ForwardIt, class Inserter>
static void upsert_device(ForwardIt first, ForwardIt last, Inserter inserter, udev_device *dev);
template <class ForwardIt, class Inserter>
static void enumerate_devices(ForwardIt first, ForwardIt last, Inserter inserter, udev *udev);
bool is_login_proxy_initialized() const { return static_cast<bool>(login_proxy_); }
template <class ForwardIt>
static const BacklightDevice *best_device(ForwardIt first, ForwardIt last, std::string_view);
std::vector<BacklightDevice> devices_;
std::mutex udev_thread_mutex_;
private:
void set_brightness_internal(std::string device_name, int brightness, int max_brightness);
std::function<void()> on_updated_cb_;
std::chrono::milliseconds polling_interval_;
std::optional<BacklightDevice> previous_best_;
// thread must destruct before shared data
util::SleeperThread udev_thread_;
Glib::RefPtr<Gio::DBus::Proxy> login_proxy_;
static constexpr int EPOLL_MAX_EVENTS = 16;
};
} // namespace waybar::util

View File

@@ -112,6 +112,10 @@ inline FILE* open(const std::string& cmd, int& pid) {
execlp("/bin/sh", "sh", "-c", cmd.c_str(), (char*)0);
exit(0);
} else {
reap_mtx.lock();
reap.push_back(child_pid);
reap_mtx.unlock();
::close(fd[1]);
}
pid = child_pid;

19
include/util/enum.hpp Normal file
View File

@@ -0,0 +1,19 @@
#pragma once
#include <map>
#include <stdexcept>
#include <string>
namespace waybar::util {
template <typename EnumType>
struct EnumParser {
public:
EnumParser();
~EnumParser();
EnumType parseStringToEnum(const std::string& str,
const std::map<std::string, EnumType>& enumMap);
};
} // namespace waybar::util

View File

@@ -93,7 +93,7 @@ template <>
struct formatter<Glib::ustring> : formatter<std::string> {
template <typename FormatContext>
auto format(const Glib::ustring& value, FormatContext& ctx) {
return formatter<std::string>::format(value, ctx);
return formatter<std::string>::format(static_cast<std::string>(value), ctx);
}
};
} // namespace fmt

38
include/util/portal.hpp Normal file
View File

@@ -0,0 +1,38 @@
#include <giomm/dbusproxy.h>
#include <string>
#include "fmt/format.h"
namespace waybar {
using namespace Gio;
enum class Appearance {
UNKNOWN = 0,
DARK = 1,
LIGHT = 2,
};
class Portal : private DBus::Proxy {
public:
Portal();
void refreshAppearance();
Appearance getAppearance();
typedef sigc::signal<void, Appearance> type_signal_appearance_changed;
type_signal_appearance_changed signal_appearance_changed() { return m_signal_appearance_changed; }
private:
type_signal_appearance_changed m_signal_appearance_changed;
Appearance currentMode;
void on_signal(const Glib::ustring& sender_name, const Glib::ustring& signal_name,
const Glib::VariantContainerBase& parameters);
};
} // namespace waybar
template <>
struct fmt::formatter<waybar::Appearance> : formatter<fmt::string_view> {
// parse is inherited from formatter<string_view>.
auto format(waybar::Appearance c, format_context& ctx) const;
};

View File

@@ -0,0 +1,51 @@
#pragma once
#include <json/json.h>
#include <functional>
#include <regex>
#include <string>
namespace waybar::util {
struct Rule {
std::regex rule;
std::string repr;
int priority;
// Fix for Clang < 16
// See https://en.cppreference.com/w/cpp/compiler_support/20 "Parenthesized initialization of
// aggregates"
Rule(std::regex rule, std::string repr, int priority)
: rule(rule), repr(repr), priority(priority) {}
};
int default_priority_function(std::string& key);
/* A collection of regexes and strings, with a default string to return if no regexes.
* When a regex is matched, the corresponding string is returned.
* All regexes that are matched are cached, so that the regexes are only
* evaluated once against a given string.
* Regexes may be given a higher priority than others, so that they are matched
* first. The priority function is given the regex string, and should return a
* higher number for higher priority regexes.
*/
class RegexCollection {
private:
std::vector<Rule> rules;
std::map<std::string, std::string> regex_cache;
std::string default_repr;
std::string& find_match(std::string& value, bool& matched_any);
public:
RegexCollection() = default;
RegexCollection(const Json::Value& map, std::string default_repr = "",
std::function<int(std::string&)> priority_function = default_priority_function);
~RegexCollection() = default;
std::string& get(std::string& value, bool& matched_any);
std::string& get(std::string& value);
};
} // namespace waybar::util

View File

@@ -5,4 +5,6 @@
namespace waybar::util {
std::string rewriteString(const std::string&, const Json::Value&);
}
std::string rewriteStringOnce(const std::string& value, const Json::Value& rules,
bool& matched_any);
} // namespace waybar::util

View File

@@ -0,0 +1,21 @@
#pragma once
#include <utility>
namespace waybar::util {
template <typename Func>
class ScopeGuard {
public:
explicit ScopeGuard(Func&& exit_function) : f{std::forward<Func>(exit_function)} {}
ScopeGuard(const ScopeGuard&) = delete;
ScopeGuard(ScopeGuard&&) = default;
ScopeGuard& operator=(const ScopeGuard&) = delete;
ScopeGuard& operator=(ScopeGuard&&) = default;
~ScopeGuard() { f(); }
private:
Func f;
};
} // namespace waybar::util

View File

@@ -58,10 +58,22 @@ class SleeperThread {
bool isRunning() const { return do_run_; }
auto sleep() {
std::unique_lock lk(mutex_);
CancellationGuard cancel_lock;
return condvar_.wait(lk, [this] { return signal_ || !do_run_; });
}
auto sleep_for(std::chrono::system_clock::duration dur) {
std::unique_lock lk(mutex_);
CancellationGuard cancel_lock;
return condvar_.wait_for(lk, dur, [this] { return signal_ || !do_run_; });
constexpr auto max_time_point = std::chrono::steady_clock::time_point::max();
auto wait_end = max_time_point;
auto now = std::chrono::steady_clock::now();
if (now < max_time_point - dur) {
wait_end = now + dur;
}
return condvar_.wait_until(lk, wait_end, [this] { return signal_ || !do_run_; });
}
auto sleep_until(

View File

@@ -1,5 +1,6 @@
#pragma once
#include <iostream>
#include <string>
const std::string WHITESPACE = " \n\r\t\f\v";
@@ -15,3 +16,10 @@ inline std::string rtrim(const std::string& s) {
}
inline std::string trim(const std::string& s) { return rtrim(ltrim(s)); }
inline std::string capitalize(const std::string& str) {
std::string result = str;
std::transform(result.begin(), result.end(), result.begin(),
[](unsigned char c) { return std::toupper(c); });
return result;
}

View File

@@ -0,0 +1,88 @@
waybar-backlight-slider(5)
# NAME
waybar - backlight slider module
# DESCRIPTION
The *backlight slider* module displays and controls the current brightness of the default or preferred device.
The brightness can be controlled by dragging the slider across the bar or clicking on a specific position.
# CONFIGURATION
*min*: ++
typeof: int ++
default: 0 ++
The minimum volume value the slider should display and set.
*max*: ++
typeof: int ++
default: 100 ++
The maximum volume value the slider should display and set.
*orientation*: ++
typeof: string ++
default: horizontal ++
The orientation of the slider. Can be either `horizontal` or `vertical`.
*device*: ++
typeof: string ++
The name of the preferred device to control. If left empty, a device will be chosen automatically.
# EXAMPLES
```
"modules-right": [
"backlight-slider",
],
"backlight/slider": {
"min": 0,
"max": 100,
"orientation": "horizontal",
"device": "intel_backlight"
}
```
# STYLE
The slider is a component with multiple CSS Nodes, of which the following are exposed:
*#backlight-slider*: ++
Controls the style of the box *around* the slider and bar.
*#backlight-slider slider*: ++
Controls the style of the slider handle.
*#backlight-slider trough*: ++
Controls the style of the part of the bar that has not been filled.
*#backlight-slider highlight*: ++
Controls the style of the part of the bar that has been filled.
## STYLE EXAMPLE
```
#backlight-slider slider {
min-height: 0px;
min-width: 0px;
opacity: 0;
background-image: none;
border: none;
box-shadow: none;
}
#backlight-slider trough {
min-height: 80px;
min-width: 10px;
border-radius: 5px;
background-color: black;
}
#backlight-slider highlight {
min-width: 10px;
border-radius: 5px;
background-color: red;
}
```

View File

@@ -26,7 +26,7 @@ The *backlight* module displays the current backlight level.
*min-length*: ++
typeof: integer ++
The minimum length in characters the module should take up.
The minimum length in characters the module should accept.
*align*: ++
typeof: float ++
@@ -46,11 +46,11 @@ The *backlight* module displays the current backlight level.
*on-click-middle*: ++
typeof: string ++
Command to execute when middle-clicked on the module using mousewheel.
Command to execute when middle-clicked on the module using mouse scroll wheel.
*on-click-right*: ++
typeof: string ++
Command to execute when the module is right clicked.
Command to execute when the module is right-clicked.
*on-update*: ++
typeof: string ++
@@ -75,7 +75,7 @@ The *backlight* module displays the current backlight level.
*scroll-step*: ++
typeof: float ++
default: 1.0 ++
The speed in which to change the brightness when scrolling.
The speed at which to change the brightness when scrolling.
# EXAMPLE:

View File

@@ -25,7 +25,7 @@ The *battery* module displays the current capacity and state (eg. charging) of y
*design-capacity*: ++
typeof: bool ++
default: false ++
Option to use the battery design capacity instead of it's current maximal capacity.
Option to use the battery design capacity instead of its current maximal capacity.
*interval*: ++
typeof: integer ++
@@ -57,7 +57,7 @@ The *battery* module displays the current capacity and state (eg. charging) of y
*min-length*: ++
typeof: integer ++
The minimum length in characters the module should take up.
The minimum length in characters the module should accept.
*align*: ++
typeof: float ++
@@ -77,7 +77,7 @@ The *battery* module displays the current capacity and state (eg. charging) of y
*on-click-right*: ++
typeof: string ++
Command to execute when you right clicked on the module.
Command to execute when you right-click on the module.
*on-update*: ++
typeof: string ++
@@ -100,6 +100,11 @@ The *battery* module displays the current capacity and state (eg. charging) of y
default: true ++
Option to disable tooltip on hover.
*bat-compatibility*: ++
typeof: bool ++
default: false ++
Option to enable battery compatibility if not detected.
# FORMAT REPLACEMENTS
*{capacity}*: Capacity in percentage
@@ -121,7 +126,7 @@ The three arguments are:
# CUSTOM FORMATS
The *battery* module allows one to define custom formats based on up to two factors. The best fitting format will be selected.
The *battery* module allows one to define custom formats based on up to two factors. The best-fitting format will be selected.
*format-<state>*: With *states*, a custom format can be set depending on the capacity of your battery.
@@ -132,8 +137,8 @@ The *battery* module allows one to define custom formats based on up to two fact
# STATES
- Every entry (*state*) consists of a *<name>* (typeof: *string*) and a *<value>* (typeof: *integer*).
- The state can be addressed as a CSS class in the *style.css*. The name of the CSS class is the *<name>* of the state. Each class gets activated when the current capacity is equal or below the configured *<value>*.
- Also each state can have its own *format*. Those con be configured via *format-<name>*. Or if you want to differentiate a bit more even as *format-<status>-<state>*. For more information see *custom-formats*.
- The state can be addressed as a CSS class in the *style.css*. The name of the CSS class is the *<name>* of the state. Each class gets activated when the current capacity is equal to or below the configured *<value>*.
- Also each state can have its own *format*. Those can be configured via *format-<name>*. Or if you want to differentiate a bit more even as *format-<status>-<state>*. For more information see *custom-formats*.

View File

@@ -14,7 +14,7 @@ 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.
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 ++
@@ -42,6 +42,10 @@ Addressed by *bluetooth*
typeof: string ++
This format is used when the displayed controller is connected to at least 1 device.
*format-no-controller*: ++
typeof: string ++
This format is used when no bluetooth controller can be found
*format-icons*: ++
typeof: array/object ++
Based on the current battery percentage (see section *EXPERIMENTAL BATTERY PERCENTAGE FEATURE*), the corresponding icon gets selected. ++
@@ -58,7 +62,7 @@ Addressed by *bluetooth*
*min-length*: ++
typeof: integer ++
The minimum length in characters the module should take up.
The minimum length in characters the module should accept.
*align*: ++
typeof: float ++
@@ -74,7 +78,7 @@ Addressed by *bluetooth*
*on-click-right*: ++
typeof: string ++
Command to execute when you right clicked on the module.
Command to execute when you right-click on the module.
*on-scroll-up*: ++
typeof: string ++
@@ -113,6 +117,10 @@ Addressed by *bluetooth*
typeof: string ++
This format is used when the displayed controller is connected to at least 1 device.
*tooltip-format-no-controller*: ++
typeof: string ++
This format is used when no bluetooth controller can be found
*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.
@@ -138,7 +146,7 @@ Addressed by *bluetooth*
*{device_alias}*: Alias of the displayed device.
*{device_enumerate}*: Show a list of all connected devices, each on a separate 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.
and/or *tooltip-format-enumerate-connected-battery* config options. Can only be used in the tooltip-related format options.
# EXPERIMENTAL BATTERY PERCENTAGE FEATURE

View File

@@ -35,7 +35,7 @@ libcava lives in:
|[ *framerate*
:[ integer
:[ 30
:[ rames per second. Is used as a replacement for *interval*
:[ Frames per second. Is used as a replacement for *interval*
|[ *autosens*
:[ integer
:[ 1
@@ -60,6 +60,10 @@ libcava lives in:
:[ integer
:[ 5
:[ Seconds with no input before cava main thread goes to sleep mode
|[ *hide_on_silence*
:[ bool
:[ false
:[ Hides the widget if no input (after sleep_timer elapsed)
|[ *method*
:[ string
:[ pulse
@@ -91,19 +95,19 @@ libcava lives in:
|[ *monstercat*
:[ bool
:[ false
:[ Disables or enables the so-called "Monstercat smoothing" with of without "waves"
:[ Disables or enables the so-called "Monstercat smoothing" with or without "waves"
|[ *waves*
:[ bool
:[ false
:[ Disables or enables the so-called "Monstercat smoothing" with of without "waves"
:[ Disables or enables the so-called "Monstercat smoothing" with or without "waves"
|[ *noise_reduction*
:[ double
:[ 0.77
:[ Range between 0 - 1. The raw visualization is very noisy, this factor adjust the integral and gravity filters to keep the signal smooth. 1 - will be very slow and smooth, 0 - will be fast but noisy
:[ Range between 0 - 1. The raw visualization is very noisy, this factor adjusts the integral and gravity filters to keep the signal smooth. 1 - will be very slow and smooth, 0 - will be fast but noisy
|[ *input_delay*
:[ integer
:[ 2
:[ Sets the delay before fetching audio source thread start working. On author machine Waybar starts much faster then pipewire audio server, and without a little delay cava module fails due to pipewire is not ready
:[ Sets the delay before fetching audio source thread start working. On author's machine, Waybar starts much faster than pipewire audio server, and without a little delay cava module fails because pipewire is not ready
|[ *ascii_max_range*
:[ integer
:[ 7
@@ -120,14 +124,14 @@ libcava lives in:
Configuration can be provided as:
- The only cava configuration file which is provided through *cava_config*. The rest configuration can be skipped
- Without cava configuration file. In such case cava should be configured through provided list of the configuration option
- Mix. When provided both And cava configuration file And configuration options. In such case waybar applies configuration file first then overrides particular options by the provided list of configuration options
- Mix. When provided both And cava configuration file And configuration options. In such case, waybar applies configuration file first and then overrides particular options by the provided list of configuration options
# ACTIONS
[- *String*
:- *Action*
|[ *mode*
:< Switch main cava thread and fetching audio source thread from/to pause/resume
:< Switch main cava thread and fetch audio source thread from/to pause/resume
# DEPENDENCIES
@@ -138,16 +142,16 @@ Configuration can be provided as:
. On start Waybar throws an exception "error while loading shared libraries: libcava.so: cannot open shared object file: No such file or directory".
It might happen when libcava for some reason hasn't been registered in the system. sudo ldconfig should help
. Waybar is starting but cava module doesn't react on the music
1. In such case for at first need to make sure usual cava application is working as well
. Waybar is starting but cava module doesn't react to the music
1. In such cases at first need to make sure usual cava application is working as well
2. If so, need to comment all configuration options. Uncomment cava_config and provide the path to the working cava config
3. You might set too huge or too small input_delay. Try to setup to 4 seconds, restart waybar and check again 4 seconds past. Usual even on weak machines it should be enough
4. You might accidentally switched action mode to pause mode
3. You might set too huge or too small input_delay. Try to setup to 4 seconds, restart waybar, and check again 4 seconds past. Usual even on weak machines it should be enough
4. You might accidentally switch action mode to pause mode
# RISING ISSUES
For clear understanding: this module is a cava API's consumer. So for any bugs related to cava engine you should contact to Cava upstream(https://github.com/karlstav/cava) ++
with the one Exception. Cava upstream doesn't provide cava as a shared library. For that this module author made a fork libcava(https://github.com/LukashonakV/cava). ++
For clear understanding: this module is a cava API's consumer. So for any bugs related to cava engine you should contact Cava upstream(https://github.com/karlstav/cava) ++
with the one Exception. Cava upstream doesn't provide cava as a shared library. For that, this module author made a fork libcava(https://github.com/LukashonakV/cava). ++
So the order is:
. cava upstream
. libcava upstream.

View File

@@ -63,7 +63,7 @@ $XDG_CONFIG_HOME/waybar/config ++
|[ *on-click-right*
:[ string
:[
:[ Command to execute when you right clicked on the module
:[ Command to execute when you right-click on the module
|[ *on-scroll-up*
:[ string
:[
@@ -147,7 +147,7 @@ View all valid format options in *strftime(3)* or have a look <https://fmt.dev/l
|[ *tz_up*
:[ Switch to the next provided time zone
|[ *tz_down*
:[ Switch to the previous provided time zone
:[ Switch to the previously provided time zone
|[ *shift_up*
:[ Switch to the next calendar month/year
|[ *shift_down*
@@ -219,7 +219,7 @@ View all valid format options in *strftime(3)* or have a look <https://fmt.dev/l
# Troubleshooting
If clock module is disabled at startup with locale::facet::\_S\_create\_c\_locale ++
name not valid error message try one of the followings:
name not valid error message try one of the following:
- check if LC_TIME is set properly (glibc)
- set locale to C in the config file (musl)

View File

@@ -6,7 +6,7 @@ waybar - cpu module
# DESCRIPTION
The *cpu* module displays the current cpu utilization.
The *cpu* module displays the current CPU utilization.
# CONFIGURATION
@@ -31,7 +31,7 @@ The *cpu* module displays the current cpu utilization.
*min-length*: ++
typeof: integer ++
The minimum length in characters the module should take up.
The minimum length in characters the module should accept.
*align*: ++
typeof: float ++
@@ -43,7 +43,7 @@ The *cpu* module displays the current cpu utilization.
*states*: ++
typeof: object ++
A number of cpu usage states which get activated on certain usage levels. See *waybar-states(5)*.
A number of CPU usage states which get activated on certain usage levels. See *waybar-states(5)*.
*on-click*: ++
typeof: string ++
@@ -55,7 +55,7 @@ The *cpu* module displays the current cpu utilization.
*on-click-right*: ++
typeof: string ++
Command to execute when you right clicked on the module.
Command to execute when you right-click on the module.
*on-update*: ++
typeof: string ++
@@ -80,21 +80,21 @@ The *cpu* module displays the current cpu utilization.
# FORMAT REPLACEMENTS
*{load}*: Current cpu load.
*{load}*: Current CPU load.
*{usage}*: Current overall cpu usage.
*{usage}*: Current overall CPU usage.
*{usage*{n}*}*: Current cpu core n usage. Cores are numbered from zero, so first core will be {usage0} and 4th will be {usage3}.
*{usage*{n}*}*: Current CPU core n usage. Cores are numbered from zero, so first core will be {usage0} and 4th will be {usage3}.
*{avg_frequency}*: Current cpu average frequency (based on all cores) in GHz.
*{avg_frequency}*: Current CPU average frequency (based on all cores) in GHz.
*{max_frequency}*: Current cpu max frequency (based on the core with the highest frequency) in GHz.
*{max_frequency}*: Current CPU max frequency (based on the core with the highest frequency) in GHz.
*{min_frequency}*: Current cpu min frequency (based on the core with the lowest frequency) in GHz.
*{min_frequency}*: Current CPU min frequency (based on the core with the lowest frequency) in GHz.
*{icon}*: Icon for overall cpu usage.
*{icon}*: Icon for overall CPU usage.
*{icon*{n}*}*: Icon for cpu core n usage. Use like {icon0}.
*{icon*{n}*}*: Icon for CPU core n usage. Use like {icon0}.
# EXAMPLES
@@ -108,7 +108,7 @@ Basic configuration:
}
```
Cpu usage per core rendered as icons:
CPU usage per core rendered as icons:
```
"cpu": {

View File

@@ -34,18 +34,20 @@ Addressed by *custom/<name>*
typeof: integer ++
The interval (in seconds) in which the information gets polled. ++
Use *once* if you want to execute the module only on startup. ++
You can update it manually with a signal. If no *interval* is defined, it is assumed that the out script loops it self.
You can update it manually with a signal. If no *interval* or *signal* is defined, it is assumed that the out script loops itself. ++
If a *signal* is defined then the script will run once on startup and will only update with a signal.
*restart-interval*: ++
typeof: integer ++
The restart interval (in seconds). ++
Can't be used with the *interval* option, so only with continuous scripts. ++
Once the script exit, it'll be re-executed after the *restart-interval*.
Once the script exits, it'll be re-executed after the *restart-interval*.
*signal*: ++
typeof: integer ++
The signal number used to update the module. ++
The number is valid between 1 and N, where *SIGRTMIN+N* = *SIGRTMAX*.
The number is valid between 1 and N, where *SIGRTMIN+N* = *SIGRTMAX*. ++
If no interval is defined then a signal will be the only way to update the module.
*format*: ++
typeof: string ++
@@ -66,7 +68,7 @@ Addressed by *custom/<name>*
*min-length*: ++
typeof: integer ++
The minimum length in characters the module should take up.
The minimum length in characters the module should accept.
*align*: ++
typeof: float ++
@@ -82,7 +84,7 @@ Addressed by *custom/<name>*
*on-click-right*: ++
typeof: string ++
Command to execute when you right clicked on the module.
Command to execute when you right-click on the module.
*on-update*: ++
typeof: string ++
@@ -134,7 +136,7 @@ $text\\n$tooltip\\n$class*
*{}*: Output of the script.
*{percentage}* Percentage which can be set via a json return-type.
*{percentage}* Percentage which can be set via a json return type.
*{icon}*: An icon from 'format-icons' according to percentage.

View File

@@ -33,7 +33,7 @@ Addressed by *disk*
*states*: ++
typeof: object ++
A number of disk utilization states which get activated on certain percentage thresholds (percentage_used). See *waybar-states(5)*.
A number of disk utilization states that get activated on certain percentage thresholds (percentage_used). See *waybar-states(5)*.
*max-length*: ++
typeof: integer ++
@@ -41,7 +41,7 @@ Addressed by *disk*
*min-length*: ++
typeof: integer ++
The minimum length in characters the module should take up.
The minimum length in characters the module should accept.
*align*: ++
typeof: float ++
@@ -57,7 +57,7 @@ Addressed by *disk*
*on-click-right*: ++
typeof: string ++
Command to execute when you right clicked on the module.
Command to execute when you right-click on the module.
*on-update*: ++
typeof: string ++
@@ -85,20 +85,30 @@ Addressed by *disk*
default: "{used} out of {total} used ({percentage_used}%)" ++
The format of the information displayed in the tooltip.
*unit*: ++
typeof: string ++
Use with specific_free, specific_used, and specific_total to force calculation to always be in a certain unit. Accepts kB, kiB, MB, Mib, GB, GiB, TB, TiB.
# FORMAT REPLACEMENTS
*{percentage_used}*: Percentage of disk in use.
*{percentage_free}*: Percentage of free disk space
*{total}*: Total amount of space on the disk, partition or mountpoint.
*{total}*: Total amount of space on the disk, partition, or mountpoint. Automatically selects unit based on size remaining.
*{used}*: Amount of used disk space.
*{used}*: Amount of used disk space. Automatically selects unit based on size remaining.
*{free}*: Amount of available disk space for normal users.
*{free}*: Amount of available disk space for normal users. Automatically selects unit based on size remaining.
*{path}*: The path specified in the configuration.
*{specific_total}*: Total amount of space on the disk, partition, or mountpoint in a specific unit. Defaults to bytes.
*{specific_used}*: Amount of used disk space in a specific unit. Defaults to bytes.
*{specific_free}*: Amount of available disk space for normal users in a specific unit. Defaults to bytes.
# EXAMPLES
```
@@ -108,6 +118,15 @@ Addressed by *disk*
}
```
```
"disk": {
"interval": 30,
"format": "{specific_free:0.2f} GB out of {specific_total:0.2f} GB available. Alternatively {free} out of {total} available",
"unit": "GB"
// 1434.25 GB out of 2000.00 GB available. Alternatively 1.4TiB out of 1.9TiB available.
}
```
# STYLE
- *#disk*

View File

@@ -24,7 +24,7 @@ Addressed by *dwl/tags*
*disable-click*: ++
typeof: bool ++
default: false ++
If set to false, you can left click to set focused tag. Right click to toggle tag focus. If set to true this behaviour is disabled.
If set to false, you can left-click to set focused tag. Right-click to toggle tag focus. If set to true this behaviour is disabled.
# EXAMPLE

View File

@@ -65,11 +65,11 @@ Feral Gamemode optimizations.
*{glyph}*: The string icon glyph to use instead.
*{count}*: The amount of games running with gamemode optimizations.
*{count}*: The number of games running with gamemode optimizations.
# TOOLTIP FORMAT REPLACEMENTS
*{count}*: The amount of games running with gamemode optimizations.
*{count}*: The number of games running with gamemode optimizations.
# EXAMPLES

View File

@@ -27,7 +27,7 @@ Addressed by *hyprland/submap*
*min-length*: ++
typeof: integer ++
The minimum length in characters the module should take up.
The minimum length in characters the module should accept.
*align*: ++
typeof: float ++
@@ -43,7 +43,7 @@ Addressed by *hyprland/submap*
*on-click-right*: ++
typeof: string ++
Command to execute when you right clicked on the module.
Command to execute when you right-click on the module.
*on-update*: ++
typeof: string ++

View File

@@ -19,17 +19,51 @@ Addressed by *hyprland/workspaces*
*format-icons*: ++
typeof: array ++
Based on the workspace id and state, the corresponding icon gets selected. See *icons*.
Based on the workspace ID and state, the corresponding icon gets selected. See *icons*.
*window-rewrite*: ++
typeof: object ++
Regex rules to map window class to an icon or preferred method of representation for a workspace's window.
Keys are the rules, while the values are the methods of representation.
Rules may specify `class<...>`, `title<...>`, or both in order to fine-tune the matching.
*window-rewrite-default*:
typeof: string ++
default: "?" ++
The default method of representation for a workspace's window. This will be used for windows whose classes do not match any of the rules in *window-rewrite*.
*format-window-separator*: ++
typeof: string ++
default: " " ++
The separator to be used between windows in a workspace.
*show-special*: ++
typeof: bool ++
default: false ++
If set to true special workspaces will be shown.
If set to true, special workspaces will be shown.
*all-outputs*: ++
typeof: bool ++
default: false ++
If set to false workspaces group will be shown only in assigned output. Otherwise all workspace groups are shown.
If set to false workspaces group will be shown only in assigned output. Otherwise, all workspace groups are shown.
*active-only*: ++
typeof: bool ++
default: false ++
If set to true, only the active workspace will be shown.
*ignore-workspaces*: ++
typeof: array ++
default: [] ++
Regexes to match against workspaces names. If there's a match, the workspace will not be shown. This takes precedence over *show-special*, *all-outputs*, and *active-only*.
*sort-by*: ++
typeof: string ++
default: "default" ++
If set to number, workspaces will sort by number.
If set to name, workspaces will sort by name.
If set to id, workspaces will sort by id.
If none of those, workspaces will sort with default behavior.
# FORMAT REPLACEMENTS
@@ -43,10 +77,12 @@ Addressed by *hyprland/workspaces*
Additional to workspace name matching, the following *format-icons* can be set.
- *default*: Will be shown, when no string match is found.
- *default*: Will be shown, when no string match is found and none of the below conditions have defined icons.
- *active*: Will be shown, when workspace is active
- *special*: Will be shown on non-active special workspaces
- *persistent*: Will be shown on non-active persistent workspaces
- *empty*: Will be shown on non-active, non-special empty persistent workspaces
- *visible*: Will be shown on workspaces that are visible but not active. For example: this is useful if you want your visible workspaces on other monitors to have the same look as active.
- *persistent*: Will be shown on non-empty persistent workspaces
# EXAMPLES
@@ -62,17 +98,62 @@ Additional to workspace name matching, the following *format-icons* can be set.
"active": "",
"default": ""
},
"persistent_workspaces": {
"persistent-workspaces": {
"*": 5, // 5 workspaces by default on every monitor
"HDMI-A-1": 3 // but only three on HDMI-A-1
}
}
```
```
"hyprland/workspaces": {
"format": "{name}: {icon}",
"format-icons": {
"1": "",
"2": "",
"3": "",
"4": "",
"5": "",
"active": "",
"default": ""
},
"persistent-workspaces": {
"*": [ 2,3,4,5 ], // 2-5 on every monitor
"HDMI-A-1": [ 1 ] // but only workspace 1 on HDMI-A-1
}
}
```
```
"hyprland/workspaces": {
"format": "{name}\n{windows}",
"format-window-separator": "\n",
"window-rewrite-default": "",
"window-rewrite": {
"title<.*youtube.*>": "", // Windows whose titles contain "youtube"
"class<firefox>": "", // Windows whose classes are "firefox"
"class<firefox> title<.*github.*>": "", // Windows whose class is "firefox" and title contains "github". Note that "class" always comes first.
"foot": "", // Windows that contain "foot" in either class or title. For optimization reasons, it will only match against a title if at least one other window explicitly matches against a title.
"code": "󰨞",
}
}
```
"hyprland/workspaces": {
// Formatting omitted for brevity
"ignore-workspaces": [
"(special:)?chrome-sharing-indicator"
]
}
```
# Style
- *#workspaces*
- *#workspaces button*
- *#workspaces button.active*
- *#workspaces button.empty*
- *#workspaces button.visible*
- *#workspaces button.persistent*
- *#workspaces button.special*
- *#workspaces button.urgent*

View File

@@ -6,8 +6,8 @@ waybar - idle_inhibitor module
# DESCRIPTION
The *idle_inhibitor* module can inhibiting the idle behavior such as screen blanking, locking, and
screensaving, also known as "presentation mode".
The *idle_inhibitor* module can inhibit the idle behavior such as screen blanking, locking, and
screensaver, also known as "presentation mode".
# CONFIGURATION
@@ -29,7 +29,7 @@ screensaving, also known as "presentation mode".
*min-length*: ++
typeof: integer ++
The minimum length in characters the module should take up.
The minimum length in characters the module should accept.
*align*: ++
typeof: float ++
@@ -45,7 +45,7 @@ screensaving, also known as "presentation mode".
*on-click-right*: ++
typeof: string ++
Command to execute when you right clicked on the module.
Command to execute when you right-click on the module.
*on-update*: ++
typeof: string ++
@@ -70,7 +70,7 @@ screensaving, also known as "presentation mode".
*timeout*: ++
typeof: double ++
The number of minutes the inhibit should last.
The number of minutes the inhibition should last.
*tooltip*: ++
typeof: bool ++

View File

@@ -66,7 +66,7 @@ The *image* module displays an image from a path.
# SCRIPT OUTPUT
Similar to the *custom* module, output values of the script is *newline* separated.
Similar to the *custom* module, output values of the script are *newline* separated.
The following is the output format:
```

View File

@@ -33,7 +33,7 @@ See *systemd-inhibit*(1) for more information.
*min-length*: ++
typeof: integer ++
The minimum length in characters the module should take up.
The minimum length in characters the module should accept.
*align*: ++
typeof: float ++
@@ -49,7 +49,7 @@ See *systemd-inhibit*(1) for more information.
*on-click-right*: ++
typeof: string ++
Command to execute when you right clicked on the module.
Command to execute when you right-click on the module.
*on-update*: ++
typeof: string ++

View File

@@ -27,7 +27,7 @@ Addressed by *jack*
*format-xrun*: ++
typeof: string ++
This format is used for one polling interval, when the JACK server reports an xrun.
This format is used for one polling interval when the JACK server reports an xrun.
*realtime*: ++
typeof: bool ++
@@ -59,7 +59,7 @@ Addressed by *jack*
*min-length*: ++
typeof: integer ++
The minimum length in characters the module should take up.
The minimum length in characters the module should accept.
*align*: ++
typeof: float ++
@@ -75,7 +75,7 @@ Addressed by *jack*
*on-click-right*: ++
typeof: string ++
Command to execute when you right clicked on the module.
Command to execute when you right-click on the module.
*on-update*: ++
typeof: string ++
@@ -87,7 +87,7 @@ Addressed by *jack*
*{bufsize}*: The size of the JACK buffer.
*{samplerate}*: The samplerate at which the JACK server is running.
*{samplerate}*: The sample rate at which the JACK server is running.
*{latency}*: The duration, in ms, of the current buffer size.

View File

@@ -13,7 +13,7 @@ You must be a member of the input group to use this module.
# CONFIGURATION
*interval*: ++
Deprecated, this module use event loop now, the interval has no effect.
Deprecated, this module uses event loop now, the interval has no effect.
typeof: integer ++
default: 1 ++
The interval, in seconds, to poll the keyboard state.
@@ -48,6 +48,11 @@ You must be a member of the input group to use this module.
default: chooses first valid input device ++
Which libevdev input device to show the state of. Libevdev devices can be found in /dev/input. The device should support number lock, caps lock, and scroll lock events.
*binding-keys*: ++
typeof: array ++
default: [58, 69, 70] ++
Customize the key to trigger this module, the key number can be found in /usr/include/linux/input-event-codes.h or running sudo libinput debug-events --show-keycodes.
# FORMAT REPLACEMENTS
*{name}*: Caps, Num, or Scroll.

View File

@@ -41,7 +41,7 @@ Addressed by *memory*
*min-length*: ++
typeof: integer ++
The minimum length in characters the module should take up.
The minimum length in characters the module should accept.
*align*: ++
typeof: float ++
@@ -57,7 +57,7 @@ Addressed by *memory*
*on-click-right*: ++
typeof: string ++
Command to execute when you right clicked on the module.
Command to execute when you right-click on the module.
*on-update*: ++
typeof: string ++

View File

@@ -99,7 +99,7 @@ Addressed by *mpd*
*min-length*: ++
typeof: integer ++
The minimum length in characters the module should take up.
The minimum length in characters the module should accept.
*align*: ++
typeof: float ++
@@ -115,7 +115,7 @@ Addressed by *mpd*
*on-click-right*: ++
typeof: string ++
Command to execute when you right clicked on the module.
Command to execute when you right-click on the module.
*on-update*: ++
typeof: string ++
@@ -182,7 +182,7 @@ Addressed by *mpd*
*{queueLength}*: The length of the current queue.
*{stateIcon}*: The icon corresponding the playing or paused status of the player (see *state-icons* option)
*{stateIcon}*: The icon corresponding to the playing or paused status of the player (see *state-icons* option)
*{consumeIcon}*: The icon corresponding the "consume" option (see *consume-icons* option)

View File

@@ -13,7 +13,7 @@ The *mpris* module displays currently playing media via libplayerctl.
*player*: ++
typeof: string ++
default: playerctld ++
Name of the MPRIS player to attach to. Using the default value always follows the currenly active player.
Name of the MPRIS player to attach to. Using the default value always follows the currently active player.
*ignored-players*: ++
typeof: []string ++
@@ -21,6 +21,7 @@ The *mpris* module displays currently playing media via libplayerctl.
*interval*: ++
typeof: integer ++
default: 0 ++
Refresh MPRIS information on a timer.
*format*: ++
@@ -97,7 +98,7 @@ The *mpris* module displays currently playing media via libplayerctl.
*enable-tooltip-len-limits*: ++
typeof: bool ++
default: false ++
Option to enable the length limits for the tooltip as well. By default the tooltip ignores all length limits.
Option to enable the length limits for the tooltip as well. By default, the tooltip ignores all length limits.
*ellipsis*: ++
typeof: string ++
@@ -114,7 +115,7 @@ The *mpris* module displays currently playing media via libplayerctl.
*min-length*: ++
typeof: integer ++
The minimum length in characters the module should take up.
The minimum length in characters the module should accept.
*align*: ++
typeof: float ++
@@ -126,12 +127,12 @@ The *mpris* module displays currently playing media via libplayerctl.
default: play-pause ++
Overwrite default action toggles.
*on-middle-click*: ++
*on-click-middle*: ++
typeof: string ++
default: previous track ++
Overwrite default action toggles.
*on-right-click*: ++
*on-click-right*: ++
typeof: string ++
default: next track ++
Overwrite default action toggles.

View File

@@ -14,7 +14,7 @@ Addressed by *network*
*interface*: ++
typeof: string ++
Use the defined interface instead of auto detection. Accepts wildcard.
Use the defined interface instead of auto-detection. Accepts wildcard.
*interval*: ++
typeof: integer ++
@@ -41,7 +41,7 @@ Addressed by *network*
*format-linked*: ++
typeof: string ++
This format is used when a linked interface with no ip address is displayed.
This format is used when a linked interface with no IP address is displayed.
*format-disconnected*: ++
typeof: string ++
@@ -66,7 +66,7 @@ Addressed by *network*
*min-length*: ++
typeof: integer ++
The minimum length in characters the module should take up.
The minimum length in characters the module should accept.
*align*: ++
typeof: float ++
@@ -82,7 +82,7 @@ Addressed by *network*
*on-click-right*: ++
typeof: string ++
Command to execute when you right clicked on the module.
Command to execute when you right-click on the module.
*on-update*: ++
typeof: string ++

View File

@@ -0,0 +1,83 @@
waybar-pulseaudio-slider(5)
# NAME
waybar - pulseaudio slider module
# DESCRIPTION
The *pulseaudio slider* module displays and controls the current volume of the default sink or source as a bar.
The volume can be controlled by dragging the slider across the bar or clicking on a specific position.
# CONFIGURATION
*min*: ++
typeof: int ++
default: 0 ++
The minimum volume value the slider should display and set.
*max*: ++
typeof: int ++
default: 100 ++
The maximum volume value the slider should display and set.
*orientation*: ++
typeof: string ++
default: horizontal ++
The orientation of the slider. Can be either `horizontal` or `vertical`.
# EXAMPLES
```
"modules-right": [
"pulseaudio-slider",
],
"pulseaudio/slider": {
"min": 0,
"max": 100,
"orientation": "horizontal"
}
```
# STYLE
The slider is a component with multiple CSS Nodes, of which the following are exposed:
*#pulseaudio-slider*: ++
Controls the style of the box *around* the slider and bar.
*#pulseaudio-slider slider*: ++
Controls the style of the slider handle.
*#pulseaudio-slider trough*: ++
Controls the style of the part of the bar that has not been filled.
*#pulseaudio-slider highlight*: ++
Controls the style of the part of the bar that has been filled.
## STYLE EXAMPLE
```
#pulseaudio-slider slider {
min-height: 0px;
min-width: 0px;
opacity: 0;
background-image: none;
border: none;
box-shadow: none;
}
#pulseaudio-slider trough {
min-height: 80px;
min-width: 10px;
border-radius: 5px;
background-color: black;
}
#pulseaudio-slider highlight {
min-width: 10px;
border-radius: 5px;
background-color: green;
}
```

View File

@@ -8,7 +8,7 @@ waybar - pulseaudio module
The *pulseaudio* module displays the current volume reported by PulseAudio.
Additionally you can control the volume by scrolling *up* or *down* while the cursor is over the module.
Additionally, you can control the volume by scrolling *up* or *down* while the cursor is over the module.
# CONFIGURATION
@@ -36,7 +36,7 @@ Additionally you can control the volume by scrolling *up* or *down* while the cu
*format-icons*: ++
typeof: array ++
Based on the current port-name and volume, the corresponding icon gets selected. The order is *low* to *high*. See *Icons*.
Based on the current port name and volume, the corresponding icon gets selected. The order is *low* to *high*. See *Icons*.
*rotate*: ++
typeof: integer ++
@@ -52,7 +52,7 @@ Additionally you can control the volume by scrolling *up* or *down* while the cu
*min-length*: ++
typeof: integer ++
The minimum length in characters the module should take up.
The minimum length in characters the module should accept.
*align*: ++
typeof: float ++
@@ -61,7 +61,7 @@ Additionally you can control the volume by scrolling *up* or *down* while the cu
*scroll-step*: ++
typeof: float ++
default: 1.0 ++
The speed in which to change the volume when scrolling.
The speed at which to change the volume when scrolling.
*on-click*: ++
typeof: string ++
@@ -73,7 +73,7 @@ Additionally you can control the volume by scrolling *up* or *down* while the cu
*on-click-right*: ++
typeof: string ++
Command to execute when you right clicked on the module.
Command to execute when you right-click on the module.
*on-update*: ++
typeof: string ++
@@ -107,7 +107,7 @@ Additionally you can control the volume by scrolling *up* or *down* while the cu
*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.
Sinks in this list will not be shown as active sink by Waybar. Entries should be the sink's description field.
# FORMAT REPLACEMENTS

View File

@@ -29,7 +29,7 @@ Addressed by *river/layout*
*min-length*: ++
typeof: integer ++
The minimum length in characters the module should take up.
The minimum length in characters the module should accept.
*align*: ++
typeof: float ++
@@ -45,7 +45,7 @@ Addressed by *river/layout*
*on-click-right*: ++
typeof: string ++
Command to execute when you right clicked on the module.
Command to execute when you right-click on the module.
# EXAMPLE

View File

@@ -27,7 +27,7 @@ Addressed by *river/mode*
*min-length*: ++
typeof: integer ++
The minimum length in characters the module should take up.
The minimum length in characters the module should accept.
*align*: ++
typeof: float ++
@@ -43,7 +43,7 @@ Addressed by *river/mode*
*on-click-right*: ++
typeof: string ++
Command to execute when you right clicked on the module.
Command to execute when you right-click on the module.
*on-update*: ++
typeof: string ++

View File

@@ -24,7 +24,7 @@ Addressed by *river/tags*
*disable-click*: ++
typeof: bool ++
default: false ++
If set to false, you can left click to set focused tag. Right click to toggle tag focus. If set to true this behaviour is disabled.
If set to false, you can left-click to set focused tag. Right-click to toggle tag focus. If set to true this behaviour is disabled.
# EXAMPLE

View File

@@ -27,7 +27,7 @@ Addressed by *river/window*
*min-length*: ++
typeof: integer ++
The minimum length in characters the module should take up.
The minimum length in characters the module should accept.
*align*: ++
typeof: float ++
@@ -43,7 +43,7 @@ Addressed by *river/window*
*on-click-right*: ++
typeof: string ++
Command to execute when you right clicked on the module.
Command to execute when you right-click on the module.
# EXAMPLES

View File

@@ -28,7 +28,7 @@ cursor is over the module, and clicking on the module toggles mute.
*min-length*: ++
typeof: integer ++
The minimum length in characters the module should take up.
The minimum length in characters the module should accept.
*align*: ++
typeof: float ++
@@ -37,7 +37,7 @@ cursor is over the module, and clicking on the module toggles mute.
*scroll-step*: ++
typeof: int ++
default: 5 ++
The speed in which to change the volume when scrolling.
The speed at which to change the volume when scrolling.
*on-click*: ++
typeof: string ++
@@ -50,7 +50,7 @@ cursor is over the module, and clicking on the module toggles mute.
*on-click-right*: ++
typeof: string ++
Command to execute when you right clicked on the module.
Command to execute when you right-click on the module.
*on-update*: ++
typeof: string ++

View File

@@ -27,7 +27,7 @@ Addressed by *sway/mode*
*min-length*: ++
typeof: integer ++
The minimum length in characters the module should take up.
The minimum length in characters the module should accept.
*align*: ++
typeof: float ++
@@ -43,7 +43,7 @@ Addressed by *sway/mode*
*on-click-right*: ++
typeof: string ++
Command to execute when you right clicked on the module.
Command to execute when you right-click on the module.
*on-update*: ++
typeof: string ++

View File

@@ -27,7 +27,7 @@ Addressed by *sway/window*
*min-length*: ++
typeof: integer ++
The minimum length in characters the module should take up.
The minimum length in characters the module should accept.
*align*: ++
typeof: float ++
@@ -43,7 +43,7 @@ Addressed by *sway/window*
*on-click-right*: ++
typeof: string ++
Command to execute when you right clicked on the module.
Command to execute when you right-click on the module.
*on-update*: ++
typeof: string ++
@@ -78,7 +78,7 @@ Addressed by *sway/window*
*offscreen-css-text*: ++
typeof: string ++
Only effective when both all-outputs and offscreen-style are true. On screens currently not focused, show the given text along with that workspaces styles.
Only effective when both all-outputs and offscreen-style are true. On screens currently not focused, show the given text along with that workspace styles.
*show-focused-workspace-name*: ++
typeof: bool ++
@@ -106,7 +106,7 @@ Addressed by *sway/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'.
running through xwayland, otherwise, it's 'xdg-shell'.
# REWRITE RULES

View File

@@ -60,10 +60,10 @@ Addressed by *sway/workspaces*
default: false ++
If set to true. Only focused workspaces will be shown.
*persistent_workspaces*: ++
*persistent-workspaces*: ++
typeof: json (see below) ++
default: empty ++
Lists workspaces that should always be shown, even when non existent
Lists workspaces that should always be shown, even when non-existent
*on-update*: ++
typeof: string ++
@@ -98,11 +98,11 @@ warp-on-scroll: ++
Additional to workspace name matching, the following *format-icons* can be set.
- *default*: Will be shown, when no string matches is found.
- *default*: Will be shown, when no string matches are found.
- *urgent*: Will be shown, when workspace is flagged as urgent
- *focused*: Will be shown, when workspace is focused
- *persistent*: Will be shown, when workspace is persistent one.
- *high-priority-named*: Icons by names will be shown always for that workspaces, independent by state.
- *persistent*: Will be shown, when workspace is persistent.
- *high-priority-named*: Icons by names will be shown always for those workspaces, independent by state.
# PERSISTENT WORKSPACES
@@ -112,10 +112,10 @@ an empty list denoting all outputs.
```
"sway/workspaces": {
"persistent_workspaces": {
"3": [], // Always show a workspace with name '3', on all outputs if it does not exists
"4": ["eDP-1"], // Always show a workspace with name '4', on output 'eDP-1' if it does not exists
"5": ["eDP-1", "DP-2"] // Always show a workspace with name '5', on outputs 'eDP-1' and 'DP-2' if it does not exists
"persistent-workspaces": {
"3": [], // Always show a workspace with name '3', on all outputs if it does not exist
"4": ["eDP-1"], // Always show a workspace with name '4', on output 'eDP-1' if it does not exist
"5": ["eDP-1", "DP-2"] // Always show a workspace with name '5', on outputs 'eDP-1' and 'DP-2' if it does not exist
}
}
```

View File

@@ -67,7 +67,7 @@ Addressed by *temperature*
*min-length*: ++
typeof: integer ++
The minimum length in characters the module should take up.
The minimum length in characters the module should accept.
*align*: ++
typeof: float ++
@@ -75,7 +75,7 @@ Addressed by *temperature*
*on-click*: ++
typeof: string ++
Command to execute when you clicked on the module.
Command to execute when you click on the module.
*on-click-middle*: ++
typeof: string ++
@@ -83,7 +83,7 @@ Addressed by *temperature*
*on-click-right*: ++
typeof: string ++
Command to execute when you right clicked on the module.
Command to execute when you right-click on the module.
*on-update*: ++
typeof: string ++

View File

@@ -43,7 +43,7 @@ The *wireplumber* module displays the current volume reported by WirePlumber.
*min-length*: ++
typeof: integer ++
The minimum length in characters the module should take up.
The minimum length in characters the module should accept.
*align*: ++
typeof: float ++
@@ -52,7 +52,7 @@ The *wireplumber* module displays the current volume reported by WirePlumber.
*scroll-step*: ++
typeof: float ++
default: 1.0 ++
The speed in which to change the volume when scrolling.
The speed at which to change the volume when scrolling.
*on-click*: ++
typeof: string ++
@@ -64,7 +64,7 @@ The *wireplumber* module displays the current volume reported by WirePlumber.
*on-click-right*: ++
typeof: string ++
Command to execute when you right clicked on the module.
Command to execute when you right-click on the module.
*on-update*: ++
typeof: string ++

View File

@@ -16,7 +16,7 @@ Addressed by *wlr/taskbar*
*all-outputs*: ++
typeof: bool ++
default: false ++
If set to false applications on the waybar's current output will be shown. Otherwise all applications are shown.
If set to false applications on the waybar's current output will be shown. Otherwise, all applications are shown.
*format*: ++
typeof: string ++
@@ -89,7 +89,7 @@ Addressed by *wlr/taskbar*
*{icon}*: The icon of the application.
*{name}*: The application name as in desktop file if appropriate desktop fils found, otherwise same as {app_id}
*{name}*: The application name as in desktop file if appropriate desktop files are found, otherwise same as {app_id}
*{title}*: The title of the application.

View File

@@ -30,17 +30,17 @@ Addressed by *wlr/workspaces*
typeof: bool ++
default: true ++
Should workspaces be sorted by coordinates. ++
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.
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.
*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.
If set to true, workspace names will be sorted numerically. Takes precedence over any other sort-by option.
*all-outputs*: ++
typeof: bool ++
default: false ++
If set to false workspaces group will be shown only in assigned output. Otherwise all workspace groups are shown.
If set to false workspaces group will be shown only in assigned output. Otherwise, all workspace groups are shown.
*active-only*: ++
typeof: bool ++
@@ -61,7 +61,7 @@ Addressed by *wlr/workspaces*
# ICONS
Additional to workspace name matching, the following *format-icons* can be set.
In addition to workspace name matching, the following *format-icons* can be set.
- *default*: Will be shown, when no string match is found.
- *active*: Will be shown, when workspace is active

View File

@@ -17,7 +17,7 @@ Valid locations for this file are:
- *@sysconfdir@/xdg/waybar/config*
A good starting point is the default configuration found at https://github.com/Alexays/Waybar/blob/master/resources/config
Also a minimal example configuration can be found on the at the bottom of this man page.
Also, a minimal example configuration can be found at the bottom of this man page.
# BAR CONFIGURATION
@@ -30,7 +30,7 @@ Also a minimal example configuration can be found on the at the bottom of this m
*output* ++
typeof: string|array ++
Specifies on which screen this bar will be displayed. Exclamation mark(*!*) can be used to exclude specific output.
Output specification follows sway's and can either be the output port such as "HDMI-A-1" or a string consisting of the make, model and serial such as "Some Company ABC123 0x00000000". See *sway-output(5)* for details.
Output specification follows sway's and can either be the output port such as "HDMI-A-1" or a string consisting of the make, model, and serial such as "Some Company ABC123 0x00000000". See *sway-output(5)* for details.
In an array, star '*\**' can be used at the end to accept all outputs, in case all previous entries are exclusions.
*position* ++
@@ -68,7 +68,7 @@ Also a minimal example configuration can be found on the at the bottom of this m
*spacing* ++
typeof: integer ++
Size of gaps in between of the different modules.
Size of gaps in between the different modules.
*name* ++
typeof: string ++
@@ -89,7 +89,7 @@ Also a minimal example configuration can be found on the at the bottom of this m
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.
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* ++
typeof: bool ++
@@ -118,11 +118,11 @@ Also a minimal example configuration can be found on the at the bottom of this m
typeof: bool ++
default: false ++
Option to subscribe to the Sway IPC bar configuration and visibility events and control waybar with *swaymsg bar* commands. ++
Requires *bar_id* value from sway configuration to be either passed with the *-b* commandline argument or specified with the *id* option.
Requires *bar_id* value from sway configuration to be either passed with the *-b* command line argument or specified with the *id* option.
*id* ++
typeof: string ++
*bar_id* for the Sway IPC. Use this if you need to override the value passed with the *-b bar_id* commandline argument for the specific bar instance.
*bar_id* for the Sway IPC. Use this if you need to override the value passed with the *-b bar_id* command line argument for the specific bar instance.
*include* ++
typeof: string|array ++
@@ -142,7 +142,7 @@ e.g.
# MULTIPLE INSTANCES OF A MODULE
If you want to have a second instance of a module, you can suffix it by a '#' and a custom name.
For example if you want a second battery module, you can add *"battery#bat2"* to your modules.
For example, if you want a second battery module, you can add *"battery#bat2"* to your modules.
To configure the newly added module, you then also add a module configuration with the same name.
This could then look something like this *(this is an incomplete example)*:
@@ -236,11 +236,11 @@ When positioning Waybar on the left or right side of the screen, sometimes it's
}
```
Valid options for the "rotate" property are: 0, 90, 180 and 270.
Valid options for the "rotate" property are: 0, 90, 180, and 270.
## Grouping modules
Module groups allow stacking modules in the direction orthogonal to the bar direction. When the bar is positioned on the top or bottom of the screen, modules in a group are stacked vertically. Likewise, when positioned on the left or right, modules in a group are stacked horizontally.
Module groups allow stacking modules in any direction. By default, when the bar is positioned on the top or bottom of the screen, modules in a group are stacked vertically. Likewise, when positioned on the left or right, modules in a group are stacked horizontally. This can be changed with the "orientation" property.
A module group is defined by specifying a module named "group/some-group-name". The group must also be configured with a list of contained modules. Example:
@@ -263,6 +263,43 @@ A module group is defined by specifying a module named "group/some-group-name".
Valid options for the (optional) "orientation" property are: "horizontal", "vertical", "inherit", and "orthogonal" (default).
## Group Drawers
A group may hide all but one element, showing them only on mouse hover. In order to configure this, you can use the `drawer` property, whose value is an object with the following properties:
*transition-duration*: ++
typeof: integer ++
default: 500 ++
Defines the duration of the transition animation in milliseconds.
*children-class*: ++
typeof: string ++
default: "hidden" ++
Defines the CSS class to be applied to the hidden elements.
*transition-left-to-right*: ++
typeof: bool ++
default: true ++
Defines the direction of the transition animation. If true, the hidden elements will slide from left to right. If false, they will slide from right to left.
When the bar is vertical, it reads as top-to-bottom.
```
"group/power": {
"orientation": "inherit",
"drawer": {
"transition-duration": 500,
"children-class": "not-power",
"transition-left-to-right": false,
},
"modules": [
"custom/power", // First element is the "group leader" and won't ever be hidden
"custom/quit",
"custom/lock",
"custom/reboot",
]
},
```
# SUPPORTED MODULES
- *waybar-backlight(5)*
@@ -273,28 +310,39 @@ Valid options for the (optional) "orientation" property are: "horizontal", "vert
- *waybar-cpu(5)*
- *waybar-custom(5)*
- *waybar-disk(5)*
- *waybar-dwl-tags(5)*
- *waybar-gamemode(5)*
- *waybar-hyprland-language(5)*
- *waybar-hyprland-submap(5)*
- *waybar-hyprland-window(5)*
- *waybar-hyprland-workspaces(5)*
- *waybar-idle-inhibitor(5)*
- *waybar-image(5)*
- *waybar-inhibitor(5)*
- *waybar-jack(5)*
- *waybar-keyboard-state(5)*
- *waybar-memory(5)*
- *waybar-mpd(5)*
- *waybar-mpris(5)*
- *waybar-network(5)*
- *waybar-pulseaudio(5)*
- *waybar-river-layout(5)*
- *waybar-river-mode(5)*
- *waybar-river-tags(5)*
- *waybar-river-window(5)*
- *waybar-river-layout(5)*
- *waybar-sndio(5)*
- *waybar-states(5)*
- *waybar-sway-language(5)*
- *waybar-sway-mode(5)*
- *waybar-sway-scratchpad(5)*
- *waybar-sway-window(5)*
- *waybar-sway-workspaces(5)*
- *waybar-temperature(5)*
- *waybar-tray(5)*
- *waybar-upower(5)*
- *waybar-wireplumber(5)*
- *waybar-wlr-taskbar(5)*
- *waybar-wlr-workspaces(5)*
- *waybar-temperature(5)*
- *waybar-tray(5)*
# SEE ALSO

View File

@@ -1,6 +1,6 @@
project(
'waybar', 'cpp', 'c',
version: '0.9.21',
version: '0.9.23',
license: 'MIT',
meson_version: '>= 0.50.0',
default_options : [
@@ -164,18 +164,23 @@ src_files = files(
'src/modules/disk.cpp',
'src/modules/idle_inhibitor.cpp',
'src/modules/image.cpp',
'src/modules/load.cpp',
'src/modules/temperature.cpp',
'src/modules/user.cpp',
'src/ASlider.cpp',
'src/main.cpp',
'src/bar.cpp',
'src/client.cpp',
'src/config.cpp',
'src/group.cpp',
'src/util/portal.cpp',
'src/util/enum.cpp',
'src/util/prepare_for_sleep.cpp',
'src/util/ustring_clen.cpp',
'src/util/sanitize_str.cpp',
'src/util/rewrite_string.cpp',
'src/util/gtk_icon.cpp'
'src/util/gtk_icon.cpp',
'src/util/regex_collection.cpp'
)
inc_dirs = ['include']
@@ -185,8 +190,11 @@ if is_linux
add_project_arguments('-DHAVE_MEMORY_LINUX', language: 'cpp')
src_files += files(
'src/modules/battery.cpp',
'src/modules/cpu/common.cpp',
'src/modules/cpu/linux.cpp',
'src/modules/cpu.cpp',
'src/modules/cpu_frequency/common.cpp',
'src/modules/cpu_frequency/linux.cpp',
'src/modules/cpu_usage/common.cpp',
'src/modules/cpu_usage/linux.cpp',
'src/modules/memory/common.cpp',
'src/modules/memory/linux.cpp',
)
@@ -194,8 +202,11 @@ elif is_dragonfly or is_freebsd or is_netbsd or is_openbsd
add_project_arguments('-DHAVE_CPU_BSD', language: 'cpp')
add_project_arguments('-DHAVE_MEMORY_BSD', language: 'cpp')
src_files += files(
'src/modules/cpu/bsd.cpp',
'src/modules/cpu/common.cpp',
'src/modules/cpu.cpp',
'src/modules/cpu_frequency/bsd.cpp',
'src/modules/cpu_frequency/common.cpp',
'src/modules/cpu_usage/bsd.cpp',
'src/modules/cpu_usage/common.cpp',
'src/modules/memory/bsd.cpp',
'src/modules/memory/common.cpp',
)
@@ -270,6 +281,8 @@ endif
if libpulse.found()
add_project_arguments('-DHAVE_LIBPULSE', language: 'cpp')
src_files += 'src/modules/pulseaudio.cpp'
src_files += 'src/modules/pulseaudio_slider.cpp'
src_files += 'src/util/audio_backend.cpp'
endif
if libjack.found()
@@ -295,6 +308,8 @@ endif
if libudev.found() and (is_linux or libepoll.found())
add_project_arguments('-DHAVE_LIBUDEV', language: 'cpp')
src_files += 'src/modules/backlight.cpp'
src_files += 'src/modules/backlight_slider.cpp'
src_files += 'src/util/backlight_backend.cpp'
endif
if libevdev.found() and (is_linux or libepoll.found()) and libinput.found() and (is_linux or libinotify.found())
@@ -346,7 +361,7 @@ if get_option('experimental')
endif
cava = dependency('cava',
version : '>=0.8.5',
version : '>=0.9.1',
required: get_option('cava'),
fallback : ['cava', 'cava_dep'],
not_found_message: 'cava is not found. Building waybar without cava')
@@ -422,6 +437,7 @@ if scdoc.found()
man_files = [
main_manpage_path,
'waybar-backlight.5.scd',
'waybar-backlight-slider.5.scd',
'waybar-battery.5.scd',
'waybar-cava.5.scd',
'waybar-clock.5.scd',
@@ -437,6 +453,7 @@ if scdoc.found()
'waybar-mpris.5.scd',
'waybar-network.5.scd',
'waybar-pulseaudio.5.scd',
'waybar-pulseaudio-slider.5.scd',
'waybar-river-mode.5.scd',
'waybar-river-tags.5.scd',
'waybar-river-window.5.scd',

View File

@@ -12,7 +12,7 @@ ALabel::ALabel(const Json::Value& config, const std::string& name, const std::st
: 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::max()
: std::chrono::seconds(
config_["interval"].isUInt() ? config_["interval"].asUInt() : interval)),
default_format_(format_) {

View File

@@ -27,18 +27,28 @@ AModule::AModule(const Json::Value& config, const std::string& name, const std::
}
// configure events' user commands
bool hasEvent =
// hasUserEvent is true if any element from eventMap_ is satisfying the condition in the lambda
bool hasUserEvent =
std::find_if(eventMap_.cbegin(), eventMap_.cend(), [&config](const auto& eventEntry) {
return config[eventEntry.second].isString();
// True if there is any non-release type event
return eventEntry.first.second != GdkEventType::GDK_BUTTON_RELEASE &&
config[eventEntry.second].isString();
}) != eventMap_.cend();
if (enable_click || hasEvent) {
if (enable_click || hasUserEvent) {
event_box_.add_events(Gdk::BUTTON_PRESS_MASK);
event_box_.signal_button_press_event().connect(sigc::mem_fun(*this, &AModule::handleToggle));
// register key release
}
bool hasReleaseEvent =
std::find_if(eventMap_.cbegin(), eventMap_.cend(), [&config](const auto& eventEntry) {
// True if there is any non-release type event
return eventEntry.first.second == GdkEventType::GDK_BUTTON_RELEASE &&
config[eventEntry.second].isString();
}) != eventMap_.cend();
if (hasReleaseEvent) {
event_box_.add_events(Gdk::BUTTON_RELEASE_MASK);
event_box_.signal_button_release_event().connect(sigc::mem_fun(*this, &AModule::handleToggle));
event_box_.signal_button_release_event().connect(sigc::mem_fun(*this, &AModule::handleRelease));
}
if (config_["on-scroll-up"].isString() || config_["on-scroll-down"].isString() || enable_scroll) {
event_box_.add_events(Gdk::SCROLL_MASK | Gdk::SMOOTH_SCROLL_MASK);
@@ -70,7 +80,11 @@ auto AModule::doAction(const std::string& name) -> void {
}
}
bool AModule::handleToggle(GdkEventButton* const& e) {
bool AModule::handleToggle(GdkEventButton* const& e) { return handleUserEvent(e); }
bool AModule::handleRelease(GdkEventButton* const& e) { return handleUserEvent(e); }
bool AModule::handleUserEvent(GdkEventButton* const& e) {
std::string format{};
const std::map<std::pair<uint, GdkEventType>, std::string>::const_iterator& rec{
eventMap_.find(std::pair(e->button, e->type))};

34
src/ASlider.cpp Normal file
View File

@@ -0,0 +1,34 @@
#include "ASlider.hpp"
#include "gtkmm/adjustment.h"
#include "gtkmm/enums.h"
namespace waybar {
ASlider::ASlider(const Json::Value& config, const std::string& name, const std::string& id)
: AModule(config, name, id, false, false),
vertical_(config_["orientation"].asString() == "vertical"),
scale_(vertical_ ? Gtk::ORIENTATION_VERTICAL : Gtk::ORIENTATION_HORIZONTAL) {
scale_.set_name(name);
if (!id.empty()) {
scale_.get_style_context()->add_class(id);
}
event_box_.add(scale_);
scale_.signal_value_changed().connect(sigc::mem_fun(*this, &ASlider::onValueChanged));
if (config_["min"].isUInt()) {
min_ = config_["min"].asUInt();
}
if (config_["max"].isUInt()) {
max_ = config_["max"].asUInt();
}
scale_.set_inverted(vertical_);
scale_.set_draw_value(false);
scale_.set_adjustment(Gtk::Adjustment::create(curr_, min_, max_ + 1, 1, 1, 1));
}
void ASlider::onValueChanged() {}
} // namespace waybar

View File

@@ -481,6 +481,9 @@ waybar::Bar::Bar(struct waybar_output* w_output, const Json::Value& w_config)
: output(w_output),
config(w_config),
window{Gtk::WindowType::WINDOW_TOPLEVEL},
x_global(0),
y_global(0),
margins_{.top = 0, .right = 0, .bottom = 0, .left = 0},
left_(Gtk::ORIENTATION_HORIZONTAL, 0),
center_(Gtk::ORIENTATION_HORIZONTAL, 0),
right_(Gtk::ORIENTATION_HORIZONTAL, 0),
@@ -516,8 +519,6 @@ waybar::Bar::Bar(struct waybar_output* w_output, const Json::Value& w_config)
uint32_t height = config["height"].isUInt() ? config["height"].asUInt() : 0;
uint32_t width = config["width"].isUInt() ? config["width"].asUInt() : 0;
struct bar_margins margins_;
if (config["margin-top"].isInt() || config["margin-right"].isInt() ||
config["margin-bottom"].isInt() || config["margin-left"].isInt()) {
margins_ = {
@@ -563,6 +564,10 @@ waybar::Bar::Bar(struct waybar_output* w_output, const Json::Value& w_config)
margins_ = {.top = gaps, .right = gaps, .bottom = gaps, .left = gaps};
}
window.signal_configure_event().connect_notify(sigc::mem_fun(*this, &Bar::onConfigure));
output->monitor->property_geometry().signal_changed().connect(
sigc::mem_fun(*this, &Bar::onOutputGeometryChanged));
#ifdef HAVE_GTK_LAYER_SHELL
bool use_gls = config["gtk-layer-shell"].isBool() ? config["gtk-layer-shell"].asBool() : true;
if (use_gls) {
@@ -674,6 +679,7 @@ void waybar::Bar::onMap(GdkEventAny*) {
*/
auto gdk_window = window.get_window()->gobj();
surface = gdk_wayland_window_get_wl_surface(gdk_window);
configureGlobalOffset(gdk_window_get_width(gdk_window), gdk_window_get_height(gdk_window));
}
void waybar::Bar::setVisible(bool value) {
@@ -734,7 +740,7 @@ void waybar::Bar::handleSignal(int signal) {
}
void waybar::Bar::getModules(const Factory& factory, const std::string& pos,
Gtk::Box* group = nullptr) {
waybar::Group* group = nullptr) {
auto module_list = group ? config[pos]["modules"] : config[pos];
if (module_list.isArray()) {
for (const auto& name : module_list) {
@@ -747,10 +753,11 @@ void waybar::Bar::getModules(const Factory& factory, const std::string& pos,
auto id_name = ref.substr(6, hash_pos - 6);
auto class_name = hash_pos != std::string::npos ? ref.substr(hash_pos + 1) : "";
auto parent = group ? group : &this->box_;
auto vertical = parent->get_orientation() == Gtk::ORIENTATION_VERTICAL;
auto vertical = (group ? group->getBox().get_orientation() : box_.get_orientation()) ==
Gtk::ORIENTATION_VERTICAL;
auto group_module = new waybar::Group(id_name, class_name, config[ref], vertical);
getModules(factory, ref, &group_module->box);
getModules(factory, ref, group_module);
module = group_module;
} else {
module = factory.makeModule(ref);
@@ -759,7 +766,7 @@ void waybar::Bar::getModules(const Factory& factory, const std::string& pos,
std::shared_ptr<AModule> module_sp(module);
modules_all_.emplace_back(module_sp);
if (group) {
group->pack_start(*module, false, false);
group->addWidget(*module);
} else {
if (pos == "modules-left") {
modules_left_.emplace_back(module_sp);
@@ -815,3 +822,47 @@ auto waybar::Bar::setupWidgets() -> void {
right_.pack_end(*module, false, false);
}
}
void waybar::Bar::onConfigure(GdkEventConfigure* ev) {
configureGlobalOffset(ev->width, ev->height);
}
void waybar::Bar::configureGlobalOffset(int width, int height) {
auto monitor_geometry = *output->monitor->property_geometry().get_value().gobj();
auto position = config["position"].asString();
int x;
int y;
if (position == "bottom") {
if (width + margins_.left + margins_.right >= monitor_geometry.width)
x = margins_.left;
else
x = (monitor_geometry.width - width) / 2;
y = monitor_geometry.height - height - margins_.bottom;
} else if (position == "left") {
x = margins_.left;
if (height + margins_.top + margins_.bottom >= monitor_geometry.height)
y = margins_.top;
else
y = (monitor_geometry.height - height) / 2;
} else if (position == "right") {
x = monitor_geometry.width - width - margins_.right;
if (height + margins_.top + margins_.bottom >= monitor_geometry.height)
y = margins_.top;
else
y = (monitor_geometry.height - height) / 2;
} else {
// position is top
if (width + margins_.left + margins_.right >= monitor_geometry.width)
x = margins_.left;
else
x = (monitor_geometry.width - width) / 2;
y = margins_.top;
}
x_global = x + monitor_geometry.x;
y_global = y + monitor_geometry.y;
}
void waybar::Bar::onOutputGeometryChanged() {
configureGlobalOffset(window.get_width(), window.get_height());
}

View File

@@ -151,8 +151,26 @@ void waybar::Client::handleDeferredMonitorRemoval(Glib::RefPtr<Gdk::Monitor> mon
outputs_.remove_if([&monitor](const auto &output) { return output.monitor == monitor; });
}
const std::string waybar::Client::getStyle(const std::string &style) {
auto css_file = style.empty() ? Config::findConfigPath({"style.css"}) : style;
const std::string waybar::Client::getStyle(const std::string &style,
std::optional<Appearance> appearance = std::nullopt) {
std::optional<std::string> css_file;
if (style.empty()) {
std::vector<std::string> search_files;
switch (appearance.value_or(portal->getAppearance())) {
case waybar::Appearance::LIGHT:
search_files.push_back("style-light.css");
break;
case waybar::Appearance::DARK:
search_files.push_back("style-dark.css");
break;
case waybar::Appearance::UNKNOWN:
break;
}
search_files.push_back("style.css");
css_file = Config::findConfigPath(search_files);
} else {
css_file = style;
}
if (!css_file) {
throw std::runtime_error("Missing required resource files");
}
@@ -235,8 +253,15 @@ int waybar::Client::main(int argc, char *argv[]) {
}
wl_display = gdk_wayland_display_get_wl_display(gdk_display->gobj());
config.load(config_opt);
if (!portal) {
portal = std::make_unique<waybar::Portal>();
}
auto css_file = getStyle(style_opt);
setupCss(css_file);
portal->signal_appearance_changed().connect([&](waybar::Appearance appearance) {
auto css_file = getStyle(style_opt, appearance);
setupCss(css_file);
});
bindInterfaces();
gtk_app->hold();
gtk_app->run();
@@ -244,4 +269,8 @@ int waybar::Client::main(int argc, char *argv[]) {
return 0;
}
void waybar::Client::reset() { gtk_app->quit(); }
void waybar::Client::reset() {
gtk_app->quit();
// delete signal handler for css changes
portal->signal_appearance_changed().clear();
}

View File

@@ -1,5 +1,13 @@
#include "factory.hpp"
#ifdef HAVE_LIBPULSE
#include "modules/pulseaudio_slider.hpp"
#endif
#ifdef HAVE_LIBUDEV
#include "modules/backlight_slider.hpp"
#endif
waybar::Factory::Factory(const Bar& bar, const Json::Value& config) : bar_(bar), config_(config) {}
waybar::AModule* waybar::Factory::makeModule(const std::string& name) const {
@@ -99,6 +107,17 @@ waybar::AModule* waybar::Factory::makeModule(const std::string& name) const {
if (ref == "cpu") {
return new waybar::modules::Cpu(id, config_[name]);
}
#if defined(HAVE_CPU_LINUX)
if (ref == "cpu_frequency") {
return new waybar::modules::CpuFrequency(id, config_[name]);
}
#endif
if (ref == "cpu_usage") {
return new waybar::modules::CpuUsage(id, config_[name]);
}
if (ref == "load") {
return new waybar::modules::Load(id, config_[name]);
}
#endif
if (ref == "clock") {
return new waybar::modules::Clock(id, config_[name]);
@@ -126,6 +145,9 @@ waybar::AModule* waybar::Factory::makeModule(const std::string& name) const {
if (ref == "backlight") {
return new waybar::modules::Backlight(id, config_[name]);
}
if (ref == "backlight/slider") {
return new waybar::modules::BacklightSlider(id, config_[name]);
}
#endif
#ifdef HAVE_LIBEVDEV
if (ref == "keyboard-state") {
@@ -136,6 +158,9 @@ waybar::AModule* waybar::Factory::makeModule(const std::string& name) const {
if (ref == "pulseaudio") {
return new waybar::modules::Pulseaudio(id, config_[name]);
}
if (ref == "pulseaudio/slider") {
return new waybar::modules::PulseaudioSlider(id, config_[name]);
}
#endif
#ifdef HAVE_LIBMPDCLIENT
if (ref == "mpd") {

View File

@@ -4,12 +4,32 @@
#include <util/command.hpp>
#include "gdkmm/device.h"
#include "gtkmm/widget.h"
namespace waybar {
const Gtk::RevealerTransitionType getPreferredTransitionType(bool is_vertical, bool left_to_right) {
if (is_vertical) {
if (left_to_right) {
return Gtk::RevealerTransitionType::REVEALER_TRANSITION_TYPE_SLIDE_DOWN;
} else {
return Gtk::RevealerTransitionType::REVEALER_TRANSITION_TYPE_SLIDE_UP;
}
} else {
if (left_to_right) {
return Gtk::RevealerTransitionType::REVEALER_TRANSITION_TYPE_SLIDE_RIGHT;
} else {
return Gtk::RevealerTransitionType::REVEALER_TRANSITION_TYPE_SLIDE_LEFT;
}
}
}
Group::Group(const std::string& name, const std::string& id, const Json::Value& config,
bool vertical)
: AModule(config, name, id, false, false),
box{vertical ? Gtk::ORIENTATION_VERTICAL : Gtk::ORIENTATION_HORIZONTAL, 0} {
: AModule(config, name, id, true, true),
box{vertical ? Gtk::ORIENTATION_VERTICAL : Gtk::ORIENTATION_HORIZONTAL, 0},
revealer_box{vertical ? Gtk::ORIENTATION_VERTICAL : Gtk::ORIENTATION_HORIZONTAL, 0} {
box.set_name(name_);
if (!id.empty()) {
box.get_style_context()->add_class(id);
@@ -29,12 +49,77 @@ Group::Group(const std::string& name, const std::string& id, const Json::Value&
} else {
throw std::runtime_error("Invalid orientation value: " + orientation);
}
if (config_["drawer"].isObject()) {
is_drawer = true;
const auto& drawer_config = config_["drawer"];
const int transition_duration =
(drawer_config["transition-duration"].isInt() ? drawer_config["transition-duration"].asInt()
: 500);
add_class_to_drawer_children =
(drawer_config["children-class"].isString() ? drawer_config["children-class"].asString()
: "drawer-child");
const bool left_to_right = (drawer_config["transition-left-to-right"].isBool()
? drawer_config["transition-left-to-right"].asBool()
: true);
auto transition_type = getPreferredTransitionType(vertical, left_to_right);
revealer.set_transition_type(transition_type);
revealer.set_transition_duration(transition_duration);
revealer.set_reveal_child(false);
revealer.get_style_context()->add_class("drawer");
revealer.add(revealer_box);
box.pack_start(revealer);
addHoverHandlerTo(revealer);
}
}
bool Group::handleMouseHover(GdkEventCrossing* const& e) {
switch (e->type) {
case GDK_ENTER_NOTIFY:
revealer.set_reveal_child(true);
break;
case GDK_LEAVE_NOTIFY:
revealer.set_reveal_child(false);
break;
default:
break;
}
return true;
}
void Group::addHoverHandlerTo(Gtk::Widget& widget) {
widget.add_events(Gdk::EventMask::ENTER_NOTIFY_MASK | Gdk::EventMask::LEAVE_NOTIFY_MASK);
widget.signal_enter_notify_event().connect(sigc::mem_fun(*this, &Group::handleMouseHover));
widget.signal_leave_notify_event().connect(sigc::mem_fun(*this, &Group::handleMouseHover));
}
auto Group::update() -> void {
// noop
}
Gtk::Box& Group::getBox() { return is_drawer ? (is_first_widget ? box : revealer_box) : box; }
void Group::addWidget(Gtk::Widget& widget) {
getBox().pack_start(widget, false, false);
if (is_drawer) {
// Necessary because of GTK's hitbox detection
addHoverHandlerTo(widget);
if (!is_first_widget) {
widget.get_style_context()->add_class(add_class_to_drawer_children);
}
}
is_first_widget = false;
}
Group::operator Gtk::Widget&() { return box; }
} // namespace waybar

View File

@@ -2,6 +2,7 @@
#include <fmt/format.h>
#include <libudev.h>
#include <spdlog/spdlog.h>
#include <sys/epoll.h>
#include <unistd.h>
@@ -9,179 +10,26 @@
#include <chrono>
#include <memory>
namespace {
class FileDescriptor {
public:
explicit FileDescriptor(int fd) : fd_(fd) {}
FileDescriptor(const FileDescriptor &other) = delete;
FileDescriptor(FileDescriptor &&other) noexcept = delete;
FileDescriptor &operator=(const FileDescriptor &other) = delete;
FileDescriptor &operator=(FileDescriptor &&other) noexcept = delete;
~FileDescriptor() {
if (fd_ != -1) {
if (close(fd_) != 0) {
fmt::print(stderr, "Failed to close fd: {}\n", errno);
}
}
}
int get() const { return fd_; }
private:
int fd_;
};
struct UdevDeleter {
void operator()(udev *ptr) { udev_unref(ptr); }
};
struct UdevDeviceDeleter {
void operator()(udev_device *ptr) { udev_device_unref(ptr); }
};
struct UdevEnumerateDeleter {
void operator()(udev_enumerate *ptr) { udev_enumerate_unref(ptr); }
};
struct UdevMonitorDeleter {
void operator()(udev_monitor *ptr) { udev_monitor_unref(ptr); }
};
void check_eq(int rc, int expected, const char *message = "eq, rc was: ") {
if (rc != expected) {
throw std::runtime_error(fmt::format(fmt::runtime(message), rc));
}
}
void check_neq(int rc, int bad_rc, const char *message = "neq, rc was: ") {
if (rc == bad_rc) {
throw std::runtime_error(fmt::format(fmt::runtime(message), rc));
}
}
void check0(int rc, const char *message = "rc wasn't 0") { check_eq(rc, 0, message); }
void check_gte(int rc, int gte, const char *message = "rc was: ") {
if (rc < gte) {
throw std::runtime_error(fmt::format(fmt::runtime(message), rc));
}
}
void check_nn(const void *ptr, const char *message = "ptr was null") {
if (ptr == nullptr) {
throw std::runtime_error(message);
}
}
} // namespace
waybar::modules::Backlight::BacklightDev::BacklightDev(std::string name, int actual, int max,
bool powered)
: name_(std::move(name)), actual_(actual), max_(max), powered_(powered) {}
std::string_view waybar::modules::Backlight::BacklightDev::name() const { return name_; }
int waybar::modules::Backlight::BacklightDev::get_actual() const { return actual_; }
void waybar::modules::Backlight::BacklightDev::set_actual(int actual) { actual_ = actual; }
int waybar::modules::Backlight::BacklightDev::get_max() const { return max_; }
void waybar::modules::Backlight::BacklightDev::set_max(int max) { max_ = max; }
bool waybar::modules::Backlight::BacklightDev::get_powered() const { return powered_; }
void waybar::modules::Backlight::BacklightDev::set_powered(bool powered) { powered_ = powered; }
#include "util/backend_common.hpp"
#include "util/backlight_backend.hpp"
waybar::modules::Backlight::Backlight(const std::string &id, const Json::Value &config)
: ALabel(config, "backlight", id, "{percent}%", 2),
preferred_device_(config["device"].isString() ? config["device"].asString() : "") {
// Get initial state
{
std::unique_ptr<udev, UdevDeleter> udev_check{udev_new()};
check_nn(udev_check.get(), "Udev check new failed");
enumerate_devices(devices_.begin(), devices_.end(), std::back_inserter(devices_),
udev_check.get());
if (devices_.empty()) {
throw std::runtime_error("No backlight found");
}
dp.emit();
}
preferred_device_(config["device"].isString() ? config["device"].asString() : ""),
backend(interval_, [this] { dp.emit(); }) {
dp.emit();
// Set up scroll handler
event_box_.add_events(Gdk::SCROLL_MASK | Gdk::SMOOTH_SCROLL_MASK);
event_box_.signal_scroll_event().connect(sigc::mem_fun(*this, &Backlight::handleScroll));
// Connect to the login interface
login_proxy_ = Gio::DBus::Proxy::create_for_bus_sync(
Gio::DBus::BusType::BUS_TYPE_SYSTEM, "org.freedesktop.login1",
"/org/freedesktop/login1/session/self", "org.freedesktop.login1.Session");
udev_thread_ = [this] {
std::unique_ptr<udev, UdevDeleter> udev{udev_new()};
check_nn(udev.get(), "Udev new failed");
std::unique_ptr<udev_monitor, UdevMonitorDeleter> mon{
udev_monitor_new_from_netlink(udev.get(), "udev")};
check_nn(mon.get(), "udev monitor new failed");
check_gte(udev_monitor_filter_add_match_subsystem_devtype(mon.get(), "backlight", nullptr), 0,
"udev failed to add monitor filter: ");
udev_monitor_enable_receiving(mon.get());
auto udev_fd = udev_monitor_get_fd(mon.get());
auto epoll_fd = FileDescriptor{epoll_create1(EPOLL_CLOEXEC)};
check_neq(epoll_fd.get(), -1, "epoll init failed: ");
epoll_event ctl_event{};
ctl_event.events = EPOLLIN;
ctl_event.data.fd = udev_fd;
check0(epoll_ctl(epoll_fd.get(), EPOLL_CTL_ADD, ctl_event.data.fd, &ctl_event),
"epoll_ctl failed: {}");
epoll_event events[EPOLL_MAX_EVENTS];
while (udev_thread_.isRunning()) {
const int event_count = epoll_wait(epoll_fd.get(), events, EPOLL_MAX_EVENTS,
std::chrono::milliseconds{interval_}.count());
if (!udev_thread_.isRunning()) {
break;
}
decltype(devices_) devices;
{
std::scoped_lock<std::mutex> lock(udev_thread_mutex_);
devices = devices_;
}
for (int i = 0; i < event_count; ++i) {
const auto &event = events[i];
check_eq(event.data.fd, udev_fd, "unexpected udev fd");
std::unique_ptr<udev_device, UdevDeviceDeleter> dev{udev_monitor_receive_device(mon.get())};
check_nn(dev.get(), "epoll dev was null");
upsert_device(devices.begin(), devices.end(), std::back_inserter(devices), dev.get());
}
// Refresh state if timed out
if (event_count == 0) {
enumerate_devices(devices.begin(), devices.end(), std::back_inserter(devices), udev.get());
}
{
std::scoped_lock<std::mutex> lock(udev_thread_mutex_);
devices_ = devices;
}
dp.emit();
}
};
}
waybar::modules::Backlight::~Backlight() = default;
auto waybar::modules::Backlight::update() -> void {
decltype(devices_) devices;
{
std::scoped_lock<std::mutex> lock(udev_thread_mutex_);
devices = devices_;
}
GET_BEST_DEVICE(best, backend, preferred_device_);
const auto best = best_device(devices.cbegin(), devices.cend(), preferred_device_);
const auto previous_best_device = backend.get_previous_best_device();
if (best != nullptr) {
if (previous_best_.has_value() && previous_best_.value() == *best &&
if (previous_best_device != nullptr && *previous_best_device == *best &&
!previous_format_.empty() && previous_format_ == format_) {
return;
}
@@ -211,82 +59,16 @@ auto waybar::modules::Backlight::update() -> void {
event_box_.hide();
}
} else {
if (!previous_best_.has_value()) {
if (previous_best_device == nullptr) {
return;
}
label_.set_markup("");
}
previous_best_ = best == nullptr ? std::nullopt : std::optional{*best};
backend.set_previous_best_device(best);
previous_format_ = format_;
// Call parent update
ALabel::update();
}
template <class ForwardIt>
const waybar::modules::Backlight::BacklightDev *waybar::modules::Backlight::best_device(
ForwardIt first, ForwardIt last, std::string_view preferred_device) {
const auto found = std::find_if(
first, last, [preferred_device](const auto &dev) { return dev.name() == preferred_device; });
if (found != last) {
return &(*found);
}
const auto max = std::max_element(
first, last, [](const auto &l, const auto &r) { return l.get_max() < r.get_max(); });
return max == last ? nullptr : &(*max);
}
template <class ForwardIt, class Inserter>
void waybar::modules::Backlight::upsert_device(ForwardIt first, ForwardIt last, Inserter inserter,
udev_device *dev) {
const char *name = udev_device_get_sysname(dev);
check_nn(name);
const char *actual_brightness_attr =
strncmp(name, "amdgpu_bl", 9) == 0 ? "brightness" : "actual_brightness";
const char *actual = udev_device_get_sysattr_value(dev, actual_brightness_attr);
const char *max = udev_device_get_sysattr_value(dev, "max_brightness");
const char *power = udev_device_get_sysattr_value(dev, "bl_power");
auto found =
std::find_if(first, last, [name](const auto &device) { return device.name() == name; });
if (found != last) {
if (actual != nullptr) {
found->set_actual(std::stoi(actual));
}
if (max != nullptr) {
found->set_max(std::stoi(max));
}
if (power != nullptr) {
found->set_powered(std::stoi(power) == 0);
}
} else {
const int actual_int = actual == nullptr ? 0 : std::stoi(actual);
const int max_int = max == nullptr ? 0 : std::stoi(max);
const bool power_bool = power == nullptr ? true : std::stoi(power) == 0;
*inserter = BacklightDev{name, actual_int, max_int, power_bool};
++inserter;
}
}
template <class ForwardIt, class Inserter>
void waybar::modules::Backlight::enumerate_devices(ForwardIt first, ForwardIt last,
Inserter inserter, udev *udev) {
std::unique_ptr<udev_enumerate, UdevEnumerateDeleter> enumerate{udev_enumerate_new(udev)};
udev_enumerate_add_match_subsystem(enumerate.get(), "backlight");
udev_enumerate_scan_devices(enumerate.get());
udev_list_entry *enum_devices = udev_enumerate_get_list_entry(enumerate.get());
udev_list_entry *dev_list_entry;
udev_list_entry_foreach(dev_list_entry, enum_devices) {
const char *path = udev_list_entry_get_name(dev_list_entry);
std::unique_ptr<udev_device, UdevDeviceDeleter> dev{udev_device_new_from_syspath(udev, path)};
check_nn(dev.get(), "dev new failed");
upsert_device(first, last, inserter, dev.get());
}
}
bool waybar::modules::Backlight::handleScroll(GdkEventScroll *e) {
// Check if the user has set a custom command for scrolling
if (config_["on-scroll-up"].isString() || config_["on-scroll-down"].isString()) {
@@ -294,14 +76,33 @@ bool waybar::modules::Backlight::handleScroll(GdkEventScroll *e) {
}
// Fail fast if the proxy could not be initialized
if (!login_proxy_) {
if (!backend.is_login_proxy_initialized()) {
return true;
}
// Check scroll direction
auto dir = AModule::getScrollDir(e);
if (dir == SCROLL_DIR::NONE) {
return true;
// No worries, it will always be set because of the switch below. This is purely to suppress a
// warning
util::ChangeType ct = util::ChangeType::Increase;
switch (dir) {
case SCROLL_DIR::UP:
[[fallthrough]];
case SCROLL_DIR::RIGHT:
ct = util::ChangeType::Increase;
break;
case SCROLL_DIR::DOWN:
[[fallthrough]];
case SCROLL_DIR::LEFT:
ct = util::ChangeType::Decrease;
break;
case SCROLL_DIR::NONE:
return true;
break;
}
// Get scroll step
@@ -311,38 +112,7 @@ bool waybar::modules::Backlight::handleScroll(GdkEventScroll *e) {
step = config_["scroll-step"].asDouble();
}
// Get the best device
decltype(devices_) devices;
{
std::scoped_lock<std::mutex> lock(udev_thread_mutex_);
devices = devices_;
}
const auto best = best_device(devices.cbegin(), devices.cend(), preferred_device_);
if (best == nullptr) {
return true;
}
// Compute the absolute step
const auto abs_step = static_cast<int>(round(step * best->get_max() / 100.0f));
// Compute the new value
int new_value = best->get_actual();
if (dir == SCROLL_DIR::UP) {
new_value += abs_step;
} else if (dir == SCROLL_DIR::DOWN) {
new_value -= abs_step;
}
// Clamp the value
new_value = std::clamp(new_value, 0, best->get_max());
// Set the new value
auto call_args = Glib::VariantContainerBase(
g_variant_new("(ssu)", "backlight", std::string(best->name()).c_str(), new_value));
login_proxy_->call_sync("SetBrightness", call_args);
backend.set_brightness(preferred_device_, ct, step);
return true;
}

View File

@@ -0,0 +1,23 @@
#include "modules/backlight_slider.hpp"
#include "ASlider.hpp"
namespace waybar::modules {
BacklightSlider::BacklightSlider(const std::string& id, const Json::Value& config)
: ASlider(config, "backlight-slider", id),
interval_(config_["interval"].isUInt() ? config_["interval"].asUInt() : 1000),
preferred_device_(config["device"].isString() ? config["device"].asString() : ""),
backend(interval_, [this] { this->dp.emit(); }) {}
void BacklightSlider::update() {
uint16_t brightness = backend.get_scaled_brightness(preferred_device_);
scale_.set_value(brightness);
}
void BacklightSlider::onValueChanged() {
auto brightness = scale_.get_value();
backend.set_scaled_brightness(preferred_device_, brightness);
}
} // namespace waybar::modules

View File

@@ -100,9 +100,11 @@ void waybar::modules::Battery::refreshBatteries() {
}
auto dir_name = node.path().filename();
auto bat_defined = config_["bat"].isString();
bool bat_compatibility = config_["bat-compatibility"].asBool();
if (((bat_defined && dir_name == config_["bat"].asString()) || !bat_defined) &&
(fs::exists(node.path() / "capacity") || fs::exists(node.path() / "charge_now")) &&
fs::exists(node.path() / "uevent") && fs::exists(node.path() / "status") &&
fs::exists(node.path() / "uevent") &&
(fs::exists(node.path() / "status") || bat_compatibility) &&
fs::exists(node.path() / "type")) {
std::string type;
std::ifstream(node.path() / "type") >> type;
@@ -252,7 +254,13 @@ const std::tuple<uint8_t, float, std::string, float> waybar::modules::Battery::g
for (auto const& item : batteries_) {
auto bat = item.first;
std::string _status;
std::getline(std::ifstream(bat / "status"), _status);
/* Check for adapter status if battery is not available */
if (!std::ifstream(bat / "status")) {
std::getline(std::ifstream(adapter_ / "status"), _status);
} else {
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.
@@ -534,6 +542,13 @@ const std::tuple<uint8_t, float, std::string, float> waybar::modules::Battery::g
}
}
// Handle weighted-average
if ((config_["weighted-average"].isBool() ? config_["weighted-average"].asBool() : false) &&
total_energy_exists && total_energy_full_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) {

View File

@@ -6,12 +6,19 @@
#include <algorithm>
#include <sstream>
#include "util/scope_guard.hpp"
namespace {
using GDBusManager = std::unique_ptr<GDBusObjectManager, void (*)(GDBusObjectManager*)>;
auto generateManager() -> GDBusManager {
GError* error = nullptr;
waybar::util::ScopeGuard error_deleter([error]() {
if (error) {
g_error_free(error);
}
});
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,
@@ -19,7 +26,6 @@ auto generateManager() -> GDBusManager {
if (error) {
spdlog::error("g_dbus_object_manager_client_new_for_bus_sync() failed: {}", error->message);
g_error_free(error);
}
auto destructor = [](GDBusObjectManager* manager) {
@@ -92,28 +98,30 @@ waybar::modules::Bluetooth::Bluetooth(const std::string& id, const Json::Value&
std::back_inserter(device_preference_), [](auto x) { return x.asString(); });
}
// NOTE: assumption made that the controller that is selcected stays unchanged
// NOTE: assumption made that the controller that is selected stays unchanged
// for duration of the module
if (!findCurController(cur_controller_)) {
if (cur_controller_ = 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_);
update();
} else {
// These calls only make sense if a controller could be found
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);
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();
}
@@ -144,12 +152,16 @@ auto waybar::modules::Bluetooth::update() -> void {
std::string state;
std::string tooltip_format;
if (!cur_controller_.powered)
state = "off";
else if (!connected_devices_.empty())
state = "connected";
else
state = "on";
if (cur_controller_) {
if (!cur_controller_->powered)
state = "off";
else if (!connected_devices_.empty())
state = "connected";
else
state = "on";
} else {
state = "no-controller";
}
#ifdef WANT_RFKILL
if (rfkill_.getState()) state = "disabled";
#endif
@@ -187,8 +199,6 @@ auto waybar::modules::Bluetooth::update() -> void {
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 && !label_.get_style_context()->has_class(style_class)) {
label_.get_style_context()->add_class(style_class);
@@ -196,25 +206,32 @@ auto waybar::modules::Bluetooth::update() -> void {
label_.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);
update_style_context("discoverable", cur_controller_ ? cur_controller_->discoverable : false);
update_style_context("discovering", cur_controller_ ? cur_controller_->discovering : false);
update_style_context("pairable", cur_controller_ ? cur_controller_->pairable : false);
if (!state_.empty()) {
update_style_context(state_, false);
}
update_style_context(state, true);
state_ = state;
label_.set_markup(fmt::format(
fmt::runtime(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 (format_.empty()) {
event_box_.hide();
} else {
event_box_.show();
label_.set_markup(fmt::format(
fmt::runtime(format_), fmt::arg("status", state_),
fmt::arg("num_connections", connected_devices_.size()),
fmt::arg("controller_address", cur_controller_ ? cur_controller_->address : "null"),
fmt::arg("controller_address_type",
cur_controller_ ? cur_controller_->address_type : "null"),
fmt::arg("controller_alias", cur_controller_ ? cur_controller_->alias : "null"),
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()) {
bool tooltip_enumerate_connections_ = config_["tooltip-format-enumerate-connected"].isString();
@@ -250,9 +267,10 @@ auto waybar::modules::Bluetooth::update() -> void {
label_.set_tooltip_text(fmt::format(
fmt::runtime(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("controller_address", cur_controller_ ? cur_controller_->address : "null"),
fmt::arg("controller_address_type",
cur_controller_ ? cur_controller_->address_type : "null"),
fmt::arg("controller_alias", cur_controller_ ? cur_controller_->alias : "null"),
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),
@@ -292,8 +310,8 @@ auto waybar::modules::Bluetooth::onInterfaceProxyPropertiesChanged(
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_);
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") {
@@ -378,22 +396,23 @@ auto waybar::modules::Bluetooth::getControllerProperties(GDBusObject* object,
return false;
}
auto waybar::modules::Bluetooth::findCurController(ControllerInfo& controller_info) -> bool {
bool found_controller = false;
auto waybar::modules::Bluetooth::findCurController() -> std::optional<ControllerInfo> {
std::optional<ControllerInfo> controller_info;
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) &&
ControllerInfo info;
if (getControllerProperties(object, info) &&
(!config_["controller-alias"].isString() ||
config_["controller-alias"].asString() == controller_info.alias)) {
found_controller = true;
config_["controller-alias"].asString() == info.alias)) {
controller_info = std::move(info);
break;
}
}
g_list_free_full(objects, g_object_unref);
return found_controller;
return controller_info;
}
auto waybar::modules::Bluetooth::findConnectedDevices(const std::string& cur_controller_path,
@@ -404,7 +423,7 @@ auto waybar::modules::Bluetooth::findConnectedDevices(const std::string& cur_con
GDBusObject* object = G_DBUS_OBJECT(l->data);
DeviceInfo device;
if (getDeviceProperties(object, device) && device.connected &&
device.paired_controller == cur_controller_.path) {
device.paired_controller == cur_controller_->path) {
connected_devices.push_back(device);
}
}

View File

@@ -25,7 +25,7 @@ waybar::modules::Cava::Cava(const std::string& id, const Json::Value& config)
// Override cava parameters by the user config
prm_.inAtty = 0;
prm_.output = output_method::OUTPUT_RAW;
prm_.output = cava::output_method::OUTPUT_RAW;
strcpy(prm_.data_format, "ascii");
strcpy(prm_.raw_target, "/dev/stdout");
prm_.ascii_range = config_["format-icons"].size() - 1;
@@ -34,9 +34,9 @@ waybar::modules::Cava::Cava(const std::string& id, const Json::Value& config)
prm_.bar_spacing = 0;
prm_.bar_height = 32;
prm_.bar_width = 1;
prm_.orientation = ORIENT_TOP;
prm_.xaxis = xaxis_scale::NONE;
prm_.mono_opt = AVERAGE;
prm_.orientation = cava::ORIENT_TOP;
prm_.xaxis = cava::xaxis_scale::NONE;
prm_.mono_opt = cava::AVERAGE;
prm_.autobars = 0;
prm_.gravity = 0;
prm_.integral = 1;
@@ -51,7 +51,7 @@ waybar::modules::Cava::Cava(const std::string& id, const Json::Value& config)
prm_.upper_cut_off = config_["higher_cutoff_freq"].asLargestInt();
if (config_["sleep_timer"].isInt()) prm_.sleep_timer = config_["sleep_timer"].asInt();
if (config_["method"].isString())
prm_.input = input_method_by_name(config_["method"].asString().c_str());
prm_.input = cava::input_method_by_name(config_["method"].asString().c_str());
if (config_["source"].isString()) prm_.audio_source = config_["source"].asString().data();
if (config_["sample_rate"].isNumeric()) prm_.fifoSample = config_["sample_rate"].asLargestInt();
if (config_["sample_bits"].isInt()) prm_.fifoSampleBits = config_["sample_bits"].asInt();
@@ -64,8 +64,9 @@ waybar::modules::Cava::Cava(const std::string& id, const Json::Value& config)
prm_.noise_reduction = config_["noise_reduction"].asDouble();
if (config_["input_delay"].isInt())
fetch_input_delay_ = std::chrono::seconds(config_["input_delay"].asInt());
if (config_["hide_on_silence"].isBool()) hide_on_silence_ = config_["hide_on_silence"].asBool();
// Make cava parameters configuration
plan_ = new cava_plan{};
plan_ = new cava::cava_plan{};
audio_raw_.height = prm_.ascii_range;
audio_data_.format = -1;
@@ -155,12 +156,13 @@ auto waybar::modules::Cava::update() -> void {
downThreadDelay(frame_time_milsec_, suspend_silence_delay_);
// Process: execute cava
pthread_mutex_lock(&audio_data_.lock);
cava_execute(audio_data_.cava_in, audio_data_.samples_counter, audio_raw_.cava_out, plan_);
cava::cava_execute(audio_data_.cava_in, audio_data_.samples_counter, audio_raw_.cava_out,
plan_);
if (audio_data_.samples_counter > 0) audio_data_.samples_counter = 0;
pthread_mutex_unlock(&audio_data_.lock);
// Do transformation under raw data
audio_raw_fetch(&audio_raw_, &prm_, &rePaint_);
audio_raw_fetch(&audio_raw_, &prm_, &rePaint_, plan_);
if (rePaint_ == 1) {
text_.clear();
@@ -174,10 +176,13 @@ auto waybar::modules::Cava::update() -> void {
}
label_.set_markup(text_);
label_.show();
ALabel::update();
}
} else
} else {
upThreadDelay(frame_time_milsec_, suspend_silence_delay_);
if (hide_on_silence_) label_.hide();
}
}
auto waybar::modules::Cava::doAction(const std::string& name) -> void {

63
src/modules/cpu.cpp Normal file
View File

@@ -0,0 +1,63 @@
#include "modules/cpu.hpp"
#include "modules/cpu_frequency.hpp"
#include "modules/cpu_usage.hpp"
#include "modules/load.hpp"
// In the 80000 version of fmt library authors decided to optimize imports
// and moved declarations required for fmt::dynamic_format_arg_store in new
// header fmt/args.h
#if (FMT_VERSION >= 80000)
#include <fmt/args.h>
#else
#include <fmt/core.h>
#endif
waybar::modules::Cpu::Cpu(const std::string& id, const Json::Value& config)
: ALabel(config, "cpu", id, "{usage}%", 10) {
thread_ = [this] {
dp.emit();
thread_.sleep_for(interval_);
};
}
auto waybar::modules::Cpu::update() -> void {
// TODO: as creating dynamic fmt::arg arrays is buggy we have to calc both
auto [load1, load5, load15] = Load::getLoad();
auto [cpu_usage, tooltip] = CpuUsage::getCpuUsage(prev_times_);
auto [max_frequency, min_frequency, avg_frequency] = CpuFrequency::getCpuFrequency();
if (tooltipEnabled()) {
label_.set_tooltip_text(tooltip);
}
auto format = format_;
auto total_usage = cpu_usage.empty() ? 0 : cpu_usage[0];
auto state = getState(total_usage);
if (!state.empty() && config_["format-" + state].isString()) {
format = config_["format-" + state].asString();
}
if (format.empty()) {
event_box_.hide();
} else {
event_box_.show();
auto icons = std::vector<std::string>{state};
fmt::dynamic_format_arg_store<fmt::format_context> store;
store.push_back(fmt::arg("load", load1));
store.push_back(fmt::arg("usage", total_usage));
store.push_back(fmt::arg("icon", getIcon(total_usage, icons)));
store.push_back(fmt::arg("max_frequency", max_frequency));
store.push_back(fmt::arg("min_frequency", min_frequency));
store.push_back(fmt::arg("avg_frequency", avg_frequency));
for (size_t i = 1; i < cpu_usage.size(); ++i) {
auto core_i = i - 1;
auto core_format = fmt::format("usage{}", core_i);
store.push_back(fmt::arg(core_format.c_str(), cpu_usage[i]));
auto icon_format = fmt::format("icon{}", core_i);
store.push_back(fmt::arg(icon_format.c_str(), getIcon(cpu_usage[i], icons)));
}
label_.set_markup(fmt::vformat(format, store));
}
// Call parent update
ALabel::update();
}

View File

@@ -0,0 +1,15 @@
#include <spdlog/spdlog.h>
#include <cmath> // NAN
#include "modules/cpu_frequency.hpp"
std::vector<float> waybar::modules::CpuFrequency::parseCpuFrequencies() {
static std::vector<float> frequencies;
if (frequencies.empty()) {
spdlog::warn(
"cpu/bsd: parseCpuFrequencies is not implemented, expect garbage in {*_frequency}");
frequencies.push_back(NAN);
}
return frequencies;
}

View File

@@ -0,0 +1,67 @@
#include "modules/cpu_frequency.hpp"
// In the 80000 version of fmt library authors decided to optimize imports
// and moved declarations required for fmt::dynamic_format_arg_store in new
// header fmt/args.h
#if (FMT_VERSION >= 80000)
#include <fmt/args.h>
#else
#include <fmt/core.h>
#endif
waybar::modules::CpuFrequency::CpuFrequency(const std::string& id, const Json::Value& config)
: ALabel(config, "cpu_frequency", id, "{avg_frequency}", 10) {
thread_ = [this] {
dp.emit();
thread_.sleep_for(interval_);
};
}
auto waybar::modules::CpuFrequency::update() -> void {
// TODO: as creating dynamic fmt::arg arrays is buggy we have to calc both
auto [max_frequency, min_frequency, avg_frequency] = CpuFrequency::getCpuFrequency();
if (tooltipEnabled()) {
auto tooltip =
fmt::format("Minimum frequency: {}\nAverage frequency: {}\nMaximum frequency: {}\n",
min_frequency, avg_frequency, max_frequency);
label_.set_tooltip_text(tooltip);
}
auto format = format_;
auto state = getState(avg_frequency);
if (!state.empty() && config_["format-" + state].isString()) {
format = config_["format-" + state].asString();
}
if (format.empty()) {
event_box_.hide();
} else {
event_box_.show();
auto icons = std::vector<std::string>{state};
fmt::dynamic_format_arg_store<fmt::format_context> store;
store.push_back(fmt::arg("icon", getIcon(avg_frequency, icons)));
store.push_back(fmt::arg("max_frequency", max_frequency));
store.push_back(fmt::arg("min_frequency", min_frequency));
store.push_back(fmt::arg("avg_frequency", avg_frequency));
label_.set_markup(fmt::vformat(format, store));
}
// Call parent update
ALabel::update();
}
std::tuple<float, float, float> waybar::modules::CpuFrequency::getCpuFrequency() {
std::vector<float> frequencies = CpuFrequency::parseCpuFrequencies();
if (frequencies.empty()) {
return {0.f, 0.f, 0.f};
}
auto [min, max] = std::minmax_element(std::begin(frequencies), std::end(frequencies));
float avg_frequency =
std::accumulate(std::begin(frequencies), std::end(frequencies), 0.0) / frequencies.size();
// Round frequencies with double decimal precision to get GHz
float max_frequency = std::ceil(*max / 10.0) / 100.0;
float min_frequency = std::ceil(*min / 10.0) / 100.0;
avg_frequency = std::ceil(avg_frequency / 10.0) / 100.0;
return {max_frequency, min_frequency, avg_frequency};
}

View File

@@ -1,36 +1,8 @@
#include <filesystem>
#include "modules/cpu.hpp"
#include "modules/cpu_frequency.hpp"
std::vector<std::tuple<size_t, size_t>> waybar::modules::Cpu::parseCpuinfo() {
const std::string data_dir_ = "/proc/stat";
std::ifstream info(data_dir_);
if (!info.is_open()) {
throw std::runtime_error("Can't open " + data_dir_);
}
std::vector<std::tuple<size_t, size_t>> cpuinfo;
std::string line;
while (getline(info, line)) {
if (line.substr(0, 3).compare("cpu") != 0) {
break;
}
std::stringstream sline(line.substr(5));
std::vector<size_t> times;
for (size_t time = 0; sline >> time; times.push_back(time))
;
size_t idle_time = 0;
size_t total_time = 0;
if (times.size() >= 4) {
idle_time = times[3];
total_time = std::accumulate(times.begin(), times.end(), 0);
}
cpuinfo.emplace_back(idle_time, total_time);
}
return cpuinfo;
}
std::vector<float> waybar::modules::Cpu::parseCpuFrequencies() {
std::vector<float> waybar::modules::CpuFrequency::parseCpuFrequencies() {
const std::string file_path_ = "/proc/cpuinfo";
std::ifstream info(file_path_);
if (!info.is_open()) {

View File

@@ -8,7 +8,8 @@
#include <cmath> // NAN
#include <cstdlib> // malloc
#include "modules/cpu.hpp"
#include "modules/cpu_usage.hpp"
#include "util/scope_guard.hpp"
#if defined(__NetBSD__) || defined(__OpenBSD__)
#include <sys/sched.h>
@@ -27,12 +28,17 @@ typedef uint64_t pcp_time_t;
typedef long pcp_time_t;
#endif
std::vector<std::tuple<size_t, size_t>> waybar::modules::Cpu::parseCpuinfo() {
std::vector<std::tuple<size_t, size_t>> waybar::modules::CpuUsage::parseCpuinfo() {
cp_time_t sum_cp_time[CPUSTATES];
size_t sum_sz = sizeof(sum_cp_time);
int ncpu = sysconf(_SC_NPROCESSORS_CONF);
size_t sz = CPUSTATES * (ncpu + 1) * sizeof(pcp_time_t);
pcp_time_t *cp_time = static_cast<pcp_time_t *>(malloc(sz)), *pcp_time = cp_time;
waybar::util::ScopeGuard cp_time_deleter([cp_time]() {
if (cp_time) {
free(cp_time);
}
});
#if defined(__NetBSD__)
int mib[] = {
CTL_KERN,
@@ -97,16 +103,5 @@ std::vector<std::tuple<size_t, size_t>> waybar::modules::Cpu::parseCpuinfo() {
}
cpuinfo.emplace_back(single_cp_time[CP_IDLE], total);
}
free(cp_time);
return cpuinfo;
}
std::vector<float> waybar::modules::Cpu::parseCpuFrequencies() {
static std::vector<float> frequencies;
if (frequencies.empty()) {
spdlog::warn(
"cpu/bsd: parseCpuFrequencies is not implemented, expect garbage in {*_frequency}");
frequencies.push_back(NAN);
}
return frequencies;
}

View File

@@ -1,4 +1,4 @@
#include "modules/cpu.hpp"
#include "modules/cpu_usage.hpp"
// In the 80000 version of fmt library authors decided to optimize imports
// and moved declarations required for fmt::dynamic_format_arg_store in new
@@ -9,19 +9,17 @@
#include <fmt/core.h>
#endif
waybar::modules::Cpu::Cpu(const std::string& id, const Json::Value& config)
: ALabel(config, "cpu", id, "{usage}%", 10) {
waybar::modules::CpuUsage::CpuUsage(const std::string& id, const Json::Value& config)
: ALabel(config, "cpu_usage", id, "{usage}%", 10) {
thread_ = [this] {
dp.emit();
thread_.sleep_for(interval_);
};
}
auto waybar::modules::Cpu::update() -> void {
auto waybar::modules::CpuUsage::update() -> void {
// TODO: as creating dynamic fmt::arg arrays is buggy we have to calc both
auto cpu_load = getCpuLoad();
auto [cpu_usage, tooltip] = getCpuUsage();
auto [max_frequency, min_frequency, avg_frequency] = getCpuFrequency();
auto [cpu_usage, tooltip] = CpuUsage::getCpuUsage(prev_times_);
if (tooltipEnabled()) {
label_.set_tooltip_text(tooltip);
}
@@ -38,12 +36,8 @@ auto waybar::modules::Cpu::update() -> void {
event_box_.show();
auto icons = std::vector<std::string>{state};
fmt::dynamic_format_arg_store<fmt::format_context> store;
store.push_back(fmt::arg("load", cpu_load));
store.push_back(fmt::arg("usage", total_usage));
store.push_back(fmt::arg("icon", getIcon(total_usage, icons)));
store.push_back(fmt::arg("max_frequency", max_frequency));
store.push_back(fmt::arg("min_frequency", min_frequency));
store.push_back(fmt::arg("avg_frequency", avg_frequency));
for (size_t i = 1; i < cpu_usage.size(); ++i) {
auto core_i = i - 1;
auto core_format = fmt::format("usage{}", core_i);
@@ -58,25 +52,18 @@ auto waybar::modules::Cpu::update() -> void {
ALabel::update();
}
double waybar::modules::Cpu::getCpuLoad() {
double load[1];
if (getloadavg(load, 1) != -1) {
return std::ceil(load[0] * 100.0) / 100.0;
}
throw std::runtime_error("Can't get Cpu load");
}
std::tuple<std::vector<uint16_t>, std::string> waybar::modules::Cpu::getCpuUsage() {
if (prev_times_.empty()) {
prev_times_ = parseCpuinfo();
std::tuple<std::vector<uint16_t>, std::string> waybar::modules::CpuUsage::getCpuUsage(
std::vector<std::tuple<size_t, size_t>>& prev_times) {
if (prev_times.empty()) {
prev_times = CpuUsage::parseCpuinfo();
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
std::vector<std::tuple<size_t, size_t>> curr_times = parseCpuinfo();
std::vector<std::tuple<size_t, size_t>> curr_times = CpuUsage::parseCpuinfo();
std::string tooltip;
std::vector<uint16_t> usage;
for (size_t i = 0; i < curr_times.size(); ++i) {
auto [curr_idle, curr_total] = curr_times[i];
auto [prev_idle, prev_total] = prev_times_[i];
auto [prev_idle, prev_total] = prev_times[i];
const float delta_idle = curr_idle - prev_idle;
const float delta_total = curr_total - prev_total;
uint16_t tmp = 100 * (1 - delta_idle / delta_total);
@@ -87,23 +74,6 @@ std::tuple<std::vector<uint16_t>, std::string> waybar::modules::Cpu::getCpuUsage
}
usage.push_back(tmp);
}
prev_times_ = curr_times;
prev_times = curr_times;
return {usage, tooltip};
}
std::tuple<float, float, float> waybar::modules::Cpu::getCpuFrequency() {
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));
float avg_frequency =
std::accumulate(std::begin(frequencies), std::end(frequencies), 0.0) / frequencies.size();
// Round frequencies with double decimal precision to get GHz
float max_frequency = std::ceil(*max / 10.0) / 100.0;
float min_frequency = std::ceil(*min / 10.0) / 100.0;
avg_frequency = std::ceil(avg_frequency / 10.0) / 100.0;
return {max_frequency, min_frequency, avg_frequency};
}

View File

@@ -0,0 +1,31 @@
#include <filesystem>
#include "modules/cpu_usage.hpp"
std::vector<std::tuple<size_t, size_t>> waybar::modules::CpuUsage::parseCpuinfo() {
const std::string data_dir_ = "/proc/stat";
std::ifstream info(data_dir_);
if (!info.is_open()) {
throw std::runtime_error("Can't open " + data_dir_);
}
std::vector<std::tuple<size_t, size_t>> cpuinfo;
std::string line;
while (getline(info, line)) {
if (line.substr(0, 3).compare("cpu") != 0) {
break;
}
std::stringstream sline(line.substr(5));
std::vector<size_t> times;
for (size_t time = 0; sline >> time; times.push_back(time))
;
size_t idle_time = 0;
size_t total_time = 0;
if (times.size() >= 4) {
idle_time = times[3];
total_time = std::accumulate(times.begin(), times.end(), 0);
}
cpuinfo.emplace_back(idle_time, total_time);
}
return cpuinfo;
}

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