Merge remote-tracking branch 'upstream/master' into connected-no-internet

pull/2372/head
Absobel 2024-03-06 17:32:34 +01:00
commit 30763ea5de
206 changed files with 8415 additions and 3245 deletions

29
.clang-tidy 100644
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 100644
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)"

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

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,28 +2,35 @@ name: freebsd
on: [push, pull_request] on: [push, pull_request]
concurrency:
group: ${{ github.workflow }}-freebsd-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs: jobs:
clang: 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/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: ubuntu-latest
runs-on: macos-12
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- name: Test in FreeBSD VM - name: Test in FreeBSD VM
uses: vmactions/freebsd-vm@v0 uses: cross-platform-actions/action@v0.23.0
timeout-minutes: 180
env:
CPPFLAGS: '-isystem/usr/local/include'
LDFLAGS: '-L/usr/local/lib'
with: with:
mem: 2048 operating_system: freebsd
usesh: true version: "13.2"
prepare: | environment_variables: CPPFLAGS LDFLAGS
export CPPFLAGS=-isystem/usr/local/include LDFLAGS=-L/usr/local/lib # sndio sync_files: runner-to-vm
sed -i '' 's/quarterly/latest/' /etc/pkg/FreeBSD.conf run: |
pkg install -y git # subprojects/date sudo sed -i '' 's/quarterly/latest/' /etc/pkg/FreeBSD.conf
pkg install -y catch evdev-proto gtk-layer-shell gtkmm30 jsoncpp \ sudo pkg install -y git # subprojects/date
sudo pkg install -y catch evdev-proto gtk-layer-shell gtkmm30 jsoncpp \
libdbusmenu libevdev libfmt libmpdclient libudev-devd meson \ libdbusmenu libevdev libfmt libmpdclient libudev-devd meson \
pkgconf pulseaudio scdoc sndio spdlog wayland-protocols upower \ pkgconf pulseaudio scdoc sndio spdlog wayland-protocols upower \
libinotify libinotify
run: |
meson build -Dman-pages=enabled meson build -Dman-pages=enabled
ninja -C build ninja -C build
meson test -C build --no-rebuild --print-errorlogs --suite waybar meson test -C build --no-rebuild --print-errorlogs --suite waybar

19
.github/workflows/labeler.yml vendored 100644
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.13
with:
source: '.'
extensions: 'h,cpp,c'
clangFormatVersion: 12

View File

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

4
.gitignore vendored
View File

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

View File

