Compare commits

..

288 Commits

Author SHA1 Message Date
Alex
32eac3ccb7 chore: 0.10.0 2024-03-13 19:46:56 +01:00
Alexis Rouillard
20f08b881a Merge pull request #2996 from rroohhh/feat/horizontal_scroll
feat: allow horizontal scroll
2024-03-13 19:45:20 +01:00
Alexis Rouillard
214858f413 Merge pull request #3001 from grimpy/fixpersitantworkspaces
Fix peristant workspaces for sway
2024-03-12 14:22:18 +01:00
Jo De Boeck
7b3d155608 Fix peristant workspaces for sway
Fixes: #2998

Signed-off-by: Jo De Boeck <deboeck.jo@gmail.com>
2024-03-12 04:40:54 +02:00
Robin Ole Heinemann
207e99876d feat: allow horizontal scroll 2024-03-08 21:48:27 +01:00
Alexis Rouillard
4c46d7d245 Merge pull request #2887 from dann-merlin/master
Add justify config option for Labels
2024-03-05 09:01:44 +01:00
Merlin Sievers
25b85800a5 Add documentation for justify option 2024-03-04 20:00:57 +01:00
Alexis Rouillard
380607583e Merge pull request #2971 from picnoir/pic/power-profiles-daemon
Introduce a power-profiles-daemon module
2024-03-04 14:25:16 +01:00
Alexis Rouillard
26af1066e1 Merge pull request #2984 from alebastr/too-much-logs-mpd
mpd: less aggressive logging and reconnections
2024-03-03 10:05:22 +01:00
Alexis Rouillard
97cd2b47b8 Merge pull request #2986 from ErikReider/sway-workspaces-scroll-fix 2024-03-02 23:37:06 +01:00
Erik Reider
9de0e393ab Sway-Workspaces: Fixed scrolling not working
Fixes regression in bb843e0 that caused scrolling over the bar not working
2024-03-02 23:08:21 +01:00
Félix Baylac Jacqué
5578c122ab modules/power-profiles-daemon: kebab case name in config
power_profiles_daemon => power-profiles-daemon
2024-03-02 18:44:25 +01:00
Félix Baylac Jacqué
5ba7c9eb60 modules/power-profiles-daemon: add some right padding
The icon is not really centered in the box. This is likely coming from
a bogus glyph width calculation. It's not a big deal, but that's not
really pleasant aesthetically-wise.

