diff --git a/.clang-tidy b/.clang-tidy
index f74eae65..3d4cf260 100644
--- a/.clang-tidy
+++ b/.clang-tidy
@@ -15,15 +15,15 @@ Checks: >
-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 }
+# 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 }
diff --git a/.github/workflows/clang-format.yml b/.github/workflows/clang-format.yml
index 40fd3126..25f62c8e 100644
--- a/.github/workflows/clang-format.yml
+++ b/.github/workflows/clang-format.yml
@@ -7,13 +7,12 @@ concurrency:
cancel-in-progress: true
jobs:
- build:
+ lint:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
- - uses: DoozyX/clang-format-lint-action@v0.16.2
+ - uses: actions/checkout@v6
+ - uses: RafikFarhad/clang-format-github-action@v6
name: clang-format
with:
- source: "."
- extensions: "hpp,h,cpp,c"
- clangFormatVersion: 16
+ sources: "src/**/*.hpp,src/**/*.cpp"
+ style: "file"
diff --git a/.github/workflows/clang-tidy.yml b/.github/workflows/clang-tidy.yml.bak
similarity index 97%
rename from .github/workflows/clang-tidy.yml
rename to .github/workflows/clang-tidy.yml.bak
index a39bd23d..9e9da80c 100644
--- a/.github/workflows/clang-tidy.yml
+++ b/.github/workflows/clang-tidy.yml.bak
@@ -7,12 +7,12 @@ concurrency:
cancel-in-progress: true
jobs:
- build:
+ lint:
runs-on: ubuntu-latest
container:
image: alexays/waybar:debian
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v6
- name: configure
run: |
meson -Dcpp_std=c++20 build # necessary to generate compile_commands.json
diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml
new file mode 100644
index 00000000..ea8eb08b
--- /dev/null
+++ b/.github/workflows/docker.yml
@@ -0,0 +1,34 @@
+name: Build and Push Docker Image
+
+on:
+ workflow_dispatch:
+ schedule:
+ # run monthly
+ - cron: '0 0 1 * *'
+
+jobs:
+ build-and-push:
+ runs-on: ubuntu-latest
+ if: github.event_name != 'schedule' || github.repository == 'Alexays/Waybar'
+ strategy:
+ fail-fast: false # don't fail the other jobs if one of the images fails to build
+ matrix:
+ os: [ 'alpine', 'archlinux', 'debian', 'fedora', 'gentoo', 'opensuse' ]
+
+ steps:
+ - name: Checkout repository
+ - uses: actions/checkout@v6
+
+ - name: Login to Docker Hub
+ uses: docker/login-action@v3
+ with:
+ username: ${{ secrets.DOCKERHUB_USERNAME }}
+ password: ${{ secrets.DOCKERHUB_TOKEN }}
+
+ - name: Build and push Docker image
+ uses: docker/build-push-action@v5
+ with:
+ context: .
+ file: Dockerfiles/${{ matrix.os }}
+ push: true
+ tags: alexays/waybar:${{ matrix.os }}
diff --git a/.github/workflows/freebsd.yml b/.github/workflows/freebsd.yml
index 7b27fdb6..f6c96f95 100644
--- a/.github/workflows/freebsd.yml
+++ b/.github/workflows/freebsd.yml
@@ -7,30 +7,29 @@ concurrency:
cancel-in-progress: true
jobs:
- clang:
+ build:
# Run actions in a FreeBSD VM on the ubuntu runner
# https://github.com/actions/runner/issues/385 - for FreeBSD runner support
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v6
- name: Test in FreeBSD VM
- uses: cross-platform-actions/action@v0.23.0
+ uses: cross-platform-actions/action@v0.28.0
timeout-minutes: 180
env:
CPPFLAGS: '-isystem/usr/local/include'
- LDFLAGS: '-L/usr/local/lib'
+ LDFLAGS: '-L/usr/local/lib'
with:
operating_system: freebsd
- version: "13.2"
+ version: "14.2"
environment_variables: CPPFLAGS LDFLAGS
sync_files: runner-to-vm
run: |
- sudo sed -i '' 's/quarterly/latest/' /etc/pkg/FreeBSD.conf
sudo pkg install -y git # subprojects/date
sudo pkg install -y catch evdev-proto gtk-layer-shell gtkmm30 jsoncpp \
libdbusmenu libevdev libfmt libmpdclient libudev-devd meson \
- pkgconf pulseaudio scdoc sndio spdlog wayland-protocols upower \
+ pkgconf pipewire pulseaudio scdoc sndio spdlog wayland-protocols upower \
libinotify
- meson build -Dman-pages=enabled
+ meson setup build -Dman-pages=enabled
ninja -C build
meson test -C build --no-rebuild --print-errorlogs --suite waybar
diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml
index dc6b7ede..12a995d7 100644
--- a/.github/workflows/linux.yml
+++ b/.github/workflows/linux.yml
@@ -9,6 +9,7 @@ concurrency:
jobs:
build:
strategy:
+ fail-fast: false
matrix:
distro:
- alpine
@@ -24,9 +25,9 @@ jobs:
image: alexays/waybar:${{ matrix.distro }}
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v6
- name: configure
- run: meson -Dman-pages=enabled -Dcpp_std=${{matrix.cpp_std}} build
+ run: meson setup -Dman-pages=enabled -Dcpp_std=${{matrix.cpp_std}} build
- name: build
run: ninja -C build
- name: test
diff --git a/.github/workflows/nix-tests.yml b/.github/workflows/nix-tests.yml
new file mode 100644
index 00000000..c2193b99
--- /dev/null
+++ b/.github/workflows/nix-tests.yml
@@ -0,0 +1,20 @@
+name: "Nix-Tests"
+on:
+ pull_request:
+ push:
+concurrency:
+ group: ${{ github.workflow }}-nix-${{ github.event.pull_request.number || github.ref }}
+ cancel-in-progress: true
+jobs:
+ nix-flake-check:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v6
+ - uses: cachix/install-nix-action@v31
+ with:
+ extra_nix_config: |
+ experimental-features = nix-command flakes
+ access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
+ - run: nix flake show
+ - run: nix flake check --print-build-logs
+ - run: nix build --print-build-logs
diff --git a/.github/workflows/nix-update-flake-lock.yml b/.github/workflows/nix-update-flake-lock.yml
new file mode 100644
index 00000000..de8a0ea1
--- /dev/null
+++ b/.github/workflows/nix-update-flake-lock.yml
@@ -0,0 +1,22 @@
+name: update-flake-lock
+on:
+ workflow_dispatch: # allows manual triggering
+ schedule:
+ - cron: '0 0 1 * *' # Run monthly
+ push:
+ paths:
+ - 'flake.nix'
+jobs:
+ lockfile:
+ runs-on: ubuntu-latest
+ if: github.event_name != 'schedule' || github.repository == 'Alexays/Waybar'
+ steps:
+ - name: Checkout repository
+ - uses: actions/checkout@v6
+ - name: Install Nix
+ uses: cachix/install-nix-action@v31
+ with:
+ extra_nix_config: |
+ access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
+ - name: Update flake.lock
+ uses: DeterminateSystems/update-flake-lock@v28
diff --git a/.gitignore b/.gitignore
index 68bc0dc4..f21700d6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,6 +7,7 @@ vgcore.*
*.swp
packagecache
/subprojects/**/
+/subprojects/.wraplock
/build*
/dist
/meson.egg-info
@@ -48,3 +49,7 @@ packagecache
# Nix
result
result-*
+
+.ccls-cache
+_codeql_detected_source_root
+heaptrack*
diff --git a/Dockerfiles/archlinux b/Dockerfiles/archlinux
index 73f19067..d4274a46 100644
--- a/Dockerfiles/archlinux
+++ b/Dockerfiles/archlinux
@@ -3,5 +3,5 @@
FROM archlinux:base-devel
RUN pacman -Syu --noconfirm && \
- pacman -S --noconfirm git meson base-devel libinput wayland wayland-protocols pixman libxkbcommon mesa gtkmm3 jsoncpp pugixml scdoc libpulse libdbusmenu-gtk3 libmpdclient gobject-introspection libxkbcommon playerctl iniparser fftw && \
+ pacman -S --noconfirm git meson base-devel libinput wayland wayland-protocols glib2-devel pixman libxkbcommon mesa gtkmm3 jsoncpp pugixml scdoc libpulse libdbusmenu-gtk3 libmpdclient gobject-introspection libxkbcommon playerctl iniparser fftw && \
sed -Ei 's/#(en_(US|GB)\.UTF)/\1/' /etc/locale.gen && locale-gen
diff --git a/Dockerfiles/debian b/Dockerfiles/debian
index 0745935e..c2584ccf 100644
--- a/Dockerfiles/debian
+++ b/Dockerfiles/debian
@@ -1,6 +1,6 @@
# vim: ft=Dockerfile
-FROM debian:sid
+FROM debian:sid-slim
RUN apt update && \
apt install --no-install-recommends --no-install-suggests -y \
@@ -34,7 +34,7 @@ RUN apt update && \
libudev-dev \
libupower-glib-dev \
libwayland-dev \
- libwireplumber-0.4-dev \
+ libwireplumber-0.5-dev \
libxkbcommon-dev \
libxkbregistry-dev \
locales \
diff --git a/Dockerfiles/fedora b/Dockerfiles/fedora
index 5892159c..9dc0337b 100644
--- a/Dockerfiles/fedora
+++ b/Dockerfiles/fedora
@@ -29,6 +29,6 @@ RUN dnf install -y @c-development \
'pkgconfig(wayland-client)' \
'pkgconfig(wayland-cursor)' \
'pkgconfig(wayland-protocols)' \
- 'pkgconfig(wireplumber-0.4)' \
+ 'pkgconfig(wireplumber-0.5)' \
'pkgconfig(xkbregistry)' && \
dnf clean all -y
diff --git a/Dockerfiles/gentoo b/Dockerfiles/gentoo
index f2ec0dc9..f7023825 100644
--- a/Dockerfiles/gentoo
+++ b/Dockerfiles/gentoo
@@ -6,6 +6,6 @@ RUN export FEATURES="-ipc-sandbox -network-sandbox -pid-sandbox -sandbox -usersa
emerge --sync && \
eselect news read --quiet new 1>/dev/null 2>&1 && \
emerge --verbose --update --deep --with-bdeps=y --backtrack=30 --newuse @world && \
- USE="wayland gtk3 gtk -doc X pulseaudio minimal" emerge dev-vcs/git dev-libs/wayland dev-libs/wayland-protocols =dev-cpp/gtkmm-3.24.6 x11-libs/libxkbcommon \
+ USE="wayland gtk3 gtk -doc X pulseaudio minimal" emerge dev-vcs/git dev-libs/wayland dev-libs/wayland-protocols dev-cpp/gtkmm:3.0 x11-libs/libxkbcommon \
x11-libs/gtk+:3 dev-libs/libdbusmenu dev-libs/libnl sys-power/upower media-libs/libpulse dev-libs/libevdev media-libs/libmpdclient \
media-sound/sndio gui-libs/gtk-layer-shell app-text/scdoc media-sound/playerctl dev-libs/iniparser sci-libs/fftw
diff --git a/Dockerfiles/opensuse b/Dockerfiles/opensuse
index bdb42fbf..6ac3e058 100644
--- a/Dockerfiles/opensuse
+++ b/Dockerfiles/opensuse
@@ -6,4 +6,4 @@ RUN zypper -n up && \
zypper addrepo https://download.opensuse.org/repositories/X11:Wayland/openSUSE_Tumbleweed/X11:Wayland.repo | echo 'a' && \
zypper -n refresh && \
zypper -n install -t pattern devel_C_C++ && \
- zypper -n install git meson clang libinput10 libinput-devel pugixml-devel libwayland-client0 libwayland-cursor0 wayland-protocols-devel wayland-devel Mesa-libEGL-devel Mesa-libGLESv2-devel libgbm-devel libxkbcommon-devel libudev-devel libpixman-1-0-devel gtkmm3-devel jsoncpp-devel libxkbregistry-devel scdoc playerctl-devel
+ zypper -n install git meson clang libinput10 libinput-devel pugixml-devel libwayland-client0 libwayland-cursor0 wayland-protocols-devel wayland-devel Mesa-libEGL-devel Mesa-libGLESv2-devel libgbm-devel libxkbcommon-devel libudev-devel libpixman-1-0-devel gtkmm3-devel jsoncpp-devel libxkbregistry-devel scdoc playerctl-devel python3-packaging
diff --git a/LICENSE b/LICENSE
index 41eb81d8..d1bad1b4 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
MIT License
-Copyright (c) 2018 Alex
+Copyright (c) 2025 Alex
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/Makefile b/Makefile
index b1dbfc6e..12af8e0e 100644
--- a/Makefile
+++ b/Makefile
@@ -3,11 +3,11 @@
default: build
build:
- meson build
+ meson setup build
ninja -C build
build-debug:
- meson build --buildtype=debug
+ meson setup build --buildtype=debug
ninja -C build
install: build
@@ -20,8 +20,12 @@ debug-run: build-debug
./build/waybar --log-level debug
test:
- meson test -C build --no-rebuild --verbose --suite waybar
+ meson test -C build --verbose --suite waybar
.PHONY: test
+test-detailed:
+ meson test -C build --verbose --print-errorlogs --test-args='--reporter console -s'
+.PHONY: test-detailed
+
clean:
rm -rf build
diff --git a/README.md b/README.md
index 32fbfa69..687f8234 100644
--- a/README.md
+++ b/README.md
@@ -8,7 +8,9 @@
- Sway (Workspaces, Binding mode, Focused window name)
- River (Mapping mode, Tags, Focused window name)
- Hyprland (Window Icons, Workspaces, Focused window name)
-- DWL (Tags) [requires dwl ipc patch](https://github.com/djpohly/dwl/wiki/ipc)
+- Niri (Workspaces, Focused window name, Language)
+- Mango (Workspaces, Focused window name, Language, Keymode)
+- DWL (Tags, Focused window name) [requires dwl ipc patch](https://codeberg.org/dwl/dwl-patches/src/branch/main/patches/ipc)
- Tray [#21](https://github.com/Alexays/Waybar/issues/21)
- Local time
- Battery
@@ -48,7 +50,7 @@ An Ubuntu PPA with more recent versions is available
```bash
$ git clone https://github.com/Alexays/Waybar
$ cd Waybar
-$ meson build
+$ meson setup build
$ ninja -C build
$ ./build/waybar
# If you want to install it
@@ -115,11 +117,45 @@ sudo apt install \
libxkbregistry-dev
```
+On Arch, you can use this command:
+
+```
+pacman -S --asdeps \
+ gtkmm3 \
+ jsoncpp \
+ libsigc++ \
+ fmt \
+ wayland \
+ chrono-date \
+ spdlog \
+ gtk3 \
+ gobject-introspection \
+ libgirepository \
+ libpulse \
+ libnl \
+ libappindicator-gtk3 \
+ libdbusmenu-gtk3 \
+ libmpdclient \
+ sndio \
+ libevdev \
+ libxkbcommon \
+ upower \
+ meson \
+ cmake \
+ scdoc \
+ wayland-protocols \
+ glib2-devel
+```
+
Contributions welcome!
Have fun :)
The style guidelines are [Google's](https://google.github.io/styleguide/cppguide.html)
+> [!CAUTION]
+> Distributions of Waybar are only released on the [official GitHub page](https://github.com/Alexays/Waybar).
+> Waybar does **not** have an official website. Do not trust any sites that claim to be official.
+
## License
Waybar is licensed under the MIT license. [See LICENSE for more information](https://github.com/Alexays/Waybar/blob/master/LICENSE).
diff --git a/_codeql_detected_source_root b/_codeql_detected_source_root
new file mode 120000
index 00000000..945c9b46
--- /dev/null
+++ b/_codeql_detected_source_root
@@ -0,0 +1 @@
+.
\ No newline at end of file
diff --git a/asan.supp b/asan.supp
new file mode 100644
index 00000000..3633b361
--- /dev/null
+++ b/asan.supp
@@ -0,0 +1,5 @@
+# Suppress common address sanitizer issues in dependencies, these are often non-fixable or not an issue.
+# Use it like this (when in repo root): ASAN_OPTIONS="suppressions=./asan.supp" ./build/waybar
+leak:libpangoft2-1.0.so.0
+leak:libgtk-3.so.0
+leak:libfontconfig.so.1
\ No newline at end of file
diff --git a/default.nix b/default.nix
index 2cccff28..6466507b 100644
--- a/default.nix
+++ b/default.nix
@@ -1,10 +1,9 @@
-(import
- (
- let lock = builtins.fromJSON (builtins.readFile ./flake.lock); in
- fetchTarball {
- url = "https://github.com/edolstra/flake-compat/archive/${lock.nodes.flake-compat.locked.rev}.tar.gz";
- sha256 = lock.nodes.flake-compat.locked.narHash;
- }
- )
- { src = ./.; }
-).defaultNix
+(import (
+ let
+ lock = builtins.fromJSON (builtins.readFile ./flake.lock);
+ in
+ fetchTarball {
+ url = "https://github.com/edolstra/flake-compat/archive/${lock.nodes.flake-compat.locked.rev}.tar.gz";
+ sha256 = lock.nodes.flake-compat.locked.narHash;
+ }
+) { src = ./.; }).defaultNix
diff --git a/flake.lock b/flake.lock
index 25f12644..e3e70a02 100644
--- a/flake.lock
+++ b/flake.lock
@@ -3,11 +3,11 @@
"flake-compat": {
"flake": false,
"locked": {
- "lastModified": 1696426674,
- "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
+ "lastModified": 1767039857,
+ "narHash": "sha256-vNpUSpF5Nuw8xvDLj2KCwwksIbjua2LZCqhV1LNRDns=",
"owner": "edolstra",
"repo": "flake-compat",
- "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
+ "rev": "5edf11c44bc78a0d334f6334cdaf7d60d732daab",
"type": "github"
},
"original": {
@@ -18,11 +18,11 @@
},
"nixpkgs": {
"locked": {
- "lastModified": 1704538339,
- "narHash": "sha256-1734d3mQuux9ySvwf6axRWZRBhtcZA9Q8eftD6EZg6U=",
+ "lastModified": 1769461804,
+ "narHash": "sha256-msG8SU5WsBUfVVa/9RPLaymvi5bI8edTavbIq3vRlhI=",
"owner": "NixOS",
"repo": "nixpkgs",
- "rev": "46ae0210ce163b3cba6c7da08840c1d63de9c701",
+ "rev": "bfc1b8a4574108ceef22f02bafcf6611380c100d",
"type": "github"
},
"original": {
diff --git a/flake.nix b/flake.nix
index ebaeb81f..b2f96731 100644
--- a/flake.nix
+++ b/flake.nix
@@ -9,59 +9,118 @@
};
};
- outputs = { self, nixpkgs, ... }:
+ outputs =
+ { self, nixpkgs, ... }:
let
inherit (nixpkgs) lib;
- genSystems = func: lib.genAttrs [
- "x86_64-linux"
- "aarch64-linux"
- ]
- (system: func (import nixpkgs { inherit system; }));
+ genSystems =
+ func:
+ lib.genAttrs
+ [
+ "x86_64-linux"
+ "aarch64-linux"
+ ]
+ (
+ system:
+ func (
+ import nixpkgs {
+ inherit system;
+ overlays = with self.overlays; [
+ waybar
+ ];
+ }
+ )
+ );
- mkDate = longDate: (lib.concatStringsSep "-" [
- (builtins.substring 0 4 longDate)
- (builtins.substring 4 2 longDate)
- (builtins.substring 6 2 longDate)
- ]);
+ mkDate =
+ longDate:
+ (lib.concatStringsSep "-" [
+ (builtins.substring 0 4 longDate)
+ (builtins.substring 4 2 longDate)
+ (builtins.substring 6 2 longDate)
+ ]);
in
{
- devShells = genSystems
- (pkgs:
- {
- default =
- pkgs.mkShell
- {
- name = "waybar-shell";
+ devShells = genSystems (pkgs: {
+ default = pkgs.mkShell {
+ name = "waybar-shell";
- # inherit attributes from upstream nixpkgs derivation
- inherit (pkgs.waybar) buildInputs depsBuildBuild depsBuildBuildPropagated depsBuildTarget
- depsBuildTargetPropagated depsHostHost depsHostHostPropagated depsTargetTarget
- depsTargetTargetPropagated propagatedBuildInputs propagatedNativeBuildInputs strictDeps;
+ # inherit attributes from upstream nixpkgs derivation
+ inherit (pkgs.waybar)
+ buildInputs
+ depsBuildBuild
+ depsBuildBuildPropagated
+ depsBuildTarget
+ depsBuildTargetPropagated
+ depsHostHost
+ depsHostHostPropagated
+ depsTargetTarget
+ depsTargetTargetPropagated
+ propagatedBuildInputs
+ propagatedNativeBuildInputs
+ strictDeps
+ ;
- # overrides for local development
- nativeBuildInputs = pkgs.waybar.nativeBuildInputs ++ (with pkgs; [
- clang-tools
- gdb
- ]);
- };
- });
+ # overrides for local development
+ nativeBuildInputs =
+ pkgs.waybar.nativeBuildInputs
+ ++ (with pkgs; [
+ nixfmt
+ clang-tools
+ gdb
+ ]);
+ };
+ });
- 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");
+ formatter = genSystems (
+ pkgs:
+ pkgs.treefmt.withConfig {
+ settings = {
+ formatter = {
+ clang-format = {
+ options = [ "-i" ];
+ command = lib.getExe' pkgs.clang-tools "clang-format";
+ excludes = [ ];
+ includes = [
+ "*.c"
+ "*.cpp"
+ "*.h"
+ "*.hpp"
+ ];
+ };
+ nixfmt = {
+ command = lib.getExe pkgs.nixfmt;
+ includes = [ "*.nix" ];
+ };
+ };
+ tree-root-file = ".git/index";
+ };
+ }
+ );
+
+ overlays = {
+ default = self.overlays.waybar;
+ waybar = final: prev: {
+ waybar = final.callPackage ./nix/default.nix {
+ waybar = prev.waybar;
+ # 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;
- });
+ packages = genSystems (pkgs: {
+ default = self.packages.${pkgs.stdenv.hostPlatform.system}.waybar;
+ inherit (pkgs) waybar;
+ });
};
}
diff --git a/include/AAppIconLabel.hpp b/include/AAppIconLabel.hpp
index d09ab14a..e8532e18 100644
--- a/include/AAppIconLabel.hpp
+++ b/include/AAppIconLabel.hpp
@@ -9,15 +9,15 @@ namespace waybar {
class AAppIconLabel : public AIconLabel {
public:
- AAppIconLabel(const Json::Value &config, const std::string &name, const std::string &id,
- const std::string &format, uint16_t interval = 0, bool ellipsize = false,
+ AAppIconLabel(const Json::Value& config, const std::string& name, const std::string& id,
+ const std::string& format, uint16_t interval = 0, bool ellipsize = false,
bool enable_click = false, bool enable_scroll = false);
virtual ~AAppIconLabel() = default;
auto update() -> void override;
protected:
- void updateAppIconName(const std::string &app_identifier,
- const std::string &alternative_app_identifier);
+ void updateAppIconName(const std::string& app_identifier,
+ const std::string& alternative_app_identifier);
void updateAppIcon();
unsigned app_icon_size_{24};
bool update_app_icon_{true};
diff --git a/include/AGraph.hpp b/include/AGraph.hpp
new file mode 100644
index 00000000..e2ada835
--- /dev/null
+++ b/include/AGraph.hpp
@@ -0,0 +1,57 @@
+#pragma once
+
+#include
+#include
+#include
+
+#include
+#include
+
+#include "AModule.hpp"
+
+namespace waybar {
+
+enum class GraphType { LINE, BAR, GAUGE };
+
+class AGraph : public AModule {
+ public:
+ AGraph(const Json::Value&, const std::string&, const std::string&, uint16_t interval = 0,
+ bool enable_click = false, bool enable_scroll = false);
+ virtual ~AGraph() = default;
+ auto update() -> void override;
+
+ protected:
+ Gtk::DrawingArea graph_;
+ std::deque values_;
+ uint16_t datapoints_ = 20;
+ GraphType graph_type_ = GraphType::LINE;
+
+ void addValue(const int n);
+
+ const std::chrono::seconds interval_;
+
+ bool onDraw(const Cairo::RefPtr& cr);
+
+ std::map submenus_;
+ std::map menuActionsMap_;
+ static void handleGtkMenuEvent(GtkMenuItem* menuitem, gpointer data);
+
+ private:
+ void drawFilledArea(const Cairo::RefPtr& cr,
+ const std::vector>& points, double height,
+ const Gdk::RGBA& bg_color);
+
+ void drawLine(const Cairo::RefPtr& cr,
+ const std::vector>& points, const Gdk::RGBA& fg_color);
+
+ void drawPath(const Cairo::RefPtr& cr,
+ const std::vector>& points);
+
+ void drawBars(const Cairo::RefPtr& cr, double width, double height,
+ int current_value, const Gdk::RGBA& fg_color);
+
+ void drawGauge(const Cairo::RefPtr& cr, double width, double height,
+ int current_value, const Gdk::RGBA& fg_color);
+};
+
+} // namespace waybar
diff --git a/include/AIconLabel.hpp b/include/AIconLabel.hpp
index 054d031a..80aa431a 100644
--- a/include/AIconLabel.hpp
+++ b/include/AIconLabel.hpp
@@ -9,15 +9,19 @@ namespace waybar {
class AIconLabel : public ALabel {
public:
- AIconLabel(const Json::Value &config, const std::string &name, const std::string &id,
- const std::string &format, uint16_t interval = 0, bool ellipsize = false,
+ AIconLabel(const Json::Value& config, const std::string& name, const std::string& id,
+ const std::string& format, uint16_t interval = 0, bool ellipsize = false,
bool enable_click = false, bool enable_scroll = false);
virtual ~AIconLabel() = default;
auto update() -> void override;
+ static std::tuple extractIcon(const std::string& input);
protected:
Gtk::Image image_;
Gtk::Box box_;
+ unsigned app_icon_size_{24};
+
+ bool label_contains_icon{false};
bool iconEnabled() const;
};
diff --git a/include/ALabel.hpp b/include/ALabel.hpp
index 888c65a8..201d640c 100644
--- a/include/ALabel.hpp
+++ b/include/ALabel.hpp
@@ -1,32 +1,94 @@
#pragma once
+#include
+#include
#include
#include
#include
+#include
+#include
+#include
+
#include "AModule.hpp"
namespace waybar {
class ALabel : public AModule {
public:
- ALabel(const Json::Value &, const std::string &, const std::string &, const std::string &format,
+ ALabel(const Json::Value&, const std::string&, const std::string&, const std::string& format,
uint16_t interval = 0, bool ellipsize = false, bool enable_click = false,
bool enable_scroll = false);
virtual ~ALabel() = default;
auto update() -> void override;
- virtual std::string getIcon(uint16_t, const std::string &alt = "", uint16_t max = 0);
- virtual std::string getIcon(uint16_t, const std::vector &alts, uint16_t max = 0);
+ virtual std::string getIcon(uint16_t, const std::string& alt = "", uint16_t max = 0);
+ virtual std::string getIcon(uint16_t, const std::vector& alts, uint16_t max = 0);
protected:
Gtk::Label label_;
std::string format_;
- const std::chrono::seconds interval_;
+ const std::chrono::milliseconds interval_;
bool alt_ = false;
std::string default_format_;
- bool handleToggle(GdkEventButton *const &e) override;
+ bool setLabelMarkup(const Glib::ustring& markup);
+ bool setTooltipMarkup(const Glib::ustring& markup);
+
+ // resolveTooltipFormat() / resolveFormat() are inherited from AModule.
+
+ // Combined label + tooltip helper. Builds a single fmt argument store from
+ // `args`, renders `labelFormat` into the label and the resolved tooltip format
+ // into the tooltip, both through the dedup-aware setters. Honors the `tooltip`
+ // toggle. This replaces the label/tooltip formatting boilerplate that modules
+ // used to duplicate. `state` selects `tooltip-format-` when non-empty.
+ template
+ void updateLabelAndTooltipForState(const std::string& state, const std::string& labelFormat,
+ const std::string& tooltipDefault, Args&&... args) {
+ fmt::dynamic_format_arg_store store;
+ (store.push_back(std::forward(args)), ...);
+ setLabelMarkup(fmt::vformat(labelFormat, store));
+ if (tooltipEnabled()) {
+ setTooltipMarkup(fmt::vformat(resolveTooltipFormat(tooltipDefault, state), store));
+ }
+ }
+
+ template
+ void updateLabelAndTooltip(const std::string& labelFormat, const std::string& tooltipDefault,
+ Args&&... args) {
+ updateLabelAndTooltipForState("", labelFormat, tooltipDefault, std::forward(args)...);
+ }
+
+ // Overloads accepting a pre-built argument store, for modules that must
+ // assemble a dynamic set of format arguments (e.g. per-core CPU stats) that
+ // cannot be expressed through a fixed variadic call.
+ // A non-const reference is used so this overload is preferred over the
+ // variadic template above (which would otherwise bind the store as a single
+ // forwarded argument).
+ void updateLabelAndTooltipForState(const std::string& state, const std::string& labelFormat,
+ const std::string& tooltipDefault,
+ fmt::dynamic_format_arg_store& store) {
+ setLabelMarkup(fmt::vformat(labelFormat, store));
+ if (tooltipEnabled()) {
+ setTooltipMarkup(fmt::vformat(resolveTooltipFormat(tooltipDefault, state), store));
+ }
+ }
+
+ void updateLabelAndTooltip(const std::string& labelFormat, const std::string& tooltipDefault,
+ fmt::dynamic_format_arg_store& store) {
+ updateLabelAndTooltipForState("", labelFormat, tooltipDefault, store);
+ }
+
+ bool handleToggle(GdkEventButton* const& e) override;
+ void copyToClipboard(const std::string&);
virtual std::string getState(uint8_t value, bool lesser = false);
+
+ std::map submenus_;
+ std::map menuActionsMap_;
+ static void handleGtkMenuEvent(GtkMenuItem* menuitem, gpointer data);
+
+ private:
+ std::optional last_label_markup_;
+ std::optional last_tooltip_markup_;
};
} // namespace waybar
diff --git a/include/AModule.hpp b/include/AModule.hpp
index c15efb00..0a1216d5 100644
--- a/include/AModule.hpp
+++ b/include/AModule.hpp
@@ -1,52 +1,108 @@
#pragma once
+#include
+#include
#include
#include
+#include
#include
#include
+#include
+#include
+
#include "IModule.hpp"
namespace waybar {
class AModule : public IModule {
public:
- static constexpr const char *MODULE_CLASS = "module";
+ static constexpr const char* MODULE_CLASS = "module";
- virtual ~AModule();
+ ~AModule() override;
auto update() -> void override;
- virtual auto refresh(int) -> void{};
- operator Gtk::Widget &() override;
- auto doAction(const std::string &name) -> void override;
+ virtual auto refresh(int shouldRefresh) -> void {};
+ operator Gtk::Widget&() override;
+ auto doAction(const std::string& name) -> void override;
/// Emitting on this dispatcher triggers a update() call
Glib::Dispatcher dp;
+ bool expandEnabled() const;
+
+ virtual void suspend() {};
+ virtual void resume() {};
+ bool shouldSuspend() const { return disable_on_sleep_; }
+
protected:
// Don't need to make an object directly
// Derived classes are able to use it
- AModule(const Json::Value &, const std::string &, const std::string &, bool enable_click = false,
+ AModule(const Json::Value&, const std::string&, const std::string&, bool enable_click = false,
bool enable_scroll = false);
enum SCROLL_DIR { NONE, UP, DOWN, LEFT, RIGHT };
- SCROLL_DIR getScrollDir(GdkEventScroll *e);
- bool tooltipEnabled();
+ SCROLL_DIR getScrollDir(GdkEventScroll* e);
+ bool tooltipEnabled() const;
+ // --- Generic format/tooltip resolution (config-only, usable by any module,
+ // ALabel-derived or not). Prefers `-`, then ``, then default.
+ std::string resolveFormat(const std::string& defaultFormat, const std::string& state = "") const {
+ if (!state.empty() && config_["format-" + state].isString()) {
+ return config_["format-" + state].asString();
+ }
+ if (config_["format"].isString()) {
+ return config_["format"].asString();
+ }
+ return defaultFormat;
+ }
+ std::string resolveTooltipFormat(const std::string& defaultFormat,
+ const std::string& state = "") const {
+ if (!state.empty() && config_["tooltip-format-" + state].isString()) {
+ return config_["tooltip-format-" + state].asString();
+ }
+ if (config_["tooltip-format"].isString()) {
+ return config_["tooltip-format"].asString();
+ }
+ return defaultFormat;
+ }
+
+ // Generic tooltip for any widget: honors the `tooltip` toggle and
+ // `tooltip-format`, formats with the given args and applies it. Lets modules
+ // that are not ALabel-derived (e.g. gamemode) reuse the shared logic.
+ template
+ void updateTooltip(Gtk::Widget& widget, const std::string& defaultFormat, Args&&... args) {
+ if (!tooltipEnabled()) {
+ return;
+ }
+ widget.set_tooltip_markup(
+ fmt::format(fmt::runtime(resolveTooltipFormat(defaultFormat)), std::forward(args)...));
+ }
+
+ std::vector pid_children_;
const std::string name_;
- const Json::Value &config_;
+ const Json::Value& config_;
Gtk::EventBox event_box_;
- virtual bool handleToggle(GdkEventButton *const &ev);
- virtual bool handleScroll(GdkEventScroll *);
- virtual bool handleRelease(GdkEventButton *const &ev);
+ virtual void setCursor(std::string const& c);
+
+ virtual bool handleToggle(GdkEventButton* const& ev);
+ virtual bool handleMouseEnter(GdkEventCrossing* const& ev);
+ virtual bool handleMouseLeave(GdkEventCrossing* const& ev);
+ virtual bool handleScroll(GdkEventScroll*);
+ virtual bool handleRelease(GdkEventButton* const& ev);
+
+ bool disable_on_sleep_{false};
+ GObject* menu_ = nullptr;
private:
- bool handleUserEvent(GdkEventButton *const &ev);
+ bool handleUserEvent(GdkEventButton* const& ev);
const bool isTooltip;
- std::vector pid_;
+ const bool isExpand;
+ bool hasUserEvents_;
gdouble distance_scrolled_y_;
gdouble distance_scrolled_x_;
+ sigc::connection cursor_timeout_conn_;
std::map eventActionMap_;
static const inline std::map, std::string> eventMap_{
{std::make_pair(1, GdkEventType::GDK_BUTTON_PRESS), "on-click"},
@@ -68,7 +124,8 @@ class AModule : public IModule {
{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_3BUTTON_PRESS), "on-triple-click-forward"}};
+ {std::make_pair(9, GdkEventType::GDK_3BUTTON_PRESS), "on-triple-click-forward"},
+ {std::make_pair(10, GdkEventType::GDK_BUTTON_PRESS), "on-click-copy"}};
};
} // namespace waybar
diff --git a/include/bar.hpp b/include/bar.hpp
index 6dc3c03d..783dd282 100644
--- a/include/bar.hpp
+++ b/include/bar.hpp
@@ -9,10 +9,12 @@
#include
#include
+#include
#include
#include "AModule.hpp"
#include "group.hpp"
+#include "util/kill_signal.hpp"
#include "xdg-output-unstable-v1-client-protocol.h"
namespace waybar {
@@ -53,25 +55,31 @@ class BarIpcClient;
}
#endif // HAVE_SWAY
-class Bar {
+class Bar : public sigc::trackable {
public:
using bar_mode_map = std::map;
static const bar_mode_map PRESET_MODES;
static const std::string MODE_DEFAULT;
static const std::string MODE_INVISIBLE;
- Bar(struct waybar_output *w_output, const Json::Value &);
- Bar(const Bar &) = delete;
+ Bar(struct waybar_output* w_output, const Json::Value&);
+ Bar(const Bar&) = delete;
~Bar();
- void setMode(const std::string &mode);
- void setVisible(bool visible);
+ void setMode(const std::string& mode);
+ void setVisible(bool value);
void toggle();
+ void show();
+ void hide();
void handleSignal(int);
+ util::KillSignalAction getOnSigusr1Action();
+ util::KillSignalAction getOnSigusr2Action();
- struct waybar_output *output;
+ void toggleSuspend(bool suspend);
+
+ struct waybar_output* output;
Json::Value config;
- struct wl_surface *surface;
+ struct wl_surface* surface;
bool visible = true;
Gtk::Window window;
Gtk::Orientation orientation = Gtk::ORIENTATION_HORIZONTAL;
@@ -85,15 +93,16 @@ class Bar {
#endif
private:
- void onMap(GdkEventAny *);
+ void onMap(GdkEventAny*);
auto setupWidgets() -> void;
- void getModules(const Factory &, const std::string &, waybar::Group *);
- void setupAltFormatKeyForModule(const std::string &module_name);
- void setupAltFormatKeyForModuleList(const char *module_list_name);
- void setMode(const bar_mode &);
+ void getModules(const Factory&, const std::string&, waybar::Group*);
+ void setupAltFormatKeyForModule(const std::string& module_name);
+ void setupAltFormatKeyForModuleList(const char* module_list_name);
+ void setMode(const bar_mode&);
void setPassThrough(bool passthrough);
void setPosition(Gtk::PositionType position);
- void onConfigure(GdkEventConfigure *ev);
+ void forceLayerCommit();
+ void onConfigure(GdkEventConfigure* ev);
void configureGlobalOffset(int width, int height);
void onOutputGeometryChanged();
@@ -117,6 +126,9 @@ class Bar {
std::unique_ptr _ipc_client;
#endif
std::vector> modules_all_;
+
+ waybar::util::KillSignalAction onSigusr1 = util::SIGNALACTION_DEFAULT_SIGUSR1;
+ waybar::util::KillSignalAction onSigusr2 = util::SIGNALACTION_DEFAULT_SIGUSR2;
};
} // namespace waybar
diff --git a/include/client.hpp b/include/client.hpp
index 0e68f002..09f9090f 100644
--- a/include/client.hpp
+++ b/include/client.hpp
@@ -12,40 +12,43 @@
struct zwp_idle_inhibitor_v1;
struct zwp_idle_inhibit_manager_v1;
+struct ext_idle_notifier_v1;
namespace waybar {
class Client {
public:
- static Client *inst();
- int main(int argc, char *argv[]);
+ static Client* inst();
+ int main(int argc, char* argv[]);
void reset();
Glib::RefPtr gtk_app;
Glib::RefPtr gdk_display;
- struct wl_display *wl_display = nullptr;
- struct wl_registry *registry = nullptr;
- struct zxdg_output_manager_v1 *xdg_output_manager = nullptr;
- struct zwp_idle_inhibit_manager_v1 *idle_inhibit_manager = nullptr;
+ struct wl_display* wl_display = nullptr;
+ struct wl_registry* registry = nullptr;
+ struct zxdg_output_manager_v1* xdg_output_manager = nullptr;
+ struct zwp_idle_inhibit_manager_v1* idle_inhibit_manager = nullptr;
+ struct ext_idle_notifier_v1* idle_notifier = nullptr;
std::vector> bars;
Config config;
std::string bar_id;
private:
Client() = default;
- const std::string getStyle(const std::string &style, std::optional appearance);
+ const std::string getStyle(const std::string& style, std::optional appearance);
void bindInterfaces();
- void handleOutput(struct waybar_output &output);
- auto setupCss(const std::string &css_file) -> void;
- struct waybar_output &getOutput(void *);
- std::vector getOutputConfigs(struct waybar_output &output);
+ void handleOutput(struct waybar_output& output);
+ auto setupCss(const std::string& css_file) -> void;
+ struct waybar_output& getOutput(void*);
+ std::vector getOutputConfigs(struct waybar_output& output);
- static void handleGlobal(void *data, struct wl_registry *registry, uint32_t name,
- const char *interface, uint32_t version);
- static void handleGlobalRemove(void *data, struct wl_registry *registry, uint32_t name);
- static void handleOutputDone(void *, struct zxdg_output_v1 *);
- static void handleOutputName(void *, struct zxdg_output_v1 *, const char *);
- static void handleOutputDescription(void *, struct zxdg_output_v1 *, const char *);
+ static void handleGlobal(void* data, struct wl_registry* registry, uint32_t name,
+ const char* interface, uint32_t version);
+ static void handleGlobalRemove(void* data, struct wl_registry* registry, uint32_t name);
+ static void handleOutputDone(void*, struct zxdg_output_v1*);
+ void createBarsBatch();
+ static void handleOutputName(void*, struct zxdg_output_v1*, const char*);
+ static void handleOutputDescription(void*, struct zxdg_output_v1*, const char*);
void handleMonitorAdded(Glib::RefPtr monitor);
void handleMonitorRemoved(Glib::RefPtr monitor);
void handleDeferredMonitorRemoval(Glib::RefPtr monitor);
@@ -56,6 +59,10 @@ class Client {
std::list outputs_;
std::unique_ptr m_cssReloadHelper;
std::string m_cssFile;
+ sigc::connection monitor_added_connection_;
+ sigc::connection monitor_removed_connection_;
+ std::list pending_outputs_;
+ bool bars_scheduled_ = false;
};
} // namespace waybar
diff --git a/include/config.hpp b/include/config.hpp
index 66945542..1ef9ef5f 100644
--- a/include/config.hpp
+++ b/include/config.hpp
@@ -14,24 +14,29 @@ namespace waybar {
class Config {
public:
static const std::vector CONFIG_DIRS;
- static const char *CONFIG_PATH_ENV;
+ static const char* CONFIG_PATH_ENV;
/* Try to find any of provided names in the supported set of config directories */
static std::optional findConfigPath(
- const std::vector &names, const std::vector &dirs = CONFIG_DIRS);
+ const std::vector& names, const std::vector& dirs = CONFIG_DIRS);
+
+ static std::vector tryExpandPath(const std::string& base,
+ const std::string& filename);
Config() = default;
- void load(const std::string &config);
+ void load(const std::string& config);
- Json::Value &getConfig() { return config_; }
+ Json::Value& getConfig() { return config_; }
- std::vector getOutputConfigs(const std::string &name, const std::string &identifier);
+ std::vector getOutputConfigs(const std::string& name, const std::string& identifier);
private:
- void setupConfig(Json::Value &dst, const std::string &config_file, int depth);
- void resolveConfigIncludes(Json::Value &config, int depth);
- void mergeConfig(Json::Value &a_config_, Json::Value &b_config_);
+ void setupConfig(Json::Value& dst, const std::string& config_file, int depth);
+ void resolveConfigIncludes(Json::Value& config, int depth);
+ void mergeConfig(Json::Value& a_config_, Json::Value& b_config_);
+ static std::vector findIncludePath(
+ const std::string& name, const std::vector& dirs = CONFIG_DIRS);
std::string config_file_;
diff --git a/include/group.hpp b/include/group.hpp
index 67cf4385..afd705b0 100644
--- a/include/group.hpp
+++ b/include/group.hpp
@@ -10,26 +10,33 @@
namespace waybar {
class Group : public AModule {
+ sigc::connection reveal_timeout_;
+
public:
Group(const std::string&, const std::string&, const Json::Value&, bool);
- virtual ~Group() = default;
+ ~Group() override = default;
auto update() -> void override;
operator Gtk::Widget&() override;
virtual Gtk::Box& getBox();
void addWidget(Gtk::Widget& widget);
- bool handleMouseHover(GdkEventCrossing* const& e);
-
protected:
Gtk::Box box;
Gtk::Box revealer_box;
Gtk::Revealer revealer;
bool is_first_widget = true;
bool is_drawer = false;
+ bool click_to_reveal = false;
+ bool empty_if_drawer_empty = false;
+ int reveal_delay = 0;
std::string add_class_to_drawer_children;
-
- void addHoverHandlerTo(Gtk::Widget& widget);
+ bool handleMouseEnter(GdkEventCrossing* const& ev) override;
+ bool handleMouseLeave(GdkEventCrossing* const& ev) override;
+ bool handleToggle(GdkEventButton* const& ev) override;
+ bool handleScroll(GdkEventScroll* e) override;
+ void show_group();
+ void hide_group();
};
} // namespace waybar
diff --git a/include/modules/backlight.hpp b/include/modules/backlight.hpp
index 110cd434..46b38972 100644
--- a/include/modules/backlight.hpp
+++ b/include/modules/backlight.hpp
@@ -17,11 +17,11 @@ namespace waybar::modules {
class Backlight : public ALabel {
public:
- Backlight(const std::string &, const Json::Value &);
+ Backlight(const std::string&, const Json::Value&);
virtual ~Backlight() = default;
auto update() -> void override;
- bool handleScroll(GdkEventScroll *e) override;
+ bool handleScroll(GdkEventScroll* e) override;
const std::string preferred_device_;
diff --git a/include/modules/battery.hpp b/include/modules/battery.hpp
index 7955e598..fb6d092f 100644
--- a/include/modules/battery.hpp
+++ b/include/modules/battery.hpp
@@ -6,8 +6,10 @@
#if defined(__linux__)
#include
#endif
+#include
#include
+#include
#include
#include
#include
@@ -15,6 +17,7 @@
#include "ALabel.hpp"
#include "bar.hpp"
#include "util/sleeper_thread.hpp"
+#include "util/udev_deleter.hpp"
namespace waybar::modules {
@@ -32,19 +35,28 @@ class Battery : public ALabel {
void refreshBatteries();
void worker();
const std::string getAdapterStatus(uint8_t capacity) const;
- const std::tuple getInfos();
+ std::tuple getInfos();
const std::string formatTimeRemaining(float hoursRemaining);
void setBarClass(std::string&);
+ void processEvents(std::string& state, std::string& status, uint8_t capacity);
- int global_watch;
std::map batteries_;
+ std::unique_ptr udev_;
+ std::array poll_fds_;
+ std::unique_ptr mon_;
fs::path adapter_;
int battery_watch_fd_;
- int global_watch_fd_;
std::mutex battery_list_mutex_;
std::string old_status_;
+ std::string last_event_;
bool warnFirstTime_{true};
+ bool weightedAverage_{true};
const Bar& bar_;
+ bool smoothPowerEnable_{false};
+ double time_constant_s_{260.0};
+ double smooth_power_{0.0}; // µW
+ std::chrono::steady_clock::time_point last_t_{std::chrono::steady_clock::now()};
+ std::string old_status_raw_{""};
util::SleeperThread thread_;
util::SleeperThread thread_battery_update_;
diff --git a/include/modules/bluetooth.hpp b/include/modules/bluetooth.hpp
index 89658dcf..5e03b118 100644
--- a/include/modules/bluetooth.hpp
+++ b/include/modules/bluetooth.hpp
@@ -41,6 +41,7 @@ class Bluetooth : public ALabel {
bool services_resolved;
// NOTE: experimental feature in bluez
std::optional battery_percentage;
+ std::optional battery_percentage_peripheral;
};
public:
@@ -49,6 +50,9 @@ class Bluetooth : public ALabel {
auto update() -> void override;
private:
+ static auto onObjectAdded(GDBusObjectManager*, GDBusObject*, gpointer) -> void;
+ static auto onObjectRemoved(GDBusObjectManager*, GDBusObject*, gpointer) -> void;
+
static auto onInterfaceAddedOrRemoved(GDBusObjectManager*, GDBusObject*, GDBusInterface*,
gpointer) -> void;
static auto onInterfaceProxyPropertiesChanged(GDBusObjectManagerClient*, GDBusObjectProxy*,
@@ -56,6 +60,12 @@ class Bluetooth : public ALabel {
gpointer) -> void;
auto getDeviceBatteryPercentage(GDBusObject*) -> std::optional;
+ auto getDeviceGattBatteryLevels(GDBusObject*, std::optional&,
+ std::optional&) -> void;
+ static auto processBatteryServiceCharacteristics(GList*, const std::string&, const std::string&,
+ const std::string&,
+ std::optional&,
+ std::optional&) -> void;
auto getDeviceProperties(GDBusObject*, DeviceInfo&) -> bool;
auto getControllerProperties(GDBusObject*, ControllerInfo&) -> bool;
diff --git a/include/modules/cava.hpp b/include/modules/cava.hpp
deleted file mode 100644
index 430c71b7..00000000
--- a/include/modules/cava.hpp
+++ /dev/null
@@ -1,49 +0,0 @@
-#pragma once
-
-#include "ALabel.hpp"
-#include "util/sleeper_thread.hpp"
-
-namespace cava {
-extern "C" {
-#include
-}
-} // namespace cava
-
-namespace waybar::modules {
-using namespace std::literals::chrono_literals;
-
-class Cava final : public ALabel {
- public:
- Cava(const std::string&, const Json::Value&);
- virtual ~Cava();
- auto update() -> void override;
- auto doAction(const std::string& name) -> void override;
-
- private:
- util::SleeperThread thread_;
- util::SleeperThread thread_fetch_input_;
-
- struct cava::error_s error_ {}; // cava errors
- struct cava::config_params prm_ {}; // cava parameters
- struct cava::audio_raw audio_raw_ {}; // cava handled raw audio data(is based on audio_data)
- struct cava::audio_data audio_data_ {}; // cava audio data
- struct cava::cava_plan* plan_; //{new cava_plan{}};
- // Cava API to read audio source
- cava::ptr input_source_;
- // Delay to handle audio source
- std::chrono::milliseconds frame_time_milsec_{1s};
- // Text to display
- std::string text_{""};
- int rePaint_{1};
- std::chrono::seconds fetch_input_delay_{4};
- std::chrono::seconds suspend_silence_delay_{0};
- bool silence_{false};
- bool hide_on_silence_{false};
- int sleep_counter_{0};
- // Cava method
- void pause_resume();
- // ModuleActionMap
- static inline std::map actionMap_{
- {"mode", &waybar::modules::Cava::pause_resume}};
-};
-} // namespace waybar::modules
diff --git a/include/modules/cava/cavaGLSL.hpp b/include/modules/cava/cavaGLSL.hpp
new file mode 100644
index 00000000..d2632aff
--- /dev/null
+++ b/include/modules/cava/cavaGLSL.hpp
@@ -0,0 +1,43 @@
+#pragma once
+
+#include
+
+#include "AModule.hpp"
+#include "cava_backend.hpp"
+
+namespace waybar::modules::cava {
+
+class CavaGLSL final : public AModule, public Gtk::GLArea {
+ public:
+ CavaGLSL(const std::string&, const Json::Value&);
+ ~CavaGLSL() = default;
+
+ private:
+ std::shared_ptr backend_;
+ struct ::cava::config_params prm_;
+ int frame_counter{0};
+ bool silence_{false};
+ bool hide_on_silence_{false};
+ // Cava method
+ auto onUpdate(const ::cava::audio_raw& input) -> void;
+ auto onSilence() -> void;
+ // Member variable to store the shared pointer
+ std::shared_ptr<::cava::audio_raw> m_data_;
+ GLuint shaderProgram_;
+ // OpenGL variables
+ GLuint fbo_;
+ GLuint texture_;
+ GLint uniform_bars_;
+ GLint uniform_previous_bars_;
+ GLint uniform_bars_count_;
+ GLint uniform_time_;
+ // Methods
+ void onRealize();
+ bool onRender(const Glib::RefPtr& context);
+
+ void initShaders();
+ void initSurface();
+ void initGLSL();
+ GLuint loadShader(const std::string& fileName, GLenum type);
+};
+} // namespace waybar::modules::cava
diff --git a/include/modules/cava/cavaRaw.hpp b/include/modules/cava/cavaRaw.hpp
new file mode 100644
index 00000000..f4ceb603
--- /dev/null
+++ b/include/modules/cava/cavaRaw.hpp
@@ -0,0 +1,30 @@
+#pragma once
+
+#include "ALabel.hpp"
+#include "cava_backend.hpp"
+
+namespace waybar::modules::cava {
+
+class Cava final : public ALabel, public sigc::trackable {
+ public:
+ Cava(const std::string&, const Json::Value&);
+ ~Cava() = default;
+ auto doAction(const std::string& name) -> void override;
+
+ private:
+ std::shared_ptr backend_;
+ // Text to display
+ Glib::ustring label_text_{""};
+ bool silence_{false};
+ bool hide_on_silence_{false};
+ std::string format_silent_{""};
+ int ascii_range_{0};
+ // Cava method
+ void pause_resume();
+ auto onUpdate(const std::string& input) -> void;
+ auto onSilence() -> void;
+ // ModuleActionMap
+ static inline std::map
+ actionMap_{{"mode", &waybar::modules::cava::Cava::pause_resume}};
+};
+} // namespace waybar::modules::cava
diff --git a/include/modules/cava/cava_backend.hpp b/include/modules/cava/cava_backend.hpp
new file mode 100644
index 00000000..4022a2ff
--- /dev/null
+++ b/include/modules/cava/cava_backend.hpp
@@ -0,0 +1,84 @@
+#pragma once
+
+#include
+#include
+
+#include "util/sleeper_thread.hpp"
+
+namespace cava {
+extern "C" {
+// Need sdl_glsl output feature to be enabled on libcava
+#ifndef SDL_GLSL
+#define SDL_GLSL
+#endif
+
+#include
+
+#ifdef SDL_GLSL
+#undef SDL_GLSL
+#endif
+}
+} // namespace cava
+
+namespace waybar::modules::cava {
+using namespace std::literals::chrono_literals;
+
+class CavaBackend final {
+ public:
+ static std::shared_ptr inst(const Json::Value& config);
+
+ virtual ~CavaBackend();
+ // Methods
+ int getAsciiRange();
+ void doPauseResume();
+ void Update();
+ const struct ::cava::config_params* getPrm();
+ std::chrono::milliseconds getFrameTimeMilsec();
+
+ // Signal accessor
+ using type_signal_update = sigc::signal;
+ type_signal_update signal_update();
+ using type_signal_audio_raw_update = sigc::signal;
+ type_signal_audio_raw_update signal_audio_raw_update();
+ using type_signal_silence = sigc::signal;
+ type_signal_silence signal_silence();
+
+ private:
+ CavaBackend(const Json::Value& config);
+ util::SleeperThread read_thread_;
+ util::SleeperThread out_thread_;
+
+ // Cava API to read audio source
+ ::cava::ptr input_source_{NULL};
+
+ struct ::cava::error_s error_{}; // cava errors
+ struct ::cava::config_params prm_{}; // cava parameters
+ struct ::cava::audio_raw audio_raw_{}; // cava handled raw audio data(is based on audio_data)
+ struct ::cava::audio_data audio_data_{}; // cava audio data
+ struct ::cava::cava_plan* plan_{NULL}; //{new cava_plan{}};
+
+ std::chrono::seconds fetch_input_delay_{4};
+ // Delay to handle audio source
+ std::chrono::milliseconds frame_time_milsec_{1s};
+
+ const Json::Value& config_;
+ int re_paint_{0};
+ bool silence_{false};
+ bool silence_prev_{false};
+ std::chrono::seconds suspend_silence_delay_{0};
+ int sleep_counter_{0};
+ std::string output_{};
+ // Methods
+ void invoke();
+ void execute();
+ bool isSilence();
+ void doUpdate(bool force = false);
+ void loadConfig();
+ void freeBackend();
+
+ // Signal
+ type_signal_update m_signal_update_;
+ type_signal_audio_raw_update m_signal_audio_raw_;
+ type_signal_silence m_signal_silence_;
+};
+} // namespace waybar::modules::cava
diff --git a/include/modules/cava/cava_frontend.hpp b/include/modules/cava/cava_frontend.hpp
new file mode 100644
index 00000000..402a9bad
--- /dev/null
+++ b/include/modules/cava/cava_frontend.hpp
@@ -0,0 +1,27 @@
+#pragma once
+
+#ifdef HAVE_LIBCAVA
+#include "cavaRaw.hpp"
+#include "cava_backend.hpp"
+#ifdef HAVE_LIBCAVAGLSL
+#include "cavaGLSL.hpp"
+#endif
+#endif
+
+namespace waybar::modules::cava {
+AModule* getModule(const std::string& id, const Json::Value& config) {
+#ifdef HAVE_LIBCAVA
+ const std::shared_ptr backend_{waybar::modules::cava::CavaBackend::inst(config)};
+ switch (backend_->getPrm()->output) {
+#ifdef HAVE_LIBCAVAGLSL
+ case ::cava::output_method::OUTPUT_SDL_GLSL:
+ return new waybar::modules::cava::CavaGLSL(id, config);
+#endif
+ default:
+ return new waybar::modules::cava::Cava(id, config);
+ }
+#else
+ throw std::runtime_error("Unknown module");
+#endif
+};
+} // namespace waybar::modules::cava
diff --git a/include/modules/clock.hpp b/include/modules/clock.hpp
index 8b597c4e..5fd9df54 100644
--- a/include/modules/clock.hpp
+++ b/include/modules/clock.hpp
@@ -21,10 +21,12 @@ class Clock final : public ALabel {
auto doAction(const std::string&) -> void override;
private:
- const std::locale locale_;
+ const std::locale m_locale_;
// tooltip
- const std::string tlpFmt_;
- std::string tlpText_{""}; // tooltip text to print
+ const std::string m_tlpFmt_;
+ std::string m_tlpText_{""}; // tooltip text to print
+ const Glib::RefPtr m_tooltip_; // tooltip as a separate Gtk::Label
+ bool query_tlp_cb(int, int, bool, const Glib::RefPtr& tooltip);
// Calendar
const bool cldInTooltip_; // calendar in tooltip
/*
@@ -36,48 +38,60 @@ class Clock final : public ALabel {
5 - tooltip-format
*/
std::map 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)
+ 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
+ date::months cldCurrShift_{0}; // calendar months shift
+ int cldShift_{1}; // calendar months shift factor
+ date::year_month_day cldYearShift_; // calendar Year mode. Cached ymd
+ std::string cldYearCached_; // calendar Year mode. Cached calendar
+ date::year_month cldMonShift_; // calendar Month mode. Cached ym
+ std::string cldMonCached_; // calendar Month mode. Cached calendar
+ date::day cldBaseDay_{0}; // calendar Cached day. Is used when today is changing(midnight)
std::string cldText_{""}; // calendar text to print
+ bool iso8601Calendar_{false}; // whether the calendar is in ISO8601
CldMode cldMode_{CldMode::MONTH};
- auto get_calendar(const year_month_day& today, const year_month_day& ymd, const time_zone* tz)
- -> const std::string;
+ auto get_calendar(const date::year_month_day& today, const date::year_month_day& ymd,
+ const date::time_zone* tz) -> const std::string;
+
+ // get local time zone
+ auto local_zone() -> const date::time_zone*;
// time zoned time in tooltip
- const bool tzInTooltip_; // if need to print time zones text
- std::vector tzList_; // time zones list
- int tzCurrIdx_; // current time zone index for tzList_
- std::string tzText_{""}; // time zones text to print
+ const bool tzInTooltip_; // if need to print time zones text
+ std::vector tzList_; // time zones list
+ int tzCurrIdx_; // current time zone index for tzList_
+ std::string tzText_{""}; // time zones text to print
+ std::string tzTooltipFormat_{""}; // optional timezone tooltip format
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 get_ordinal_date(const date::year_month_day& today) -> std::string;
- auto getTZtext(sys_seconds now) -> std::string;
- auto first_day_of_week() -> weekday;
+ auto getTZtext(date::sys_seconds now) -> std::string;
+ auto first_day_of_week() -> date::weekday;
// Module actions
void cldModeSwitch();
void cldShift_up();
void cldShift_down();
+ void cldShift_reset();
void tz_up();
void tz_down();
+ void action_exec(const std::string& action);
// Module Action Map
- static inline std::map actionMap_{
+ static inline std::map actionMap_{
{"mode", &waybar::modules::Clock::cldModeSwitch},
{"shift_up", &waybar::modules::Clock::cldShift_up},
{"shift_down", &waybar::modules::Clock::cldShift_down},
+ {"shift_reset", &waybar::modules::Clock::cldShift_reset},
{"tz_up", &waybar::modules::Clock::tz_up},
{"tz_down", &waybar::modules::Clock::tz_down}};
+ static inline std::map
+ actionWithArgsMap_{{"exec", &waybar::modules::Clock::action_exec}};
};
} // namespace waybar::modules
diff --git a/include/modules/cpu_graph.hpp b/include/modules/cpu_graph.hpp
new file mode 100644
index 00000000..cf74a3fe
--- /dev/null
+++ b/include/modules/cpu_graph.hpp
@@ -0,0 +1,32 @@
+#pragma once
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "AGraph.hpp"
+#include "util/sleeper_thread.hpp"
+
+namespace waybar::modules {
+
+class CpuGraph : public AGraph {
+ public:
+ CpuGraph(const std::string&, const Json::Value&);
+ virtual ~CpuGraph() = default;
+ auto update() -> void override;
+
+ private:
+ static constexpr const char* MODERATE_CLASS = "cpu-moderate";
+ static constexpr const char* HIGH_CLASS = "cpu-high";
+ static constexpr const char* INTENSIVE_CLASS = "cpu-intensive";
+
+ std::vector> prev_times_;
+ util::SleeperThread thread_;
+};
+
+} // namespace waybar::modules
diff --git a/include/modules/custom.hpp b/include/modules/custom.hpp
index 2c7ba8a8..442b1c37 100644
--- a/include/modules/custom.hpp
+++ b/include/modules/custom.hpp
@@ -5,14 +5,14 @@
#include
#include
-#include "ALabel.hpp"
+#include "AIconLabel.hpp"
#include "util/command.hpp"
#include "util/json.hpp"
#include "util/sleeper_thread.hpp"
namespace waybar::modules {
-class Custom : public ALabel {
+class Custom : public AIconLabel {
public:
Custom(const std::string&, const std::string&, const Json::Value&, const std::string&);
virtual ~Custom();
@@ -35,6 +35,11 @@ class Custom : public ALabel {
std::string id_;
std::string alt_;
std::string tooltip_;
+ std::string last_tooltip_markup_;
+ std::string image_path_;
+ std::string image_name_;
+ unsigned app_icon_size_{24};
+ const bool tooltip_format_enabled_;
std::vector class_;
int percentage_;
FILE* fp_;
diff --git a/include/modules/custom_graph.hpp b/include/modules/custom_graph.hpp
new file mode 100644
index 00000000..a081f376
--- /dev/null
+++ b/include/modules/custom_graph.hpp
@@ -0,0 +1,49 @@
+#pragma once
+
+#include
+
+#include
+#include
+
+#include "AGraph.hpp"
+#include "util/command.hpp"
+#include "util/json.hpp"
+#include "util/sleeper_thread.hpp"
+
+namespace waybar::modules {
+
+class CustomGraph : public AGraph {
+ public:
+ CustomGraph(const std::string&, const std::string&, const Json::Value&, const std::string&);
+ virtual ~CustomGraph();
+ auto update() -> void override;
+ void refresh(int /*signal*/) override;
+
+ private:
+ void delayWorker();
+ void continuousWorker();
+ void waitingWorker();
+ void parseOutputRaw();
+ void parseOutputJson();
+ void handleEvent();
+ bool handleScroll(GdkEventScroll* e) override;
+ bool handleToggle(GdkEventButton* const& e) override;
+
+ const std::string name_;
+ const std::string output_name_;
+ std::string text_;
+ std::string id_;
+ std::string alt_;
+ std::string tooltip_;
+ const bool tooltip_format_enabled_;
+ std::vector class_;
+ int percentage_;
+ FILE* fp_;
+ int pid_;
+ util::command::res output_;
+ util::JsonParser parser_;
+
+ util::SleeperThread thread_;
+};
+
+} // namespace waybar::modules
diff --git a/include/modules/disk.hpp b/include/modules/disk.hpp
index 1b4f3176..1ebd1907 100644
--- a/include/modules/disk.hpp
+++ b/include/modules/disk.hpp
@@ -4,6 +4,7 @@
#include
#include
+#include
#include "ALabel.hpp"
#include "util/format.hpp"
@@ -19,10 +20,12 @@ class Disk : public ALabel {
private:
util::SleeperThread thread_;
- std::string path_;
+ std::string header_;
+ std::vector paths_;
+ std::string separator_;
std::string unit_;
- float calc_specific_divisor(const std::string divisor);
+ float calc_specific_divisor(const std::string& divisor);
};
} // namespace waybar::modules
diff --git a/include/modules/dwl/tags.hpp b/include/modules/dwl/tags.hpp
index 53dff989..4fee30fb 100644
--- a/include/modules/dwl/tags.hpp
+++ b/include/modules/dwl/tags.hpp
@@ -12,23 +12,26 @@ namespace waybar::modules::dwl {
class Tags : public waybar::AModule {
public:
- Tags(const std::string &, const waybar::Bar &, const Json::Value &);
+ Tags(const std::string&, const waybar::Bar&, const Json::Value&);
virtual ~Tags();
// Handlers for wayland events
void handle_view_tags(uint32_t tag, uint32_t state, uint32_t clients, uint32_t focused);
void handle_primary_clicked(uint32_t tag);
- bool handle_button_press(GdkEventButton *event_button, uint32_t tag);
+ bool handle_button_press(GdkEventButton* event_button, uint32_t tag);
- struct zdwl_ipc_manager_v2 *status_manager_;
- struct wl_seat *seat_;
+ void handle_active_output(zdwl_ipc_output_v2* zdwl_output_v2, uint32_t active);
+
+ struct zdwl_ipc_manager_v2* status_manager_;
+ struct wl_seat* seat_;
private:
- const waybar::Bar &bar_;
+ const waybar::Bar& bar_;
Gtk::Box box_;
std::vector buttons_;
- struct zdwl_ipc_output_v2 *output_status_;
+ bool hide_vacant_;
+ struct zdwl_ipc_output_v2* output_status_;
};
} /* namespace waybar::modules::dwl */
diff --git a/include/modules/dwl/window.hpp b/include/modules/dwl/window.hpp
new file mode 100644
index 00000000..e731e8e4
--- /dev/null
+++ b/include/modules/dwl/window.hpp
@@ -0,0 +1,42 @@
+#pragma once
+
+#include
+
+#include
+
+#include "AAppIconLabel.hpp"
+#include "bar.hpp"
+#include "dwl-ipc-unstable-v2-client-protocol.h"
+#include "util/json.hpp"
+
+namespace waybar::modules::dwl {
+
+class Window : public AAppIconLabel, public sigc::trackable {
+ public:
+ Window(const std::string&, const waybar::Bar&, const Json::Value&);
+ ~Window();
+
+ void handle_layout(const uint32_t layout);
+ void handle_title(const char* title);
+ void handle_appid(const char* ppid);
+ void handle_active(const uint32_t active);
+ void handle_layout_symbol(const char* layout_symbol);
+ void handle_frame();
+
+ struct zdwl_ipc_manager_v2* status_manager_;
+
+ private:
+ const Bar& bar_;
+
+ std::string title_;
+ std::string appid_;
+ std::string layout_symbol_;
+ bool active_;
+ bool hide_inactive_;
+ bool hide_empty_;
+ uint32_t layout_;
+
+ struct zdwl_ipc_output_v2* output_status_;
+};
+
+} // namespace waybar::modules::dwl
diff --git a/include/modules/ext/workspace_manager.hpp b/include/modules/ext/workspace_manager.hpp
new file mode 100644
index 00000000..f21ff26e
--- /dev/null
+++ b/include/modules/ext/workspace_manager.hpp
@@ -0,0 +1,141 @@
+#pragma once
+
+#include
+#include
+#include
+#include
+
+#include