@ -2,6 +2,48 @@
FROM debian:sid FROM debian:sid
RUN apt-get update && \ RUN apt 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 install --no-install-recommends --no-install-suggests -y \
apt-get clean 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) # 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> > Highly customizable Wayland bar for Sway and Wlroots based compositors.<br>
> Available in Arch [community](https://www.archlinux.org/packages/extra/x86_64/waybar/) or > Available in [all major distributions](https://github.com/Alexays/Waybar/wiki/Installation)<br>
[AUR](https://aur.archlinux.org/packages/waybar-git/), [Gentoo](https://packages.gentoo.org/packages/gui-apps/waybar), [openSUSE](https://build.opensuse.org/package/show/X11:Wayland/waybar), and [Alpine Linux](https://pkgs.alpinelinux.org/packages?name=waybar).<br>
> *Waybar [examples](https://github.com/Alexays/Waybar/wiki/Examples)* > *Waybar [examples](https://github.com/Alexays/Waybar/wiki/Examples)*
#### Current features #### Current features
- Sway (Workspaces, Binding mode, Focused window name) - Sway (Workspaces, Binding mode, Focused window name)
- River (Mapping mode, Tags, Focused window name) - 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) - DWL (Tags) [requires dwl ipc patch](https://github.com/djpohly/dwl/wiki/ipc)
- Tray [#21](https://github.com/Alexays/Waybar/issues/21) - Tray [#21](https://github.com/Alexays/Waybar/issues/21)
- Local time - Local time
- Battery - Battery
- UPower - UPower
- Power profiles daemon
- Network - Network
- Bluetooth - Bluetooth
- Pulseaudio - Pulseaudio
- Privacy Info
- Wireplumber - Wireplumber
- Disk - Disk
- Memory - Memory

View File

@ -1,32 +1,13 @@
{ {
"nodes": { "nodes": {
"devshell": {
"inputs": {
"flake-utils": "flake-utils",
"nixpkgs": "nixpkgs"
},
"locked": {
"lastModified": 1676293499,
"narHash": "sha256-uIOTlTxvrXxpKeTvwBI1JGDGtCxMXE3BI0LFwoQMhiQ=",
"owner": "numtide",
"repo": "devshell",
"rev": "71e3022e3ab20bbf1342640547ef5bc14fb43bf4",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "devshell",
"type": "github"
}
},
"flake-compat": { "flake-compat": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1673956053, "lastModified": 1696426674,
"narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=", "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
"owner": "edolstra", "owner": "edolstra",
"repo": "flake-compat", "repo": "flake-compat",
"rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9", "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -35,59 +16,13 @@
"type": "github" "type": "github"
} }
}, },
"flake-utils": {
"locked": {
"lastModified": 1642700792,
"narHash": "sha256-XqHrk7hFb+zBvRg6Ghl+AZDq03ov6OshJLiSWOoX5es=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "846b2ae0fc4cc943637d3d1def4454213e203cba",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"flake-utils_2": {
"locked": {
"lastModified": 1676283394,
"narHash": "sha256-XX2f9c3iySLCw54rJ/CZs+ZK6IQy7GXNY4nSOyu2QG4=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "3db36a8b464d0c4532ba1c7dda728f4576d6d073",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1643381941, "lastModified": 1704538339,
"narHash": "sha256-pHTwvnN4tTsEKkWlXQ8JMY423epos8wUOhthpwJjtpc=", "narHash": "sha256-1734d3mQuux9ySvwf6axRWZRBhtcZA9Q8eftD6EZg6U=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "5efc8ca954272c4376ac929f4c5ffefcc20551d5", "rev": "46ae0210ce163b3cba6c7da08840c1d63de9c701",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixpkgs-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_2": {
"locked": {
"lastModified": 1676300157,
"narHash": "sha256-1HjRzfp6LOLfcj/HJHdVKWAkX9QRAouoh6AjzJiIerU=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "545c7a31e5dedea4a6d372712a18e00ce097d462",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -99,10 +34,8 @@
}, },
"root": { "root": {
"inputs": { "inputs": {
"devshell": "devshell",
"flake-compat": "flake-compat", "flake-compat": "flake-compat",
"flake-utils": "flake-utils_2", "nixpkgs": "nixpkgs"
"nixpkgs": "nixpkgs_2"
} }
} }
}, },

104
flake.nix
View File

@ -1,27 +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 = { inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
devshell.url = "github:numtide/devshell";
flake-utils.url = "github:numtide/flake-utils";
flake-compat = { flake-compat = {
url = "github:edolstra/flake-compat"; url = "github:edolstra/flake-compat";
flake = false; flake = false;
}; };
}; };
outputs = { self, flake-utils, devshell, nixpkgs, flake-compat }: outputs = { self, nixpkgs, ... }:
let let
inherit (nixpkgs) lib; inherit (nixpkgs) lib;
genSystems = lib.genAttrs [ genSystems = func: lib.genAttrs [
"x86_64-linux" "x86_64-linux"
]; "aarch64-linux"
]
pkgsFor = genSystems (system: (system: func (import nixpkgs { inherit system; }));
import nixpkgs {
inherit system;
});
mkDate = longDate: (lib.concatStringsSep "-" [ mkDate = longDate: (lib.concatStringsSep "-" [
(builtins.substring 0 4 longDate) (builtins.substring 0 4 longDate)
@ -30,64 +25,43 @@
]); ]);
in in
{ {
overlays.default = _: prev: { devShells = genSystems
waybar = prev.callPackage ./nix/default.nix { (pkgs:
version = prev.waybar.version + "+date=" + (mkDate (self.lastModifiedDate or "19700101")) + "_" + (self.shortRev or "dirty");
};
};
packages = genSystems
(system:
(self.overlays.default null pkgsFor.${system})
// {
default = self.packages.${system}.waybar;
});
} //
flake-utils.lib.eachDefaultSystem (system: {
devShell =
let pkgs = import nixpkgs {
inherit system;
overlays = [ devshell.overlay ];
};
in
pkgs.devshell.mkShell {
imports = [ "${pkgs.devshell.extraModulesDir}/language/c.nix" ];
commands = [
{ {
package = pkgs.devshell.cli; default =
help = "Per project developer environments"; pkgs.mkShell
} {
]; name = "waybar-shell";
devshell.packages = with pkgs; [
# 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 clang-tools
gdb 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"; }
];
}; };
}); });
overlays.default = final: prev: {
waybar = final.callPackage ./nix/default.nix {
# 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 (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 { class AModule : public IModule {
public: public:
static constexpr const char *MODULE_CLASS = "module";
virtual ~AModule(); virtual ~AModule();
auto update() -> void override; auto update() -> void override;
virtual auto refresh(int) -> void{}; virtual auto refresh(int) -> void{};
operator Gtk::Widget &() override; operator Gtk::Widget &() override;
auto doAction(const std::string &name) -> void override; auto doAction(const std::string &name) -> void override;
/// Emitting on this dispatcher triggers a update() call
Glib::Dispatcher dp; Glib::Dispatcher dp;
protected: protected:
@ -36,26 +39,34 @@ class AModule : public IModule {
virtual bool handleToggle(GdkEventButton *const &ev); virtual bool handleToggle(GdkEventButton *const &ev);
virtual bool handleScroll(GdkEventScroll *); virtual bool handleScroll(GdkEventScroll *);
virtual bool handleRelease(GdkEventButton *const &ev);
private: private:
bool handleUserEvent(GdkEventButton *const &ev);
const bool isTooltip;
std::vector<int> pid_; std::vector<int> pid_;
gdouble distance_scrolled_y_; gdouble distance_scrolled_y_;
gdouble distance_scrolled_x_; gdouble distance_scrolled_x_;
std::map<std::string, std::string> eventActionMap_; std::map<std::string, std::string> eventActionMap_;
static const inline std::map<std::pair<uint, GdkEventType>, std::string> eventMap_{ static const inline std::map<std::pair<uint, GdkEventType>, std::string> eventMap_{
{std::make_pair(1, GdkEventType::GDK_BUTTON_PRESS), "on-click"}, {std::make_pair(1, GdkEventType::GDK_BUTTON_PRESS), "on-click"},
{std::make_pair(1, GdkEventType::GDK_BUTTON_RELEASE), "on-click-release"},
{std::make_pair(1, GdkEventType::GDK_2BUTTON_PRESS), "on-double-click"}, {std::make_pair(1, GdkEventType::GDK_2BUTTON_PRESS), "on-double-click"},
{std::make_pair(1, GdkEventType::GDK_3BUTTON_PRESS), "on-triple-click"}, {std::make_pair(1, GdkEventType::GDK_3BUTTON_PRESS), "on-triple-click"},
{std::make_pair(2, GdkEventType::GDK_BUTTON_PRESS), "on-click-middle"}, {std::make_pair(2, GdkEventType::GDK_BUTTON_PRESS), "on-click-middle"},
{std::make_pair(2, GdkEventType::GDK_BUTTON_RELEASE), "on-click-middle-release"},
{std::make_pair(2, GdkEventType::GDK_2BUTTON_PRESS), "on-double-click-middle"}, {std::make_pair(2, GdkEventType::GDK_2BUTTON_PRESS), "on-double-click-middle"},
{std::make_pair(2, GdkEventType::GDK_3BUTTON_PRESS), "on-triple-click-middle"}, {std::make_pair(2, GdkEventType::GDK_3BUTTON_PRESS), "on-triple-click-middle"},
{std::make_pair(3, GdkEventType::GDK_BUTTON_PRESS), "on-click-right"}, {std::make_pair(3, GdkEventType::GDK_BUTTON_PRESS), "on-click-right"},
{std::make_pair(3, GdkEventType::GDK_BUTTON_RELEASE), "on-click-right-release"},
{std::make_pair(3, GdkEventType::GDK_2BUTTON_PRESS), "on-double-click-right"}, {std::make_pair(3, GdkEventType::GDK_2BUTTON_PRESS), "on-double-click-right"},
{std::make_pair(3, GdkEventType::GDK_3BUTTON_PRESS), "on-triple-click-right"}, {std::make_pair(3, GdkEventType::GDK_3BUTTON_PRESS), "on-triple-click-right"},
{std::make_pair(8, GdkEventType::GDK_BUTTON_PRESS), "on-click-backward"}, {std::make_pair(8, GdkEventType::GDK_BUTTON_PRESS), "on-click-backward"},
{std::make_pair(8, GdkEventType::GDK_BUTTON_RELEASE), "on-click-backward-release"},
{std::make_pair(8, GdkEventType::GDK_2BUTTON_PRESS), "on-double-click-backward"}, {std::make_pair(8, GdkEventType::GDK_2BUTTON_PRESS), "on-double-click-backward"},
{std::make_pair(8, GdkEventType::GDK_3BUTTON_PRESS), "on-triple-click-backward"}, {std::make_pair(8, GdkEventType::GDK_3BUTTON_PRESS), "on-triple-click-backward"},
{std::make_pair(9, GdkEventType::GDK_BUTTON_PRESS), "on-click-forward"}, {std::make_pair(9, GdkEventType::GDK_BUTTON_PRESS), "on-click-forward"},
{std::make_pair(9, GdkEventType::GDK_BUTTON_RELEASE), "on-click-forward-release"},
{std::make_pair(9, GdkEventType::GDK_2BUTTON_PRESS), "on-double-click-forward"}, {std::make_pair(9, GdkEventType::GDK_2BUTTON_PRESS), "on-double-click-forward"},
{std::make_pair(9, GdkEventType::GDK_3BUTTON_PRESS), "on-triple-click-forward"}}; {std::make_pair(9, GdkEventType::GDK_3BUTTON_PRESS), "on-triple-click-forward"}};
}; };

View File

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

View File

@ -12,6 +12,7 @@
#include <vector> #include <vector>
#include "AModule.hpp" #include "AModule.hpp"
#include "group.hpp"
#include "xdg-output-unstable-v1-client-protocol.h" #include "xdg-output-unstable-v1-client-protocol.h"
namespace waybar { namespace waybar {
@ -52,34 +53,18 @@ class BarIpcClient;
} }
#endif // HAVE_SWAY #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 { class Bar {
public: 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 bar_mode_map PRESET_MODES;
static const std::string_view MODE_DEFAULT; static const std::string MODE_DEFAULT;
static const std::string_view MODE_INVISIBLE; static const std::string MODE_INVISIBLE;
Bar(struct waybar_output *w_output, const Json::Value &); Bar(struct waybar_output *w_output, const Json::Value &);
Bar(const Bar &) = delete; Bar(const Bar &) = delete;
~Bar(); ~Bar();
void setMode(const std::string_view &); void setMode(const std::string &mode);
void setVisible(bool visible); void setVisible(bool visible);
void toggle(); void toggle();
void handleSignal(int); void handleSignal(int);
@ -88,8 +73,12 @@ class Bar {
Json::Value config; Json::Value config;
struct wl_surface *surface; struct wl_surface *surface;
bool visible = true; bool visible = true;
bool vertical = false;
Gtk::Window window; Gtk::Window window;
Gtk::Orientation orientation = Gtk::ORIENTATION_HORIZONTAL;
Gtk::PositionType position = Gtk::POS_TOP;
int x_global;
int y_global;
#ifdef HAVE_SWAY #ifdef HAVE_SWAY
std::string bar_id; std::string bar_id;
@ -98,16 +87,24 @@ class Bar {
private: private:
void onMap(GdkEventAny *); void onMap(GdkEventAny *);
auto setupWidgets() -> void; auto setupWidgets() -> void;
void getModules(const Factory &, const std::string &, Gtk::Box *); void getModules(const Factory &, const std::string &, waybar::Group *);
void setupAltFormatKeyForModule(const std::string &module_name); void setupAltFormatKeyForModule(const std::string &module_name);
void setupAltFormatKeyForModuleList(const char *module_list_name); void setupAltFormatKeyForModuleList(const char *module_list_name);
void setMode(const bar_mode &); 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();
/* Copy initial set of modes to allow customization */ /* Copy initial set of modes to allow customization */
bar_mode_map configured_modes = PRESET_MODES; bar_mode_map configured_modes = PRESET_MODES;
std::string last_mode_{MODE_DEFAULT}; std::string last_mode_{MODE_DEFAULT};
std::unique_ptr<BarSurface> surface_impl_; struct bar_margins margins_;
uint32_t width_, height_;
bool passthrough_;
Gtk::Box left_; Gtk::Box left_;
Gtk::Box center_; Gtk::Box center_;
Gtk::Box right_; Gtk::Box right_;

View File

@ -7,8 +7,9 @@
#include "bar.hpp" #include "bar.hpp"
#include "config.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_inhibitor_v1;
struct zwp_idle_inhibit_manager_v1; struct zwp_idle_inhibit_manager_v1;
@ -24,7 +25,6 @@ class Client {
Glib::RefPtr<Gdk::Display> gdk_display; Glib::RefPtr<Gdk::Display> gdk_display;
struct wl_display *wl_display = nullptr; struct wl_display *wl_display = nullptr;
struct wl_registry *registry = nullptr; struct wl_registry *registry = nullptr;
struct zwlr_layer_shell_v1 *layer_shell = nullptr;
struct zxdg_output_manager_v1 *xdg_output_manager = nullptr; struct zxdg_output_manager_v1 *xdg_output_manager = nullptr;
struct zwp_idle_inhibit_manager_v1 *idle_inhibit_manager = nullptr; struct zwp_idle_inhibit_manager_v1 *idle_inhibit_manager = nullptr;
std::vector<std::unique_ptr<Bar>> bars; std::vector<std::unique_ptr<Bar>> bars;
@ -33,7 +33,7 @@ class Client {
private: private:
Client() = default; Client() = default;
const std::string getStyle(const std::string &style); const std::string getStyle(const std::string &style, std::optional<Appearance> appearance);
void bindInterfaces(); void bindInterfaces();
void handleOutput(struct waybar_output &output); void handleOutput(struct waybar_output &output);
auto setupCss(const std::string &css_file) -> void; auto setupCss(const std::string &css_file) -> void;
@ -52,7 +52,10 @@ class Client {
Glib::RefPtr<Gtk::StyleContext> style_context_; Glib::RefPtr<Gtk::StyleContext> style_context_;
Glib::RefPtr<Gtk::CssProvider> css_provider_; Glib::RefPtr<Gtk::CssProvider> css_provider_;
std::unique_ptr<Portal> portal;
std::list<struct waybar_output> outputs_; std::list<struct waybar_output> outputs_;
std::unique_ptr<CssReloadHelper> m_cssReloadHelper;
std::string m_cssFile;
}; };
} // namespace waybar } // namespace waybar

View File

@ -1,104 +1,17 @@
#pragma once #pragma once
#include <json/json.h> #include <json/json.h>
#if defined(HAVE_CHRONO_TIMEZONES) || defined(HAVE_LIBDATE)
#include "modules/clock.hpp" #include <AModule.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"
#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"
namespace waybar { namespace waybar {
class Bar;
class Factory { class Factory {
public: public:
Factory(const Bar& bar, const Json::Value& config); 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: private:
const Bar& bar_; const Bar& bar_;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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 { namespace waybar::modules {
const std::string kCalendarPlaceholder = "calendar"; const std::string kCldPlaceholder{"calendar"};
const std::string KTimezonedTimeListPlaceholder = "timezoned_time_list"; const std::string kTZPlaceholder{"tz_list"};
const std::string kOrdPlaceholder{"ordinal_date"};
enum class WeeksSide {
LEFT,
RIGHT,
HIDDEN,
};
enum class CldMode { MONTH, YEAR }; enum class CldMode { MONTH, YEAR };
enum class WS { LEFT, RIGHT, HIDDEN };
class Clock final : public ALabel { class Clock final : public ALabel {
public: public:
Clock(const std::string&, const Json::Value&); Clock(const std::string&, const Json::Value&);
virtual ~Clock() = default; virtual ~Clock() = default;
auto update() -> void override; auto update() -> void override;
auto doAction(const std::string& name) -> void override; auto doAction(const std::string&) -> void override;
private: private:
util::SleeperThread thread_; const std::locale locale_;
std::locale locale_; // tooltip
std::vector<const date::time_zone*> time_zones_; const std::string tlpFmt_;
int current_time_zone_idx_; std::string tlpText_{""}; // tooltip text to print
bool is_calendar_in_tooltip_; // Calendar
bool is_timezoned_list_in_tooltip_; const bool cldInTooltip_; // calendar 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};
/* /*
0 - calendar.format.months 0 - calendar.format.months
1 - calendar.format.weekdays 1 - calendar.format.weekdays
@ -47,29 +36,41 @@ class Clock final : public ALabel {
5 - tooltip-format 5 - tooltip-format
*/ */
std::map<int, std::string const> fmtMap_; 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}; CldMode cldMode_{CldMode::MONTH};
uint cldMonCols_{3}; // Count of the month in the row auto get_calendar(const year_month_day& today, const year_month_day& ymd, const time_zone* tz)
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; -> const std::string;
/*Clock actions*/
// 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 cldModeSwitch();
void cldShift_up(); void cldShift_up();
void cldShift_down(); void cldShift_down();
void tz_up(); void tz_up();
void tz_down(); void tz_down();
// Module Action Map // Module Action Map
static inline std::map<const std::string, void (waybar::modules::Clock::*const)()> actionMap_{ static inline std::map<const std::string, void (waybar::modules::Clock::*const)()> actionMap_{
{"mode", &waybar::modules::Clock::cldModeSwitch}, {"mode", &waybar::modules::Clock::cldModeSwitch},
@ -78,4 +79,5 @@ class Clock final : public ALabel {
{"tz_up", &waybar::modules::Clock::tz_up}, {"tz_up", &waybar::modules::Clock::tz_up},
{"tz_down", &waybar::modules::Clock::tz_down}}; {"tz_down", &waybar::modules::Clock::tz_down}};
}; };
} // namespace waybar::modules } // namespace waybar::modules

View File

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

View File

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

View File

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

View File

@ -14,7 +14,7 @@ namespace waybar::modules {
class Custom : public ALabel { class Custom : public ALabel {
public: 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(); virtual ~Custom();
auto update() -> void override; auto update() -> void override;
void refresh(int /*signal*/) override; void refresh(int /*signal*/) override;
@ -22,6 +22,7 @@ class Custom : public ALabel {
private: private:
void delayWorker(); void delayWorker();
void continuousWorker(); void continuousWorker();
void waitingWorker();
void parseOutputRaw(); void parseOutputRaw();
void parseOutputJson(); void parseOutputJson();
void handleEvent(); void handleEvent();
@ -29,6 +30,7 @@ class Custom : public ALabel {
bool handleToggle(GdkEventButton* const& e) override; bool handleToggle(GdkEventButton* const& e) override;
const std::string name_; const std::string name_;
const std::string output_name_;
std::string text_; std::string text_;
std::string id_; std::string id_;
std::string alt_; std::string alt_;

View File

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

View File

@ -1,10 +1,10 @@
#pragma once #pragma once
#include <functional>
#include <list> #include <list>
#include <memory> #include <memory>
#include <mutex> #include <mutex>
#include <string> #include <string>
#include <thread> #include <utility>
#include "util/json.hpp" #include "util/json.hpp"
@ -20,19 +20,19 @@ class IPC {
public: public:
IPC() { startIPC(); } IPC() { startIPC(); }
void registerForIPC(const std::string&, EventHandler*); void registerForIPC(const std::string& ev, EventHandler* ev_handler);
void unregisterForIPC(EventHandler*); 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); Json::Value getSocket1JsonReply(const std::string& rq);
private: private:
void startIPC(); void startIPC();
void parseIPC(const std::string&); void parseIPC(const std::string&);
std::mutex callbackMutex; std::mutex callbackMutex_;
util::JsonParser parser_; 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; inline std::unique_ptr<IPC> gIPC;

View File

@ -1,5 +1,9 @@
#pragma once
#include <fmt/format.h> #include <fmt/format.h>
#include <string>
#include "ALabel.hpp" #include "ALabel.hpp"
#include "bar.hpp" #include "bar.hpp"
#include "modules/hyprland/backend.hpp" #include "modules/hyprland/backend.hpp"
@ -26,7 +30,7 @@ class Language : public waybar::ALabel, public EventHandler {
std::string short_description; std::string short_description;
}; };
auto getLayout(const std::string&) -> Layout; static auto getLayout(const std::string&) -> Layout;
std::mutex mutex_; std::mutex mutex_;
const Bar& bar_; const Bar& bar_;

View File

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

View File

@ -1,5 +1,9 @@
#pragma once
#include <fmt/format.h> #include <fmt/format.h>
#include <string>
#include "AAppIconLabel.hpp" #include "AAppIconLabel.hpp"
#include "bar.hpp" #include "bar.hpp"
#include "modules/hyprland/backend.hpp" #include "modules/hyprland/backend.hpp"
@ -10,7 +14,7 @@ namespace waybar::modules::hyprland {
class Window : public waybar::AAppIconLabel, public EventHandler { class Window : public waybar::AAppIconLabel, public EventHandler {
public: public:
Window(const std::string&, const waybar::Bar&, const Json::Value&); Window(const std::string&, const waybar::Bar&, const Json::Value&);
virtual ~Window(); ~Window() override;
auto update() -> void override; auto update() -> void override;
@ -21,7 +25,7 @@ class Window : public waybar::AAppIconLabel, public EventHandler {
std::string last_window; std::string last_window;
std::string last_window_title; std::string last_window_title;
static auto parse(const Json::Value&) -> Workspace; static auto parse(const Json::Value& value) -> Workspace;
}; };
struct WindowData { struct WindowData {
@ -37,24 +41,25 @@ class Window : public waybar::AAppIconLabel, public EventHandler {
static auto parse(const Json::Value&) -> WindowData; static auto parse(const Json::Value&) -> WindowData;
}; };
auto getActiveWorkspace(const std::string&) -> Workspace; static auto getActiveWorkspace(const std::string&) -> Workspace;
auto getActiveWorkspace() -> Workspace; static auto getActiveWorkspace() -> Workspace;
void onEvent(const std::string&) override; void onEvent(const std::string& ev) override;
void queryActiveWorkspace(); void queryActiveWorkspace();
void setClass(const std::string&, bool enable); void setClass(const std::string&, bool enable);
bool separate_outputs; bool separateOutputs_;
std::mutex mutex_; std::mutex mutex_;
const Bar& bar_; const Bar& bar_;
util::JsonParser parser_; util::JsonParser parser_;
WindowData window_data_; WindowData windowData_;
Workspace workspace_; Workspace workspace_;
std::string solo_class_; std::string soloClass_;
std::string last_solo_class_; std::string lastSoloClass_;
bool solo_; bool solo_;
bool all_floating_; bool allFloating_;
bool swallowing_; bool swallowing_;
bool fullscreen_; bool fullscreen_;
bool focused_;
}; };
} // namespace waybar::modules::hyprland } // namespace waybar::modules::hyprland

View File

@ -1,47 +1,119 @@
#pragma once
#include <gtkmm/button.h> #include <gtkmm/button.h>
#include <gtkmm/label.h> #include <gtkmm/label.h>
#include <json/value.h>
#include <cstddef>
#include <cstdint>
#include <map>
#include <memory> #include <memory>
#include <optional>
#include <regex>
#include <string>
#include <variant>
#include <vector>
#include "AModule.hpp" #include "AModule.hpp"
#include "bar.hpp" #include "bar.hpp"
#include "modules/hyprland/backend.hpp" #include "modules/hyprland/backend.hpp"
#include "util/enum.hpp"
#include "util/regex_collection.hpp"
using WindowAddress = std::string;
namespace waybar::modules::hyprland { namespace waybar::modules::hyprland {
class Workspaces;
class WindowCreationPayload {
public:
WindowCreationPayload(std::string workspace_name, WindowAddress window_address,
std::string window_repr);
WindowCreationPayload(std::string workspace_name, WindowAddress window_address,
std::string window_class, std::string window_title);
WindowCreationPayload(Json::Value const& client_data);
int incrementTimeSpentUncreated();
bool isEmpty(Workspaces& workspace_manager);
bool reprIsReady() const { return std::holds_alternative<Repr>(m_window); }
std::string repr(Workspaces& workspace_manager);
std::string getWorkspaceName() const { return m_workspaceName; }
WindowAddress getAddress() const { return m_windowAddress; }
void moveToWorksace(std::string& new_workspace_name);
private:
void clearAddr();
void clearWorkspaceName();
using Repr = std::string;
using ClassAndTitle = std::pair<std::string, std::string>;
std::variant<Repr, ClassAndTitle> m_window;
WindowAddress m_windowAddress;
std::string m_workspaceName;
int m_timeSpentUncreated = 0;
};
class Workspace { class Workspace {
public: public:
Workspace(const Json::Value& workspace_data); explicit Workspace(const Json::Value& workspace_data, Workspaces& workspace_manager,
std::string& select_icon(std::map<std::string, std::string>& icons_map); const Json::Value& clients_data = Json::Value::nullRef);
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_; }; int id() const { return m_id; };
std::string name() const { return name_; }; std::string name() const { return m_name; };
std::string output() const { return output_; }; std::string output() const { return m_output; };
bool active() const { return active_; }; bool isActive() const { return m_isActive; };
bool is_special() const { return is_special_; }; bool isSpecial() const { return m_isSpecial; };
bool is_persistent() const { return is_persistent_; }; bool isPersistent() const { return m_isPersistentRule || m_isPersistentConfig; };
bool is_empty() const { return windows_ == 0; }; 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; };
auto handle_clicked(GdkEventButton* bt) -> bool; bool handleClicked(GdkEventButton* bt) const;
void set_active(bool value = true) { active_ = value; }; void setActive(bool value = true) { m_isActive = value; };
void set_persistent(bool value = true) { is_persistent_ = value; }; void setPersistentRule(bool value = true) { m_isPersistentRule = value; };
void set_windows(uint value) { windows_ = 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 onWindowOpened(WindowCreationPayload const& create_window_paylod);
std::optional<std::string> closeWindow(WindowAddress const& addr);
void update(const std::string& format, const std::string& icon); void update(const std::string& format, const std::string& icon);
private: private:
int id_; Workspaces& m_workspaceManager;
std::string name_;
std::string output_;
uint windows_;
bool active_ = false;
bool is_special_ = false;
bool is_persistent_ = false;
Gtk::Button button_; int m_id;
Gtk::Box content_; std::string m_name;
Gtk::Label label_; 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> m_windowMap;
Gtk::Button m_button;
Gtk::Box m_content;
Gtk::Label m_label;
}; };
class Workspaces : public AModule, public EventHandler { class Workspaces : public AModule, public EventHandler {
@ -51,37 +123,101 @@ class Workspaces : public AModule, public EventHandler {
void update() override; void update() override;
void init(); void init();
auto all_outputs() const -> bool { return all_outputs_; } auto allOutputs() const -> bool { return m_allOutputs; }
auto show_special() const -> bool { return show_special_; } 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 getRewrite(std::string window_class, std::string window_title);
std::string& getWindowSeparator() { return m_formatWindowSeparator; }
bool isWorkspaceIgnored(std::string const& workspace_name);
bool windowRewriteConfigUsesTitle() const { return m_anyWindowRewriteRuleUsesTitle; }
private: private:
void onEvent(const std::string&) override; void onEvent(const std::string& e) override;
void update_window_count(); void updateWindowCount();
void sort_workspaces(); void sortWorkspaces();
void create_workspace(Json::Value& value); void createWorkspace(Json::Value const& workspaceData,
void remove_workspace(std::string name); 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();
bool all_outputs_ = false; // workspace events
bool show_special_ = false; 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);
void fill_persistent_workspaces(); // monitor events
void create_persistent_workspaces(); void onMonitorFocused(std::string const& payload);
std::vector<std::string> persistent_workspaces_to_create_;
bool persistent_created_ = false;
std::string format_; // window events
std::map<std::string, std::string> icons_map_; void onWindowOpened(std::string const& payload);
bool with_icon_; void onWindowClosed(std::string const& addr);
uint64_t monitor_id_; void onWindowMoved(std::string const& payload);
std::string active_workspace_name_;
std::vector<std::unique_ptr<Workspace>> workspaces_; void onWindowTitleEvent(std::string const& payload);
std::vector<Json::Value> workspaces_to_create_;
std::vector<std::string> workspaces_to_remove_; void onConfigReloaded();
std::mutex mutex_;
const Bar& bar_; int windowRewritePriorityFunction(std::string const& window_rule);
Gtk::Box box_;
void doUpdate();
void extendOrphans(int workspaceId, Json::Value const& clientsJson);
void registerOrphanWindow(WindowCreationPayload create_window_payload);
void initializeWorkspaces();
void setCurrentMonitorId();
void loadPersistentWorkspacesFromConfig(Json::Value const& clientsJson);
void loadPersistentWorkspacesFromWorkspaceRules(const Json::Value& clientsJson);
bool m_allOutputs = false;
bool m_showSpecial = false;
bool m_activeOnly = false;
Json::Value m_persistentWorkspaceConfig;
// 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;
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::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 } // namespace waybar::modules::hyprland

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

@ -12,6 +12,7 @@
#include "client.hpp" #include "client.hpp"
#include "modules/sway/ipc/client.hpp" #include "modules/sway/ipc/client.hpp"
#include "util/json.hpp" #include "util/json.hpp"
#include "util/regex_collection.hpp"
namespace waybar::modules::sway { namespace waybar::modules::sway {
@ -27,10 +28,13 @@ class Workspaces : public AModule, public sigc::trackable {
R"(workspace {} "{}"; move workspace to output "{}"; workspace {} "{}")"; R"(workspace {} "{}"; move workspace to output "{}"; workspace {} "{}")";
static int convertWorkspaceNameToNum(std::string name); static int convertWorkspaceNameToNum(std::string name);
static int windowRewritePriorityFunction(std::string const& window_rule);
void onCmd(const struct Ipc::ipc_response&); void onCmd(const struct Ipc::ipc_response&);
void onEvent(const struct Ipc::ipc_response&); void onEvent(const struct Ipc::ipc_response&);
bool filterButtons(); bool filterButtons();
static bool hasFlag(const Json::Value&, const std::string&);
void updateWindows(const Json::Value&, std::string&);
Gtk::Button& addButton(const Json::Value&); Gtk::Button& addButton(const Json::Value&);
void onButtonReady(const Json::Value&, Gtk::Button&); void onButtonReady(const Json::Value&, Gtk::Button&);
std::string getIcon(const std::string&, const Json::Value&); 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> high_priority_named_;
std::vector<std::string> workspaces_order_; std::vector<std::string> workspaces_order_;
Gtk::Box box_; Gtk::Box box_;
std::string m_formatWindowSeperator;
std::string m_windowRewriteDefault;
util::RegexCollection m_windowRewriteRules;
util::JsonParser parser_; util::JsonParser parser_;
std::unordered_map<std::string, Gtk::Button> buttons_; std::unordered_map<std::string, Gtk::Button> buttons_;
std::mutex mutex_; 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; Devices devices;
std::mutex m_Mutex; std::mutex m_Mutex;
UpClient *client; UpClient *client;
UpDevice *displayDevice; UpDevice *displayDevice = nullptr;
guint login1_id; guint login1_id;
GDBusConnection *login1_connection; GDBusConnection *login1_connection;
UPowerTooltip *upower_tooltip; std::unique_ptr<UPowerTooltip> upower_tooltip;
std::string lastStatus; std::string lastStatus;
bool showAltText; bool showAltText;
bool showIcon = true;
bool upowerRunning; bool upowerRunning;
guint upowerWatcher_id; guint upowerWatcher_id;
std::string nativePath_; std::string nativePath_;

View File

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

View File

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

View File

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

View File

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

View File

@ -66,7 +66,7 @@ inline int close(FILE* fp, pid_t pid) {
return stat; 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; if (cmd == "") return nullptr;
int fd[2]; int fd[2];
// Open the pipe with the close-on-exec flag set, so it will not be inherited // 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]); ::close(fd[0]);
dup2(fd[1], 1); dup2(fd[1], 1);
setpgid(child_pid, child_pid); 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); execlp("/bin/sh", "sh", "-c", cmd.c_str(), (char*)0);
exit(0); exit(0);
} else { } else {
@ -118,9 +121,9 @@ inline FILE* open(const std::string& cmd, int& pid) {
return fdopen(fd[0], "r"); 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; int pid;
auto fp = command::open(cmd, pid); auto fp = command::open(cmd, pid, output_name);
if (!fp) return {-1, ""}; if (!fp) return {-1, ""};
auto output = command::read(fp); auto output = command::read(fp);
auto stat = command::close(fp, pid); 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) { inline struct res execNoRead(const std::string& cmd) {
int pid; int pid;
auto fp = command::open(cmd, pid); auto fp = command::open(cmd, pid, "");
if (!fp) return {-1, ""}; if (!fp) return {-1, ""};
auto stat = command::close(fp, pid); auto stat = command::close(fp, pid);
return {WEXITSTATUS(stat), ""}; 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 #pragma once
#include <fmt/format.h> #include <chrono>
#if HAVE_CHRONO_TIMEZONES #if HAVE_CHRONO_TIMEZONES
#include <chrono>
#include <format> #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 #else
#include <date/tz.h> #include <date/tz.h>
#include <fmt/format.h>
#include <regex>
#endif #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> template <typename Duration, typename TimeZonePtr>
struct fmt::formatter<date::zoned_time<Duration, TimeZonePtr>> { struct fmt::formatter<date::zoned_time<Duration, TimeZonePtr>> {
std::string_view specs; 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)); return fmt::format_to(ctx.out(), "{}", date::format(fmt::to_string(specs), ztime));
} }
}; };
#endif
using namespace date;

View File

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

View File

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

View File

@ -3,6 +3,12 @@
#include <fmt/ostream.h> #include <fmt/ostream.h>
#include <json/json.h> #include <json/json.h>
#include <algorithm>
#include <codecvt>
#include <iostream>
#include <locale>
#include <regex>
#if (FMT_VERSION >= 90000) #if (FMT_VERSION >= 90000)
template <> template <>
@ -12,25 +18,30 @@ struct fmt::formatter<Json::Value> : ostream_formatter {};
namespace waybar::util { namespace waybar::util {
struct JsonParser { class JsonParser {
JsonParser() {} public:
JsonParser() = default;
const Json::Value parse(const std::string& data) const { Json::Value parse(const std::string& jsonStr) {
Json::Value root(Json::objectValue); Json::Value root;
if (data.empty()) {
// 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);
}
return root; return root;
} }
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: 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 } // 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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

@ -14,7 +14,7 @@ Addressed by *bluetooth*
*controller*: ++ *controller*: ++
typeof: string ++ typeof: string ++
Use the controller with the defined alias. Otherwise a random controller is used. Recommended to define when there is more than 1 controller available to the system. Use the controller with the defined alias. Otherwise, a random controller is used. Recommended to define when there is more than 1 controller available to the system.
*format-device-preference*: ++ *format-device-preference*: ++
typeof: array ++ typeof: array ++
@ -42,6 +42,10 @@ Addressed by *bluetooth*
typeof: string ++ typeof: string ++
This format is used when the displayed controller is connected to at least 1 device. This format is used when the displayed controller is connected to at least 1 device.
*format-no-controller*: ++
typeof: string ++
This format is used when no bluetooth controller can be found
*format-icons*: ++ *format-icons*: ++
typeof: array/object ++ typeof: array/object ++
Based on the current battery percentage (see section *EXPERIMENTAL BATTERY PERCENTAGE FEATURE*), the corresponding icon gets selected. ++ Based on the current battery percentage (see section *EXPERIMENTAL BATTERY PERCENTAGE FEATURE*), the corresponding icon gets selected. ++
@ -58,11 +62,15 @@ Addressed by *bluetooth*
*min-length*: ++ *min-length*: ++
typeof: integer ++ typeof: integer ++
The minimum length in characters the module should take up. The minimum length in characters the module should accept.
*align*: ++ *align*: ++
typeof: float ++ 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*: ++ *on-click*: ++
typeof: string ++ typeof: string ++
@ -74,7 +82,7 @@ Addressed by *bluetooth*
*on-click-right*: ++ *on-click-right*: ++
typeof: string ++ typeof: string ++
Command to execute when you right clicked on the module. Command to execute when you right-click on the module.
*on-scroll-up*: ++ *on-scroll-up*: ++
typeof: string ++ typeof: string ++
@ -113,6 +121,10 @@ Addressed by *bluetooth*
typeof: string ++ typeof: string ++
This format is used when the displayed controller is connected to at least 1 device. This format is used when the displayed controller is connected to at least 1 device.
*tooltip-format-no-controller*: ++
typeof: string ++
This format is used when no bluetooth controller can be found
*tooltip-format-enumerate-connected*: ++ *tooltip-format-enumerate-connected*: ++
typeof: string ++ typeof: string ++
This format is used to define how each connected device should be displayed within the *device_enumerate* format replacement in the tooltip menu. This format is used to define how each connected device should be displayed within the *device_enumerate* format replacement in the tooltip menu.
@ -138,7 +150,7 @@ Addressed by *bluetooth*
*{device_alias}*: Alias of the displayed device. *{device_alias}*: Alias of the displayed device.
*{device_enumerate}*: Show a list of all connected devices, each on a separate line. Define the format of each device with the *tooltip-format-enumerate-connected* ++ *{device_enumerate}*: Show a list of all connected devices, each on a separate line. Define the format of each device with the *tooltip-format-enumerate-connected* ++
and/or *tooltip-format-enumerate-connected-battery* config options. Can only be used in the tooltip related format options. and/or *tooltip-format-enumerate-connected-battery* config options. Can only be used in the tooltip-related format options.
# EXPERIMENTAL BATTERY PERCENTAGE FEATURE # EXPERIMENTAL BATTERY PERCENTAGE FEATURE

View File

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

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -27,11 +27,15 @@ Addressed by *hyprland/submap*
*min-length*: ++ *min-length*: ++
typeof: integer ++ typeof: integer ++
The minimum length in characters the module should take up. The minimum length in characters the module should accept.
*align*: ++ *align*: ++
typeof: float ++ 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*: ++ *on-click*: ++
typeof: string ++ typeof: string ++
@ -43,7 +47,7 @@ Addressed by *hyprland/submap*
*on-click-right*: ++ *on-click-right*: ++
typeof: string ++ typeof: string ++
Command to execute when you right clicked on the module. Command to execute when you right-click on the module.
*on-update*: ++ *on-update*: ++
typeof: string ++ typeof: string ++
@ -80,3 +84,4 @@ Addressed by *hyprland/submap*
# STYLE # STYLE
- *#submap* - *#submap*
- *#submap.<name>*

View File

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

View File

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

View File

@ -66,7 +66,7 @@ The *image* module displays an image from a path.
# SCRIPT OUTPUT # SCRIPT OUTPUT
Similar to the *custom* module, output values of the script is *newline* separated. Similar to the *custom* module, output values of the script are *newline* separated.
The following is the output format: The following is the output format:
``` ```
@ -87,3 +87,4 @@ $path\\n$tooltip
# STYLE # STYLE
- *#image* - *#image*
- *#image.empty*

View File

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

View File

@ -27,7 +27,7 @@ Addressed by *jack*
*format-xrun*: ++ *format-xrun*: ++
typeof: string ++ typeof: string ++
This format is used for one polling interval, when the JACK server reports an xrun. This format is used for one polling interval when the JACK server reports an xrun.
*realtime*: ++ *realtime*: ++
typeof: bool ++ typeof: bool ++
@ -59,11 +59,15 @@ Addressed by *jack*
*min-length*: ++ *min-length*: ++
typeof: integer ++ typeof: integer ++
The minimum length in characters the module should take up. The minimum length in characters the module should accept.
*align*: ++ *align*: ++
typeof: float ++ 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*: ++ *on-click*: ++
typeof: string ++ typeof: string ++
@ -75,7 +79,7 @@ Addressed by *jack*
*on-click-right*: ++ *on-click-right*: ++
typeof: string ++ typeof: string ++
Command to execute when you right clicked on the module. Command to execute when you right-click on the module.
*on-update*: ++ *on-update*: ++
typeof: string ++ typeof: string ++

View File

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

View File

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

View File

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

View File

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

View File

@ -14,7 +14,7 @@ Addressed by *network*
*interface*: ++ *interface*: ++
typeof: string ++ typeof: string ++
Use the defined interface instead of auto detection. Accepts wildcard. Use the defined interface instead of auto-detection. Accepts wildcard.
*interval*: ++ *interval*: ++
typeof: integer ++ typeof: integer ++
@ -49,7 +49,7 @@ Addressed by *network*
*format-linked*: ++ *format-linked*: ++
typeof: string ++ typeof: string ++
This format is used when a linked interface with no ip address is displayed. This format is used when a linked interface with no IP address is displayed.
*format-disconnected*: ++ *format-disconnected*: ++
typeof: string ++ typeof: string ++
@ -78,11 +78,15 @@ Addressed by *network*
*min-length*: ++ *min-length*: ++
typeof: integer ++ typeof: integer ++
The minimum length in characters the module should take up. The minimum length in characters the module should accept.
*align*: ++ *align*: ++
typeof: float ++ 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*: ++ *on-click*: ++
typeof: string ++ typeof: string ++
@ -94,7 +98,7 @@ Addressed by *network*
*on-click-right*: ++ *on-click-right*: ++
typeof: string ++ typeof: string ++
Command to execute when you right clicked on the module. Command to execute when you right-click on the module.
*on-update*: ++ *on-update*: ++
typeof: string ++ 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": ""
}
}
```

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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