Adding a bit of right padding makes it much more pleasant to watch. It
does not really disrupt a wider display form, like one that
explicitely writes the active profile.
2024-03-02 18:20:46 +01:00
Félix Baylac Jacqué
cc759a8b8f Power profiles daemon: address review comments
Adding :
- A missing try/catch
- Glib::Error catch
- Remove the useless destructor
- Populate the profiles vector more efficiently
- Numerous nits
2024-03-02 18:20:46 +01:00
Félix Baylac Jacqué
bddc870340 modules/power-profiles-daemon: add man page
There was no way to display the default value of format-icons without
breaking the table :(
2024-03-02 09:46:14 +01:00
Félix Baylac Jacqué
09bb6a055d modules/power_profiles_daemon: safely call dbus asynchronously
2 changes to address the review feedback:

1. Aleksei pointed out in this
   comment (https://github.com/Alexays/Waybar/pull/2971#issuecomment-1972364896)
   that there's no way to tell if a proxy is alive other than trying to
   call a method on it. We perform a little dance to check whether or
   not power-profiles-daemon is available on the system by calling
   properties.GetAll. If something responds, we assume
   power-profiles-daemon is installed, it's then safe to draw the
   widget and attach the callback to the active profile.
2. We replaced all the synchronous DBus operations by their async
   counterparts.
2024-03-01 12:55:37 +01:00
Félix Baylac Jacqué
61fed6a214 modules/power_profiles_daemon: add custom format from config
We move to a single icon label format to save space on the bar. We
still display the profile name and the driver in the tooltip.
2024-03-01 11:18:24 +01:00
Aleksei Bavshin
c03fa38974 fix(mpd): use default interval in the example config
2 seconds is 2.5 times more often than the default for the module.
2024-03-01 00:53:12 -08:00
Aleksei Bavshin
bb60d41842 fix(mpd): use timers with second granularity where possible
Reuse already armed timer in Disconnected state.
2024-03-01 00:27:23 -08:00
Aleksei Bavshin
653c24cee1 feat(mpd): tone down logs if the server is not running 2024-03-01 00:16:19 -08:00
Alexis Rouillard
bdff489850 Merge pull request #2983 from alebastr/ci-freebsd-on-ubuntu
ci: move FreeBSD to ubuntu runners
2024-03-01 05:41:40 +01:00
Félix Baylac Jacqué
162b41c4d0 modules/power-profiles-daemon: apply clang-tidy suggestions 2024-02-29 21:46:27 +01:00
Aleksei Bavshin
55915f95f1 ci: move FreeBSD to ubuntu runners
With the recent runner hardware upgrade[1] and support in the
cross-platform-actions[2] it became possible to use a Linux runner for
this workflow.
Linux-based configuration appears to be faster and stabler than macOS,
so it's now recommended for use.

[1]: https://github.blog/2024-01-17-github-hosted-runners-double-the-power-for-open-source/
[2]: https://github.com/cross-platform-actions/action/releases/tag/v0.23.0
2024-02-28 23:56:10 -08:00
Alexis Rouillard
e7c7ef6814 Merge pull request #2979 from grimpy/filterscratch
Filter out special output __i3 which contains scratchpad
2024-02-28 10:38:33 +01:00
Alexis Rouillard
04f73e7303 Merge pull request #2973 from Azazel-Woodwind/feature/hyprland-window-improvements
Improved hyprland/window by fixing icon search and implementing configurable spacing
2024-02-28 09:29:54 +01:00
Azazel
ba48d26dd4 chore: amend default icon spacing 2024-02-28 00:24:58 +00:00
Jo De Boeck
5a887fe1ef Filter out special output __i3 which contains scratchpad
Fixes: #2966

Signed-off-by: Jo De Boeck <deboeck.jo@gmail.com>
2024-02-27 23:43:00 +02:00
Alexis Rouillard
e79ea93d7d Merge pull request #2967 from aruhier/pr_hyprland_workspaces
hyprland/workspaces: Improve the workspaces persistency logic
2024-02-27 16:41:32 +01:00
Azazel
615c9050e7 fix: prevent icon showing when app_identifier is empty 2024-02-26 22:52:28 +00:00
Azazel
c59bb509bd fix: hide icon if window is unfocused 2024-02-26 21:00:16 +00:00
Azazel
a7d8b1bacf feat: re-add default and configurable icon spacing 2024-02-26 20:58:38 +00:00
Félix Baylac Jacqué
968f469289 modules/power-profiles-daemon: run clang format 2024-02-26 14:44:14 +01:00
Félix Baylac Jacqué
c38d05b04f Introduce power-profiles-daemon module
We introduce a module in charge to display and toggle on click the
power profiles via power-profiles-daemon.

https://gitlab.freedesktop.org/upower/power-profiles-daemon

This daemon is pretty widespread. It's the component used by Gnome and
KDE to manage the power profiles. The power management daemon is a
pretty important software component for laptops and other
battery-powered devices.

We're using the daemon DBus interface to:

- Fetch the available power profiles.
- Track the active power profile.
- Change the active power profile.

The original author recently gave up maintenance on the project. The
Upower group took over the maintenance burden… …and created a new
DBus name for the project. The old name is still advertised for now.
We use the old name for compatibility sake: most distributions did not
release 0.20, which introduces this new DBus name. We'll likely revisit
this in the future and point to the new bus name. See the inline
comment for more details.

Given how widespread this daemon is, I activated the module in the
default configuration.
2024-02-26 14:44:14 +01:00
Azazel
695c786354 refactor: reuse toLowerCase function 2024-02-26 04:17:45 +00:00
Azazel
16aced7f9f feat: move name and classes from label_ to box_ 2024-02-26 04:07:03 +00:00
Anthony Ruhier
d6d4d87cf7 Attributes doc format fix from the review
Co-authored-by: Tuur Vanhoutte <4633209+zjeffer@users.noreply.github.com>
2024-02-26 00:21:36 +01:00
Anthony Ruhier
b3ee94d87a Improve hyprland/workspaces persistency logic
Fixes #2945

Split the config and rule persistency in 2 attributes, one storing the
persistency as set in Waybar's config, the other one storing the
persistency as set in Hyprland.

It fixes some conflicts between the persistency state of a workspace as
set in Waybar's config and its dynamic state in Hyprland.

It allows to remove a persistent workspace in Waybar if this workspace
is removed from Hyprland and if the workspace is not set as persistent
in Waybar's config.
2024-02-26 00:14:25 +01:00
Azazel
3a5aa5ee83 feat: improve default spacing and add to config 2024-02-25 22:56:52 +00:00
Azazel
0ead42e52b feat: improve search of .desktop files 2024-02-25 22:55:30 +00:00
Alexis Rouillard
6703adc37f Merge pull request #2972 from alebastr/config-tweaks
RFC: Rename config to config.jsonc
2024-02-25 23:43:25 +01:00
Aleksei Bavshin
43aabf046c chore: rename config to config.jsonc
Only changes the name of the default config we install and does not
affect the lookup logic in any way.

Man pages were already fixed in #2744
2024-02-25 12:00:53 -08:00
Aleksei Bavshin
2108959644 chore(config): add modeline for Emacs json-mode
json-mode supports jsonc format since 1.8.0, but does not register
.jsonc as a file extension.
2024-02-25 11:21:58 -08:00
Alexis Rouillard
3a33c0b290 Merge pull request #2930 from zjeffer/fix/zjeffer/hyprland-clang-tidy
fix clang-tidy errors in hyprland module
2024-02-25 17:11:13 +01:00
Alexis Rouillard
fb193529fc Merge pull request #2961 from alebastr/sway-language-single-layout
feat(sway/language): option to hide module with single layout
2024-02-25 17:10:50 +01:00
Alexis Rouillard
75dce1ef4b Merge pull request #2969 from alebastr/config-tweaks
Config tweaks
2024-02-25 17:10:22 +01:00
zjeffer
42f4386e2e fix clang-tidy errors in hyprland module 2024-02-25 12:11:22 +01:00
zjeffer
edd723d95c Change PrivateMember styling to use trailing underscore instead of m_ in .clang-tidy 2024-02-25 11:44:55 +01:00
Aleksei Bavshin
05fbbc1c43 style: align 'sway/mode' text with other modules
Use `box-shadow` instead of borders for consistent vertical alignment.
See 77c7e10 for a similar conversion of other modules.
2024-02-24 18:26:02 -08:00
Aleksei Bavshin
2540c07f1d chore: wrap module lists in the config
"modules-right" has gotten too long, and it's easier to compare configs
that way.
2024-02-24 18:24:39 -08:00
Aleksei Bavshin
188789592e feat(sway/language): option to hide module with single layout 2024-02-24 00:30:45 -08:00
Aleksei Bavshin
99c48bca36 fix: formatting 2024-02-24 00:30:44 -08:00
Alexis Rouillard
601af3de81 Merge pull request #2958 from JonnyTischbein/mediaplayer-exclude 2024-02-24 00:06:03 +01:00
Jonny Tischbein
3d31e9a22a mediaplayer: add exclude player option 2024-02-23 18:41:45 +01:00
Alexis Rouillard
793394c862 Merge pull request #2949 from aokblast/feat/bsd_cpufreq
feat: implement cpufreq for bsd by sysctl
2024-02-22 01:25:21 +01:00
aokblast
514d00803c feat: implement cpufreq for bsd by sysctl 2024-02-22 04:47:09 +08:00
Alexis Rouillard
977c66e7c5 Merge pull request #2948 from alebastr/clang-tidy-fix
ci: fix clang-tidy action
2024-02-21 09:19:20 +01:00
Alex
450a344426 chore: only label issues 2024-02-21 09:19:03 +01:00
Aleksei Bavshin
5fc2b97194 ci: fix clang-tidy action 2024-02-20 17:22:33 -08:00
Alex
efb2eb5073 chore: update cpp-linter 2024-02-20 22:24:30 +01:00
Alexis Rouillard
1606dce62e Merge pull request #2944 from grimpy/waybarwindows
Implement windows formating in sway/workspaces
2024-02-20 18:34:32 +01:00
Jo De Boeck
bb843e0494 Implement windows formating in sway/workspaces
This implementation mimics to some extend the implementation of hyprland

Signed-off-by: Jo De Boeck <deboeck.jo@gmail.com>
2024-02-20 19:12:26 +02:00
Alexis Rouillard
1b4008c58b Merge pull request #2943 from iynaix/master
nix: update libcava version and removal of gtk-layer-shell meson option
2024-02-20 11:34:04 +01:00
Alex
a45932973a fix: lint 2024-02-20 11:33:41 +01:00
Lin Xianyi
00ee538c95 nix: update libcava version and removal of gtk-layer-shell meson option 2024-02-20 17:57:07 +08:00
Alexis Rouillard
4ef5b48474 Merge pull request #2934 from tomben13/master
Fixed window#waybar.swallowing for module hyprland/window
2024-02-20 10:39:33 +01:00
Tom Benham
e6aa06cdf3 window#waybar.swallowing -- backward compatibility 2024-02-20 09:39:03 +01:00
Alex
e42635197c chore: more labels 2024-02-20 08:35:28 +01:00
Alex
b8324be8c4 fix: token 2024-02-20 08:26:14 +01:00
Alexis Rouillard
197bc6a877 Merge pull request #2938 from thejch/click-special 2024-02-20 08:03:16 +01:00
Alexis Rouillard
536933ca24 Merge pull request #2940 from alebastr/clock 2024-02-20 08:02:08 +01:00
Alexis Rouillard
a118af0d1b Merge pull request #2939 from alebastr/ci-update-debian-dependencies 2024-02-20 08:01:18 +01:00
Aleksei Bavshin
f885baba61 fix(clock): remove literal operator with reserved name
```
../include/util/date.hpp:34:26: warning: literal operator suffixes not preceded by ‘_’ are reserved for future standardization [-Wliteral-suffix]
   34 | constexpr decltype(auto) operator""d(unsigned long long d) noexcept {
```
2024-02-19 21:56:47 -08:00
Aleksei Bavshin
a2deff3689 fix(clock): crash on scrolling with local timezone ("") in the list
While we at it, eliminate use of non-portable GCC conditional expression
syntax. There are no significant side-effects that would justify use of
the language extension.
2024-02-19 21:56:46 -08:00
Aleksei Bavshin
5d6acfd1d4 test: restore compatibility with older Catch2 releases 2024-02-19 17:00:01 -08:00
Aleksei Bavshin
d59d6e8765 chore: remove duplicate fedora/c++20 job definition 2024-02-19 16:35:56 -08:00
Aleksei Bavshin
bdb2f2bd1a chore: update Debian CI dependencies
This should speed-up "linux (debian)" and "clang-tidy" builds and enable
lints for more modules.
2024-02-19 16:35:21 -08:00
Jeremy Huang
4a5444d196 fix click special 2024-02-19 16:16:46 -08:00
Alexis Rouillard
ce5a1cf2f9 Merge pull request #2937 from alebastr/factory-includes
refactor: move all module includes to factory.cpp
2024-02-20 00:44:38 +01:00
Aleksei Bavshin
c6f5cbdf0c refactor: move all module includes to factory.cpp
None of these includes are required in the header.
2024-02-19 15:11:08 -08:00
Alexis Rouillard
6048e23e09 Merge pull request #2926 from alebastr/meson-cleanup
build: refactorings and deprecation fixes
2024-02-19 23:44:52 +01:00
Alexis Rouillard
3d75167e67 Merge pull request #2936 from Alexays/revert-2773-waybarwindows
Revert "Implement windows formating in sway/workspaces"
2024-02-19 23:28:15 +01:00
Alexis Rouillard
ee2407496f Revert "Implement windows formating in sway/workspaces" 2024-02-19 23:28:08 +01:00
Alex
175852e527 chore: auto label 2024-02-19 23:24:20 +01:00
Alexis Rouillard
d36f15c26b Merge pull request #2935 from Alexays/revert-2915-cpu_style
Revert "Add style class for CPU state"
2024-02-19 23:10:20 +01:00
Alexis Rouillard
742cd7f371 Revert "Add style class for CPU state" 2024-02-19 23:10:10 +01:00
Alex
41b2d0cb29 chore(workflows): concurrency 2024-02-19 23:09:24 +01:00
Aleksei Bavshin
a95b6a39c9 build: mark bluetooth as Linux-specific 2024-02-19 14:08:22 -08:00
Alex
bd0bf836c7 fix: lint 2024-02-19 23:07:50 +01:00
Alexis Rouillard
ae1e11db22 Merge pull request #2773 from grimpy/waybarwindows
Implement windows formating in sway/workspaces
2024-02-19 23:05:24 +01:00
Alexis Rouillard
347197865f Merge pull request #2885 from jones-josh/ordinal-date
Add ordinal date toolbar format specifier to clock module
2024-02-19 23:03:40 +01:00
Alexis Rouillard
91b79a2e9e Merge pull request #2894 from jramrath/active-for-hyprland-special-workspaces
Add css classes to hyprland special workspaces
2024-02-19 23:02:17 +01:00
Alexis Rouillard
70dc388dff Merge pull request #2915 from haasn/cpu_style
Add style class for CPU state
2024-02-19 22:58:21 +01:00
Alexis Rouillard
bba8da76b6 Merge pull request #2836 from alebastr/require-gtk-layer-shell
Require gtk-layer-shell
2024-02-19 22:57:50 +01:00
Alexis Rouillard
9abd0da1c7 Merge pull request #2603 from zjeffer/hyprland/persistent-workspaces
Hyprland/workspaces: use Hyprland's workspace rules for persistency
2024-02-19 22:55:28 +01:00
Alexis Rouillard
6fbae3bd7b Merge pull request #2888 from imran1008/hwmon-path-abs-subdir
Search for the first hwmon* directory
2024-02-19 22:53:31 +01:00
Alexis Rouillard
9191cae13b Merge pull request #2923 from jones-josh/custom-tooltip-format
Add check for tooltip-format for custom modules
2024-02-19 22:47:22 +01:00
Alexis Rouillard
a18b6dcc29 Merge pull request #2925 from LukashonakV/bump_cava
libcava bump 0.10.1
2024-02-19 22:47:04 +01:00
Alexis Rouillard
c553e3028e Merge pull request #2928 from zjeffer/fix/zjeffer/build-warnings
fix build warning in bar.cpp
2024-02-19 22:41:44 +01:00
Tom Benham
745d5687b8 Fixed window#waybar.swallowing for module hyprland/window 2024-02-19 22:23:03 +01:00
Aleksei Bavshin
8a4a44896a refactor: merge BarSurface into Bar
With only one implementation left, the abstraction is no longer
necessary.
2024-02-19 03:00:38 -08:00
Aleksei Bavshin
4420447e74 fix(bar): use std::string for mode names
`string_view` leads to UAF when reading custom mode definitions from the
configuration.
2024-02-19 01:50:40 -08:00
zjeffer
11310b89f0 hyprland/workspaces: Use hyprland's persistent workspaces configuration 2024-02-18 16:04:47 +01:00
zjeffer
a02bacdd53 fix build warning 2024-02-18 12:01:36 +01:00
Aleksei Bavshin
543290ab07 fix: -Wnon-virtual-dtor warning in CssReloadHelper
```
../include/util/css_reload_helper.hpp:15:7: warning: 'class waybar::CssReloadHelper' has virtual functions and accessible non-virtual destructor [-Wnon-virtual-dtor]
```
2024-02-17 21:43:10 -08:00
Aleksei Bavshin
fd5a03dc5f build: disable catch2 unit-tests
The library tests take more time to complie than the entire Waybar.
2024-02-17 21:43:09 -08:00
Aleksei Bavshin
f3063e86aa build: install man pages only for enabled modules 2024-02-17 21:43:08 -08:00
Aleksei Bavshin
3cb587945a fix: use gtk_layer_set_keyboard_mode()
`gtk_layer_set_keyboard_interactivity()` is deprecated and was removed
in gtk4-layer-shell.
Note that this bumps version requirement to 0.6.0
2024-02-17 11:23:19 -08:00
Aleksei Bavshin
9a21884272 feat!: drop RawSurfaceImpl with direct use of wlr-layer-shell
BREAKING CHANGE: gtk-layer-shell is now required and unconditionally
used. The corresponding config option is removed.

As a part of preparation for future versions of GTK, remove an ability
to use wlr-layer-shell directly. The APIs it required were dropped in
GTK4, and with the menus/tooltips positioning issue being practically
unsolvable it doesn't make sense to keep maintaining the code.
2024-02-17 11:23:17 -08:00
Aleksei Bavshin
4f5dd53571 chore: update gtk-layer-shell subproject to 0.8.2 2024-02-17 11:21:43 -08:00
Aleksei Bavshin
4b34486143 man: fix missing code block fence in hyprland-workspaces 2024-02-17 08:45:44 -08:00
Aleksei Bavshin
63935ba0fb build: don't use sh for scdoc 2024-02-17 08:45:18 -08:00
Aleksei Bavshin
d9f9fb51ff build: use / instead of join_paths 2024-02-17 08:45:17 -08:00
Aleksei Bavshin
c2f37705ad build: address meson deprecation warnings:
- `ExternalProgram.path`
- `dependency.get_pkgconfig_variable`
- `meson.build_root`
- `meson.source_root`
2024-02-17 08:45:16 -08:00
Aleksei Bavshin
72406fa3f2 build: require gio-unix-2.0 unconditionally
We already use it without checking (`<gio/gdesktopappinfo.h>` in
wlr/taskbar), it's a transitive dependency of GTK and it's always
available on Unix platforms.
2024-02-17 08:33:31 -08:00
Aleksei Bavshin
104accdc34 build: drop std::filesystem checks
The `<experimental/filesystem>` and `-lc++experimental` aren't needed
since LLVM 9.0. And since we now require C++20, checking for the
`<filesystem>` support shouldn't be necessary either.
2024-02-17 08:33:22 -08:00
Viktar Lukashonak
d7d4dca6ba libcava bump 0.10.1
Signed-off-by: Viktar Lukashonak <myxabeer@gmail.com>
2024-02-17 18:20:03 +03:00
Josh Jones
7f3e396383 add tooltip-format to custom module man page 2024-02-16 15:26:36 +01:00
Alexis Rouillard
3cd311819b Merge pull request #2921 from alebastr/module-classes
Add `module` class to the root elements of the modules
2024-02-16 13:34:50 +01:00
Josh Jones
9c3881f6f8 add check for tooltip-format for custom modules 2024-02-16 01:33:04 +01:00
Aleksei Bavshin
d590d508ca feat: add module class to the root elements of the modules
Previously, the only way to select all the module labels was with the
following kind of selector:
```css
.modules-left > widget > label,
.modules-center > widget > label,
.modules-right > widget > label {
    /* ... */
}
```
(and a matching block for the `box` containers).

Now, this can be expressed as
```css
label.module, box.module {
    /* ... */
}
```
2024-02-14 22:41:13 -08:00
Aleksei Bavshin
2f555a6936 refactor(bar): use Gtk enums for position and orientation
Ensure that the position and the corresponding CSS class on window are
always set.
2024-02-14 22:11:21 -08:00
Alexis Rouillard
28cd9dff47 Merge pull request #2916 from alttabber/master
Add style classes for hyprland/submap
2024-02-13 13:25:23 +01:00
alttabber
77c7b91b40 Add style classes for hyprland/submap 2024-02-13 11:46:27 +01:00
Niklas Haas
a0bac34329 Add style class for CPU state
Fixes: https://github.com/Alexays/Waybar/issues/2911
2024-02-13 10:49:57 +01:00
Alexis Rouillard
2c244b5e83 Merge pull request #2912 from zjeffer/fix/zjeffer/build-warnings
Fix build warnings
2024-02-12 20:30:58 +01:00
zjeffer
dd8d6fbe6c Fix build warnings 2024-02-12 20:09:22 +01:00
Jannik
acf6611098 clang-format 2024-02-10 17:35:46 +01:00
Jannik
a2925fa5da fix 'visible' class for special workspaces 2024-02-10 17:26:44 +01:00
Jannik
240b49f9d2 Add 'empty' css class to special workspaces 2024-02-10 16:59:53 +01:00
Jannik
d4331ce7fe improve handling of special workspace name 2024-02-09 13:49:39 +01:00
Alexis Rouillard
4d076a71f7 Merge pull request #2899 from OpenSauce04/battery-full-no-alt
Make battery estimate inaccessible in the "Full" state on default config
2024-02-09 10:54:22 +01:00
OpenSauce04
90c2415b64 Battery estimate is no longer accessible in the "Full" state on default config 2024-02-08 15:10:21 +00:00
Jannik
692f8f4ea4 add/remove 'active' on 'focusedmon' IPC event 2024-02-07 22:42:05 +01:00
Jannik
61be2267ab add 'visible' css class to special workspaces 2024-02-07 21:10:17 +01:00
Jannik
c30541b954 remove whitespaces 2024-02-07 16:56:37 +01:00
Jannik
3bfcd5e086 Add 'active' css class to special workspaces 2024-02-07 16:33:19 +01:00
Alexis Rouillard
b6f4a0dae2 Merge pull request #2881 from jramrath/drawer-direction
Fix: drawer not appearing on configured side
2024-02-06 16:18:52 +01:00
Imran Haider
92875711c6 Search for the first hwmon* directory
Background and Motivation
-------------------------
When the `hwmon-path-abs` and the `input-filename` fields are used for
the temperature module, we evaluated the following path:

```
[hwmon-path-abs] / [gap] / [input-filename]
```

where `gap` is the first file or directory in the `hwmon-path-abs`
directory. This usually works but it doesn't seem to work for NVME or
WiFi temperature sensors. For those cases, there are a bunch of other
files in the `hwmon-path-abs` directory. In the bad case, the first
selected file is not the one with the prefix `hwmon` and we end up
checking the wrong location for the `input-filename`.

Change description
------------------
We are simply going through the `hwmon-path-abs` directory and searching
for the first file/directory that begins with `hwmon`.

Test case
---------
I tested this on a AMD based Framework 13 laptop.
2024-02-05 21:40:24 -05:00
Merlin Sievers
89b3203bfa Add justify config option for Labels
This is especially useful for centering labels on vertical bars.
2024-02-05 14:44:59 +01:00
Jannik
08b32cb901 Removing unnecessary parts of transition_type handling 2024-02-04 16:17:06 +01:00
Josh Jones
1fa1045af9 remove duplicated segment 2024-02-04 16:11:39 +01:00
Josh Jones
e02cb9cfb9 add ordinal format specifier to man clock 2024-02-04 15:49:14 +01:00
Josh Jones
718dd4afae add ordinal date toolbar format specifier to clock module 2024-02-04 15:41:39 +01:00
Jo De Boeck
c641d52e06 Implement windows formating in sway/workspaces
This implementation mimics to some extend the implementation of hyprland

Signed-off-by: Jo De Boeck <deboeck.jo@gmail.com>
2024-02-03 12:31:06 +02:00
Jannik
029b380c15 Fix: drawer not appearing on configured side 2024-02-02 20:54:16 +01:00
Alexis Rouillard
4c5ff80bbd Merge pull request #2874 from Alexays/fix-reload-style
fix: reload style
2024-01-31 23:09:54 +01:00
Alex
f1016322b9 fix: tpyo 2024-01-31 22:59:09 +01:00
Alex
6dcae2cade fix: reload style 2024-01-31 22:57:20 +01:00
Alex
fb6658e8fd chore: lint 2024-01-30 09:07:37 +01:00
Alexis Rouillard
1dce607c42 Merge pull request #2852 from dpayne/add_css_reload
Adding css reloader
2024-01-29 22:44:29 +01:00
dpayne
10cb4180f6 * Fixing clang tidy comments
* Fixing missing includes
* Fixing formatting
2024-01-28 14:44:25 -08:00
Alexis Rouillard
5534fc48b1 Merge pull request #2496 from zjeffer/tests/json
Fix JSON parsing with hexadecimal characters
2024-01-28 23:38:54 +01:00
dpayne
9556b0fe89 Adding a man page entry for the realod_style_on_change option 2024-01-28 14:25:00 -08:00
Alexis Rouillard
ddad6ce136 Merge pull request #2866 from Jay-716/pa-reconnect
pulseaudio: reconnect context when pulseaudio server restarts
2024-01-28 17:04:57 +01:00
Jay-716
14d168c254 pulseaudio: extract context connecting into connectContext() 2024-01-27 23:47:39 +08:00
Jay-716
167f04a4df pulseaudio: reconnect context when pulseaudio server restarts
When pulseaudio server restarts, the context is not reconnect
automatically. So the pulseaudio module will stop updating.
2024-01-25 23:59:32 +08:00
Alexis Rouillard
5f115785cf Merge pull request #2862 from Sryther/master
Move `.empty` CSS class from Img to Box in the Image module
2024-01-25 16:12:02 +01:00
Alexis Rouillard
7caf0b9ec4 Merge pull request #2865 from chntllh/Battery-animations
Using steps() in animation to reduce cpu usage.
2024-01-25 16:11:00 +01:00
Paul Rey
94633c346a retrigger checks 2024-01-25 11:02:44 +01:00
Siddhartha Singh
7e76369ec8 Using steps() in animation 2024-01-25 14:00:21 +05:30
Paul Rey
002ff002fe Move .empty CSS class from Img to Box in the Image module
Since the GTK Image is hidden, the CSS class wasn't used for every cases.
2024-01-24 11:10:16 +01:00
Alexis Rouillard
0948a407d0 Merge pull request #2810 from ArneshRC/master
feat(battery): added support for battery state-based classes on the entire waybar
2024-01-23 22:45:24 +01:00
Arnesh Roychowdhury
90b5b21394 Merge branch 'Alexays:master' into master 2024-01-24 02:01:17 +05:30
Alexis Rouillard
8e2fa0fdbd Merge pull request #2859 from Sryther/master
Add "empty" class for Image module when path/exec is returning an empty value.
2024-01-23 18:50:50 +01:00
Paul Rey
0af8f5c691 Add "empty" class for Image module when path/exec is returning an empty value. 2024-01-23 18:15:47 +01:00
dpayne
970a7519d4 Merge branch 'master' of github.com:Alexays/Waybar into add_css_reload 2024-01-22 12:40:02 -08:00
Alexis Rouillard
0d9c492998 Merge pull request #2855 from SquishyPandaDev/upower-ptr-fix
Fix module UPower display device poniter
2024-01-22 09:49:55 +01:00
SquishyPandaDev
82b632e4ec Fix module UPower display device poniter
Force displayDevice to be a nullptr on class setup
2024-01-22 03:22:19 -05:00
Alexis Rouillard
27fec51439 Merge pull request #2853 from dpayne/fix_use_after_free_on_task_close 2024-01-22 09:01:48 +01:00
dpayne
20fa578b12 Adding config option to enable reloading style on file change 2024-01-21 21:02:01 -08:00
dpayne
f7eca99496 Using Gio::FileMonitor for watching style changes 2024-01-21 20:49:13 -08:00
dpayne
53233e47a3 Fix use after free on task close 2024-01-21 19:08:23 -08:00
dpayne
d7ed4f1fa8 Adding css reloader 2024-01-21 18:23:46 -08:00
ArneshRC
d14a4a2b1a fixed early dereference error 2024-01-19 16:00:13 +05:30
ArneshRC
dacffdb095 removed duplicate code 2024-01-19 15:27:11 +05:30
ArneshRC
74e863ed73 updated man waybar-battery 2024-01-19 14:45:49 +05:30
Arnesh Roychowdhury
3de6d2e859 Merge branch 'Alexays:master' into master 2024-01-17 18:29:14 +05:30
Alexis Rouillard
6e12f81223 Merge pull request #2840 from m-bdf/clock-tz-changes
clock: fix construction with calendar.format.today
2024-01-17 13:44:28 +01:00
Maëlys Bras de fer
4f0fbaba8e clock: fix construction with calendar.format.today 2024-01-17 13:30:32 +01:00
Alexis Rouillard
392f83e71d Merge pull request #2838 from m-bdf/clock-tz-changes 2024-01-16 22:48:31 +01:00
Maëlys Bras de fer
d343f616fc clock: handle timezone changes (again again) 2024-01-16 21:35:42 +01:00
Arnesh Roychowdhury
8c502378aa Merge branch 'Alexays:master' into master 2024-01-15 14:24:27 +05:30
Alexis Rouillard
07eabc5328 Merge pull request #2831 from JManch/tray-fix-spacing
fix(tray): completely hide tray when it is empty
2024-01-14 16:33:28 +01:00
Joshua Manchester
95ffc291f6 fix: hide tray event box instead of box 2024-01-14 15:06:06 +00:00
zjeffer
8f5d0098d6 Fixed json parsing with hexadecimal characters
* replace \x with \u00 to follow JSON spec
* fixes #2475 and #2495
* added unit tests for json parsing
2024-01-14 14:06:06 +01:00
Arnesh Roychowdhury
4eef1ce10f Merge branch 'Alexays:master' into master 2024-01-13 16:07:11 +05:30
Alexis Rouillard
f744d906be Merge pull request #2820 from oxalica/feat/systemd-failed-units
Add module systemd-failed-units to monitor failed systemd units
2024-01-12 09:45:40 +01:00
Alexis Rouillard
fa3ce14b25 Merge pull request #2817 from Syndelis/fix/window-rewrite-multiple-bars-no-overlap
Fix/Hyprland/Workspaces: Window Rewrite on multiple non-overlapping bars
2024-01-12 09:44:03 +01:00
Alexis Rouillard
e6097229ce Merge pull request #2814 from khaneliman/flake-update
flake update and direnv fix
2024-01-12 09:43:19 +01:00
Austin Horstman
b239c77d74 fix: temporary catch2_3 override until upstreamed to nixpkgs 2024-01-10 12:17:46 -06:00
Brenno Lemos
9e08512927 feat: strip workspace qualifiers when creating windows 2024-01-10 02:24:51 -03:00
oxalica
eedd1f8e6a Add module systemd-failed-units 2024-01-09 18:19:30 +08:00
Brenno Lemos
c69a6dde67 chore: update Hyprland's featureset in readme 2024-01-08 20:31:15 -03:00
Brenno Lemos
4339030c9d feat: fetch clients data when moving workspaces accross monitors 2024-01-08 20:11:39 -03:00
Brenno Lemos
bc7acbde5c fix: rename windows while queued for creation
this avoids the window arriving with the wrong icon when its eventually
able to be created
2024-01-08 18:30:53 -03:00
Brenno Lemos
512c6fb127 feat: add orphan windows attribute to workspaces
this attribute will keep every window that doesn't have an associated
workspace in the current bar
2024-01-08 18:30:53 -03:00
Austin Horstman
b90af74d15 feat: enable direnv and fix flake devshell output 2024-01-08 12:47:32 -06:00
Arnesh Roychowdhury
f1f3442e38 Merge branch 'Alexays:master' into master 2024-01-08 22:54:08 +05:30
Austin Horstman
d4d5a54e63 chore: flake lock update 2024-01-08 09:37:48 -06:00
Alexis Rouillard
748fc809b5 Merge pull request #2813 from yangyingchao/master
Improvements for Hyprland worskspaces & backend
2024-01-08 14:03:23 +01:00
yangyingchao
bdd7271da9 Improvements for Hyprland backend
1. Fix warnings reported by clang tidy
2. Use unique lock instead of manully lock/unlock on mutex.
   The RAII style locking makes sure mutex is unlocked when exceptions are thrown
2024-01-08 09:26:16 +08:00
yangyingchao
a34e3ccc86 Improvements for Hyprland workspace
1. Utilize `m_mutex` to safeguard member fields of `hyprland::Workspaces` as they are modified by multiple threads, including the event listener thread and UI thread. This applies to all member fields, not just `m_workspacesToCreate`.

2. Tidy up the create/remove workspace code.
2024-01-08 09:14:36 +08:00
ArneshRC
3390c16f52 added support for battery state-based classes on the entire waybar 2024-01-07 17:22:34 +05:30
Alexis Rouillard
4b20f522f0 Merge pull request #2789 from DreamMaoMao/master
fix:#2769
2024-01-04 15:33:26 +01:00
Alexis Rouillard
4636309117 Merge pull request #2803 from LukashonakV/catch_bump
Catch2 bump
2024-01-04 15:33:06 +01:00
Viktar Lukashonak
7783c81861 Catch2 bump
Signed-off-by: Viktar Lukashonak <myxabeer@gmail.com>
2024-01-04 17:22:27 +03:00
Alexis Rouillard
3e55d0d7f2 Merge pull request #2787 from scgtrp/master
hyprland/workspaces: allow using the original window class/title
2023-12-31 12:40:06 +01:00
Emily Ellis
ff09ef6d71 hyprland/workspaces: allow using the original window class/title
This turns the values of window rewrite rules in hyprland/workspaces from static strings to format strings with the values {class} and {title} available.
2023-12-30 21:07:40 -05:00
Alexis Rouillard
99d26e44ee Merge pull request #2778 from an-prata/master
fix `restart-interval` being ignored while `signal` is defined (#2650)
2023-12-29 10:59:13 +01:00
Evan Overman
19bf4d0544 clang format trailing whitespace 2023-12-28 19:38:01 -08:00
Evan Overman
6b860f8690 clang formating 2023-12-28 19:36:21 -08:00
Evan Overman
182272b8b5 fix #2650 2023-12-28 19:30:26 -08:00
DreamMaoMao
e64d66ab24 fix:the workspace data is null in a small probability
update

fix clang-format warn

no manual unlock
2023-12-25 21:55:46 +08:00
Alexis Rouillard
41ebdc3cb6 Merge pull request #2768 from zjeffer/feat/zjeffer/freebsd-bump 2023-12-25 08:31:03 +01:00
Alexis Rouillard
8ccb959992 Merge pull request #2767 from zjeffer/master 2023-12-25 00:28:32 +01:00
zjeffer
13e904c20d Bump cross-platform-action to attempt fixing freebsd runner 2023-12-25 00:26:39 +01:00
zjeffer
77f0584d0d Bump clang-tidy cpp-linter-action version to v2.7.5 2023-12-24 23:08:22 +01:00
Alexis Rouillard
d2767fb84a Merge pull request #2760 from avannereau/wireplumber-scroll-fix
Fix wireplumber reverse-scroll option
2023-12-22 12:00:39 +01:00
Alan Vannereau
49caab47a6 Fix wireplumber reverse-scroll option 2023-12-22 11:50:41 +01:00
Alexis Rouillard
08361be9f0 Merge pull request #2756 from grimpy/custom_output_env_var
Pass WAYBAR_OUTPUT_NAME environment variable to custom exec scripts
2023-12-21 08:55:30 +01:00
Alexis Rouillard
2674982c7b Merge pull request #2755 from zjeffer/master
Added clang-tidy GitHub action
2023-12-20 23:25:33 +01:00
Tuur Vanhoutte
dbe02ebe41 Added clang-tidy GitHub action
Created clang-tidy.yml
Renamed lint.yml to clang-format.yml
2023-12-20 14:31:27 +01:00
Jo De Boeck
0ea5143493 Pass WAYBAR_OUTPUT_NAME environment variable to custom exec scripts
Signed-off-by: Jo De Boeck <deboeck.jo@gmail.com>
2023-12-19 22:54:12 +02:00
Alexis Rouillard
f5370fcff5 Merge pull request #2573 from CromFr/cabi_plugins
C ABI plugin system
2023-12-18 14:10:02 +01:00
Alexis Rouillard
7b79281437 Merge pull request #2742 from zjeffer/feat/zjeffer/debian-docker-add-clang-tidy-requirements
Added sudo, python3-pip & python3-venv to debian image, required for clang-tidy GH action
2023-12-18 09:06:54 +01:00
Alexis Rouillard
acc2da7310 Merge pull request #2744 from rpdelaney/jsonC
Specify config is JSONC
2023-12-18 09:06:28 +01:00
Ryan Delaney
68e525df58 Remove 'config' from list of valid locations
Since the file can also be named config.jsonc, that will remove ambiguity
2023-12-13 11:22:57 -05:00
Ryan Delaney
2cd67fdd0a The file can also be named config.jsonc 2023-12-13 10:40:13 -05:00
Ryan Delaney
2600f53bdd Clarify that the configuration file is JSON*C*
JSON is JSONC
2023-12-13 10:39:59 -05:00
zjeffer
da9cc77db8 Added sudo, python3-pip & python3-venv to debian image, required for clang-tidy GH action 2023-12-13 11:54:04 +01:00
Crom (Thibaut CHARLES)
75f9141cac Added cffi man page 2023-12-12 16:23:03 +01:00
Alexis Rouillard
f03b684bd8 Merge pull request #2736 from Rice8Dyb6/master 2023-12-10 19:27:52 +01:00
Rice8Dyb6
4822f967b2 Sway/workspaces: fix persistent icon 2023-12-11 00:17:35 +07:00
Alexis Rouillard
dc208b66b3 Merge pull request #2720 from zjeffer/master
Applied clang-tidy suggestions for hyprland workspaces
2023-12-07 08:34:19 +01:00
Alexis Rouillard
77ebc45336 Merge pull request #2731 from mcepl/patch-1 2023-12-07 08:25:49 +01:00
Matěj Cepl
d94519a93c Clear README.md from duplicated list of distributions
It doesn’t make sense to keep the list in README.md when we maintain it in Wiki as well.
2023-12-07 07:53:45 +01:00
zjeffer
4d5b715dc4 applied clang-tidy suggestions for hyprland workspaces 2023-12-06 21:58:26 +01:00
zjeffer
8a84cb609e clang-tidy: added StaticConstantCase CheckOption 2023-12-06 21:58:26 +01:00
Alexis Rouillard
5f8ae44233 Merge pull request #2703 from czadowanie/master
upower: show-icon config option
2023-12-05 23:34:43 +01:00
czadowanie
4283195803 man: add dot in upower/show-icon 2023-12-04 21:32:08 +01:00
czadowanie
44f309678b man: document upower/show-icon 2023-12-04 21:28:37 +01:00
Alexis Rouillard
4846ff7950 Merge pull request #2595 from zjeffer/master
Added initial .clang-tidy file
2023-12-04 09:29:12 +01:00
Alexis Rouillard
0ec2aada26 Merge pull request #2711 from chayleaf/flake
flake: update & cleanup
2023-12-04 09:28:16 +01:00
Alexis Rouillard
dfa0f5701e Merge pull request #2712 from khaneliman/fix/nix-flake
chore: lint fix
2023-12-04 09:28:05 +01:00
Austin Horstman
b1744278d1 chore: lint fix 2023-12-01 22:05:40 -06:00
chayleaf
2e2cb67cf1 flake: update & cleanup 2023-12-02 02:41:59 +07:00
Alexis Rouillard
1572bc8c75 Merge pull request #2707 from alexbakker/fix-2154 2023-11-30 08:37:59 +01:00
Alexander Bakker
6be5f7cb29 Disconnect from PipeWire when destroying the WirePlumber module
This fixes a crash where PipeWire tries to send events to a destroyed
WirePlumber module.
2023-11-29 22:46:58 +01:00
czadowanie
2334faa7fd upower: show-icon config option 2023-11-28 19:39:08 +01:00
Alexis Rouillard
58db0baaf4 Merge pull request #2701 from thejch/hl-ws-click
Add button click check to hyprland workspaces module
2023-11-28 09:20:51 +01:00
Jeremy Huang
0162dbd485 add button single click check to hyprland workspaces 2023-11-27 16:20:05 -08:00
Alexis Rouillard
1fe4a4ee9d Merge pull request #2686 from aruhier/pr_privacy_visibility
privacy: fix visibility when a module is disabled
2023-11-23 09:52:44 +01:00
Anthony Ruhier
50a4fe9623 privacy: fix visibility when a module is disabled
Only consider a privacy module as visible if it is enabled in the
configuration. Otherwise, when screensharing or audio-in or audio-out is
in use but the associated module is not enabled, the privacy widget is
empty but still considered as visible.
2023-11-23 00:45:31 +01:00
Alexis Rouillard
061c68ce92 Merge pull request #2677 from sjoblomj/master
Using 'image-missing' fallback if no taskbar icon is found
2023-11-20 14:03:52 +01:00
Alexis Rouillard
20b89d5d13 Merge pull request #2679 from aserowy/master
hyprland module: added sort_workspaces after rename occured
2023-11-20 14:02:39 +01:00
Alexis Rouillard
c299ea9369 Merge pull request #2681 from tactikauan/master 2023-11-19 14:20:54 +01:00
Kauan Decarli
d2dd2d553f cpu_usage/linux: count iowait toward idle time 2023-11-18 13:59:21 -03:00
aserowy
b6b495e1bc hyprland module: added sort_workspaces after rename occured
Signed-off-by: aserowy <serowy@hotmail.com>
2023-11-18 11:36:47 +01:00
Johan Sjöblom
d4559c7f00 Using 'image-missing' fallback if no taskbar icon is found 2023-11-16 16:59:05 +01:00
Alexis Rouillard
0a747ddafc Merge pull request #2672 from fdev31/master 2023-11-15 17:53:48 +01:00
fdev31
375a38a489 Fix for #2646 2023-11-14 21:26:17 +01:00
Alexis Rouillard
9ac27de7d8 Merge pull request #2668 from LukashonakV/cpp20_clock 2023-11-13 08:34:59 +01:00
Viktar Lukashonak
7308893adb Happy clang. fmt9-10
Signed-off-by: Viktar Lukashonak <myxabeer@gmail.com>
2023-11-13 09:59:50 +03:00
Alexis Rouillard
a51dd8fc52 Merge pull request #2659 from LukashonakV/cpp20_clock
c++20. clock chrono API. STL + format
2023-11-12 09:17:59 +01:00
Viktar Lukashonak
86a38980e4 c++20. clock chrono API. STL + format
Signed-off-by: Viktar Lukashonak <myxabeer@gmail.com>
2023-11-10 17:57:26 +03:00
Alexis Rouillard
c4330a1e36 Merge pull request #2648 from Mrcarrot1/wp-segfault
Fix segmentation fault in WirePlumber module
2023-11-06 16:58:40 +01:00
Caleb Harper
4d339f05af Fix segmentation fault in WirePlumber module
The WirePlumber module assumes that either the node's name or
description will not be null. This leads to a segmentation fault when
both are.

The solution provided is to set self->node_name_ to a default value in
this case.
2023-11-06 09:50:13 -06:00
Alexis Rouillard
e24adbc3c2 Merge pull request #2612 from ErikReider/privacy-module
Add Privacy Module
2023-11-06 09:42:35 +01:00
Alexis Rouillard
7d7a047fcc Merge pull request #2643 from qbe/bugfix-dst-ambiguous-hour-err 2023-11-06 08:51:26 +01:00
Lukas Hannen
aa1f8a428b avoid converting to local_time when converting to zoned_time afterwards 2023-11-06 01:28:48 +01:00
Erik Reider
f21b1dfa4d fixed linter issues 2023-11-04 15:16:13 +01:00
Erik Reider
6050fa3a43 Added documentation 2023-11-04 15:16:13 +01:00
Erik Reider
ca7c9a68f1 Made creation of privacy modules more modular 2023-11-04 14:05:01 +01:00
zjeffer
23bc4d66bf Added initial .clang-tidy file 2023-11-02 23:09:49 +01:00
Erik Reider
49caa4bf31 Add the PrivacyNodeInfo object as pw_proxy data 2023-10-31 11:38:01 +01:00
Erik Reider
c60a8e9836 free pipewire listeners on proxy destruction 2023-10-31 08:52:54 +01:00
Erik Reider
c4226f3745 Readded signal_timeout instead of map to fix indicator being stuck 2023-10-30 18:01:47 +01:00
Erik Reider
d32da917e4 Added tooltips 2023-10-29 00:17:53 +02:00
Erik Reider
46e36c0e68 Simplified the privacy_item hiding/showing logic 2023-10-28 18:30:50 +02:00
Erik Reider
86491e1512 Call module emit in privacy module contructor 2023-10-28 16:47:06 +02:00
Erik Reider
4a4c888d7d Fixed linter complaining 2023-10-27 00:01:40 +02:00
Erik Reider
ace319b515 Updated default CSS to include the privacy module 2023-10-26 23:44:04 +02:00
Erik Reider
e73ea8d608 Fixed cases where the module would be hidden when it should be visible 2023-10-26 23:37:10 +02:00
Erik Reider
f7224d8459 Initial implementation 2023-10-26 23:22:02 +02:00
Crom (Thibaut CHARLES)
02c64f3f1e Moved all waybar info into a single struct 2023-10-24 20:16:50 +02:00
Crom (Thibaut CHARLES)
d86059016e Send update dispatcher though FFI 2023-10-24 20:16:50 +02:00
Crom (Thibaut CHARLES)
088ca6b963 Added cffi/* module for third-party advanced modules 2023-10-24 20:16:50 +02:00
Crom (Thibaut CHARLES)
6ae354f564 PoC 2023-10-24 20:16:23 +02:00
146 changed files with 5187 additions and 2615 deletions

29
.clang-tidy Normal file
View File

@@ -0,0 +1,29 @@
Checks: >
-*,
bugprone-*
misc-*,
modernize-*,
performance-*,
portability-*,
readability-*,
-fuchsia-trailing-return,
-readability-magic-numbers,
-modernize-use-nodiscard,
-modernize-use-trailing-return-type,
-readability-braces-around-statements,
-readability-redundant-access-specifiers,
-readability-redundant-member-init,
-readability-redundant-string-init,
-readability-identifier-length
CheckOptions:
- { key: readability-identifier-naming.NamespaceCase, value: lower_case }
- { key: readability-identifier-naming.ClassCase, value: CamelCase }
- { key: readability-identifier-naming.StructCase, value: CamelCase }
- { key: readability-identifier-naming.FunctionCase, value: camelBack }
- { key: readability-identifier-naming.VariableCase, value: camelBack }
- { key: readability-identifier-naming.PrivateMemberCase, value: camelBack }
- { key: readability-identifier-naming.PrivateMemberSuffix, value: _ }
- { key: readability-identifier-naming.EnumCase, value: CamelCase }
- { key: readability-identifier-naming.EnumConstantCase, value: UPPER_CASE }
- { key: readability-identifier-naming.GlobalConstantCase, value: UPPER_CASE }
- { key: readability-identifier-naming.StaticConstantCase, value: UPPER_CASE }

65
.github/labeler.yml vendored Normal file
View File

@@ -0,0 +1,65 @@
bug:
- "(crash|bug|error|coredump|freeze|segfault|issue|problem)"
enhancement:
- "(feature|enhancement|improvement|request|suggestion)"
hyprland:
- "(hyprland)"
network:
- "(network|wifi|ethernet)"
bluetooth:
- "(bluetooth|bluez)"
sway:
- "(sway)"
cpu:
- "(cpu)"
memory:
- "(memory|ram)"
disk:
- "(disk|storage)"
battery:
- "(upower|battery)"
sni:
- "(sni|tray)"
dwl:
- "(dwl)"
custom:
- "(custom|module|extension|plugin|script)"
mpd:
- "(mpd|music)"
audio:
- "(pulseaudio|alsa|jack|audio|pirewire|wireplumber)"
temperature:
- "(temperature|thermal|hwmon)"
clock:
- "(clock|time|date)"
gamemode:
- "(gamemode|game|gaming)"
inhibitor:
- "(inhibitor|idle|lock|suspend|hibernate|logout)"
cava:
- "(cava|audio-visualizer)"
backlight:
- "(backlight|brightness)"
keyboard:
- "(keyboard|keymap|layout|shortcut)"

19
.github/workflows/clang-format.yml vendored Normal file
View File

@@ -0,0 +1,19 @@
name: clang-format
on: [push, pull_request]
concurrency:
group: ${{ github.workflow }}-format-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: DoozyX/clang-format-lint-action@v0.16.2
name: clang-format
with:
source: "."
extensions: "hpp,h,cpp,c"
clangFormatVersion: 16

39
.github/workflows/clang-tidy.yml vendored Normal file
View File

@@ -0,0 +1,39 @@
name: clang-tidy
on: [push, pull_request]
concurrency:
group: ${{ github.workflow }}-tidy-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
build:
runs-on: ubuntu-latest
container:
image: alexays/waybar:debian
steps:
- uses: actions/checkout@v3
- name: configure
run: |
meson -Dcpp_std=c++20 build # necessary to generate compile_commands.json
ninja -C build # necessary to find certain .h files (xdg, wayland, etc.)
- uses: actions/setup-python@v5
with:
python-version: '3.10' # to be kept in sync with cpp-linter-action
update-environment: true # the python dist installed by the action needs LD_LIBRARY_PATH to work
- uses: cpp-linter/cpp-linter-action@v2.9.1
name: clang-tidy
id: clang-tidy-check
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PIP_NO_CACHE_DIR: false
with:
style: "" # empty string => don't do clang-format checks here, we do them in clang-format.yml
files-changed-only: true # only check files that have changed
lines-changed-only: true # only check lines that have changed
tidy-checks: "" # empty string => use the .clang-tidy file
version: "17" # clang-tools version
database: "build" # path to the compile_commands.json file
- name: Check if clang-tidy failed on any files
if: steps.clang-tidy-check.outputs.checks-failed > 0
run: echo "Some files failed the linting checks!" && exit 1

View File

@@ -2,21 +2,28 @@ name: freebsd
on: [push, pull_request]
concurrency:
group: ${{ github.workflow }}-freebsd-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
clang:
# Run actions in a FreeBSD VM on the macos-12 runner
# Run actions in a FreeBSD VM on the ubuntu runner
# https://github.com/actions/runner/issues/385 - for FreeBSD runner support
# https://github.com/actions/virtual-environments/issues/4060 - for lack of VirtualBox on MacOS 11 runners
runs-on: macos-12
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Test in FreeBSD VM
uses: cross-platform-actions/action@v0.19.1
uses: cross-platform-actions/action@v0.23.0
timeout-minutes: 180
env:
CPPFLAGS: '-isystem/usr/local/include'
LDFLAGS: '-L/usr/local/lib'
with:
operating_system: freebsd
version: "13.2"
environment_variables: CPPFLAGS=-isystem/usr/local/include LDFLAGS=-L/usr/local/lib
environment_variables: CPPFLAGS LDFLAGS
sync_files: runner-to-vm
run: |
sudo sed -i '' 's/quarterly/latest/' /etc/pkg/FreeBSD.conf
sudo pkg install -y git # subprojects/date

19
.github/workflows/labeler.yml vendored Normal file
View File

@@ -0,0 +1,19 @@
name: "Issue Labeler"
on:
issues:
types: [opened, edited]
permissions:
issues: write
contents: read
jobs:
triage:
runs-on: ubuntu-latest
steps:
- uses: github/issue-labeler@v3.4
with:
configuration-path: .github/labeler.yml
enable-versioned-regex: 0
include-title: 1
repo-token: ${{ secrets.GITHUB_TOKEN }}

View File

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

View File

@@ -2,6 +2,10 @@ name: linux
on: [push, pull_request]
concurrency:
group: ${{ github.workflow }}-linux-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
build:
strategy:
@@ -14,9 +18,6 @@ jobs:
- opensuse
- gentoo
cpp_std: [c++20]
include:
- distro: fedora
cpp_std: c++20
runs-on: ubuntu-latest
container:

4
.gitignore vendored
View File

@@ -44,3 +44,7 @@ packagecache
*.out
*.app
/.direnv/
# Nix
result
result-*

View File

@@ -2,6 +2,48 @@
FROM debian:sid
RUN apt-get update && \
apt-get install -y build-essential meson ninja-build git pkg-config libinput10 libpugixml-dev libinput-dev wayland-protocols libwayland-client0 libwayland-cursor0 libwayland-dev libegl1-mesa-dev libgles2-mesa-dev libgbm-dev libxkbcommon-dev libudev-dev libpixman-1-dev libgtkmm-3.0-dev libjsoncpp-dev scdoc libdbusmenu-gtk3-dev libnl-3-dev libnl-genl-3-dev libpulse-dev libmpdclient-dev gobject-introspection libgirepository1.0-dev libxkbcommon-dev libxkbregistry-dev libxkbregistry0 libplayerctl-dev && \
apt-get clean
RUN apt update && \
apt install --no-install-recommends --no-install-suggests -y \
build-essential \
catch2 \
cmake \
git \
gobject-introspection \
libdbusmenu-gtk3-dev \
libegl1-mesa-dev \
libfmt-dev \
libgbm-dev \
libgirepository1.0-dev \
libgles2-mesa-dev \
libgtk-layer-shell-dev \
libgtkmm-3.0-dev \
libhowardhinnant-date-dev \
libiniparser-dev \
libinput-dev \
libjack-jackd2-dev \
libjsoncpp-dev \
libmpdclient-dev \
libnl-3-dev \
libnl-genl-3-dev \
libpixman-1-dev \
libplayerctl-dev \
libpugixml-dev \
libpulse-dev \
libsndio-dev \
libspdlog-dev \
libudev-dev \
libupower-glib-dev \
libwayland-dev \
libwireplumber-0.4-dev \
libxkbcommon-dev \
libxkbregistry-dev \
locales \
meson \
ninja-build \
pkg-config \
python3-pip \
python3-venv \
scdoc \
sudo \
wayland-protocols \
&& apt clean

View File

@@ -1,22 +1,23 @@
# Waybar [![Licence](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE) [![Paypal Donate](https://img.shields.io/badge/Donate-Paypal-2244dd.svg)](https://paypal.me/ARouillard)<br>![Waybar](https://raw.githubusercontent.com/alexays/waybar/master/preview-2.png)
> Highly customizable Wayland bar for Sway and Wlroots based compositors.<br>
> Available in Arch [extra](https://www.archlinux.org/packages/extra/x86_64/waybar/) or
[AUR](https://aur.archlinux.org/packages/waybar-git/), [Gentoo](https://packages.gentoo.org/packages/gui-apps/waybar), [openSUSE](https://build.opensuse.org/package/show/X11:Wayland/waybar), and [Alpine Linux](https://pkgs.alpinelinux.org/packages?name=waybar).<br>
> Available in [all major distributions](https://github.com/Alexays/Waybar/wiki/Installation)<br>
> *Waybar [examples](https://github.com/Alexays/Waybar/wiki/Examples)*
#### Current features
- Sway (Workspaces, Binding mode, Focused window name)
- River (Mapping mode, Tags, Focused window name)
- Hyprland (Focused window name)
- Hyprland (Window Icons, Workspaces, Focused window name)
- DWL (Tags) [requires dwl ipc patch](https://github.com/djpohly/dwl/wiki/ipc)
- Tray [#21](https://github.com/Alexays/Waybar/issues/21)
- Local time
- Battery
- UPower
- Power profiles daemon
- Network
- Bluetooth
- Pulseaudio
- Privacy Info
- Wireplumber
- Disk
- Memory

99
flake.lock generated
View File

@@ -1,32 +1,13 @@
{
"nodes": {
"devshell": {
"inputs": {
"nixpkgs": "nixpkgs",
"systems": "systems"
},
"locked": {
"lastModified": 1692523566,
"narHash": "sha256-VDJDihK6jNebVw9y3qKCVD6+6QaC/x8kxZzL4MaIPPY=",
"owner": "numtide",
"repo": "devshell",
"rev": "d208c58e2f7afef838add5f18a9936b12a71d695",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "devshell",
"type": "github"
}
},
"flake-compat": {
"flake": false,
"locked": {
"lastModified": 1673956053,
"narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=",
"lastModified": 1696426674,
"narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
"owner": "edolstra",
"repo": "flake-compat",
"rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9",
"rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
"type": "github"
},
"original": {
@@ -35,47 +16,13 @@
"type": "github"
}
},
"flake-utils": {
"inputs": {
"systems": "systems_2"
},
"locked": {
"lastModified": 1689068808,
"narHash": "sha256-6ixXo3wt24N/melDWjq70UuHQLxGV8jZvooRanIHXw0=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "919d646de7be200f3bf08cb76ae1f09402b6f9b4",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1677383253,
"narHash": "sha256-UfpzWfSxkfXHnb4boXZNaKsAcUrZT9Hw+tao1oZxd08=",
"lastModified": 1704538339,
"narHash": "sha256-1734d3mQuux9ySvwf6axRWZRBhtcZA9Q8eftD6EZg6U=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "9952d6bc395f5841262b006fbace8dd7e143b634",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixpkgs-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_2": {
"locked": {
"lastModified": 1692638711,
"narHash": "sha256-J0LgSFgJVGCC1+j5R2QndadWI1oumusg6hCtYAzLID4=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "91a22f76cd1716f9d0149e8a5c68424bb691de15",
"rev": "46ae0210ce163b3cba6c7da08840c1d63de9c701",
"type": "github"
},
"original": {
@@ -87,40 +34,8 @@
},
"root": {
"inputs": {
"devshell": "devshell",
"flake-compat": "flake-compat",
"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"
"nixpkgs": "nixpkgs"
}
}
},

101
flake.nix
View File

@@ -1,28 +1,22 @@
{
description = "Highly customizable Wayland bar for Sway and Wlroots based compositors.";
description = "Highly customizable Wayland bar for Sway and Wlroots based compositors";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
devshell.url = "github:numtide/devshell";
flake-utils.url = "github:numtide/flake-utils";
flake-compat = {
url = "github:edolstra/flake-compat";
flake = false;
};
};
outputs = { self, flake-utils, devshell, nixpkgs, flake-compat }:
outputs = { self, nixpkgs, ... }:
let
inherit (nixpkgs) lib;
genSystems = lib.genAttrs [
genSystems = func: lib.genAttrs [
"x86_64-linux"
"aarch64-linux"
];
pkgsFor = genSystems (system:
import nixpkgs {
inherit system;
});
]
(system: func (import nixpkgs { inherit system; }));
mkDate = longDate: (lib.concatStringsSep "-" [
(builtins.substring 0 4 longDate)
@@ -31,60 +25,43 @@
]);
in
{
devShells = genSystems
(pkgs:
{
default =
pkgs.mkShell
{
name = "waybar-shell";
# inherit attributes from upstream nixpkgs derivation
inherit (pkgs.waybar) buildInputs depsBuildBuild depsBuildBuildPropagated depsBuildTarget
depsBuildTargetPropagated depsHostHost depsHostHostPropagated depsTargetTarget
depsTargetTargetPropagated propagatedBuildInputs propagatedNativeBuildInputs strictDeps;
# overrides for local development
nativeBuildInputs = pkgs.waybar.nativeBuildInputs ++ (with pkgs; [
clang-tools
gdb
]);
};
});
overlays.default = final: prev: {
waybar = final.callPackage ./nix/default.nix {
version = prev.waybar.version + "+date=" + (mkDate (self.lastModifiedDate or "19700101")) + "_" + (self.shortRev or "dirty");
# take the first "version: '...'" from meson.build
version =
(builtins.head (builtins.split "'"
(builtins.elemAt
(builtins.split " version: '" (builtins.readFile ./meson.build))
2)))
+ "+date=" + (mkDate (self.lastModifiedDate or "19700101")) + "_" + (self.shortRev or "dirty");
};
};
packages = genSystems
(system:
(self.overlays.default pkgsFor.${system} pkgsFor.${system})
// {
default = self.packages.${system}.waybar;
});
} //
flake-utils.lib.eachDefaultSystem (system: {
devShell =
let pkgs = import nixpkgs {
inherit system;
overlays = [ devshell.overlays.default ];
};
in
pkgs.devshell.mkShell {
imports = [ "${pkgs.devshell.extraModulesDir}/language/c.nix" ];
devshell.packages = with pkgs; [
clang-tools
gdb
# from nativeBuildInputs
gnumake
meson
ninja
pkg-config
scdoc
] ++ (map lib.getDev [
# from buildInputs
wayland wlroots gtkmm3 libsigcxx jsoncpp spdlog gtk-layer-shell howard-hinnant-date libxkbcommon
# optional dependencies
gobject-introspection glib playerctl python3.pkgs.pygobject3
libevdev libinput libjack2 libmpdclient playerctl libnl
libpulseaudio sndio sway libdbusmenu-gtk3 udev upower wireplumber
# from propagated build inputs?
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"; }
{ name = "PKG_CONFIG_PATH"; prefix = "$DEVSHELL_DIR/share/pkgconfig"; }
{ name = "PATH"; prefix = "${wayland.bin}/bin"; }
{ name = "LIBRARY_PATH"; prefix = "${lib.getLib sndio}/lib"; }
{ name = "LIBRARY_PATH"; prefix = "${lib.getLib zlib}/lib"; }
{ name = "LIBRARY_PATH"; prefix = "${lib.getLib howard-hinnant-date}/lib"; }
];
};
});
packages = genSystems (pkgs:
let packages = self.overlays.default pkgs pkgs;
in packages // {
default = packages.waybar;
});
};
}

View File

@@ -11,12 +11,15 @@ namespace waybar {
class AModule : public IModule {
public:
static constexpr const char *MODULE_CLASS = "module";
virtual ~AModule();
auto update() -> void override;
virtual auto refresh(int) -> void{};
operator Gtk::Widget &() override;
auto doAction(const std::string &name) -> void override;
/// Emitting on this dispatcher triggers a update() call
Glib::Dispatcher dp;
protected:
@@ -40,7 +43,7 @@ class AModule : public IModule {
private:
bool handleUserEvent(GdkEventButton *const &ev);
const bool isTooltip;
std::vector<int> pid_;
gdouble distance_scrolled_y_;
gdouble distance_scrolled_x_;

View File

@@ -53,34 +53,18 @@ class BarIpcClient;
}
#endif // HAVE_SWAY
class BarSurface {
protected:
BarSurface() = default;
public:
virtual void setExclusiveZone(bool enable) = 0;
virtual void setLayer(bar_layer layer) = 0;
virtual void setMargins(const struct bar_margins &margins) = 0;
virtual void setPassThrough(bool enable) = 0;
virtual void setPosition(const std::string_view &position) = 0;
virtual void setSize(uint32_t width, uint32_t height) = 0;
virtual void commit(){};
virtual ~BarSurface() = default;
};
class Bar {
public:
using bar_mode_map = std::map<std::string_view, struct bar_mode>;
using bar_mode_map = std::map<std::string, struct bar_mode>;
static const bar_mode_map PRESET_MODES;
static const std::string_view MODE_DEFAULT;
static const std::string_view MODE_INVISIBLE;
static const std::string MODE_DEFAULT;
static const std::string MODE_INVISIBLE;
Bar(struct waybar_output *w_output, const Json::Value &);
Bar(const Bar &) = delete;
~Bar();
void setMode(const std::string_view &);
void setMode(const std::string &mode);
void setVisible(bool visible);
void toggle();
void handleSignal(int);
@@ -89,8 +73,9 @@ class Bar {
Json::Value config;
struct wl_surface *surface;
bool visible = true;
bool vertical = false;
Gtk::Window window;
Gtk::Orientation orientation = Gtk::ORIENTATION_HORIZONTAL;
Gtk::PositionType position = Gtk::POS_TOP;
int x_global;
int y_global;
@@ -106,6 +91,8 @@ class Bar {
void setupAltFormatKeyForModule(const std::string &module_name);
void setupAltFormatKeyForModuleList(const char *module_list_name);
void setMode(const bar_mode &);
void setPassThrough(bool passthrough);
void setPosition(Gtk::PositionType position);
void onConfigure(GdkEventConfigure *ev);
void configureGlobalOffset(int width, int height);
void onOutputGeometryChanged();
@@ -115,8 +102,9 @@ class Bar {
std::string last_mode_{MODE_DEFAULT};
struct bar_margins margins_;
uint32_t width_, height_;
bool passthrough_;
std::unique_ptr<BarSurface> surface_impl_;
Gtk::Box left_;
Gtk::Box center_;
Gtk::Box right_;

View File

@@ -7,9 +7,9 @@
#include "bar.hpp"
#include "config.hpp"
#include "util/css_reload_helper.hpp"
#include "util/portal.hpp"
struct zwlr_layer_shell_v1;
struct zwp_idle_inhibitor_v1;
struct zwp_idle_inhibit_manager_v1;
@@ -25,7 +25,6 @@ class Client {
Glib::RefPtr<Gdk::Display> gdk_display;
struct wl_display *wl_display = nullptr;
struct wl_registry *registry = nullptr;
struct zwlr_layer_shell_v1 *layer_shell = nullptr;
struct zxdg_output_manager_v1 *xdg_output_manager = nullptr;
struct zwp_idle_inhibit_manager_v1 *idle_inhibit_manager = nullptr;
std::vector<std::unique_ptr<Bar>> bars;
@@ -55,6 +54,8 @@ class Client {
Glib::RefPtr<Gtk::CssProvider> css_provider_;
std::unique_ptr<Portal> portal;
std::list<struct waybar_output> outputs_;
std::unique_ptr<CssReloadHelper> m_cssReloadHelper;
std::string m_cssFile;
};
} // namespace waybar

View File

@@ -1,107 +1,17 @@
#pragma once
#include <json/json.h>
#if defined(HAVE_CHRONO_TIMEZONES) || defined(HAVE_LIBDATE)
#include "modules/clock.hpp"
#else
#include "modules/simpleclock.hpp"
#endif
#ifdef HAVE_SWAY
#include "modules/sway/language.hpp"
#include "modules/sway/mode.hpp"
#include "modules/sway/scratchpad.hpp"
#include "modules/sway/window.hpp"
#include "modules/sway/workspaces.hpp"
#endif
#ifdef HAVE_WLR
#include "modules/wlr/taskbar.hpp"
#include "modules/wlr/workspace_manager.hpp"
#endif
#ifdef HAVE_RIVER
#include "modules/river/layout.hpp"
#include "modules/river/mode.hpp"
#include "modules/river/tags.hpp"
#include "modules/river/window.hpp"
#endif
#ifdef HAVE_DWL
#include "modules/dwl/tags.hpp"
#endif
#ifdef HAVE_HYPRLAND
#include "modules/hyprland/backend.hpp"
#include "modules/hyprland/language.hpp"
#include "modules/hyprland/submap.hpp"
#include "modules/hyprland/window.hpp"
#include "modules/hyprland/workspaces.hpp"
#endif
#if defined(__FreeBSD__) || (defined(__linux__) && !defined(NO_FILESYSTEM))
#include "modules/battery.hpp"
#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)
#include "modules/memory.hpp"
#endif
#include "modules/disk.hpp"
#ifdef HAVE_DBUSMENU
#include "modules/sni/tray.hpp"
#endif
#ifdef HAVE_MPRIS
#include "modules/mpris/mpris.hpp"
#endif
#ifdef HAVE_LIBNL
#include "modules/network.hpp"
#endif
#ifdef HAVE_LIBUDEV
#include "modules/backlight.hpp"
#endif
#ifdef HAVE_LIBEVDEV
#include "modules/keyboard_state.hpp"
#endif
#ifdef HAVE_GAMEMODE
#include "modules/gamemode.hpp"
#endif
#ifdef HAVE_UPOWER
#include "modules/upower/upower.hpp"
#endif
#ifdef HAVE_LIBPULSE
#include "modules/pulseaudio.hpp"
#endif
#ifdef HAVE_LIBMPDCLIENT
#include "modules/mpd/mpd.hpp"
#endif
#ifdef HAVE_LIBSNDIO
#include "modules/sndio.hpp"
#endif
#ifdef HAVE_GIO_UNIX
#include "modules/bluetooth.hpp"
#include "modules/inhibitor.hpp"
#endif
#ifdef HAVE_LIBJACK
#include "modules/jack.hpp"
#endif
#ifdef HAVE_LIBWIREPLUMBER
#include "modules/wireplumber.hpp"
#endif
#ifdef HAVE_LIBCAVA
#include "modules/cava.hpp"
#endif
#include "bar.hpp"
#include "modules/custom.hpp"
#include "modules/image.hpp"
#include "modules/temperature.hpp"
#include "modules/user.hpp"
#include <AModule.hpp>
namespace waybar {
class Bar;
class Factory {
public:
Factory(const Bar& bar, const Json::Value& config);
AModule* makeModule(const std::string& name) const;
AModule* makeModule(const std::string& name, const std::string& pos) const;
private:
const Bar& bar_;

View File

@@ -1,11 +1,8 @@
#pragma once
#ifdef FILESYSTEM_EXPERIMENTAL
#include <experimental/filesystem>
#else
#include <filesystem>
#endif
#include <fmt/format.h>
#include <filesystem>
#if defined(__linux__)
#include <sys/inotify.h>
#endif
@@ -16,19 +13,16 @@
#include <vector>
#include "ALabel.hpp"
#include "bar.hpp"
#include "util/sleeper_thread.hpp"
namespace waybar::modules {
#ifdef FILESYSTEM_EXPERIMENTAL
namespace fs = std::experimental::filesystem;
#else
namespace fs = std::filesystem;
#endif
class Battery : public ALabel {
public:
Battery(const std::string&, const Json::Value&);
Battery(const std::string&, const waybar::Bar&, const Json::Value&);
virtual ~Battery();
auto update() -> void override;
@@ -40,6 +34,7 @@ class Battery : public ALabel {
const std::string getAdapterStatus(uint8_t capacity) const;
const std::tuple<uint8_t, float, std::string, float> getInfos();
const std::string formatTimeRemaining(float hoursRemaining);
void setBarClass(std::string&);
int global_watch;
std::map<fs::path, int> batteries_;
@@ -49,6 +44,7 @@ class Battery : public ALabel {
std::mutex battery_list_mutex_;
std::string old_status_;
bool warnFirstTime_{true};
const Bar& bar_;
util::SleeperThread thread_;
util::SleeperThread thread_battery_update_;

60
include/modules/cffi.hpp Normal file
View File

@@ -0,0 +1,60 @@
#pragma once
#include <string>
#include "AModule.hpp"
#include "util/command.hpp"
#include "util/json.hpp"
#include "util/sleeper_thread.hpp"
namespace waybar::modules {
namespace ffi {
extern "C" {
typedef struct wbcffi_module wbcffi_module;
typedef struct {
wbcffi_module* obj;
const char* waybar_version;
GtkContainer* (*get_root_widget)(wbcffi_module*);
void (*queue_update)(wbcffi_module*);
} wbcffi_init_info;
struct wbcffi_config_entry {
const char* key;
const char* value;
};
}
} // namespace ffi
class CFFI : public AModule {
public:
CFFI(const std::string&, const std::string&, const Json::Value&);
virtual ~CFFI();
virtual auto refresh(int signal) -> void override;
virtual auto doAction(const std::string& name) -> void override;
virtual auto update() -> void override;
private:
///
void* cffi_instance_ = nullptr;
typedef void*(InitFn)(const ffi::wbcffi_init_info* init_info,
const ffi::wbcffi_config_entry* config_entries, size_t config_entries_len);
typedef void(DenitFn)(void* instance);
typedef void(RefreshFn)(void* instance, int signal);
typedef void(DoActionFn)(void* instance, const char* name);
typedef void(UpdateFn)(void* instance);
// FFI hooks
struct {
std::function<InitFn> init = nullptr;
std::function<DenitFn> deinit = nullptr;
std::function<RefreshFn> refresh = [](void*, int) {};
std::function<DoActionFn> doAction = [](void*, const char*) {};
std::function<UpdateFn> update = [](void*) {};
} hooks_;
};
} // namespace waybar::modules

View File

@@ -6,38 +6,27 @@
namespace waybar::modules {
const std::string kCalendarPlaceholder = "calendar";
const std::string KTimezonedTimeListPlaceholder = "timezoned_time_list";
enum class WeeksSide {
LEFT,
RIGHT,
HIDDEN,
};
const std::string kCldPlaceholder{"calendar"};
const std::string kTZPlaceholder{"tz_list"};
const std::string kOrdPlaceholder{"ordinal_date"};
enum class CldMode { MONTH, YEAR };
enum class WS { LEFT, RIGHT, HIDDEN };
class Clock final : public ALabel {
public:
Clock(const std::string&, const Json::Value&);
virtual ~Clock() = default;
auto update() -> void override;
auto doAction(const std::string& name) -> void override;
auto doAction(const std::string&) -> void override;
private:
util::SleeperThread thread_;
std::locale locale_;
std::vector<const date::time_zone*> time_zones_;
int current_time_zone_idx_;
bool is_calendar_in_tooltip_;
bool is_timezoned_list_in_tooltip_;
auto first_day_of_week() -> date::weekday;
const date::time_zone* current_timezone();
auto timezones_text(std::chrono::system_clock::time_point now) -> std::string;
/*Calendar properties*/
WeeksSide cldWPos_{WeeksSide::HIDDEN};
const std::locale locale_;
// tooltip
const std::string tlpFmt_;
std::string tlpText_{""}; // tooltip text to print
// Calendar
const bool cldInTooltip_; // calendar in tooltip
/*
0 - calendar.format.months
1 - calendar.format.weekdays
@@ -47,28 +36,42 @@ class Clock final : public ALabel {
5 - tooltip-format
*/
std::map<int, std::string const> fmtMap_;
uint cldMonCols_{3}; // calendar count month columns
int cldWnLen_{3}; // calendar week number length
const int cldMonColLen_{20}; // calendar month column length
WS cldWPos_{WS::HIDDEN}; // calendar week side to print
months cldCurrShift_{0}; // calendar months shift
year_month_day cldYearShift_; // calendar Year mode. Cached ymd
std::string cldYearCached_; // calendar Year mode. Cached calendar
year_month cldMonShift_; // calendar Month mode. Cached ym
std::string cldMonCached_; // calendar Month mode. Cached calendar
day cldBaseDay_{0}; // calendar Cached day. Is used when today is changing(midnight)
std::string cldText_{""}; // calendar text to print
CldMode cldMode_{CldMode::MONTH};
uint cldMonCols_{3}; // Count of the month in the row
int cldMonColLen_{20}; // Length of the month column
int cldWnLen_{3}; // Length of the week number
date::year_month_day cldYearShift_;
date::year_month cldMonShift_;
date::months cldCurrShift_{0};
date::months cldShift_{0};
std::string cldYearCached_{};
std::string cldMonCached_{};
date::day cldBaseDay_{0};
/*Calendar functions*/
auto get_calendar(const date::year_month_day& today, const date::year_month_day& ymd,
const date::time_zone* tz) -> const std::string;
/*Clock actions*/
auto get_calendar(const year_month_day& today, const year_month_day& ymd, const time_zone* tz)
-> const std::string;
// time zoned time in tooltip
const bool tzInTooltip_; // if need to print time zones text
std::vector<const time_zone*> tzList_; // time zones list
int tzCurrIdx_; // current time zone index for tzList_
std::string tzText_{""}; // time zones text to print
util::SleeperThread thread_;
// ordinal date in tooltip
const bool ordInTooltip_;
std::string ordText_{""};
auto get_ordinal_date(const year_month_day& today) -> std::string;
auto getTZtext(sys_seconds now) -> std::string;
auto first_day_of_week() -> weekday;
// Module actions
void cldModeSwitch();
void cldShift_up();
void cldShift_down();
void tz_up();
void tz_down();
// ModuleActionMap
// Module Action Map
static inline std::map<const std::string, void (waybar::modules::Clock::*const)()> actionMap_{
{"mode", &waybar::modules::Clock::cldModeSwitch},
{"shift_up", &waybar::modules::Clock::cldShift_up},
@@ -76,4 +79,5 @@ class Clock final : public ALabel {
{"tz_up", &waybar::modules::Clock::tz_up},
{"tz_down", &waybar::modules::Clock::tz_down}};
};
} // namespace waybar::modules

View File

@@ -14,7 +14,7 @@ namespace waybar::modules {
class Custom : public ALabel {
public:
Custom(const std::string&, const std::string&, const Json::Value&);
Custom(const std::string&, const std::string&, const Json::Value&, const std::string&);
virtual ~Custom();
auto update() -> void override;
void refresh(int /*signal*/) override;
@@ -30,6 +30,7 @@ class Custom : public ALabel {
bool handleToggle(GdkEventButton* const& e) override;
const std::string name_;
const std::string output_name_;
std::string text_;
std::string id_;
std::string alt_;

View File

@@ -1,11 +1,9 @@
#pragma once
#include <functional>
#include <list>
#include <memory>
#include <mutex>
#include <string>
#include <thread>
#include <utility>
#include "util/json.hpp"
@@ -22,19 +20,19 @@ class IPC {
public:
IPC() { startIPC(); }
void registerForIPC(const std::string&, EventHandler*);
void unregisterForIPC(EventHandler*);
void registerForIPC(const std::string& ev, EventHandler* ev_handler);
void unregisterForIPC(EventHandler* handler);
std::string getSocket1Reply(const std::string& rq);
static std::string getSocket1Reply(const std::string& rq);
Json::Value getSocket1JsonReply(const std::string& rq);
private:
void startIPC();
void parseIPC(const std::string&);
std::mutex callbackMutex;
std::mutex callbackMutex_;
util::JsonParser parser_;
std::list<std::pair<std::string, EventHandler*>> callbacks;
std::list<std::pair<std::string, EventHandler*>> callbacks_;
};
inline std::unique_ptr<IPC> gIPC;

View File

@@ -30,7 +30,7 @@ class Language : public waybar::ALabel, public EventHandler {
std::string short_description;
};
auto getLayout(const std::string&) -> Layout;
static auto getLayout(const std::string&) -> Layout;
std::mutex mutex_;
const Bar& bar_;

View File

@@ -14,12 +14,12 @@ namespace waybar::modules::hyprland {
class Submap : public waybar::ALabel, public EventHandler {
public:
Submap(const std::string&, const waybar::Bar&, const Json::Value&);
virtual ~Submap();
~Submap() override;
auto update() -> void override;
private:
void onEvent(const std::string&) override;
void onEvent(const std::string& ev) override;
std::mutex mutex_;
const Bar& bar_;

View File

@@ -25,7 +25,7 @@ class Window : public waybar::AAppIconLabel, public EventHandler {
std::string last_window;
std::string last_window_title;
static auto parse(const Json::Value&) -> Workspace;
static auto parse(const Json::Value& value) -> Workspace;
};
struct WindowData {
@@ -41,24 +41,25 @@ class Window : public waybar::AAppIconLabel, public EventHandler {
static auto parse(const Json::Value&) -> WindowData;
};
auto getActiveWorkspace(const std::string&) -> Workspace;
auto getActiveWorkspace() -> Workspace;
void onEvent(const std::string&) override;
static auto getActiveWorkspace(const std::string&) -> Workspace;
static auto getActiveWorkspace() -> Workspace;
void onEvent(const std::string& ev) override;
void queryActiveWorkspace();
void setClass(const std::string&, bool enable);
bool separate_outputs;
bool separateOutputs_;
std::mutex mutex_;
const Bar& bar_;
util::JsonParser parser_;
WindowData window_data_;
WindowData windowData_;
Workspace workspace_;
std::string solo_class_;
std::string last_solo_class_;
std::string soloClass_;
std::string lastSoloClass_;
bool solo_;
bool all_floating_;
bool allFloating_;
bool swallowing_;
bool fullscreen_;
bool focused_;
};
} // namespace waybar::modules::hyprland

View File

@@ -34,82 +34,86 @@ class WindowCreationPayload {
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_); }
int incrementTimeSpentUncreated();
bool isEmpty(Workspaces& workspace_manager);
bool reprIsReady() const { return std::holds_alternative<Repr>(m_window); }
std::string repr(Workspaces& workspace_manager);
std::string workspace_name() const { return workspace_name_; }
WindowAddress addr() const { return window_address_; }
std::string getWorkspaceName() const { return m_workspaceName; }
WindowAddress getAddress() const { return m_windowAddress; }
void move_to_worksace(std::string& new_workspace_name);
void moveToWorksace(std::string& new_workspace_name);
private:
void clear_addr();
void clear_workspace_name();
void clearAddr();
void clearWorkspaceName();
using Repr = std::string;
using ClassAndTitle = std::pair<std::string, std::string>;
std::variant<Repr, ClassAndTitle> window_;
std::variant<Repr, ClassAndTitle> m_window;
WindowAddress window_address_;
std::string workspace_name_;
WindowAddress m_windowAddress;
std::string m_workspaceName;
int time_spent_uncreated_ = 0;
int m_timeSpentUncreated = 0;
};
class Workspace {
public:
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_; };
std::string& selectIcon(std::map<std::string, std::string>& icons_map);
Gtk::Button& button() { return m_button; };
int id() const { return id_; };
std::string name() const { return name_; };
std::string output() const { return output_; };
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_; };
int id() const { return m_id; };
std::string name() const { return m_name; };
std::string output() const { return m_output; };
bool isActive() const { return m_isActive; };
bool isSpecial() const { return m_isSpecial; };
bool isPersistent() const { return m_isPersistentRule || m_isPersistentConfig; };
bool isPersistentConfig() const { return m_isPersistentConfig; };
bool isPersistentRule() const { return m_isPersistentRule; };
bool isVisible() const { return m_isVisible; };
bool isEmpty() const { return m_windows == 0; };
bool isUrgent() const { return m_isUrgent; };
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 handleClicked(GdkEventButton* bt) const;
void setActive(bool value = true) { m_isActive = value; };
void setPersistentRule(bool value = true) { m_isPersistentRule = value; };
void setPersistentConfig(bool value = true) { m_isPersistentConfig = value; };
void setUrgent(bool value = true) { m_isUrgent = value; };
void setVisible(bool value = true) { m_isVisible = value; };
void setWindows(uint value) { m_windows = value; };
void setName(std::string const& value) { m_name = value; };
bool containsWindow(WindowAddress const& addr) const { return m_windowMap.contains(addr); }
void insertWindow(WindowCreationPayload create_window_paylod);
std::string removeWindow(WindowAddress const& addr);
void initializeWindowMap(const Json::Value& clients_data);
bool on_window_opened(WindowCreationPayload const& create_window_paylod);
std::optional<std::string> close_window(WindowAddress const& addr);
bool onWindowOpened(WindowCreationPayload const& create_window_paylod);
std::optional<std::string> closeWindow(WindowAddress const& addr);
void update(const std::string& format, const std::string& icon);
private:
Workspaces& workspace_manager_;
Workspaces& m_workspaceManager;
int id_;
std::string name_;
std::string output_;
uint windows_;
bool active_ = false;
bool is_special_ = false;
bool is_persistent_ = false;
bool is_urgent_ = false;
bool is_visible_ = false;
int m_id;
std::string m_name;
std::string m_output;
uint m_windows;
bool m_isActive = false;
bool m_isSpecial = false;
bool m_isPersistentRule = false; // represents the persistent state in hyprland
bool m_isPersistentConfig = false; // represents the persistent state in the Waybar config
bool m_isUrgent = false;
bool m_isVisible = false;
std::map<WindowAddress, std::string> window_map_;
std::map<WindowAddress, std::string> m_windowMap;
Gtk::Button button_;
Gtk::Box content_;
Gtk::Label label_;
Gtk::Button m_button;
Gtk::Box m_content;
Gtk::Label m_label;
};
class Workspaces : public AModule, public EventHandler {
@@ -119,85 +123,101 @@ class Workspaces : public AModule, public EventHandler {
void update() override;
void init();
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 allOutputs() const -> bool { return m_allOutputs; }
auto showSpecial() const -> bool { return m_showSpecial; }
auto activeOnly() const -> bool { return m_activeOnly; }
auto get_bar_output() const -> std::string { return bar_.output->name; }
auto getBarOutput() const -> std::string { return m_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);
std::string getRewrite(std::string window_class, std::string window_title);
std::string& getWindowSeparator() { return m_formatWindowSeparator; }
bool isWorkspaceIgnored(std::string const& workspace_name);
bool window_rewrite_config_uses_title() const { return any_window_rewrite_rule_uses_title_; }
bool windowRewriteConfigUsesTitle() const { return m_anyWindowRewriteRuleUsesTitle; }
private:
void onEvent(const std::string& e) override;
void update_window_count();
void sort_workspaces();
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();
void updateWindowCount();
void sortWorkspaces();
void createWorkspace(Json::Value const& workspaceData,
Json::Value const& clientsData = Json::Value::nullRef);
void removeWorkspace(std::string const& name);
void setUrgentWorkspace(std::string const& windowaddress);
void parseConfig(const Json::Value& config);
void registerIpc();
// 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);
void onWorkspaceActivated(std::string const& payload);
void onSpecialWorkspaceActivated(std::string const& payload);
void onWorkspaceDestroyed(std::string const& payload);
void onWorkspaceCreated(std::string const& workspaceName,
Json::Value const& clientsData = Json::Value::nullRef);
void onWorkspaceMoved(std::string const& payload);
void onWorkspaceRenamed(std::string const& payload);
// monitor events
void on_monitor_focused(std::string const& payload);
void onMonitorFocused(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 onWindowOpened(std::string const& payload);
void onWindowClosed(std::string const& addr);
void onWindowMoved(std::string const& payload);
void on_window_title_event(std::string const& payload);
void onWindowTitleEvent(std::string const& payload);
int window_rewrite_priority_function(std::string const& window_rule);
void onConfigReloaded();
bool all_outputs_ = false;
bool show_special_ = false;
bool active_only_ = false;
int windowRewritePriorityFunction(std::string const& window_rule);
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 doUpdate();
void fill_persistent_workspaces();
void create_persistent_workspaces();
std::vector<std::string> persistent_workspaces_to_create_;
bool persistent_created_ = false;
void extendOrphans(int workspaceId, Json::Value const& clientsJson);
void registerOrphanWindow(WindowCreationPayload create_window_payload);
std::string format_;
void initializeWorkspaces();
void setCurrentMonitorId();
void loadPersistentWorkspacesFromConfig(Json::Value const& clientsJson);
void loadPersistentWorkspacesFromWorkspaceRules(const Json::Value& clientsJson);
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 m_allOutputs = false;
bool m_showSpecial = false;
bool m_activeOnly = false;
Json::Value m_persistentWorkspaceConfig;
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_;
// Map for windows stored in workspaces not present in the current bar.
// This happens when the user has multiple monitors (hence, multiple bars)
// and doesn't share windows accross bars (a.k.a `all-outputs` = false)
std::map<WindowAddress, std::string> m_orphanWindowMap;
std::vector<std::regex> ignore_workspaces_;
enum class SortMethod { ID, NAME, NUMBER, DEFAULT };
util::EnumParser<SortMethod> m_enumParser;
SortMethod m_sortBy = SortMethod::DEFAULT;
std::map<std::string, SortMethod> m_sortMap = {{"ID", SortMethod::ID},
{"NAME", SortMethod::NAME},
{"NUMBER", SortMethod::NUMBER},
{"DEFAULT", SortMethod::DEFAULT}};
std::mutex mutex_;
const Bar& bar_;
Gtk::Box box_;
std::string m_format;
std::map<std::string, std::string> m_iconsMap;
util::RegexCollection m_windowRewriteRules;
bool m_anyWindowRewriteRuleUsesTitle = false;
std::string m_formatWindowSeparator;
bool m_withIcon;
uint64_t m_monitorId;
std::string m_activeWorkspaceName;
std::string m_activeSpecialWorkspaceName;
std::vector<std::unique_ptr<Workspace>> m_workspaces;
std::vector<std::pair<Json::Value, Json::Value>> m_workspacesToCreate;
std::vector<std::string> m_workspacesToRemove;
std::vector<WindowCreationPayload> m_windowsToCreate;
std::vector<std::regex> m_ignoreWorkspaces;
std::mutex m_mutex;
const Bar& m_bar;
Gtk::Box m_box;
};
} // namespace waybar::modules::hyprland

View File

@@ -148,6 +148,7 @@ class Stopped : public State {
class Disconnected : public State {
Context* const ctx_;
sigc::connection timer_connection_;
int last_interval_;
public:
Disconnected(Context* const ctx) : ctx_{ctx} {}
@@ -162,7 +163,7 @@ class Disconnected : public State {
Disconnected(Disconnected const&) = delete;
Disconnected& operator=(Disconnected const&) = delete;
void arm_timer(int interval) noexcept;
bool arm_timer(int interval) noexcept;
void disarm_timer() noexcept;
bool on_timer();

View File

@@ -0,0 +1,46 @@
#pragma once
#include <fmt/format.h>
#include "ALabel.hpp"
#include "giomm/dbusproxy.h"
namespace waybar::modules {
struct Profile {
std::string name;
std::string driver;
};
class PowerProfilesDaemon : public ALabel {
public:
PowerProfilesDaemon(const std::string &, const Json::Value &);
auto update() -> void override;
void profileChangedCb(const Gio::DBus::Proxy::MapChangedProperties &,
const std::vector<Glib::ustring> &);
void busConnectedCb(Glib::RefPtr<Gio::AsyncResult> &r);
void getAllPropsCb(Glib::RefPtr<Gio::AsyncResult> &r);
void setPropCb(Glib::RefPtr<Gio::AsyncResult> &r);
void populateInitState();
bool handleToggle(GdkEventButton *const &e) override;
private:
// True if we're connected to the dbug interface. False if we're
// not.
bool connected_;
// Look for a profile name in the list of available profiles and
// switch activeProfile_ to it.
void switchToProfile(std::string const &);
// Used to toggle/display the profiles
std::vector<Profile> availableProfiles_;
// Points to the active profile in the profiles list
std::vector<Profile>::iterator activeProfile_;
// Current CSS class applied to the label
std::string currentStyle_;
// Format string
std::string tooltipFormat_;
// DBus Proxy used to track the current active profile
Glib::RefPtr<Gio::DBus::Proxy> powerProfilesProxy_;
};
} // namespace waybar::modules

View File

@@ -0,0 +1,41 @@
#pragma once
#include <iostream>
#include <map>
#include <string>
#include "ALabel.hpp"
#include "gtkmm/box.h"
#include "modules/privacy/privacy_item.hpp"
#include "util/pipewire/pipewire_backend.hpp"
#include "util/pipewire/privacy_node_info.hpp"
using waybar::util::PipewireBackend::PrivacyNodeInfo;
namespace waybar::modules::privacy {
class Privacy : public AModule {
public:
Privacy(const std::string &, const Json::Value &, const std::string &pos);
auto update() -> void override;
void onPrivacyNodesChanged();
private:
std::list<PrivacyNodeInfo *> nodes_screenshare; // Screen is being shared
std::list<PrivacyNodeInfo *> nodes_audio_in; // Application is using the microphone
std::list<PrivacyNodeInfo *> nodes_audio_out; // Application is outputting audio
std::mutex mutex_;
sigc::connection visibility_conn;
// Config
Gtk::Box box_;
uint iconSpacing = 4;
uint iconSize = 20;
uint transition_duration = 250;
std::shared_ptr<util::PipewireBackend::PipewireBackend> backend = nullptr;
};
} // namespace waybar::modules::privacy

View File

@@ -0,0 +1,51 @@
#pragma once
#include <json/value.h>
#include <iostream>
#include <map>
#include <mutex>
#include <string>
#include "gtkmm/box.h"
#include "gtkmm/image.h"
#include "gtkmm/revealer.h"
#include "util/pipewire/privacy_node_info.hpp"
using waybar::util::PipewireBackend::PrivacyNodeInfo;
using waybar::util::PipewireBackend::PrivacyNodeType;
namespace waybar::modules::privacy {
class PrivacyItem : public Gtk::Revealer {
public:
PrivacyItem(const Json::Value &config_, enum PrivacyNodeType privacy_type_,
std::list<PrivacyNodeInfo *> *nodes, const std::string &pos, const uint icon_size,
const uint transition_duration);
enum PrivacyNodeType privacy_type;
void set_in_use(bool in_use);
private:
std::list<PrivacyNodeInfo *> *nodes;
sigc::connection signal_conn;
Gtk::Box tooltip_window;
bool init = false;
bool in_use = false;
// Config
std::string iconName = "image-missing-symbolic";
bool tooltip = true;
uint tooltipIconSize = 24;
Gtk::Box box_;
Gtk::Image icon_;
void update_tooltip();
};
} // namespace waybar::modules::privacy

View File

@@ -56,6 +56,7 @@ class Language : public ALabel, public sigc::trackable {
Layout layout_;
std::string tooltip_format_ = "";
std::map<std::string, Layout> layouts_map_;
bool hide_single_;
bool is_variant_displayed;
std::byte displayed_short_flag = static_cast<std::byte>(DispayedShortFlag::None);

View File

@@ -12,6 +12,7 @@
#include "client.hpp"
#include "modules/sway/ipc/client.hpp"
#include "util/json.hpp"
#include "util/regex_collection.hpp"
namespace waybar::modules::sway {
@@ -27,10 +28,13 @@ class Workspaces : public AModule, public sigc::trackable {
R"(workspace {} "{}"; move workspace to output "{}"; workspace {} "{}")";
static int convertWorkspaceNameToNum(std::string name);
static int windowRewritePriorityFunction(std::string const& window_rule);
void onCmd(const struct Ipc::ipc_response&);
void onEvent(const struct Ipc::ipc_response&);
bool filterButtons();
static bool hasFlag(const Json::Value&, const std::string&);
void updateWindows(const Json::Value&, std::string&);
Gtk::Button& addButton(const Json::Value&);
void onButtonReady(const Json::Value&, Gtk::Button&);
std::string getIcon(const std::string&, const Json::Value&);
@@ -44,6 +48,9 @@ class Workspaces : public AModule, public sigc::trackable {
std::vector<std::string> high_priority_named_;
std::vector<std::string> workspaces_order_;
Gtk::Box box_;
std::string m_formatWindowSeperator;
std::string m_windowRewriteDefault;
util::RegexCollection m_windowRewriteRules;
util::JsonParser parser_;
std::unordered_map<std::string, Gtk::Button> buttons_;
std::mutex mutex_;

View File

@@ -0,0 +1,31 @@
#pragma once
#include <giomm/dbusproxy.h>
#include <string>
#include "ALabel.hpp"
namespace waybar::modules {
class SystemdFailedUnits : public ALabel {
public:
SystemdFailedUnits(const std::string &, const Json::Value &);
virtual ~SystemdFailedUnits();
auto update() -> void override;
private:
bool hide_on_ok;
std::string format_ok;
bool update_pending;
uint32_t nr_failed_system, nr_failed_user;
std::string last_status;
Glib::RefPtr<Gio::DBus::Proxy> system_proxy, user_proxy;
void notify_cb(const Glib::ustring &sender_name, const Glib::ustring &signal_name,
const Glib::VariantContainerBase &arguments);
void updateData();
};
} // namespace waybar::modules

View File

@@ -66,12 +66,13 @@ class UPower : public AModule {
Devices devices;
std::mutex m_Mutex;
UpClient *client;
UpDevice *displayDevice;
UpDevice *displayDevice = nullptr;
guint login1_id;
GDBusConnection *login1_connection;
std::unique_ptr<UPowerTooltip> upower_tooltip;
std::string lastStatus;
bool showAltText;
bool showIcon = true;
bool upowerRunning;
guint upowerWatcher_id;
std::string nativePath_;

View File

@@ -22,6 +22,7 @@ class AudioBackend {
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*);
void connectContext();
pa_threaded_mainloop* mainloop_;
pa_mainloop_api* mainloop_api_;

View File

@@ -66,7 +66,7 @@ inline int close(FILE* fp, pid_t pid) {
return stat;
}
inline FILE* open(const std::string& cmd, int& pid) {
inline FILE* open(const std::string& cmd, int& pid, const std::string& output_name) {
if (cmd == "") return nullptr;
int fd[2];
// Open the pipe with the close-on-exec flag set, so it will not be inherited
@@ -109,6 +109,9 @@ inline FILE* open(const std::string& cmd, int& pid) {
::close(fd[0]);
dup2(fd[1], 1);
setpgid(child_pid, child_pid);
if (output_name != "") {
setenv("WAYBAR_OUTPUT_NAME", output_name.c_str(), 1);
}
execlp("/bin/sh", "sh", "-c", cmd.c_str(), (char*)0);
exit(0);
} else {
@@ -118,9 +121,9 @@ inline FILE* open(const std::string& cmd, int& pid) {
return fdopen(fd[0], "r");
}
inline struct res exec(const std::string& cmd) {
inline struct res exec(const std::string& cmd, const std::string& output_name) {
int pid;
auto fp = command::open(cmd, pid);
auto fp = command::open(cmd, pid, output_name);
if (!fp) return {-1, ""};
auto output = command::read(fp);
auto stat = command::close(fp, pid);
@@ -129,7 +132,7 @@ inline struct res exec(const std::string& cmd) {
inline struct res execNoRead(const std::string& cmd) {
int pid;
auto fp = command::open(cmd, pid);
auto fp = command::open(cmd, pid, "");
if (!fp) return {-1, ""};
auto stat = command::close(fp, pid);
return {WEXITSTATUS(stat), ""};

View File

@@ -0,0 +1,49 @@
#pragma once
#include <functional>
#include <string>
#include <unordered_map>
#include <vector>
#include "giomm/file.h"
#include "giomm/filemonitor.h"
#include "glibmm/refptr.h"
struct pollfd;
namespace waybar {
class CssReloadHelper {
public:
CssReloadHelper(std::string cssFile, std::function<void()> callback);
virtual ~CssReloadHelper() = default;
virtual void monitorChanges();
protected:
std::vector<std::string> parseImports(const std::string& cssFile);
void parseImports(const std::string& cssFile, std::unordered_map<std::string, bool>& imports);
void watchFiles(const std::vector<std::string>& files);
bool handleInotifyEvents(int fd);
bool watch(int inotifyFd, pollfd* pollFd);
virtual std::string getFileContents(const std::string& filename);
virtual std::string findPath(const std::string& filename);
void handleFileChange(Glib::RefPtr<Gio::File> const& file,
Glib::RefPtr<Gio::File> const& other_type,
Gio::FileMonitorEvent event_type);
private:
std::string m_cssFile;
std::function<void()> m_callback;
std::vector<std::tuple<Glib::RefPtr<Gio::FileMonitor>>> m_fileMonitors;
};
} // namespace waybar

View File

@@ -1,34 +1,48 @@
#pragma once
#include <fmt/format.h>
#include <chrono>
#if HAVE_CHRONO_TIMEZONES
#include <chrono>
#include <format>
/* Compatibility layer for <date/tz.h> on top of C++20 <chrono> */
namespace date {
using namespace std::chrono;
namespace literals {
using std::chrono::last;
}
inline auto format(const std::string& spec, const auto& ztime) {
return spec.empty() ? "" : std::vformat("{:L" + spec + "}", std::make_format_args(ztime));
}
inline auto format(const std::locale& loc, const std::string& spec, const auto& ztime) {
return spec.empty() ? "" : std::vformat(loc, "{:L" + spec + "}", std::make_format_args(ztime));
}
} // namespace date
#else
#include <date/tz.h>
#include <fmt/format.h>
#include <regex>
#endif
// Date
namespace date {
#if HAVE_CHRONO_TIMEZONES
using namespace std::chrono;
using namespace std;
#else
using system_clock = std::chrono::system_clock;
using seconds = std::chrono::seconds;
template <typename T>
inline auto format(const char* spec, const T& arg) {
return date::format(std::regex_replace(spec, std::regex("\\{:L|\\}"), ""), arg);
}
template <typename T>
inline auto format(const std::locale& loc, const char* spec, const T& arg) {
return date::format(loc, std::regex_replace(spec, std::regex("\\{:L|\\}"), ""), arg);
}
#endif
} // namespace date
// Format
namespace waybar::util::date::format {
#if HAVE_CHRONO_TIMEZONES
using namespace std;
#else
using namespace fmt;
#endif
} // namespace waybar::util::date::format
#if not HAVE_CHRONO_TIMEZONES
template <typename Duration, typename TimeZonePtr>
struct fmt::formatter<date::zoned_time<Duration, TimeZonePtr>> {
std::string_view specs;
@@ -58,3 +72,6 @@ struct fmt::formatter<date::zoned_time<Duration, TimeZonePtr>> {
return fmt::format_to(ctx.out(), "{}", date::format(fmt::to_string(specs), ztime));
}
};
#endif
using namespace date;

View File

@@ -3,6 +3,12 @@
#include <fmt/ostream.h>
#include <json/json.h>
#include <algorithm>
#include <codecvt>
#include <iostream>
#include <locale>
#include <regex>
#if (FMT_VERSION >= 90000)
template <>
@@ -12,25 +18,30 @@ struct fmt::formatter<Json::Value> : ostream_formatter {};
namespace waybar::util {
struct JsonParser {
JsonParser() {}
class JsonParser {
public:
JsonParser() = default;
const Json::Value parse(const std::string& data) const {
Json::Value root(Json::objectValue);
if (data.empty()) {
return root;
Json::Value parse(const std::string& jsonStr) {
Json::Value root;
// replace all occurrences of "\x" with "\u00", because JSON doesn't allow "\x" escape sequences
std::string modifiedJsonStr = replaceHexadecimalEscape(jsonStr);
std::istringstream jsonStream(modifiedJsonStr);
std::string errs;
if (!Json::parseFromStream(m_readerBuilder, jsonStream, &root, &errs)) {
throw std::runtime_error("Error parsing JSON: " + errs);
}
std::unique_ptr<Json::CharReader> const reader(builder_.newCharReader());
std::string err;
bool res = reader->parse(data.c_str(), data.c_str() + data.size(), &root, &err);
if (!res) throw std::runtime_error(err);
return root;
}
~JsonParser() = default;
private:
Json::CharReaderBuilder builder_;
};
Json::CharReaderBuilder m_readerBuilder;
static std::string replaceHexadecimalEscape(const std::string& str) {
static std::regex re("\\\\x");
return std::regex_replace(str, re, "\\u00");
}
};
} // namespace waybar::util

View File

@@ -0,0 +1,40 @@
#pragma once
#include <pipewire/pipewire.h>
#include "util/backend_common.hpp"
#include "util/pipewire/privacy_node_info.hpp"
namespace waybar::util::PipewireBackend {
class PipewireBackend {
private:
pw_thread_loop* mainloop_;
pw_context* context_;
pw_core* core_;
spa_hook registry_listener;
/* 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:
std::mutex mutex_;
pw_registry* registry;
sigc::signal<void> privacy_nodes_changed_signal_event;
std::unordered_map<uint32_t, PrivacyNodeInfo*> privacy_nodes;
static std::shared_ptr<PipewireBackend> getInstance();
PipewireBackend(private_constructor_tag tag);
~PipewireBackend();
};
} // namespace waybar::util::PipewireBackend

View File

@@ -0,0 +1,62 @@
#pragma once
#include <pipewire/pipewire.h>
#include <string>
#include "util/gtk_icon.hpp"
namespace waybar::util::PipewireBackend {
enum PrivacyNodeType {
PRIVACY_NODE_TYPE_NONE,
PRIVACY_NODE_TYPE_VIDEO_INPUT,
PRIVACY_NODE_TYPE_AUDIO_INPUT,
PRIVACY_NODE_TYPE_AUDIO_OUTPUT
};
class PrivacyNodeInfo {
public:
PrivacyNodeType type = PRIVACY_NODE_TYPE_NONE;
uint32_t id;
uint32_t client_id;
enum pw_node_state state = PW_NODE_STATE_IDLE;
std::string media_class;
std::string media_name;
std::string node_name;
std::string application_name;
std::string pipewire_access_portal_app_id;
std::string application_icon_name;
struct spa_hook object_listener;
struct spa_hook proxy_listener;
void *data;
std::string get_name() {
const std::vector<std::string *> names{&application_name, &node_name};
std::string name = "Unknown Application";
for (auto &name_ : names) {
if (name_ != nullptr && name_->length() > 0) {
name = *name_;
name[0] = toupper(name[0]);
break;
}
}
return name;
}
std::string get_icon_name() {
const std::vector<std::string *> names{&application_icon_name, &pipewire_access_portal_app_id,
&application_name, &node_name};
const std::string name = "application-x-executable-symbolic";
for (auto &name_ : names) {
if (name_ != nullptr && name_->length() > 0 && DefaultGtkIconThemeWrapper::has_icon(*name_)) {
return *name_;
}
}
return name;
}
};
} // namespace waybar::util::PipewireBackend

View File

@@ -30,7 +30,11 @@ The *backlight* module displays the current backlight level.
*align*: ++
typeof: float ++
The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
The alignment of the label within the module, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
*justify*: ++
typeof: string ++
The alignment of the text within the module's label, allowing options 'left', 'right', or 'center' to define the positioning.
*rotate*: ++
typeof: integer ++

View File

@@ -61,7 +61,11 @@ The *battery* module displays the current capacity and state (eg. charging) of y
*align*: ++
typeof: float ++
The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
The alignment of the label within the module, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
*justify*: ++
typeof: string ++
The alignment of the text within the module's label, allowing options 'left', 'right', or 'center' to define the positioning.
*rotate*: ++
typeof: integer++
@@ -167,3 +171,10 @@ The *battery* module allows one to define custom formats based on up to two fact
- *<state>* can be defined in the *config*. For more information see *states*.
- *#battery.<status>.<state>*
- Combination of both *<status>* and *<state>*.
The following classes are applied to the entire Waybar rather than just the
battery widget:
- *window#waybar.battery-<state>*
- *<state>* can be defined in the *config*, as previously mentioned.

View File

@@ -66,7 +66,11 @@ Addressed by *bluetooth*
*align*: ++
typeof: float ++
The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
The alignment of the label within the module, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
*justify*: ++
typeof: string ++
The alignment of the text within the module's label, allowing options 'left', 'right', or 'center' to define the positioning.
*on-click*: ++
typeof: string ++

37
man/waybar-cffi.5.scd Normal file
View File

@@ -0,0 +1,37 @@
waybar-cffi(5)
# NAME
waybar - cffi module
# DESCRIPTION
The *cffi* module gives full control of a GTK widget to a third-party dynamic library, to create more complex modules using different programming languages.
# CONFIGURATION
Addressed by *cffi/<name>*
*module_path*: ++
typeof: string ++
The path to the dynamic library to load to control the widget.
Some additional configuration may be required depending on the cffi dynamic library being used.
# EXAMPLES
## C example:
An example module written in C can be found at https://github.com/Alexays/Waybar/resources/custom_modules/cffi_example/
Waybar config to enable the module:
```
"cffi/c_example": {
"module_path": ".config/waybar/cffi/wb_cffi_example.so"
}
```
# STYLE
The classes and IDs are managed by the cffi dynamic library.

View File

@@ -85,7 +85,7 @@ $XDG_CONFIG_HOME/waybar/config ++
:[ same as format
:[ Tooltip on hover
View all valid format options in *strftime(3)* or have a look <https://fmt.dev/latest/syntax.html#chrono-specs>
View all valid format options in *strftime(3)* or have a look https://en.cppreference.com/w/cpp/chrono/duration/formatter
2. Addressed by *clock: calendar*
[- *Option*
@@ -156,7 +156,8 @@ View all valid format options in *strftime(3)* or have a look <https://fmt.dev/l
# FORMAT REPLACEMENTS
- *{calendar}*: Current month calendar
- *{timezoned_time_list}*: List of time in the rest timezones, if more than one timezone is set in the config
- *{tz_list}*: List of time in the rest timezones, if more than one timezone is set in the config
- *{ordinal_date}*: The current day in (English) ordinal form, e.g. 21st
# EXAMPLES

View File

@@ -35,7 +35,11 @@ The *cpu* module displays the current CPU utilization.
*align*: ++
typeof: float ++
The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
The alignment of the label within the module, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
*justify*: ++
typeof: string ++
The alignment of the text within the module's label, allowing options 'left', 'right', or 'center' to define the positioning.
*rotate*: ++
typeof: integer ++

View File

@@ -72,7 +72,11 @@ Addressed by *custom/<name>*
*align*: ++
typeof: float ++
The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
The alignment of the label within the module, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
*justify*: ++
typeof: string ++
The alignment of the text within the module's label, allowing options 'left', 'right', or 'center' to define the positioning.
*on-click*: ++
typeof: string ++
@@ -107,6 +111,11 @@ Addressed by *custom/<name>*
default: true ++
Option to disable tooltip on hover.
*tooltip-format*: ++
typeof: string ++
The tooltip format. If specified, overrides any tooltip output from the script in *exec*. ++
Uses the same format replacements as *format*.
*escape*: ++
typeof: bool ++
default: false ++

View File

@@ -45,7 +45,11 @@ Addressed by *disk*
*align*: ++
typeof: float ++
The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
The alignment of the label within the module, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
*justify*: ++
typeof: string ++
The alignment of the text within the module's label, allowing options 'left', 'right', or 'center' to define the positioning.
*on-click*: ++
typeof: string ++

View File

@@ -31,7 +31,11 @@ Addressed by *hyprland/submap*
*align*: ++
typeof: float ++
The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
The alignment of the label within the module, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
*justify*: ++
typeof: string ++
The alignment of the text within the module's label, allowing options 'left', 'right', or 'center' to define the positioning.
*on-click*: ++
typeof: string ++
@@ -80,3 +84,4 @@ Addressed by *hyprland/submap*
# STYLE
- *#submap*
- *#submap.<name>*

View File

@@ -24,7 +24,7 @@ Addressed by *hyprland/workspaces*
*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.
Keys are the rules, while the values are the methods of representation. Values may use the placeholders {class} and {title} to use the window's original class and/or title respectively.
Rules may specify `class<...>`, `title<...>`, or both in order to fine-tune the matching.
*window-rewrite-default*:
@@ -139,6 +139,7 @@ Additional to workspace name matching, the following *format-icons* can be set.
}
```
```
"hyprland/workspaces": {
// Formatting omitted for brevity
"ignore-workspaces": [

View File

@@ -33,7 +33,11 @@ screensaver, also known as "presentation mode".
*align*: ++
typeof: float ++
The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
The alignment of the label within the module, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
*justify*: ++
typeof: string ++
The alignment of the text within the module's label, allowing options 'left', 'right', or 'center' to define the positioning.
*on-click*: ++
typeof: string ++

View File

@@ -87,3 +87,4 @@ $path\\n$tooltip
# STYLE
- *#image*
- *#image.empty*

View File

@@ -37,7 +37,11 @@ See *systemd-inhibit*(1) for more information.
*align*: ++
typeof: float ++
The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
The alignment of the label within the module, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
*justify*: ++
typeof: string ++
The alignment of the text within the module's label, allowing options 'left', 'right', or 'center' to define the positioning.
*on-click*: ++
typeof: string ++

View File

@@ -63,7 +63,11 @@ Addressed by *jack*
*align*: ++
typeof: float ++
The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
The alignment of the label within the module, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
*justify*: ++
typeof: string ++
The alignment of the text within the module's label, allowing options 'left', 'right', or 'center' to define the positioning.
*on-click*: ++
typeof: string ++

View File

@@ -45,7 +45,11 @@ Addressed by *memory*
*align*: ++
typeof: float ++
The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
The alignment of the label within the module, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
*justify*: ++
typeof: string ++
The alignment of the text within the module's label, allowing options 'left', 'right', or 'center' to define the positioning.
*on-click*: ++
typeof: string ++

View File

@@ -103,7 +103,11 @@ Addressed by *mpd*
*align*: ++
typeof: float ++
The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
The alignment of the label within the module, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
*justify*: ++
typeof: string ++
The alignment of the text within the module's label, allowing options 'left', 'right', or 'center' to define the positioning.
*on-click*: ++
typeof: string ++

View File

@@ -119,8 +119,11 @@ The *mpris* module displays currently playing media via libplayerctl.
*align*: ++
typeof: float ++
The alignment of the text, where 0 is left-aligned and 1 is right-aligned. ++
If the module is rotated, it will follow the flow of the text.
The alignment of the label within the module, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
*justify*: ++
typeof: string ++
The alignment of the text within the module's label, allowing options 'left', 'right', or 'center' to define the positioning.
*on-click*: ++
typeof: string ++

View File

@@ -70,7 +70,11 @@ Addressed by *network*
*align*: ++
typeof: float ++
The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
The alignment of the label within the module, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
*justify*: ++
typeof: string ++
The alignment of the text within the module's label, allowing options 'left', 'right', or 'center' to define the positioning.
*on-click*: ++
typeof: string ++

View File

@@ -0,0 +1,72 @@
waybar-power-profiles-daemon(5)
# NAME
waybar - power-profiles-daemon module
# DESCRIPTION
The *power-profiles-daemon* module displays the active power-profiles-daemon profile and cycle through the available profiles on click.
# FILES
$XDG_CONFIG_HOME/waybar/config
# CONFIGURATION
[- *Option*
:- *Typeof*
:- *Default*
:= *Description*
|[ *format*
:[ string
:[ "{icon}"
:[ Message displayed on the bar. {icon} and {profile} are respectively substituted with the icon representing the active profile and its full name.
|[ *tooltip-format*
:[ string
:[ "Power profile: {profile}\\nDriver: {driver}"
:[ Messaged displayed in the module tooltip. {icon} and {profile} are respectively substituted with the icon representing the active profile and its full name.
|[ *tooltip*
:[ bool
:[ true
:[ Display the tooltip.
|[ *format-icons*
:[ object
:[ See default value in the example below.
:[ Icons used to represent the various power-profile. *Note*: the default configuration uses the font-awesome icons. You may want to override it if you don't have this font installed on your system.
# CONFIGURATION EXAMPLES
Compact display (default config):
```
"power-profiles-daemon": {
"format": "{icon}",
"tooltip-format": "Power profile: {profile}\nDriver: {driver}",
"tooltip": true,
"format-icons": {
"default": "",
"performance": "",
"balanced": "",
"power-saver": ""
}
}
```
Display the full profile name:
```
"power-profiles-daemon": {
"format": "{icon} {profile}",
"tooltip-format": "Power profile: {profile}\nDriver: {driver}",
"tooltip": true,
"format-icons": {
"default": "",
"performance": "",
"balanced": "",
"power-saver": ""
}
}
```

85
man/waybar-privacy.5.scd Normal file
View File

@@ -0,0 +1,85 @@
waybar-privacy(5)
# NAME
waybar - privacy module
# DESCRIPTION
The *privacy* module displays if any application is capturing audio, sharing ++
the screen or playing audio.
# CONFIGURATION
*icon-spacing*: ++
typeof: integer ++
default: 4 ++
The spacing between each privacy icon.
*icon-size*: ++
typeof: integer ++
default: 20 ++
The size of each privacy icon.
*transition-duration*: ++
typeof: integer ++
default: 250 ++
Option to disable tooltip on hover.
*modules* ++
typeof: array of objects ++
default: [{"type": "screenshare"}, {"type": "audio-in"}] ++
Which privacy modules to monitor. See *MODULES CONFIGURATION* for++
more information.
# MODULES CONFIGURATION
*type*: ++
typeof: string ++
values: "screenshare", "audio-in", "audio-out" ++
Specifies which module to use and configure.
*tooltip*: ++
typeof: bool ++
default: true ++
Option to disable tooltip on hover.
*tooltip-icon-size*: ++
typeof: integer ++
default: 24 ++
The size of each icon in the tooltip.
# EXAMPLES
```
"privacy": {
"icon-spacing": 4,
"icon-size": 18,
"transition-duration": 250,
"modules": [
{
"type": "screenshare",
"tooltip": true,
"tooltip-icon-size": 24
},
{
"type": "audio-out",
"tooltip": true,
"tooltip-icon-size": 24
},
{
"type": "audio-in",
"tooltip": true,
"tooltip-icon-size": 24
}
]
},
```
# STYLE
- *#privacy*
- *#privacy-item*
- *#privacy-item.screenshare*
- *#privacy-item.audio-in*
- *#privacy-item.audio-out*

View File

@@ -56,7 +56,11 @@ Additionally, you can control the volume by scrolling *up* or *down* while the c
*align*: ++
typeof: float ++
The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
The alignment of the label within the module, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
*justify*: ++
typeof: string ++
The alignment of the text within the module's label, allowing options 'left', 'right', or 'center' to define the positioning.
*scroll-step*: ++
typeof: float ++

View File

@@ -33,7 +33,11 @@ Addressed by *river/layout*
*align*: ++
typeof: float ++
The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
The alignment of the label within the module, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
*justify*: ++
typeof: string ++
The alignment of the text within the module's label, allowing options 'left', 'right', or 'center' to define the positioning.
*on-click*: ++
typeof: string ++

View File

@@ -31,7 +31,11 @@ Addressed by *river/mode*
*align*: ++
typeof: float ++
The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
The alignment of the label within the module, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
*justify*: ++
typeof: string ++
The alignment of the text within the module's label, allowing options 'left', 'right', or 'center' to define the positioning.
*on-click*: ++
typeof: string ++

View File

@@ -31,7 +31,11 @@ Addressed by *river/window*
*align*: ++
typeof: float ++
The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
The alignment of the label within the module, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
*justify*: ++
typeof: string ++
The alignment of the text within the module's label, allowing options 'left', 'right', or 'center' to define the positioning.
*on-click*: ++
typeof: string ++

View File

@@ -32,7 +32,11 @@ cursor is over the module, and clicking on the module toggles mute.
*align*: ++
typeof: float ++
The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
The alignment of the label within the module, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
*justify*: ++
typeof: string ++
The alignment of the text within the module's label, allowing options 'left', 'right', or 'center' to define the positioning.
*scroll-step*: ++
typeof: int ++

View File

@@ -17,6 +17,11 @@ Addressed by *sway/language*
default: {} ++
The format, how layout should be displayed.
*hide-single-layout*: ++
typeof: bool ++
default: false ++
Defines visibility of the module if a single layout is configured
*tooltip-format*: ++
typeof: string ++
default: {} ++

View File

@@ -31,7 +31,11 @@ Addressed by *sway/mode*
*align*: ++
typeof: float ++
The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
The alignment of the label within the module, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
*justify*: ++
typeof: string ++
The alignment of the text within the module's label, allowing options 'left', 'right', or 'center' to define the positioning.
*on-click*: ++
typeof: string ++

View File

@@ -31,7 +31,11 @@ Addressed by *sway/window*
*align*: ++
typeof: float ++
The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
The alignment of the label within the module, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
*justify*: ++
typeof: string ++
The alignment of the text within the module's label, allowing options 'left', 'right', or 'center' to define the positioning.
*on-click*: ++
typeof: string ++

View File

@@ -82,6 +82,23 @@ warp-on-scroll: ++
default: true ++
If set to false, you can scroll to cycle through workspaces without mouse warping being enabled. If set to true this behaviour is disabled.
*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.
# FORMAT REPLACEMENTS
*{value}*: Name of the workspace, as defined by sway.
@@ -94,6 +111,8 @@ warp-on-scroll: ++
*{output}*: Output where the workspace is located.
*{windows}*: Result from window-rewrite
# ICONS
Additional to workspace name matching, the following *format-icons* can be set.
@@ -143,6 +162,19 @@ n.b.: the list of outputs can be obtained from command line using *swaymsg -t ge
}
```
```
"sway/workspaces": {
"format": "<span size='larger'>{name}</span> {windows}",
"format-window-separator": " | ",
"window-rewrite-default": "{name}",
"window-format": "<span color='#e0e0e0'>{name}</span>",
"window-rewrite": {
"class<firefox>": "",
"class<kitty>": "k",
}
}
```
# Style
- *#workspaces button*

View File

@@ -0,0 +1,63 @@
waybar-systemd-failed-units(5)
# NAME
waybar - systemd failed units monitor module
# DESCRIPTION
The *systemd-failed-units* module displays the number of failed systemd units.
# CONFIGURATION
Addressed by *systemd-failed-units*
*format*: ++
typeof: string ++
default: *{nr_failed} failed* ++
The format, how information should be displayed. This format is used when other formats aren't specified.
*format-ok*: ++
typeof: string ++
This format is used when there is no failing units.
*user*: ++
typeof: bool ++
default: *true* ++
Option to count user systemd units.
*system*: ++
typeof: bool ++
default: *true* ++
Option to count systemwide (PID=1) systemd units.
*hide-on-ok*: ++
typeof: bool ++
default: *true* ++
Option to hide this module when there is no failing units.
# FORMAT REPLACEMENTS
*{nr_failed_system}*: Number of failed units from systemwide (PID=1) systemd.
*{nr_failed_user}*: Number of failed units from user systemd.
*{nr_failed}*: Number of total failed units.
# EXAMPLES
```
"systemd-failed-units": {
"hide-on-ok": false,
"format": "✗ {nr_failed}",
"format-ok": "✓",
"system": true,
"user": false,
}
```
# STYLE
- *#systemd-failed-units*
- *#systemd-failed-units.ok*
- *#systemd-failed-units.degraded*

View File

@@ -71,7 +71,11 @@ Addressed by *temperature*
*align*: ++
typeof: float ++
The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
The alignment of the label within the module, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
*justify*: ++
typeof: string ++
The alignment of the text within the module's label, allowing options 'left', 'right', or 'center' to define the positioning.
*on-click*: ++
typeof: string ++

View File

@@ -57,6 +57,11 @@ compatible devices in the tooltip.
typeof: string ++
Command to execute when clicked on the module.
*show-icon*: ++
typeof: bool ++
default: true ++
Option to disable battery icon.
# FORMAT REPLACEMENTS
*{percentage}*: The battery capacity in percentage
@@ -93,6 +98,15 @@ depending on the charging state.
"tooltip": true,
"tooltip-spacing": 20
}
```
```
"upower": {
"show-icon": false,
"hide-if-empty": true,
"tooltip": true,
"tooltip-spacing": 20
}
```
# STYLE

View File

@@ -47,7 +47,11 @@ The *wireplumber* module displays the current volume reported by WirePlumber.
*align*: ++
typeof: float ++
The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
The alignment of the label within the module, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
*justify*: ++
typeof: string ++
The alignment of the text within the module's label, allowing options 'left', 'right', or 'center' to define the positioning.
*scroll-step*: ++
typeof: float ++

View File

@@ -6,17 +6,17 @@ waybar - configuration file
# DESCRIPTION
The configuration uses the JSON file format and is named *config*.
The configuration uses the JSONC file format and is named *config* or *config.jsonc*.
Valid locations for this file are:
- *$XDG_CONFIG_HOME/waybar/config*
- *~/.config/waybar/config*
- *~/waybar/config*
- */etc/xdg/waybar/config*
- *@sysconfdir@/xdg/waybar/config*
- *$XDG_CONFIG_HOME/waybar/*
- *~/.config/waybar/*
- *~/waybar/*
- */etc/xdg/waybar/*
- *@sysconfdir@/xdg/waybar/*
A good starting point is the default configuration found at https://github.com/Alexays/Waybar/blob/master/resources/config
A good starting point is the default configuration found at https://github.com/Alexays/Waybar/blob/master/resources/config.jsonc
Also, a minimal example configuration can be found at the bottom of this man page.
# BAR CONFIGURATION
@@ -108,12 +108,6 @@ Also, a minimal example configuration can be found at the bottom of this man pag
Option to pass any pointer events to the window under the bar.
Intended to be used with either *top* or *overlay* layers and without exclusive zone.
*gtk-layer-shell* ++
typeof: bool ++
default: true ++
Option to disable the use of gtk-layer-shell for popups.
Only functional if compiled with gtk-layer-shell support.
*ipc* ++
typeof: bool ++
default: false ++
@@ -130,6 +124,11 @@ Also, a minimal example configuration can be found at the bottom of this man pag
Each file can contain a single object with any of the bar configuration options. In case of duplicate options, the first defined value takes precedence, i.e. including file -> first included file -> etc. Nested includes are permitted, but make sure to avoid circular imports.
For a multi-bar config, the include directive affects only current bar configuration object.
*reload_style_on_change* ++
typeof: bool ++
default: *false* ++
Option to enable reloading the css style if a modification is detected on the style sheet file or any imported css files.
# MODULE FORMAT
You can use PangoMarkupFormat (See https://developer.gnome.org/pango/stable/PangoMarkupFormat.html#PangoMarkupFormat).

View File

@@ -1,8 +1,8 @@
project(
'waybar', 'cpp', 'c',
version: '0.9.24',
version: '0.10.0',
license: 'MIT',
meson_version: '>= 0.50.0',
meson_version: '>= 0.59.0',
default_options : [
'cpp_std=c++20',
'buildtype=release',
@@ -22,8 +22,6 @@ endif
if compiler.has_link_argument('-lc++fs')
cpp_link_args += ['-lc++fs']
elif compiler.has_link_argument('-lc++experimental')
cpp_link_args += ['-lc++experimental']
elif compiler.has_link_argument('-lstdc++fs')
cpp_link_args += ['-lstdc++fs']
endif
@@ -33,10 +31,10 @@ git = find_program('git', native: true, required: false)
if not git.found()
add_project_arguments('-DVERSION="@0@"'.format(meson.project_version()), language: 'cpp')
else
git_path = run_command([git.path(), 'rev-parse', '--show-toplevel']).stdout().strip()
if meson.source_root() == git_path
git_commit_hash = run_command([git.path(), 'describe', '--always', '--tags']).stdout().strip()
git_branch = run_command([git.path(), 'rev-parse', '--abbrev-ref', 'HEAD']).stdout().strip()
git_path = run_command(git, 'rev-parse', '--show-toplevel', check: false).stdout().strip()
if meson.project_source_root() == git_path
git_commit_hash = run_command(git, 'describe', '--always', '--tags', check: false).stdout().strip()
git_branch = run_command(git, 'rev-parse', '--abbrev-ref', 'HEAD', check: false).stdout().strip()
version = '"@0@ (branch \'@1@\')"'.format(git_commit_hash, git_branch)
add_project_arguments('-DVERSION=@0@'.format(version), language: 'cpp')
else
@@ -44,15 +42,6 @@ else
endif
endif
if not compiler.has_header('filesystem')
if compiler.has_header('experimental/filesystem')
add_project_arguments('-DFILESYSTEM_EXPERIMENTAL', language: 'cpp')
else
add_project_arguments('-DNO_FILESYSTEM', language: 'cpp')
warning('No filesystem header found, some modules may not work')
endif
endif
code = '''
#include <langinfo.h>
#include <locale.h>
@@ -86,10 +75,7 @@ wayland_cursor = dependency('wayland-cursor')
wayland_protos = dependency('wayland-protocols')
gtkmm = dependency('gtkmm-3.0', version : ['>=3.22.0'])
dbusmenu_gtk = dependency('dbusmenu-gtk3-0.4', required: get_option('dbusmenu-gtk'))
giounix = dependency('gio-unix-2.0', required: (get_option('dbusmenu-gtk').enabled() or
get_option('logind').enabled() or
get_option('upower_glib').enabled() or
get_option('mpris').enabled()))
giounix = dependency('gio-unix-2.0')
jsoncpp = dependency('jsoncpp', version : ['>=1.9.2'], fallback : ['jsoncpp', 'jsoncpp_dep'])
sigcpp = dependency('sigc++-2.0')
libinotify = dependency('libinotify', required: false)
@@ -98,6 +84,7 @@ libinput = dependency('libinput', required: get_option('libinput'))
libnl = dependency('libnl-3.0', required: get_option('libnl'))
libnlgen = dependency('libnl-genl-3.0', required: get_option('libnl'))
upower_glib = dependency('upower-glib', required: get_option('upower_glib'))
pipewire = dependency('libpipewire-0.3', required: get_option('pipewire'))
playerctl = dependency('playerctl', version : ['>=2.0.0'], required: get_option('mpris'))
libpulse = dependency('libpulse', required: get_option('pulseaudio'))
libudev = dependency('libudev', required: get_option('libudev'))
@@ -119,13 +106,28 @@ if libsndio.found()
endif
endif
gtk_layer_shell = dependency('gtk-layer-shell-0',
required: get_option('gtk-layer-shell'),
fallback : ['gtk-layer-shell', 'gtk_layer_shell_dep'])
gtk_layer_shell = dependency('gtk-layer-shell-0', version: ['>=0.6.0'],
default_options: ['introspection=false', 'vapi=false'],
fallback: ['gtk-layer-shell', 'gtk_layer_shell'])
systemd = dependency('systemd', required: get_option('systemd'))
cpp_lib_chrono = compiler.compute_int('__cpp_lib_chrono', prefix : '#include <chrono>')
have_chrono_timezones = cpp_lib_chrono >= 201907
have_chrono_timezones = cpp_lib_chrono >= 201611
if have_chrono_timezones
code = '''
#include <chrono>
using namespace std::chrono;
int main(int argc, char** argv) {
const time_zone* tz;
return 0;
}
'''
if not compiler.links(code)
have_chrono_timezones = false
endif
endif
if have_chrono_timezones
tz_dep = declare_dependency()
else
@@ -141,10 +143,10 @@ sysconfdir = get_option('sysconfdir')
conf_data = configuration_data()
conf_data.set('prefix', prefix)
add_project_arguments('-DSYSCONFDIR="/@0@"'.format(join_paths(prefix, sysconfdir)), language : 'cpp')
add_project_arguments('-DSYSCONFDIR="@0@"'.format(prefix / sysconfdir), language : 'cpp')
if systemd.found()
user_units_dir = systemd.get_pkgconfig_variable('systemduserunitdir')
user_units_dir = systemd.get_variable(pkgconfig: 'systemduserunitdir')
configure_file(
configuration: conf_data,
@@ -180,7 +182,17 @@ src_files = files(
'src/util/sanitize_str.cpp',
'src/util/rewrite_string.cpp',
'src/util/gtk_icon.cpp',
'src/util/regex_collection.cpp'
'src/util/regex_collection.cpp',
'src/util/css_reload_helper.cpp'
)
man_files = files(
'man/waybar-custom.5.scd',
'man/waybar-disk.5.scd',
'man/waybar-idle-inhibitor.5.scd',
'man/waybar-image.5.scd',
'man/waybar-states.5.scd',
'man/waybar-temperature.5.scd',
)
inc_dirs = ['include']
@@ -188,8 +200,11 @@ inc_dirs = ['include']
if is_linux
add_project_arguments('-DHAVE_CPU_LINUX', language: 'cpp')
add_project_arguments('-DHAVE_MEMORY_LINUX', language: 'cpp')
add_project_arguments('-DHAVE_SYSTEMD_MONITOR', language: 'cpp')
src_files += files(
'src/modules/battery.cpp',
'src/modules/bluetooth.cpp',
'src/modules/cffi.cpp',
'src/modules/cpu.cpp',
'src/modules/cpu_frequency/common.cpp',
'src/modules/cpu_frequency/linux.cpp',
@@ -197,11 +212,23 @@ if is_linux
'src/modules/cpu_usage/linux.cpp',
'src/modules/memory/common.cpp',
'src/modules/memory/linux.cpp',
'src/modules/power_profiles_daemon.cpp',
'src/modules/systemd_failed_units.cpp',
)
man_files += files(
'man/waybar-battery.5.scd',
'man/waybar-bluetooth.5.scd',
'man/waybar-cffi.5.scd',
'man/waybar-cpu.5.scd',
'man/waybar-memory.5.scd',
'man/waybar-systemd-failed-units.5.scd',
'man/waybar-power-profiles-daemon.5.scd',
)
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/cffi.cpp',
'src/modules/cpu.cpp',
'src/modules/cpu_frequency/bsd.cpp',
'src/modules/cpu_frequency/common.cpp',
@@ -210,89 +237,149 @@ elif is_dragonfly or is_freebsd or is_netbsd or is_openbsd
'src/modules/memory/bsd.cpp',
'src/modules/memory/common.cpp',
)
man_files += files(
'man/waybar-cffi.5.scd',
'man/waybar-cpu.5.scd',
'man/waybar-memory.5.scd',
)
if is_freebsd
src_files += files(
'src/modules/battery.cpp',
)
src_files += files('src/modules/battery.cpp')
man_files += files('man/waybar-battery.5.scd')
endif
endif
add_project_arguments('-DHAVE_SWAY', language: 'cpp')
src_files += [
'src/modules/sway/ipc/client.cpp',
'src/modules/sway/bar.cpp',
'src/modules/sway/mode.cpp',
'src/modules/sway/language.cpp',
'src/modules/sway/window.cpp',
'src/modules/sway/workspaces.cpp',
'src/modules/sway/scratchpad.cpp'
]
if true
add_project_arguments('-DHAVE_SWAY', language: 'cpp')
src_files += files(
'src/modules/sway/ipc/client.cpp',
'src/modules/sway/bar.cpp',
'src/modules/sway/mode.cpp',
'src/modules/sway/language.cpp',
'src/modules/sway/window.cpp',
'src/modules/sway/workspaces.cpp',
'src/modules/sway/scratchpad.cpp'
)
man_files += files(
'man/waybar-sway-language.5.scd',
'man/waybar-sway-mode.5.scd',
'man/waybar-sway-scratchpad.5.scd',
'man/waybar-sway-window.5.scd',
'man/waybar-sway-workspaces.5.scd',
)
endif
if true
add_project_arguments('-DHAVE_WLR', language: 'cpp')
src_files += 'src/modules/wlr/taskbar.cpp'
src_files += 'src/modules/wlr/workspace_manager.cpp'
src_files += 'src/modules/wlr/workspace_manager_binding.cpp'
add_project_arguments('-DHAVE_WLR_TASKBAR', language: 'cpp')
src_files += files('src/modules/wlr/taskbar.cpp')
man_files += files('man/waybar-wlr-taskbar.5.scd')
endif
if true
add_project_arguments('-DHAVE_RIVER', language: 'cpp')
src_files += 'src/modules/river/mode.cpp'
src_files += 'src/modules/river/tags.cpp'
src_files += 'src/modules/river/window.cpp'
src_files += 'src/modules/river/layout.cpp'
src_files += files(
'src/modules/river/layout.cpp',
'src/modules/river/mode.cpp',
'src/modules/river/tags.cpp',
'src/modules/river/window.cpp',
)
man_files += files(
'man/waybar-river-layout.5.scd',
'man/waybar-river-mode.5.scd',
'man/waybar-river-tags.5.scd',
'man/waybar-river-window.5.scd',
)
endif
if true
add_project_arguments('-DHAVE_DWL', language: 'cpp')
src_files += 'src/modules/dwl/tags.cpp'
src_files += files('src/modules/dwl/tags.cpp')
man_files += files('man/waybar-dwl-tags.5.scd')
endif
if true
add_project_arguments('-DHAVE_HYPRLAND', language: 'cpp')
src_files += 'src/modules/hyprland/backend.cpp'
src_files += 'src/modules/hyprland/window.cpp'
src_files += 'src/modules/hyprland/language.cpp'
src_files += 'src/modules/hyprland/submap.cpp'
src_files += 'src/modules/hyprland/workspaces.cpp'
src_files += files(
'src/modules/hyprland/backend.cpp',
'src/modules/hyprland/language.cpp',
'src/modules/hyprland/submap.cpp',
'src/modules/hyprland/window.cpp',
'src/modules/hyprland/workspaces.cpp',
)
man_files += files(
'man/waybar-hyprland-language.5.scd',
'man/waybar-hyprland-submap.5.scd',
'man/waybar-hyprland-window.5.scd',
'man/waybar-hyprland-workspaces.5.scd',
)
endif
if libnl.found() and libnlgen.found()
add_project_arguments('-DHAVE_LIBNL', language: 'cpp')
src_files += 'src/modules/network.cpp'
src_files += files('src/modules/network.cpp')
man_files += files('man/waybar-network.5.scd')
endif
if (giounix.found() and not get_option('logind').disabled())
add_project_arguments('-DHAVE_GAMEMODE', language: 'cpp')
src_files += 'src/modules/gamemode.cpp'
if not get_option('logind').disabled()
add_project_arguments('-DHAVE_GAMEMODE', '-DHAVE_LOGIND_INHIBITOR', language: 'cpp')
src_files += files(
'src/modules/gamemode.cpp',
'src/modules/inhibitor.cpp',
)
man_files += files(
'man/waybar-gamemode.5.scd',
'man/waybar-inhibitor.5.scd',
)
endif
if (upower_glib.found() and giounix.found() and not get_option('logind').disabled())
if (upower_glib.found() and not get_option('logind').disabled())
add_project_arguments('-DHAVE_UPOWER', language: 'cpp')
src_files += 'src/modules/upower/upower.cpp'
src_files += 'src/modules/upower/upower_tooltip.cpp'
src_files += files(
'src/modules/upower/upower.cpp',
'src/modules/upower/upower_tooltip.cpp',
)
man_files += files('man/waybar-upower.5.scd')
endif
if (playerctl.found() and giounix.found() and not get_option('logind').disabled())
if pipewire.found()
add_project_arguments('-DHAVE_PIPEWIRE', language: 'cpp')
src_files += files(
'src/modules/privacy/privacy.cpp',
'src/modules/privacy/privacy_item.cpp',
'src/util/pipewire_backend.cpp',
)
man_files += files('man/waybar-privacy.5.scd')
endif
if playerctl.found()
add_project_arguments('-DHAVE_MPRIS', language: 'cpp')
src_files += 'src/modules/mpris/mpris.cpp'
src_files += files('src/modules/mpris/mpris.cpp')
man_files += files('man/waybar-mpris.5.scd')
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'
src_files += files(
'src/modules/pulseaudio.cpp',
'src/modules/pulseaudio_slider.cpp',
'src/util/audio_backend.cpp',
)
man_files += files(
'man/waybar-pulseaudio.5.scd',
'man/waybar-pulseaudio-slider.5.scd',
)
endif
if libjack.found()
add_project_arguments('-DHAVE_LIBJACK', language: 'cpp')
src_files += 'src/modules/jack.cpp'
src_files += files('src/modules/jack.cpp')
man_files += files('man/waybar-jack.5.scd')
endif
if libwireplumber.found()
add_project_arguments('-DHAVE_LIBWIREPLUMBER', language: 'cpp')
src_files += 'src/modules/wireplumber.cpp'
src_files += files('src/modules/wireplumber.cpp')
man_files += files('man/waybar-wireplumber.5.scd')
endif
if dbusmenu_gtk.found()
@@ -303,40 +390,46 @@ if dbusmenu_gtk.found()
'src/modules/sni/host.cpp',
'src/modules/sni/item.cpp'
)
man_files += files(
'man/waybar-tray.5.scd',
)
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'
src_files += files(
'src/modules/backlight.cpp',
'src/modules/backlight_slider.cpp',
'src/util/backlight_backend.cpp',
)
man_files += files(
'man/waybar-backlight.5.scd',
'man/waybar-backlight-slider.5.scd',
)
endif
if libevdev.found() and (is_linux or libepoll.found()) and libinput.found() and (is_linux or libinotify.found())
add_project_arguments('-DHAVE_LIBEVDEV', language: 'cpp')
add_project_arguments('-DHAVE_LIBINPUT', language: 'cpp')
src_files += 'src/modules/keyboard_state.cpp'
src_files += files('src/modules/keyboard_state.cpp')
man_files += files('man/waybar-keyboard-state.5.scd')
endif
if libmpdclient.found()
add_project_arguments('-DHAVE_LIBMPDCLIENT', language: 'cpp')
src_files += 'src/modules/mpd/mpd.cpp'
src_files += 'src/modules/mpd/state.cpp'
endif
if gtk_layer_shell.found()
add_project_arguments('-DHAVE_GTK_LAYER_SHELL', language: 'cpp')
src_files += files(
'src/modules/mpd/mpd.cpp',
'src/modules/mpd/state.cpp',
)
man_files += files(
'man/waybar-mpd.5.scd',
)
endif
if libsndio.found()
add_project_arguments('-DHAVE_LIBSNDIO', language: 'cpp')
src_files += 'src/modules/sndio.cpp'
endif
if (giounix.found() and not get_option('logind').disabled())
add_project_arguments('-DHAVE_GIO_UNIX', language: 'cpp')
src_files += 'src/modules/inhibitor.cpp'
src_files += 'src/modules/bluetooth.cpp'
src_files += files('src/modules/sndio.cpp')
man_files += files('man/waybar-sndio.5.scd')
endif
if get_option('rfkill').enabled() and is_linux
@@ -348,34 +441,48 @@ endif
if have_chrono_timezones
add_project_arguments('-DHAVE_CHRONO_TIMEZONES', language: 'cpp')
src_files += 'src/modules/clock.cpp'
src_files += files('src/modules/clock.cpp')
man_files += files('man/waybar-clock.5.scd')
elif tz_dep.found()
add_project_arguments('-DHAVE_LIBDATE', language: 'cpp')
src_files += 'src/modules/clock.cpp'
src_files += files('src/modules/clock.cpp')
man_files += files('man/waybar-clock.5.scd')
else
src_files += 'src/modules/simpleclock.cpp'
src_files += files('src/modules/simpleclock.cpp')
man_files += files('man/waybar-clock.5.scd')
endif
if get_option('experimental')
add_project_arguments('-DUSE_EXPERIMENTAL', language: 'cpp')
add_project_arguments('-DHAVE_WLR_WORKSPACES', language: 'cpp')
src_files += files(
'src/modules/wlr/workspace_manager.cpp',
'src/modules/wlr/workspace_manager_binding.cpp',
)
man_files += files(
'man/waybar-wlr-workspaces.5.scd',
)
endif
cava = dependency('cava',
version : '>=0.9.1',
version : '>=0.10.1',
required: get_option('cava'),
fallback : ['cava', 'cava_dep'],
not_found_message: 'cava is not found. Building waybar without cava')
if cava.found()
add_project_arguments('-DHAVE_LIBCAVA', language: 'cpp')
src_files += 'src/modules/cava.cpp'
src_files += files('src/modules/cava.cpp')
man_files += files('man/waybar-cava.5.scd')
endif
subdir('protocol')
app_resources = []
subdir('resources/icons')
executable(
'waybar',
src_files,
[src_files, app_resources],
dependencies: [
thread_dep,
client_protos,
@@ -392,6 +499,7 @@ executable(
libnl,
libnlgen,
upower_glib,
pipewire,
playerctl,
libpulse,
libjack,
@@ -412,76 +520,26 @@ executable(
)
install_data(
'./resources/config',
'./resources/style.css',
install_dir: sysconfdir + '/xdg/waybar'
'resources/config.jsonc',
'resources/style.css',
install_dir: sysconfdir / 'xdg/waybar'
)
scdoc = dependency('scdoc', version: '>=1.9.2', native: true, required: get_option('man-pages'))
if scdoc.found()
scdoc_prog = find_program(scdoc.get_pkgconfig_variable('scdoc'), native: true)
sh = find_program('sh', native: true)
main_manpage = configure_file(
man_files += configure_file(
input: 'man/waybar.5.scd.in',
output: 'waybar.5.scd',
configuration: {
'sysconfdir': join_paths(prefix, sysconfdir)
'sysconfdir': prefix / sysconfdir
}
)
main_manpage_path = join_paths(meson.build_root(), '@0@'.format(main_manpage))
fs = import('fs')
mandir = get_option('mandir')
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',
'waybar-cpu.5.scd',
'waybar-custom.5.scd',
'waybar-disk.5.scd',
'waybar-gamemode.5.scd',
'waybar-idle-inhibitor.5.scd',
'waybar-image.5.scd',
'waybar-keyboard-state.5.scd',
'waybar-memory.5.scd',
'waybar-mpd.5.scd',
'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',
'waybar-river-layout.5.scd',
'waybar-sway-language.5.scd',
'waybar-sway-mode.5.scd',
'waybar-sway-scratchpad.5.scd',
'waybar-sway-window.5.scd',
'waybar-sway-workspaces.5.scd',
'waybar-temperature.5.scd',
'waybar-tray.5.scd',
'waybar-states.5.scd',
'waybar-wlr-taskbar.5.scd',
'waybar-wlr-workspaces.5.scd',
'waybar-bluetooth.5.scd',
'waybar-sndio.5.scd',
'waybar-upower.5.scd',
'waybar-wireplumber.5.scd',
'waybar-dwl-tags.5.scd',
]
if (giounix.found() and not get_option('logind').disabled())
man_files += 'waybar-inhibitor.5.scd'
endif
foreach file : man_files
path = '@0@'.format(file)
basename = path.split('/')[-1]
basename = fs.name(file)
topic = basename.split('.')[-3]
section = basename.split('.')[-2]
@@ -489,12 +547,11 @@ if scdoc.found()
custom_target(
output,
# drops the 'man' if `path` is an absolute path
input: join_paths('man', path),
input: file,
output: output,
command: [
sh, '-c', '@0@ < @INPUT@ > @1@'.format(scdoc_prog.path(), output)
],
command: scdoc.get_variable('scdoc'),
feed: true,
capture: true,
install: true,
install_dir: '@0@/man@1@'.format(mandir, section)
)
@@ -503,7 +560,7 @@ endif
catch2 = dependency(
'catch2',
version: '>=2.0.0',
default_options: [ 'tests=false' ],
fallback: ['catch2', 'catch2_dep'],
required: get_option('tests'),
)
@@ -519,7 +576,6 @@ if clangtidy.found()
command: [
clangtidy,
'-checks=*,-fuchsia-default-arguments',
'-p', meson.build_root()
'-p', meson.project_build_root()
] + src_files)
endif

View File

@@ -5,12 +5,12 @@ option('libudev', type: 'feature', value: 'auto', description: 'Enable libudev s
option('libevdev', type: 'feature', value: 'auto', description: 'Enable libevdev support for evdev related features')
option('pulseaudio', type: 'feature', value: 'auto', description: 'Enable support for pulseaudio')
option('upower_glib', type: 'feature', value: 'auto', description: 'Enable support for upower')
option('pipewire', type: 'feature', value: 'auto', description: 'Enable support for pipewire')
option('mpris', type: 'feature', value: 'auto', description: 'Enable support for mpris')
option('systemd', type: 'feature', value: 'auto', description: 'Install systemd user service unit')
option('dbusmenu-gtk', type: 'feature', value: 'auto', description: 'Enable support for tray')
option('man-pages', type: 'feature', value: 'auto', description: 'Generate and install man pages')
option('mpd', type: 'feature', value: 'auto', description: 'Enable support for the Music Player Daemon')
option('gtk-layer-shell', type: 'feature', value: 'auto', description: 'Use gtk-layer-shell library for popups support')
option('rfkill', type: 'feature', value: 'auto', description: 'Enable support for RFKILL')
option('sndio', type: 'feature', value: 'auto', description: 'Enable support for sndio')
option('logind', type: 'feature', value: 'auto', description: 'Enable support for logind')

View File

@@ -1,20 +1,35 @@
{ lib
, pkgs
, waybar
, version
}:
waybar.overrideAttrs (prev: {
inherit version;
# version = "0.9.17";
src = lib.cleanSourceWith {
filter = name: type:
let
baseName = baseNameOf (toString name);
in
! (
lib.hasSuffix ".nix" baseName
);
src = lib.cleanSource ../.;
let
libcava = rec {
version = "0.10.1";
src = pkgs.fetchFromGitHub {
owner = "LukashonakV";
repo = "cava";
rev = version;
hash = "sha256-iIYKvpOWafPJB5XhDOSIW9Mb4I3A4pcgIIPQdQYEqUw=";
};
};
})
in
(waybar.overrideAttrs (
oldAttrs: {
inherit version;
src = lib.cleanSourceWith {
filter = name: type: type != "regular" || !lib.hasSuffix ".nix" name;
src = lib.cleanSource ../.;
};
mesonFlags = lib.remove "-Dgtk-layer-shell=enabled" oldAttrs.mesonFlags;
postUnpack = ''
pushd "$sourceRoot"
cp -R --no-preserve=mode,ownership ${libcava.src} subprojects/cava-${libcava.version}
patchShebangs .
popd
'';
}
))

View File

@@ -1,4 +1,4 @@
wl_protocol_dir = wayland_protos.get_pkgconfig_variable('pkgdatadir')
wl_protocol_dir = wayland_protos.get_variable(pkgconfig: 'pkgdatadir')
wayland_scanner = find_program('wayland-scanner')
@@ -25,7 +25,6 @@ client_protocols = [
[wl_protocol_dir, 'stable/xdg-shell/xdg-shell.xml'],
[wl_protocol_dir, 'unstable/xdg-output/xdg-output-unstable-v1.xml'],
[wl_protocol_dir, 'unstable/idle-inhibit/idle-inhibit-unstable-v1.xml'],
['wlr-layer-shell-unstable-v1.xml'],
['wlr-foreign-toplevel-management-unstable-v1.xml'],
['ext-workspace-unstable-v1.xml'],
['river-status-unstable-v1.xml'],
@@ -44,7 +43,7 @@ endforeach
gdbus_codegen = find_program('gdbus-codegen')
r = run_command(gdbus_codegen, '--body', '--output', '/dev/null')
r = run_command(gdbus_codegen, '--body', '--output', '/dev/null', check: false)
if r.returncode() != 0
gdbus_code_dsnw = custom_target(
'dbus-status-notifier-watcher.[ch]',

View File

@@ -1,311 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<protocol name="wlr_layer_shell_unstable_v1">
<copyright>
Copyright © 2017 Drew DeVault
Permission to use, copy, modify, distribute, and sell this
software and its documentation for any purpose is hereby granted
without fee, provided that the above copyright notice appear in
all copies and that both that copyright notice and this permission
notice appear in supporting documentation, and that the name of
the copyright holders not be used in advertising or publicity
pertaining to distribution of the software without specific,
written prior permission. The copyright holders make no
representations about the suitability of this software for any
purpose. It is provided "as is" without express or implied
warranty.
THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
THIS SOFTWARE.
</copyright>
<interface name="zwlr_layer_shell_v1" version="3">
<description summary="create surfaces that are layers of the desktop">
Clients can use this interface to assign the surface_layer role to
wl_surfaces. Such surfaces are assigned to a "layer" of the output and
rendered with a defined z-depth respective to each other. They may also be
anchored to the edges and corners of a screen and specify input handling
semantics. This interface should be suitable for the implementation of
many desktop shell components, and a broad number of other applications
that interact with the desktop.
</description>
<request name="get_layer_surface">
<description summary="create a layer_surface from a surface">
Create a layer surface for an existing surface. This assigns the role of
layer_surface, or raises a protocol error if another role is already
assigned.
Creating a layer surface from a wl_surface which has a buffer attached
or committed is a client error, and any attempts by a client to attach
or manipulate a buffer prior to the first layer_surface.configure call
must also be treated as errors.
You may pass NULL for output to allow the compositor to decide which
output to use. Generally this will be the one that the user most
recently interacted with.
Clients can specify a namespace that defines the purpose of the layer
surface.
</description>
<arg name="id" type="new_id" interface="zwlr_layer_surface_v1"/>
<arg name="surface" type="object" interface="wl_surface"/>
<arg name="output" type="object" interface="wl_output" allow-null="true"/>
<arg name="layer" type="uint" enum="layer" summary="layer to add this surface to"/>
<arg name="np" type="string" summary="namespace for the layer surface"/>
</request>
<enum name="error">
<entry name="role" value="0" summary="wl_surface has another role"/>
<entry name="invalid_layer" value="1" summary="layer value is invalid"/>
<entry name="already_constructed" value="2" summary="wl_surface has a buffer attached or committed"/>
</enum>
<enum name="layer">
<description summary="available layers for surfaces">
These values indicate which layers a surface can be rendered in. They
are ordered by z depth, bottom-most first. Traditional shell surfaces
will typically be rendered between the bottom and top layers.
Fullscreen shell surfaces are typically rendered at the top layer.
Multiple surfaces can share a single layer, and ordering within a
single layer is undefined.
</description>
<entry name="background" value="0"/>
<entry name="bottom" value="1"/>
<entry name="top" value="2"/>
<entry name="overlay" value="3"/>
</enum>
<!-- Version 3 additions -->
<request name="destroy" type="destructor" since="3">
<description summary="destroy the layer_shell object">
This request indicates that the client will not use the layer_shell
object any more. Objects that have been created through this instance
are not affected.
</description>
</request>
</interface>
<interface name="zwlr_layer_surface_v1" version="3">
<description summary="layer metadata interface">
An interface that may be implemented by a wl_surface, for surfaces that
are designed to be rendered as a layer of a stacked desktop-like
environment.
Layer surface state (layer, size, anchor, exclusive zone,
margin, interactivity) is double-buffered, and will be applied at the
time wl_surface.commit of the corresponding wl_surface is called.
</description>
<request name="set_size">
<description summary="sets the size of the surface">
Sets the size of the surface in surface-local coordinates. The
compositor will display the surface centered with respect to its
anchors.
If you pass 0 for either value, the compositor will assign it and
inform you of the assignment in the configure event. You must set your
anchor to opposite edges in the dimensions you omit; not doing so is a
protocol error. Both values are 0 by default.
Size is double-buffered, see wl_surface.commit.
</description>
<arg name="width" type="uint"/>
<arg name="height" type="uint"/>
</request>
<request name="set_anchor">
<description summary="configures the anchor point of the surface">
Requests that the compositor anchor the surface to the specified edges
and corners. If two orthogonal edges are specified (e.g. 'top' and
'left'), then the anchor point will be the intersection of the edges
(e.g. the top left corner of the output); otherwise the anchor point
will be centered on that edge, or in the center if none is specified.
Anchor is double-buffered, see wl_surface.commit.
</description>
<arg name="anchor" type="uint" enum="anchor"/>
</request>
<request name="set_exclusive_zone">
<description summary="configures the exclusive geometry of this surface">
Requests that the compositor avoids occluding an area with other
surfaces. The compositor's use of this information is
implementation-dependent - do not assume that this region will not
actually be occluded.
A positive value is only meaningful if the surface is anchored to one
edge or an edge and both perpendicular edges. If the surface is not
anchored, anchored to only two perpendicular edges (a corner), anchored
to only two parallel edges or anchored to all edges, a positive value
will be treated the same as zero.
A positive zone is the distance from the edge in surface-local
coordinates to consider exclusive.
Surfaces that do not wish to have an exclusive zone may instead specify
how they should interact with surfaces that do. If set to zero, the
surface indicates that it would like to be moved to avoid occluding
surfaces with a positive exclusive zone. If set to -1, the surface
indicates that it would not like to be moved to accommodate for other
surfaces, and the compositor should extend it all the way to the edges
it is anchored to.
For example, a panel might set its exclusive zone to 10, so that
maximized shell surfaces are not shown on top of it. A notification
might set its exclusive zone to 0, so that it is moved to avoid
occluding the panel, but shell surfaces are shown underneath it. A
wallpaper or lock screen might set their exclusive zone to -1, so that
they stretch below or over the panel.
The default value is 0.
Exclusive zone is double-buffered, see wl_surface.commit.
</description>
<arg name="zone" type="int"/>
</request>
<request name="set_margin">
<description summary="sets a margin from the anchor point">
Requests that the surface be placed some distance away from the anchor
point on the output, in surface-local coordinates. Setting this value
for edges you are not anchored to has no effect.
The exclusive zone includes the margin.
Margin is double-buffered, see wl_surface.commit.
</description>
<arg name="top" type="int"/>
<arg name="right" type="int"/>
<arg name="bottom" type="int"/>
<arg name="left" type="int"/>
</request>
<request name="set_keyboard_interactivity">
<description summary="requests keyboard events">
Set to 1 to request that the seat send keyboard events to this layer
surface. For layers below the shell surface layer, the seat will use
normal focus semantics. For layers above the shell surface layers, the
seat will always give exclusive keyboard focus to the top-most layer
which has keyboard interactivity set to true.
Layer surfaces receive pointer, touch, and tablet events normally. If
you do not want to receive them, set the input region on your surface
to an empty region.
Events is double-buffered, see wl_surface.commit.
</description>
<arg name="keyboard_interactivity" type="uint"/>
</request>
<request name="get_popup">
<description summary="assign this layer_surface as an xdg_popup parent">
This assigns an xdg_popup's parent to this layer_surface. This popup
should have been created via xdg_surface::get_popup with the parent set
to NULL, and this request must be invoked before committing the popup's
initial state.
See the documentation of xdg_popup for more details about what an
xdg_popup is and how it is used.
</description>
<arg name="popup" type="object" interface="xdg_popup"/>
</request>
<request name="ack_configure">
<description summary="ack a configure event">
When a configure event is received, if a client commits the
surface in response to the configure event, then the client
must make an ack_configure request sometime before the commit
request, passing along the serial of the configure event.
If the client receives multiple configure events before it
can respond to one, it only has to ack the last configure event.
A client is not required to commit immediately after sending
an ack_configure request - it may even ack_configure several times
before its next surface commit.
A client may send multiple ack_configure requests before committing, but
only the last request sent before a commit indicates which configure
event the client really is responding to.
</description>
<arg name="serial" type="uint" summary="the serial from the configure event"/>
</request>
<request name="destroy" type="destructor">
<description summary="destroy the layer_surface">
This request destroys the layer surface.
</description>
</request>
<event name="configure">
<description summary="suggest a surface change">
The configure event asks the client to resize its surface.
Clients should arrange their surface for the new states, and then send
an ack_configure request with the serial sent in this configure event at
some point before committing the new surface.
The client is free to dismiss all but the last configure event it
received.
The width and height arguments specify the size of the window in
surface-local coordinates.
The size is a hint, in the sense that the client is free to ignore it if
it doesn't resize, pick a smaller size (to satisfy aspect ratio or
resize in steps of NxM pixels). If the client picks a smaller size and
is anchored to two opposite anchors (e.g. 'top' and 'bottom'), the
surface will be centered on this axis.
If the width or height arguments are zero, it means the client should
decide its own window dimension.
</description>
<arg name="serial" type="uint"/>
<arg name="width" type="uint"/>
<arg name="height" type="uint"/>
</event>
<event name="closed">
<description summary="surface should be closed">
The closed event is sent by the compositor when the surface will no
longer be shown. The output may have been destroyed or the user may
have asked for it to be removed. Further changes to the surface will be
ignored. The client should destroy the resource after receiving this
event, and create a new surface if they so choose.
</description>
</event>
<enum name="error">
<entry name="invalid_surface_state" value="0" summary="provided surface state is invalid"/>
<entry name="invalid_size" value="1" summary="size is invalid"/>
<entry name="invalid_anchor" value="2" summary="anchor bitfield is invalid"/>
</enum>
<enum name="anchor" bitfield="true">
<entry name="top" value="1" summary="the top edge of the anchor rectangle"/>
<entry name="bottom" value="2" summary="the bottom edge of the anchor rectangle"/>
<entry name="left" value="4" summary="the left edge of the anchor rectangle"/>
<entry name="right" value="8" summary="the right edge of the anchor rectangle"/>
</enum>
<!-- Version 2 additions -->
<request name="set_layer" since="2">
<description summary="change the layer of the surface">
Change the layer that the surface is rendered on.
Layer is double-buffered, see wl_surface.commit.
</description>
<arg name="layer" type="uint" enum="zwlr_layer_shell_v1.layer" summary="layer to move this surface to"/>
</request>
</interface>
</protocol>

View File

@@ -1,3 +1,4 @@
// -*- mode: jsonc -*-
{
// "layer": "top", // Waybar at top layer
// "position": "bottom", // Waybar position (top|bottom|left|right)
@@ -5,9 +6,32 @@
// "width": 1280, // Waybar width
"spacing": 4, // Gaps between modules (4px)
// Choose the order of the modules
"modules-left": ["sway/workspaces", "sway/mode", "sway/scratchpad", "custom/media"],
"modules-center": ["sway/window"],
"modules-right": ["mpd", "idle_inhibitor", "pulseaudio", "network", "cpu", "memory", "temperature", "backlight", "keyboard-state", "sway/language", "battery", "battery#bat2", "clock", "tray"],
"modules-left": [
"sway/workspaces",
"sway/mode",
"sway/scratchpad",
"custom/media"
],
"modules-center": [
"sway/window"
],
"modules-right": [
"mpd",
"idle_inhibitor",
"pulseaudio",
"network",
"power-profiles-daemon",
"cpu",
"memory",
"temperature",
"backlight",
"keyboard-state",
"sway/language",
"battery",
"battery#bat2",
"clock",
"tray"
],
// Modules configuration
// "sway/workspaces": {
// "disable-scroll": true,
@@ -49,7 +73,7 @@
"format-disconnected": "Disconnected ",
"format-stopped": "{consumeIcon}{randomIcon}{repeatIcon}{singleIcon}Stopped ",
"unknown-tag": "N/A",
"interval": 2,
"interval": 5,
"consume-icons": {
"on": " "
},
@@ -113,6 +137,7 @@
"critical": 15
},
"format": "{capacity}% {icon}",
"format-full": "{capacity}% {icon}",
"format-charging": "{capacity}% ",
"format-plugged": "{capacity}% ",
"format-alt": "{time} {icon}",
@@ -123,6 +148,17 @@
"battery#bat2": {
"bat": "BAT2"
},
"power-profiles-daemon": {
"format": "{icon}",
"tooltip-format": "Power profile: {profile}\nDriver: {driver}",
"tooltip": true,
"format-icons": {
"default": "",
"performance": "",
"balanced": "",
"power-saver": ""
}
},
"network": {
// "interface": "wlp2*", // (Optional) To force the use of this interface
"format-wifi": "{essid} ({signalStrength}%) ",
@@ -164,4 +200,3 @@
// "exec": "$HOME/.config/waybar/mediaplayer.py --player spotify 2> /dev/null" // Filter player based on name
}
}

View File

@@ -0,0 +1 @@
.cache/

View File

@@ -0,0 +1,38 @@
# C FFI module
A C FFI module is a dynamic library that exposes standard C functions and
constants, that Waybar can load and execute to create custom advanced widgets.
Most language can implement the required functions and constants (C, C++, Rust,
Go, Python, ...), meaning you can develop custom modules using your language of
choice, as long as there's GTK bindings.
Symbols to implement are documented in the
[waybar_cffi_module.h](waybar_cffi_module.h) file.
# Usage
## Building this module
```bash
meson setup build
meson compile -C build
```
## Load the module
Edit your waybar config:
```json
{
// ...
"modules-center": [
// ...
"cffi/c_example"
],
// ...
"cffi/c_example": {
// Path to the compiled dynamic library file
"module_path": "resources/custom_modules/cffi_example/build/wb_cffi_example.so"
}
}
```

View File

@@ -0,0 +1,70 @@
#include "waybar_cffi_module.h"
typedef struct {
wbcffi_module* waybar_module;
GtkBox* container;
GtkButton* button;
} ExampleMod;
// This static variable is shared between all instances of this module
static int instance_count = 0;
void onclicked(GtkButton* button) {
char text[256];
snprintf(text, 256, "Dice throw result: %d", rand() % 6 + 1);
gtk_button_set_label(button, text);
}
// You must
const size_t wbcffi_version = 1;
void* wbcffi_init(const wbcffi_init_info* init_info, const wbcffi_config_entry* config_entries,
size_t config_entries_len) {
printf("cffi_example: init config:\n");
for (size_t i = 0; i < config_entries_len; i++) {
printf(" %s = %s\n", config_entries[i].key, config_entries[i].value);
}
// Allocate the instance object
ExampleMod* inst = malloc(sizeof(ExampleMod));
inst->waybar_module = init_info->obj;
GtkContainer* root = init_info->get_root_widget(init_info->obj);
// Add a container for displaying the next widgets
inst->container = GTK_BOX(gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 5));
gtk_container_add(GTK_CONTAINER(root), GTK_WIDGET(inst->container));
// Add a label
GtkLabel* label = GTK_LABEL(gtk_label_new("[Example C FFI Module:"));
gtk_container_add(GTK_CONTAINER(inst->container), GTK_WIDGET(label));
// Add a button
inst->button = GTK_BUTTON(gtk_button_new_with_label("click me !"));
g_signal_connect(inst->button, "clicked", G_CALLBACK(onclicked), NULL);
gtk_container_add(GTK_CONTAINER(inst->container), GTK_WIDGET(inst->button));
// Add a label
label = GTK_LABEL(gtk_label_new("]"));
gtk_container_add(GTK_CONTAINER(inst->container), GTK_WIDGET(label));
// Return instance object
printf("cffi_example inst=%p: init success ! (%d total instances)\n", inst, ++instance_count);
return inst;
}
void wbcffi_deinit(void* instance) {
printf("cffi_example inst=%p: free memory\n", instance);
free(instance);
}
void wbcffi_update(void* instance) { printf("cffi_example inst=%p: Update request\n", instance); }
void wbcffi_refresh(void* instance, int signal) {
printf("cffi_example inst=%p: Received refresh signal %d\n", instance, signal);
}
void wbcffi_doaction(void* instance, const char* name) {
printf("cffi_example inst=%p: doAction(%s)\n", instance, name);
}

View File

@@ -0,0 +1,13 @@
project(
'waybar_cffi_example', 'c',
version: '0.1.0',
license: 'MIT',
)
shared_library('wb_cffi_example',
['main.c'],
dependencies: [
dependency('gtk+-3.0', version : ['>=3.22.0'])
],
name_prefix: ''
)

View File

@@ -0,0 +1,89 @@
#pragma once
#include <gtk/gtk.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/// Waybar ABI version. 1 is the latest version
extern const size_t wbcffi_version;
/// Private Waybar CFFI module
typedef struct wbcffi_module wbcffi_module;
/// Waybar module information
typedef struct {
/// Waybar CFFI object pointer
wbcffi_module* obj;
/// Waybar version string
const char* waybar_version;
/// Returns the waybar widget allocated for this module
/// @param obj Waybar CFFI object pointer
GtkContainer* (*get_root_widget)(wbcffi_module* obj);
/// Queues a request for calling wbcffi_update() on the next GTK main event
/// loop iteration
/// @param obj Waybar CFFI object pointer
void (*queue_update)(wbcffi_module*);
} wbcffi_init_info;
/// Config key-value pair
typedef struct {
/// Entry key
const char* key;
/// Entry value as string. JSON object and arrays are serialized.
const char* value;
} wbcffi_config_entry;
/// Module init/new function, called on module instantiation
///
/// MANDATORY CFFI function
///
/// @param init_info Waybar module information
/// @param config_entries Flat representation of the module JSON config. The data only available
/// during wbcffi_init call.
/// @param config_entries_len Number of entries in `config_entries`
///
/// @return A untyped pointer to module data, NULL if the module failed to load.
void* wbcffi_init(const wbcffi_init_info* init_info, const wbcffi_config_entry* config_entries,
size_t config_entries_len);
/// Module deinit/delete function, called when Waybar is closed or when the module is removed
///
/// MANDATORY CFFI function
///
/// @param instance Module instance data (as returned by `wbcffi_init`)
void wbcffi_deinit(void* instance);
/// Called from the GTK main event loop, to update the UI
///
/// Optional CFFI function
///
/// @param instance Module instance data (as returned by `wbcffi_init`)
/// @param action_name Action name
void wbcffi_update(void* instance);
/// Called when Waybar receives a POSIX signal and forwards it to each module
///
/// Optional CFFI function
///
/// @param instance Module instance data (as returned by `wbcffi_init`)
/// @param signal Signal ID
void wbcffi_refresh(void* instance, int signal);
/// Called on module action (see
/// https://github.com/Alexays/Waybar/wiki/Configuration#module-actions-config)
///
/// Optional CFFI function
///
/// @param instance Module instance data (as returned by `wbcffi_init`)
/// @param action_name Action name
void wbcffi_doaction(void* instance, const char* action_name);
#ifdef __cplusplus
}
#endif

View File

@@ -23,7 +23,7 @@ def signal_handler(sig, frame):
class PlayerManager:
def __init__(self, selected_player=None):
def __init__(self, selected_player=None, excluded_player=[]):
self.manager = Playerctl.PlayerManager()
self.loop = GLib.MainLoop()
self.manager.connect(
@@ -35,11 +35,14 @@ class PlayerManager:
signal.signal(signal.SIGTERM, signal_handler)
signal.signal(signal.SIGPIPE, signal.SIG_DFL)
self.selected_player = selected_player
self.excluded_player = excluded_player.split(',') if excluded_player else []
self.init_players()
def init_players(self):
for player in self.manager.props.player_names:
if player.name in self.excluded_player:
continue
if self.selected_player is not None and self.selected_player != player.name:
logger.debug(f"{player.name} is not the filtered player, skipping it")
continue
@@ -149,6 +152,8 @@ def parse_arguments():
# Increase verbosity with every occurrence of -v
parser.add_argument("-v", "--verbose", action="count", default=0)
parser.add_argument("-x", "--exclude", "- Comma-separated list of excluded player")
# Define for which player we"re listening
parser.add_argument("--player")
@@ -174,7 +179,10 @@ def main():
logger.info("Creating player manager")
if arguments.player:
logger.info(f"Filtering for player: {arguments.player}")
player = PlayerManager(arguments.player)
if arguments.exclude:
logger.info(f"Exclude player {arguments.exclude}")
player = PlayerManager(arguments.player, arguments.exclude)
player.run()

View File

@@ -0,0 +1,6 @@
gnome = import('gnome')
app_resources += gnome.compile_resources('icon-resources',
'waybar_icons.gresource.xml',
c_name: 'waybar_icons'
)

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg height="16px" viewBox="0 0 16 16" width="16px" xmlns="http://www.w3.org/2000/svg">
<path d="m 8 0 c -1.660156 0 -3 1.339844 -3 3 v 5 c 0 1.660156 1.339844 3 3 3 s 3 -1.339844 3 -3 v -5 c 0 -1.660156 -1.339844 -3 -3 -3 z m -6 6 v 2.011719 c 0 2.964843 2.164062 5.429687 5 5.90625 v 2.082031 h 2 v -2.082031 c 2.835938 -0.476563 5 -2.941407 5 -5.90625 v -2.011719 h -1.5 v 2.011719 c 0 2.5 -1.992188 4.488281 -4.5 4.488281 s -4.5 -1.988281 -4.5 -4.488281 v -2.011719 z m 0 0" fill="#2e3436"/>
</svg>

After

Width:  |  Height:  |  Size: 546 B

View File

@@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" height="16px" viewBox="0 0 16 16" width="16px"><filter id="a" height="100%" width="100%" x="0%" y="0%"><feColorMatrix color-interpolation-filters="sRGB" values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0"/></filter><mask id="b"><g filter="url(#a)"><path d="m -1.6 -1.6 h 19.2 v 19.2 h -19.2 z" fill-opacity="0.5"/></g></mask><clipPath id="c"><path d="m 0 0 h 1600 v 1200 h -1600 z"/></clipPath><mask id="d"><g filter="url(#a)"><path d="m -1.6 -1.6 h 19.2 v 19.2 h -19.2 z" fill-opacity="0.7"/></g></mask><clipPath id="e"><path d="m 0 0 h 1600 v 1200 h -1600 z"/></clipPath><mask id="f"><g filter="url(#a)"><path d="m -1.6 -1.6 h 19.2 v 19.2 h -19.2 z" fill-opacity="0.35"/></g></mask><clipPath id="g"><path d="m 0 0 h 1600 v 1200 h -1600 z"/></clipPath><path d="m 1.972656 3.773438 c -0.132812 0.007812 -0.257812 0.070312 -0.34375 0.167968 c -1.066406 1.210938 -1.628906 2.585938 -1.628906 3.984375 c 0 1.402344 0.558594 2.8125 1.617188 4.105469 c 0.175781 0.214844 0.488281 0.246094 0.703124 0.070312 c 0.214844 -0.175781 0.246094 -0.488281 0.070313 -0.703124 c -0.945313 -1.152344 -1.390625 -2.332032 -1.390625 -3.472657 c 0 -1.136719 0.441406 -2.261719 1.378906 -3.324219 c 0.183594 -0.207031 0.164063 -0.523437 -0.042968 -0.707031 c -0.101563 -0.085937 -0.230469 -0.128906 -0.363282 -0.121093 z m 11.984375 0 c -0.105469 0.011718 -0.207031 0.054687 -0.285156 0.121093 c -0.207031 0.183594 -0.226563 0.5 -0.042969 0.710938 c 0.933594 1.058593 1.375 2.183593 1.375 3.320312 c 0 1.140625 -0.445312 2.320313 -1.386718 3.472657 c -0.175782 0.214843 -0.144532 0.527343 0.070312 0.703124 c 0.210938 0.175782 0.527344 0.144532 0.703125 -0.070312 c 1.058594 -1.292969 1.613281 -2.703125 1.613281 -4.101562 c 0 -1.402344 -0.558594 -2.777344 -1.625 -3.988282 c -0.109375 -0.121094 -0.265625 -0.183594 -0.421875 -0.167968 z m -8.101562 0.164062 c -0.480469 0.023438 -0.855469 0.417969 -0.855469 0.898438 v 6.359374 c 0 0.675782 0.742188 1.085938 1.3125 0.730469 l 5.265625 -3.246093 c 0.507813 -0.3125 0.507813 -1.046876 0.003906 -1.363282 l -5.203125 -3.246094 c -0.15625 -0.097656 -0.339844 -0.144531 -0.523437 -0.132812 z m -2.359375 1.050781 c -0.160156 -0.003906 -0.3125 0.066407 -0.410156 0.195313 c -0.679688 0.886718 -1.070313 1.824218 -1.078126 2.792968 c -0.011718 0.964844 0.363282 1.921876 1.085938 2.835938 c 0.167969 0.214844 0.484375 0.25 0.699219 0.078125 c 0.214843 -0.167969 0.253906 -0.484375 0.082031 -0.699219 c -0.617188 -0.777344 -0.875 -1.5 -0.871094 -2.207031 c 0.007813 -0.703125 0.289063 -1.425781 0.875 -2.191406 c 0.167969 -0.21875 0.128906 -0.53125 -0.09375 -0.703125 c -0.082031 -0.0625 -0.183594 -0.097656 -0.289062 -0.101563 z m 9.015625 0 c -0.109375 0.003907 -0.210938 0.039063 -0.292969 0.105469 c -0.21875 0.164062 -0.261719 0.480469 -0.09375 0.699219 c 0.585938 0.765625 0.867188 1.488281 0.875 2.195312 c 0.007812 0.703125 -0.253906 1.425781 -0.867188 2.203125 c -0.171874 0.214844 -0.136718 0.53125 0.082032 0.703125 c 0.214844 0.167969 0.527344 0.132813 0.699218 -0.082031 c 0.722657 -0.914062 1.097657 -1.871094 1.085938 -2.835938 c -0.011719 -0.96875 -0.398438 -1.90625 -1.078125 -2.792968 c -0.097656 -0.128906 -0.253906 -0.199219 -0.410156 -0.195313 z m 0 0" fill="#222222"/><g mask="url(#b)"><g clip-path="url(#c)" transform="matrix(1 0 0 1 -600 -1044)"><path d="m 550 182 c -0.351562 0.003906 -0.695312 0.101562 -1 0.28125 v 3.4375 c 0.304688 0.179688 0.648438 0.277344 1 0.28125 c 1.105469 0 2 -0.894531 2 -2 s -0.894531 -2 -2 -2 z m 0 5 c -0.339844 0 -0.679688 0.058594 -1 0.175781 v 6.824219 h 4 v -4 c 0 -1.65625 -1.34375 -3 -3 -3 z m 0 0"/></g></g><g mask="url(#d)"><g clip-path="url(#e)" transform="matrix(1 0 0 1 -600 -1044)"><path d="m 569 182 v 4 c 1.105469 0 2 -0.894531 2 -2 s -0.894531 -2 -2 -2 z m 0 5 v 7 h 3 v -4 c 0 -1.65625 -1.34375 -3 -3 -3 z m 0 0"/></g></g><g mask="url(#f)"><g clip-path="url(#g)" transform="matrix(1 0 0 1 -600 -1044)"><path d="m 573 182.269531 v 3.449219 c 0.613281 -0.355469 0.996094 -1.007812 1 -1.71875 c 0 -0.714844 -0.382812 -1.375 -1 -1.730469 z m 0 4.90625 v 6.824219 h 2 v -4 c 0 -1.269531 -0.800781 -2.402344 -2 -2.824219 z m 0 0"/></g></g></svg>

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg height="16px" viewBox="0 0 16 16" width="16px" xmlns="http://www.w3.org/2000/svg">
<g fill="#2e3436">
<path d="m 3 0 c -1.660156 0 -3 1.339844 -3 3 v 7 c 0 1.660156 1.339844 3 3 3 h 10 c 1.660156 0 3 -1.339844 3 -3 v -1 c 0 -0.550781 -0.449219 -1 -1 -1 s -1 0.449219 -1 1 v 1 c 0 0.554688 -0.445312 1 -1 1 h -10 c -0.554688 0 -1 -0.445312 -1 -1 v -7 c 0 -0.554688 0.445312 -1 1 -1 h 4 c 0.550781 0 1 -0.449219 1 -1 s -0.449219 -1 -1 -1 z m 7 0 c -0.550781 0 -1 0.449219 -1 1 s 0.449219 1 1 1 h 2.585938 l -5.292969 5.289062 c -0.1875 0.191407 -0.292969 0.445313 -0.292969 0.710938 s 0.105469 0.519531 0.292969 0.707031 c 0.390625 0.390625 1.023437 0.390625 1.414062 0 l 5.292969 -5.292969 v 2.585938 c 0 0.550781 0.449219 1 1 1 s 1 -0.449219 1 -1 v -5 c 0 -0.085938 -0.011719 -0.171875 -0.035156 -0.257812 c -0.023438 -0.085938 -0.054688 -0.167969 -0.101563 -0.242188 c -0.042969 -0.074219 -0.09375 -0.144531 -0.15625 -0.207031 c 0 0 0 0 0 -0.003907 c -0.015625 -0.011718 -0.03125 -0.023437 -0.046875 -0.035156 c -0.054687 -0.046875 -0.117187 -0.089844 -0.183594 -0.128906 c -0.035156 -0.015625 -0.074218 -0.03125 -0.113281 -0.046875 c -0.050781 -0.0195312 -0.101562 -0.0351562 -0.15625 -0.0507812 c -0.039062 -0.0078126 -0.082031 -0.0117188 -0.121093 -0.015625 c -0.027344 -0.0039063 -0.058594 -0.00781255 -0.085938 -0.0117188 z m -5 14 c -1.105469 0 -2 0.894531 -2 2 h 10 c 0 -1.105469 -0.894531 -2 -2 -2 z m 0 0"/>
<path d="m 3 3 v 7 h 10 v -4.171875 l -3.585938 3.585937 c -0.773437 0.773438 -2.054687 0.773438 -2.828124 0 c -0.773438 -0.773437 -0.773438 -2.058593 0 -2.832031 l 3.585937 -3.582031 z m 0 0" fill-opacity="0.34902"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
<gresource prefix="/fr/arouillard/waybar/icons/scalable/actions">
<file preprocess="xml-stripblanks">waybar-privacy-audio-input-symbolic.svg</file>
<file preprocess="xml-stripblanks">waybar-privacy-audio-output-symbolic.svg</file>
<file preprocess="xml-stripblanks">waybar-privacy-screen-share-symbolic.svg</file>
</gresource>
</gresources>

View File

@@ -69,7 +69,7 @@ button:hover {
#mode {
background-color: #64727D;
border-bottom: 3px solid #ffffff;
box-shadow: inset 0 -3px #ffffff;
}
#clock,
@@ -87,6 +87,7 @@ button:hover {
#mode,
#idle_inhibitor,
#scratchpad,
#power-profiles-daemon,
#mpd {
padding: 0 10px;
color: #ffffff;
@@ -128,16 +129,36 @@ button:hover {
}
}
/* Using steps() instead of linear as a timing function to limit cpu usage */
#battery.critical:not(.charging) {
background-color: #f53c3c;
color: #ffffff;
animation-name: blink;
animation-duration: 0.5s;
animation-timing-function: linear;
animation-timing-function: steps(12);
animation-iteration-count: infinite;
animation-direction: alternate;
}
#power-profiles-daemon {
padding-right: 15px;
}
#power-profiles-daemon.performance {
background-color: #f53c3c;
color: #ffffff;
}
#power-profiles-daemon.balanced {
background-color: #2980b9;
color: #ffffff;
}
#power-profiles-daemon.power-saver {
background-color: #2ecc71;
color: #000000;
}
label:focus {
background-color: #000000;
}
@@ -278,3 +299,24 @@ label:focus {
#scratchpad.empty {
background-color: transparent;
}
#privacy {
padding: 0;
}
#privacy-item {
padding: 0 5px;
color: white;
}
#privacy-item.screenshare {
background-color: #cf5700;
}
#privacy-item.audio-in {
background-color: #1ca000;
}
#privacy-item.audio-out {
background-color: #0069d4;
}

View File

@@ -24,18 +24,61 @@ AAppIconLabel::AAppIconLabel(const Json::Value& config, const std::string& name,
image_.set_pixel_size(app_icon_size_);
}
std::string toLowerCase(const std::string& input) {
std::string result = input;
std::transform(result.begin(), result.end(), result.begin(),
[](unsigned char c) { return std::tolower(c); });
return result;
}
std::optional<std::string> getFileBySuffix(const std::string& dir, const std::string& suffix,
bool check_lower_case) {
if (!std::filesystem::exists(dir)) {
return {};
}
for (const auto& entry : std::filesystem::recursive_directory_iterator(dir)) {
if (entry.is_regular_file()) {
std::string filename = entry.path().filename().string();
if (filename.size() < suffix.size()) {
continue;
}
if ((filename.compare(filename.size() - suffix.size(), suffix.size(), suffix) == 0) ||
(check_lower_case && filename.compare(filename.size() - suffix.size(), suffix.size(),
toLowerCase(suffix)) == 0)) {
return entry.path().string();
}
}
}
return {};
}
std::optional<std::string> getFileBySuffix(const std::string& dir, const std::string& suffix) {
return getFileBySuffix(dir, suffix, false);
}
std::optional<std::string> getDesktopFilePath(const std::string& app_identifier,
const std::string& alternative_app_identifier) {
if (app_identifier.empty()) {
return {};
}
const auto data_dirs = Glib::get_system_data_dirs();
for (const auto& data_dir : data_dirs) {
const auto data_app_dir = data_dir + "applications/";
auto desktop_file_path = data_app_dir + app_identifier + ".desktop";
if (std::filesystem::exists(desktop_file_path)) {
const auto data_app_dir = data_dir + "/applications/";
auto desktop_file_suffix = app_identifier + ".desktop";
// searching for file by suffix catches cases like terminal emulator "foot" where class is
// "footclient" and desktop file is named "org.codeberg.dnkl.footclient.desktop"
auto desktop_file_path = getFileBySuffix(data_app_dir, desktop_file_suffix, true);
// "true" argument allows checking for lowercase - this catches cases where class name is
// "LibreWolf" and desktop file is named "librewolf.desktop"
if (desktop_file_path.has_value()) {
return desktop_file_path;
}
if (!alternative_app_identifier.empty()) {
desktop_file_path = data_app_dir + alternative_app_identifier + ".desktop";
if (std::filesystem::exists(desktop_file_path)) {
desktop_file_suffix = alternative_app_identifier + ".desktop";
desktop_file_path = getFileBySuffix(data_app_dir, desktop_file_suffix, true);
if (desktop_file_path.has_value()) {
return desktop_file_path;
}
}
@@ -58,16 +101,9 @@ std::optional<Glib::ustring> getIconName(const std::string& app_identifier,
return app_identifier_desktop;
}
const auto to_lower = [](const std::string& str) {
auto str_cpy = str;
std::transform(str_cpy.begin(), str_cpy.end(), str_cpy.begin(),
[](unsigned char c) { return std::tolower(c); });
return str;
};
const auto first_space = app_identifier.find_first_of(' ');
if (first_space != std::string::npos) {
const auto first_word = to_lower(app_identifier.substr(0, first_space));
const auto first_word = toLowerCase(app_identifier.substr(0, first_space));
if (DefaultGtkIconThemeWrapper::has_icon(first_word)) {
return first_word;
}
@@ -75,7 +111,7 @@ std::optional<Glib::ustring> getIconName(const std::string& app_identifier,
const auto first_dash = app_identifier.find_first_of('-');
if (first_dash != std::string::npos) {
const auto first_word = to_lower(app_identifier.substr(0, first_dash));
const auto first_word = toLowerCase(app_identifier.substr(0, first_dash));
if (DefaultGtkIconThemeWrapper::has_icon(first_word)) {
return first_word;
}

View File

@@ -9,10 +9,23 @@ AIconLabel::AIconLabel(const Json::Value &config, const std::string &name, const
bool enable_click, bool enable_scroll)
: ALabel(config, name, id, format, interval, ellipsize, enable_click, enable_scroll) {
event_box_.remove();
label_.unset_name();
label_.get_style_context()->remove_class(MODULE_CLASS);
box_.get_style_context()->add_class(MODULE_CLASS);
if (!id.empty()) {
label_.get_style_context()->remove_class(id);
box_.get_style_context()->add_class(id);
}
box_.set_orientation(Gtk::Orientation::ORIENTATION_HORIZONTAL);
box_.set_spacing(8);
box_.set_name(name);
int spacing = config_["icon-spacing"].isInt() ? config_["icon-spacing"].asInt() : 8;
box_.set_spacing(spacing);
box_.add(image_);
box_.add(label_);
event_box_.add(box_);
}

View File

@@ -20,6 +20,7 @@ ALabel::ALabel(const Json::Value& config, const std::string& name, const std::st
if (!id.empty()) {
label_.get_style_context()->add_class(id);
}
label_.get_style_context()->add_class(MODULE_CLASS);
event_box_.add(label_);
if (config_["max-length"].isUInt()) {
label_.set_max_width_chars(config_["max-length"].asInt());
@@ -49,6 +50,17 @@ ALabel::ALabel(const Json::Value& config, const std::string& name, const std::st
label_.set_xalign(align);
}
}
if (config_["justify"].isString()) {
auto justify_str = config_["justify"].asString();
if (justify_str == "left") {
label_.set_justify(Gtk::Justification::JUSTIFY_LEFT);
} else if (justify_str == "right") {
label_.set_justify(Gtk::Justification::JUSTIFY_RIGHT);
} else if (justify_str == "center") {
label_.set_justify(Gtk::Justification::JUSTIFY_CENTER);
}
}
}
auto ALabel::update() -> void { AModule::update(); }

View File

@@ -10,6 +10,7 @@ AModule::AModule(const Json::Value& config, const std::string& name, const std::
bool enable_click, bool enable_scroll)
: name_(std::move(name)),
config_(std::move(config)),
isTooltip{config_["tooltip"].isBool() ? config_["tooltip"].asBool() : true},
distance_scrolled_y_(0.0),
distance_scrolled_x_(0.0) {
// Configure module action Map
@@ -50,7 +51,9 @@ AModule::AModule(const Json::Value& config, const std::string& name, const std::
event_box_.add_events(Gdk::BUTTON_RELEASE_MASK);
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) {
if (config_["on-scroll-up"].isString() || config_["on-scroll-down"].isString() ||
config_["on-scroll-left"].isString() || config_["on-scroll-right"].isString() ||
enable_scroll) {
event_box_.add_events(Gdk::SCROLL_MASK | Gdk::SMOOTH_SCROLL_MASK);
event_box_.signal_scroll_event().connect(sigc::mem_fun(*this, &AModule::handleScroll));
}
@@ -178,6 +181,10 @@ bool AModule::handleScroll(GdkEventScroll* e) {
eventName = "on-scroll-up";
else if (dir == SCROLL_DIR::DOWN)
eventName = "on-scroll-down";
else if (dir == SCROLL_DIR::LEFT)
eventName = "on-scroll-left";
else if (dir == SCROLL_DIR::RIGHT)
eventName = "on-scroll-right";
// First call module actions
this->AModule::doAction(eventName);
@@ -189,9 +196,7 @@ bool AModule::handleScroll(GdkEventScroll* e) {
return true;
}
bool AModule::tooltipEnabled() {
return config_["tooltip"].isBool() ? config_["tooltip"].asBool() : true;
}
bool AModule::tooltipEnabled() { return isTooltip; }
AModule::operator Gtk::Widget&() { return event_box_; }

View File

@@ -13,6 +13,7 @@ ASlider::ASlider(const Json::Value& config, const std::string& name, const std::
if (!id.empty()) {
scale_.get_style_context()->add_class(id);
}
scale_.get_style_context()->add_class(MODULE_CLASS);
event_box_.add(scale_);
scale_.signal_value_changed().connect(sigc::mem_fun(*this, &ASlider::onValueChanged));

View File

@@ -1,16 +1,13 @@
#ifdef HAVE_GTK_LAYER_SHELL
#include <gtk-layer-shell.h>
#endif
#include "bar.hpp"
#include <gtk-layer-shell.h>
#include <spdlog/spdlog.h>
#include <type_traits>
#include "bar.hpp"
#include "client.hpp"
#include "factory.hpp"
#include "group.hpp"
#include "wlr-layer-shell-unstable-v1-client-protocol.h"
#ifdef HAVE_SWAY
#include "modules/sway/bar.hpp"
@@ -25,9 +22,6 @@ static constexpr const char* MIN_WIDTH_MSG =
static constexpr const char* BAR_SIZE_MSG = "Bar configured (width: {}, height: {}) for output: {}";
static constexpr const char* SIZE_DEFINED =
"{} size is defined in the config file so it will stay like that";
const Bar::bar_mode_map Bar::PRESET_MODES = { //
{"default",
{// Special mode to hold the global bar configuration
@@ -60,8 +54,8 @@ const Bar::bar_mode_map Bar::PRESET_MODES = { //
.passthrough = true,
.visible = true}}};
const std::string_view Bar::MODE_DEFAULT = "default";
const std::string_view Bar::MODE_INVISIBLE = "invisible";
const std::string Bar::MODE_DEFAULT = "default";
const std::string Bar::MODE_INVISIBLE = "invisible";
const std::string_view DEFAULT_BAR_ID = "bar-0";
/* Deserializer for enum bar_layer */
@@ -93,11 +87,38 @@ void from_json(const Json::Value& j, bar_mode& m) {
}
}
/* Deserializer for enum Gtk::PositionType */
void from_json(const Json::Value& j, Gtk::PositionType& pos) {
if (j == "left") {
pos = Gtk::POS_LEFT;
} else if (j == "right") {
pos = Gtk::POS_RIGHT;
} else if (j == "top") {
pos = Gtk::POS_TOP;
} else if (j == "bottom") {
pos = Gtk::POS_BOTTOM;
}
}
Glib::ustring to_string(Gtk::PositionType pos) {
switch (pos) {
case Gtk::POS_LEFT:
return "left";
case Gtk::POS_RIGHT:
return "right";
case Gtk::POS_TOP:
return "top";
case Gtk::POS_BOTTOM:
return "bottom";
}
throw std::runtime_error("Invalid Gtk::PositionType");
}
/* Deserializer for JSON Object -> map<string compatible type, Value>
* Assumes that all the values in the object are deserializable to the same type.
*/
template <typename Key, typename Value,
typename = std::enable_if_t<std::is_convertible<std::string_view, Key>::value>>
typename = std::enable_if_t<std::is_convertible<std::string, Key>::value>>
void from_json(const Json::Value& j, std::map<Key, Value>& m) {
if (j.isObject()) {
for (auto it = j.begin(); it != j.end(); ++it) {
@@ -106,375 +127,6 @@ void from_json(const Json::Value& j, std::map<Key, Value>& m) {
}
}
#ifdef HAVE_GTK_LAYER_SHELL
struct GLSSurfaceImpl : public BarSurface, public sigc::trackable {
GLSSurfaceImpl(Gtk::Window& window, struct waybar_output& output) : window_{window} {
output_name_ = output.name;
// this has to be executed before GtkWindow.realize
gtk_layer_init_for_window(window_.gobj());
gtk_layer_set_keyboard_interactivity(window.gobj(), FALSE);
gtk_layer_set_monitor(window_.gobj(), output.monitor->gobj());
gtk_layer_set_namespace(window_.gobj(), "waybar");
window.signal_map_event().connect_notify(sigc::mem_fun(*this, &GLSSurfaceImpl::onMap));
window.signal_configure_event().connect_notify(
sigc::mem_fun(*this, &GLSSurfaceImpl::onConfigure));
}
void setExclusiveZone(bool enable) override {
if (enable) {
gtk_layer_auto_exclusive_zone_enable(window_.gobj());
} else {
gtk_layer_set_exclusive_zone(window_.gobj(), 0);
}
}
void setMargins(const struct bar_margins& margins) override {
gtk_layer_set_margin(window_.gobj(), GTK_LAYER_SHELL_EDGE_LEFT, margins.left);
gtk_layer_set_margin(window_.gobj(), GTK_LAYER_SHELL_EDGE_RIGHT, margins.right);
gtk_layer_set_margin(window_.gobj(), GTK_LAYER_SHELL_EDGE_TOP, margins.top);
gtk_layer_set_margin(window_.gobj(), GTK_LAYER_SHELL_EDGE_BOTTOM, margins.bottom);
}
void setLayer(bar_layer value) override {
auto layer = GTK_LAYER_SHELL_LAYER_BOTTOM;
if (value == bar_layer::TOP) {
layer = GTK_LAYER_SHELL_LAYER_TOP;
} else if (value == bar_layer::OVERLAY) {
layer = GTK_LAYER_SHELL_LAYER_OVERLAY;
}
gtk_layer_set_layer(window_.gobj(), layer);
}
void setPassThrough(bool enable) override {
passthrough_ = enable;
auto gdk_window = window_.get_window();
if (gdk_window) {
Cairo::RefPtr<Cairo::Region> region;
if (enable) {
region = Cairo::Region::create();
}
gdk_window->input_shape_combine_region(region, 0, 0);
}
}
void setPosition(const std::string_view& position) override {
auto unanchored = GTK_LAYER_SHELL_EDGE_BOTTOM;
vertical_ = false;
if (position == "bottom") {
unanchored = GTK_LAYER_SHELL_EDGE_TOP;
} else if (position == "left") {
unanchored = GTK_LAYER_SHELL_EDGE_RIGHT;
vertical_ = true;
} else if (position == "right") {
vertical_ = true;
unanchored = GTK_LAYER_SHELL_EDGE_LEFT;
}
for (auto edge : {GTK_LAYER_SHELL_EDGE_LEFT, GTK_LAYER_SHELL_EDGE_RIGHT,
GTK_LAYER_SHELL_EDGE_TOP, GTK_LAYER_SHELL_EDGE_BOTTOM}) {
gtk_layer_set_anchor(window_.gobj(), edge, unanchored != edge);
}
// Disable anchoring for other edges too if the width
// or the height has been set to a value other than 'auto'
// otherwise the bar will use all space
if (vertical_ && height_ > 1) {
gtk_layer_set_anchor(window_.gobj(), GTK_LAYER_SHELL_EDGE_BOTTOM, false);
gtk_layer_set_anchor(window_.gobj(), GTK_LAYER_SHELL_EDGE_TOP, false);
} else if (!vertical_ && width_ > 1) {
gtk_layer_set_anchor(window_.gobj(), GTK_LAYER_SHELL_EDGE_LEFT, false);
gtk_layer_set_anchor(window_.gobj(), GTK_LAYER_SHELL_EDGE_RIGHT, false);
}
}
void setSize(uint32_t width, uint32_t height) override {
width_ = width;
height_ = height;
window_.set_size_request(width_, height_);
};
private:
Gtk::Window& window_;
std::string output_name_;
uint32_t width_;
uint32_t height_;
bool passthrough_ = false;
bool vertical_ = false;
void onMap(GdkEventAny* ev) { setPassThrough(passthrough_); }
void onConfigure(GdkEventConfigure* ev) {
/*
* GTK wants new size for the window.
* Actual resizing and management of the exclusve zone is handled within the gtk-layer-shell
* code. This event handler only updates stored size of the window and prints some warnings.
*
* Note: forced resizing to a window smaller than required by GTK would not work with
* gtk-layer-shell.
*/
if (vertical_) {
if (width_ > 1 && ev->width > static_cast<int>(width_)) {
spdlog::warn(MIN_WIDTH_MSG, width_, ev->width);
}
} else {
if (height_ > 1 && ev->height > static_cast<int>(height_)) {
spdlog::warn(MIN_HEIGHT_MSG, height_, ev->height);
}
}
width_ = ev->width;
height_ = ev->height;
spdlog::info(BAR_SIZE_MSG, width_, height_, output_name_);
}
};
#endif
struct RawSurfaceImpl : public BarSurface, public sigc::trackable {
RawSurfaceImpl(Gtk::Window& window, struct waybar_output& output) : window_{window} {
output_ = gdk_wayland_monitor_get_wl_output(output.monitor->gobj());
output_name_ = output.name;
window.signal_realize().connect_notify(sigc::mem_fun(*this, &RawSurfaceImpl::onRealize));
window.signal_map_event().connect_notify(sigc::mem_fun(*this, &RawSurfaceImpl::onMap));
window.signal_configure_event().connect_notify(
sigc::mem_fun(*this, &RawSurfaceImpl::onConfigure));
if (window.get_realized()) {
onRealize();
}
}
void setExclusiveZone(bool enable) override {
exclusive_zone_ = enable;
if (layer_surface_) {
auto zone = 0;
if (enable) {
// exclusive zone already includes margin for anchored edge,
// only opposite margin should be added
if ((anchor_ & VERTICAL_ANCHOR) == VERTICAL_ANCHOR) {
zone += width_;
zone += (anchor_ & ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT) ? margins_.right : margins_.left;
} else {
zone += height_;
zone += (anchor_ & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP) ? margins_.bottom : margins_.top;
}
}
spdlog::debug("Set exclusive zone {} for output {}", zone, output_name_);
zwlr_layer_surface_v1_set_exclusive_zone(layer_surface_.get(), zone);
}
}
void setLayer(bar_layer layer) override {
layer_ = ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM;
if (layer == bar_layer::TOP) {
layer_ = ZWLR_LAYER_SHELL_V1_LAYER_TOP;
} else if (layer == bar_layer::OVERLAY) {
layer_ = ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY;
}
// updating already mapped window
if (layer_surface_) {
if (zwlr_layer_surface_v1_get_version(layer_surface_.get()) >=
ZWLR_LAYER_SURFACE_V1_SET_LAYER_SINCE_VERSION) {
zwlr_layer_surface_v1_set_layer(layer_surface_.get(), layer_);
} else {
spdlog::warn("Unable to change layer: layer-shell implementation is too old");
}
}
}
void setMargins(const struct bar_margins& margins) override {
margins_ = margins;
// updating already mapped window
if (layer_surface_) {
zwlr_layer_surface_v1_set_margin(layer_surface_.get(), margins_.top, margins_.right,
margins_.bottom, margins_.left);
}
}
void setPassThrough(bool enable) override {
passthrough_ = enable;
/* GTK overwrites any region changes applied directly to the wl_surface,
* thus the same GTK region API as in the GLS impl has to be used. */
auto gdk_window = window_.get_window();
if (gdk_window) {
Cairo::RefPtr<Cairo::Region> region;
if (enable) {
region = Cairo::Region::create();
}
gdk_window->input_shape_combine_region(region, 0, 0);
}
}
void setPosition(const std::string_view& position) override {
anchor_ = HORIZONTAL_ANCHOR | ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP;
if (position == "bottom") {
anchor_ = HORIZONTAL_ANCHOR | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM;
} else if (position == "left") {
anchor_ = VERTICAL_ANCHOR | ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT;
} else if (position == "right") {
anchor_ = VERTICAL_ANCHOR | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT;
}
// updating already mapped window
if (layer_surface_) {
zwlr_layer_surface_v1_set_anchor(layer_surface_.get(), anchor_);
}
}
void setSize(uint32_t width, uint32_t height) override {
configured_width_ = width_ = width;
configured_height_ = height_ = height;
// layer_shell.configure handler should update exclusive zone if size changes
window_.set_size_request(width, height);
};
void commit() override {
if (surface_) {
wl_surface_commit(surface_);
}
}
private:
constexpr static uint8_t VERTICAL_ANCHOR =
ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM;
constexpr static uint8_t HORIZONTAL_ANCHOR =
ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT;
template <auto fn>
using deleter_fn = std::integral_constant<decltype(fn), fn>;
using layer_surface_ptr =
std::unique_ptr<zwlr_layer_surface_v1, deleter_fn<zwlr_layer_surface_v1_destroy>>;
Gtk::Window& window_;
std::string output_name_;
uint32_t configured_width_ = 0;
uint32_t configured_height_ = 0;
uint32_t width_ = 0;
uint32_t height_ = 0;
uint8_t anchor_ = HORIZONTAL_ANCHOR | ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP;
bool exclusive_zone_ = true;
bool passthrough_ = false;
struct bar_margins margins_;
zwlr_layer_shell_v1_layer layer_ = ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM;
struct wl_output* output_ = nullptr; // owned by GTK
struct wl_surface* surface_ = nullptr; // owned by GTK
layer_surface_ptr layer_surface_;
void onRealize() {
auto gdk_window = window_.get_window()->gobj();
gdk_wayland_window_set_use_custom_surface(gdk_window);
}
void onMap(GdkEventAny* ev) {
static const struct zwlr_layer_surface_v1_listener layer_surface_listener = {
.configure = onSurfaceConfigure,
.closed = onSurfaceClosed,
};
auto client = Client::inst();
auto gdk_window = window_.get_window()->gobj();
surface_ = gdk_wayland_window_get_wl_surface(gdk_window);
layer_surface_.reset(zwlr_layer_shell_v1_get_layer_surface(client->layer_shell, surface_,
output_, layer_, "waybar"));
zwlr_layer_surface_v1_add_listener(layer_surface_.get(), &layer_surface_listener, this);
zwlr_layer_surface_v1_set_keyboard_interactivity(layer_surface_.get(), false);
zwlr_layer_surface_v1_set_anchor(layer_surface_.get(), anchor_);
zwlr_layer_surface_v1_set_margin(layer_surface_.get(), margins_.top, margins_.right,
margins_.bottom, margins_.left);
setSurfaceSize(width_, height_);
setExclusiveZone(exclusive_zone_);
setPassThrough(passthrough_);
commit();
wl_display_roundtrip(client->wl_display);
}
void onConfigure(GdkEventConfigure* ev) {
/*
* GTK wants new size for the window.
*
* Prefer configured size if it's non-default.
* If the size is not set and the window is smaller than requested by GTK, request resize from
* layer surface.
*/
auto tmp_height = height_;
auto tmp_width = width_;
if (ev->height > static_cast<int>(height_)) {
// Default minimal value
if (height_ > 1) {
spdlog::warn(MIN_HEIGHT_MSG, height_, ev->height);
}
if (configured_height_ > 1) {
spdlog::info(SIZE_DEFINED, "Height");
} else {
tmp_height = ev->height;
}
}
if (ev->width > static_cast<int>(width_)) {
// Default minimal value
if (width_ > 1) {
spdlog::warn(MIN_WIDTH_MSG, width_, ev->width);
}
if (configured_width_ > 1) {
spdlog::info(SIZE_DEFINED, "Width");
} else {
tmp_width = ev->width;
}
}
if (tmp_width != width_ || tmp_height != height_) {
setSurfaceSize(tmp_width, tmp_height);
commit();
}
}
void setSurfaceSize(uint32_t width, uint32_t height) {
/* If the client is anchored to two opposite edges, layer_surface.configure will return
* size without margins for the axis.
* layer_surface.set_size, however, expects size with margins for the anchored axis.
* This is not specified by wlr-layer-shell and based on actual behavior of sway.
*
* If the size for unanchored axis is not set (0), change request to 1 to avoid automatic
* assignment by the compositor.
*/
if ((anchor_ & VERTICAL_ANCHOR) == VERTICAL_ANCHOR) {
width = width > 0 ? width : 1;
if (height > 1) {
height += margins_.top + margins_.bottom;
}
} else {
height = height > 0 ? height : 1;
if (width > 1) {
width += margins_.right + margins_.left;
}
}
spdlog::debug("Set surface size {}x{} for output {}", width, height, output_name_);
zwlr_layer_surface_v1_set_size(layer_surface_.get(), width, height);
}
static void onSurfaceConfigure(void* data, struct zwlr_layer_surface_v1* surface, uint32_t serial,
uint32_t width, uint32_t height) {
auto o = static_cast<RawSurfaceImpl*>(data);
if (width != o->width_ || height != o->height_) {
o->width_ = width;
o->height_ = height;
o->window_.set_size_request(o->width_, o->height_);
o->window_.resize(o->width_, o->height_);
o->setExclusiveZone(o->exclusive_zone_);
spdlog::info(BAR_SIZE_MSG, o->width_ == 1 ? "auto" : std::to_string(o->width_),
o->height_ == 1 ? "auto" : std::to_string(o->height_), o->output_name_);
o->commit();
}
zwlr_layer_surface_v1_ack_configure(surface, serial);
}
static void onSurfaceClosed(void* data, struct zwlr_layer_surface_v1* /* surface */) {
auto o = static_cast<RawSurfaceImpl*>(data);
o->layer_surface_.reset();
}
};
}; // namespace waybar
waybar::Bar::Bar(struct waybar_output* w_output, const Json::Value& w_config)
@@ -493,17 +145,18 @@ waybar::Bar::Bar(struct waybar_output* w_output, const Json::Value& w_config)
window.set_decorated(false);
window.get_style_context()->add_class(output->name);
window.get_style_context()->add_class(config["name"].asString());
window.get_style_context()->add_class(config["position"].asString());
auto position = config["position"].asString();
from_json(config["position"], position);
orientation = (position == Gtk::POS_LEFT || position == Gtk::POS_RIGHT)
? Gtk::ORIENTATION_VERTICAL
: Gtk::ORIENTATION_HORIZONTAL;
if (position == "right" || position == "left") {
left_ = Gtk::Box(Gtk::ORIENTATION_VERTICAL, 0);
center_ = Gtk::Box(Gtk::ORIENTATION_VERTICAL, 0);
right_ = Gtk::Box(Gtk::ORIENTATION_VERTICAL, 0);
box_ = Gtk::Box(Gtk::ORIENTATION_VERTICAL, 0);
vertical = true;
}
window.get_style_context()->add_class(to_string(position));
left_ = Gtk::Box(orientation, 0);
center_ = Gtk::Box(orientation, 0);
right_ = Gtk::Box(orientation, 0);
box_ = Gtk::Box(orientation, 0);
left_.get_style_context()->add_class("modules-left");
center_.get_style_context()->add_class("modules-center");
@@ -516,8 +169,8 @@ waybar::Bar::Bar(struct waybar_output* w_output, const Json::Value& w_config)
right_.set_spacing(spacing);
}
uint32_t height = config["height"].isUInt() ? config["height"].asUInt() : 0;
uint32_t width = config["width"].isUInt() ? config["width"].asUInt() : 0;
height_ = config["height"].isUInt() ? config["height"].asUInt() : 0;
width_ = config["width"].isUInt() ? config["width"].asUInt() : 0;
if (config["margin-top"].isInt() || config["margin-right"].isInt() ||
config["margin-bottom"].isInt() || config["margin-left"].isInt()) {
@@ -568,21 +221,23 @@ waybar::Bar::Bar(struct waybar_output* w_output, const Json::Value& w_config)
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) {
surface_impl_ = std::make_unique<GLSSurfaceImpl>(window, *output);
} else
#endif
{
surface_impl_ = std::make_unique<RawSurfaceImpl>(window, *output);
}
// this has to be executed before GtkWindow.realize
auto* gtk_window = window.gobj();
gtk_layer_init_for_window(gtk_window);
gtk_layer_set_keyboard_mode(gtk_window, GTK_LAYER_SHELL_KEYBOARD_MODE_NONE);
gtk_layer_set_monitor(gtk_window, output->monitor->gobj());
gtk_layer_set_namespace(gtk_window, "waybar");
gtk_layer_set_margin(gtk_window, GTK_LAYER_SHELL_EDGE_LEFT, margins_.left);
gtk_layer_set_margin(gtk_window, GTK_LAYER_SHELL_EDGE_RIGHT, margins_.right);
gtk_layer_set_margin(gtk_window, GTK_LAYER_SHELL_EDGE_TOP, margins_.top);
gtk_layer_set_margin(gtk_window, GTK_LAYER_SHELL_EDGE_BOTTOM, margins_.bottom);
window.set_size_request(width_, height_);
surface_impl_->setMargins(margins_);
surface_impl_->setSize(width, height);
// Position needs to be set after calculating the height due to the
// GTK layer shell anchors logic relying on the dimensions of the bar.
surface_impl_->setPosition(position);
setPosition(position);
/* Read custom modes if available */
if (auto modes = config.get("modes", {}); modes.isObject()) {
@@ -638,7 +293,7 @@ waybar::Bar::Bar(struct waybar_output* w_output, const Json::Value& w_config)
/* Need to define it here because of forward declared members */
waybar::Bar::~Bar() = default;
void waybar::Bar::setMode(const std::string_view& mode) {
void waybar::Bar::setMode(const std::string& mode) {
using namespace std::literals::string_literals;
auto style = window.get_style_context();
@@ -659,9 +314,23 @@ void waybar::Bar::setMode(const std::string_view& mode) {
}
void waybar::Bar::setMode(const struct bar_mode& mode) {
surface_impl_->setLayer(mode.layer);
surface_impl_->setExclusiveZone(mode.exclusive);
surface_impl_->setPassThrough(mode.passthrough);
auto* gtk_window = window.gobj();
auto layer = GTK_LAYER_SHELL_LAYER_BOTTOM;
if (mode.layer == bar_layer::TOP) {
layer = GTK_LAYER_SHELL_LAYER_TOP;
} else if (mode.layer == bar_layer::OVERLAY) {
layer = GTK_LAYER_SHELL_LAYER_OVERLAY;
}
gtk_layer_set_layer(gtk_window, layer);
if (mode.exclusive) {
gtk_layer_auto_exclusive_zone_enable(gtk_window);
} else {
gtk_layer_set_exclusive_zone(gtk_window, 0);
}
setPassThrough(passthrough_ = mode.passthrough);
if (mode.visible) {
window.get_style_context()->remove_class("hidden");
@@ -670,7 +339,58 @@ void waybar::Bar::setMode(const struct bar_mode& mode) {
window.get_style_context()->add_class("hidden");
window.set_opacity(0);
}
surface_impl_->commit();
}
void waybar::Bar::setPassThrough(bool passthrough) {
auto gdk_window = window.get_window();
if (gdk_window) {
Cairo::RefPtr<Cairo::Region> region;
if (passthrough) {
region = Cairo::Region::create();
}
gdk_window->input_shape_combine_region(region, 0, 0);
}
}
void waybar::Bar::setPosition(Gtk::PositionType position) {
std::array<gboolean, GTK_LAYER_SHELL_EDGE_ENTRY_NUMBER> anchors;
anchors.fill(TRUE);
auto orientation = (position == Gtk::POS_LEFT || position == Gtk::POS_RIGHT)
? Gtk::ORIENTATION_VERTICAL
: Gtk::ORIENTATION_HORIZONTAL;
switch (position) {
case Gtk::POS_LEFT:
anchors[GTK_LAYER_SHELL_EDGE_RIGHT] = FALSE;
break;
case Gtk::POS_RIGHT:
anchors[GTK_LAYER_SHELL_EDGE_LEFT] = FALSE;
break;
case Gtk::POS_BOTTOM:
anchors[GTK_LAYER_SHELL_EDGE_TOP] = FALSE;
break;
default: /* Gtk::POS_TOP */
anchors[GTK_LAYER_SHELL_EDGE_BOTTOM] = FALSE;
break;
};
// Disable anchoring for other edges too if the width
// or the height has been set to a value other than 'auto'
// otherwise the bar will use all space
uint32_t configured_width = config["width"].isUInt() ? config["width"].asUInt() : 0;
uint32_t configured_height = config["height"].isUInt() ? config["height"].asUInt() : 0;
if (orientation == Gtk::ORIENTATION_VERTICAL && configured_height > 1) {
anchors[GTK_LAYER_SHELL_EDGE_TOP] = FALSE;
anchors[GTK_LAYER_SHELL_EDGE_BOTTOM] = FALSE;
} else if (orientation == Gtk::ORIENTATION_HORIZONTAL && configured_width > 1) {
anchors[GTK_LAYER_SHELL_EDGE_LEFT] = FALSE;
anchors[GTK_LAYER_SHELL_EDGE_RIGHT] = FALSE;
}
for (auto edge : {GTK_LAYER_SHELL_EDGE_LEFT, GTK_LAYER_SHELL_EDGE_RIGHT, GTK_LAYER_SHELL_EDGE_TOP,
GTK_LAYER_SHELL_EDGE_BOTTOM}) {
gtk_layer_set_anchor(window.gobj(), edge, anchors[edge]);
}
}
void waybar::Bar::onMap(GdkEventAny*) {
@@ -680,6 +400,8 @@ 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));
setPassThrough(passthrough_);
}
void waybar::Bar::setVisible(bool value) {
@@ -760,7 +482,7 @@ void waybar::Bar::getModules(const Factory& factory, const std::string& pos,
getModules(factory, ref, group_module);
module = group_module;
} else {
module = factory.makeModule(ref);
module = factory.makeModule(ref, pos);
}
std::shared_ptr<AModule> module_sp(module);
@@ -824,39 +546,63 @@ auto waybar::Bar::setupWidgets() -> void {
}
void waybar::Bar::onConfigure(GdkEventConfigure* ev) {
/*
* GTK wants new size for the window.
* Actual resizing and management of the exclusve zone is handled within the gtk-layer-shell
* code. This event handler only updates stored size of the window and prints some warnings.
*
* Note: forced resizing to a window smaller than required by GTK would not work with
* gtk-layer-shell.
*/
if (orientation == Gtk::ORIENTATION_VERTICAL) {
if (width_ > 1 && ev->width > static_cast<int>(width_)) {
spdlog::warn(MIN_WIDTH_MSG, width_, ev->width);
}
} else {
if (height_ > 1 && ev->height > static_cast<int>(height_)) {
spdlog::warn(MIN_HEIGHT_MSG, height_, ev->height);
}
}
width_ = ev->width;
height_ = ev->height;
configureGlobalOffset(ev->width, ev->height);
spdlog::info(BAR_SIZE_MSG, ev->width, ev->height, output->name);
}
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)
switch (position) {
case Gtk::POS_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;
break;
case Gtk::POS_LEFT:
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)
if (height + margins_.top + margins_.bottom >= monitor_geometry.height)
y = margins_.top;
else
y = (monitor_geometry.height - height) / 2;
break;
case Gtk::POS_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;
break;
default: /* Gtk::POS_TOP */
if (width + margins_.left + margins_.right >= monitor_geometry.width)
x = margins_.left;
else
x = (monitor_geometry.width - width) / 2;
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;
break;
}
x_global = x + monitor_geometry.x;

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