diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml
index 66c465ba..0e7e2944 100644
--- a/.github/workflows/docker.yml
+++ b/.github/workflows/docker.yml
@@ -1,14 +1,15 @@
name: Build and Push Docker Image
on:
+ workflow_dispatch:
schedule:
- # run every night at midnight
- - cron: '0 0 * * *'
+ # run monthly
+ - cron: '0 0 1 * *'
jobs:
build-and-push:
runs-on: ubuntu-latest
- if: github.repository == 'Alexays/Waybar'
+ 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:
diff --git a/.github/workflows/freebsd.yml b/.github/workflows/freebsd.yml
index ca0dcbc8..b9114c31 100644
--- a/.github/workflows/freebsd.yml
+++ b/.github/workflows/freebsd.yml
@@ -14,14 +14,14 @@ jobs:
steps:
- uses: actions/checkout@v3
- name: Test in FreeBSD VM
- uses: cross-platform-actions/action@v0.25.0
+ uses: cross-platform-actions/action@v0.28.0
timeout-minutes: 180
env:
CPPFLAGS: '-isystem/usr/local/include'
LDFLAGS: '-L/usr/local/lib'
with:
operating_system: freebsd
- version: "14.1"
+ version: "14.2"
environment_variables: CPPFLAGS LDFLAGS
sync_files: runner-to-vm
run: |
diff --git a/Dockerfiles/debian b/Dockerfiles/debian
index f479062d..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 \
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/Makefile b/Makefile
index 3bb11199..12af8e0e 100644
--- a/Makefile
+++ b/Makefile
@@ -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 5266e916..4edf2253 100644
--- a/README.md
+++ b/README.md
@@ -116,6 +116,36 @@ sudo apt install \
libxkbregistry-dev
```
+On Arch, you can use this command:
+
+```
+pacman -S \
+ 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 :)
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/flake.lock b/flake.lock
index 480f004f..9b8db656 100644
--- a/flake.lock
+++ b/flake.lock
@@ -3,11 +3,11 @@
"flake-compat": {
"flake": false,
"locked": {
- "lastModified": 1733328505,
- "narHash": "sha256-NeCCThCEP3eCl2l/+27kNNK7QrwZB1IJCrXfrbv5oqU=",
+ "lastModified": 1747046372,
+ "narHash": "sha256-CIVLLkVgvHYbgI2UpXvIIBJ12HWgX+fjA8Xf8PUmqCY=",
"owner": "edolstra",
"repo": "flake-compat",
- "rev": "ff81ac966bb2cae68946d5ed5fc4994f96d0ffec",
+ "rev": "9100a0f413b0c601e0533d1d94ffd501ce2e7885",
"type": "github"
},
"original": {
@@ -18,11 +18,11 @@
},
"nixpkgs": {
"locked": {
- "lastModified": 1745391562,
- "narHash": "sha256-sPwcCYuiEopaafePqlG826tBhctuJsLx/mhKKM5Fmjo=",
+ "lastModified": 1759036355,
+ "narHash": "sha256-0m27AKv6ka+q270dw48KflE0LwQYrO7Fm4/2//KCVWg=",
"owner": "NixOS",
"repo": "nixpkgs",
- "rev": "8a2f738d9d1f1d986b5a4cd2fd2061a7127237d7",
+ "rev": "e9f00bd893984bc8ce46c895c3bf7cac95331127",
"type": "github"
},
"original": {
diff --git a/flake.nix b/flake.nix
index 7c7a2281..b2f96731 100644
--- a/flake.nix
+++ b/flake.nix
@@ -65,7 +65,7 @@
nativeBuildInputs =
pkgs.waybar.nativeBuildInputs
++ (with pkgs; [
- nixfmt-rfc-style
+ nixfmt
clang-tools
gdb
]);
@@ -75,28 +75,26 @@
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-rfc-style;
- includes = [ "*.nix" ];
- };
+ settings = {
+ formatter = {
+ clang-format = {
+ options = [ "-i" ];
+ command = lib.getExe' pkgs.clang-tools "clang-format";
+ excludes = [ ];
+ includes = [
+ "*.c"
+ "*.cpp"
+ "*.h"
+ "*.hpp"
+ ];
};
- tree-root-file = ".git/index";
- }
- ];
+ nixfmt = {
+ command = lib.getExe pkgs.nixfmt;
+ includes = [ "*.nix" ];
+ };
+ };
+ tree-root-file = ".git/index";
+ };
}
);
diff --git a/include/ALabel.hpp b/include/ALabel.hpp
index a1aae9da..92fc2e0f 100644
--- a/include/ALabel.hpp
+++ b/include/ALabel.hpp
@@ -21,7 +21,7 @@ class ALabel : public AModule {
protected:
Gtk::Label label_;
std::string format_;
- const std::chrono::seconds interval_;
+ const std::chrono::milliseconds interval_;
bool alt_ = false;
std::string default_format_;
diff --git a/include/AModule.hpp b/include/AModule.hpp
index 2ffc429c..2fcbfc23 100644
--- a/include/AModule.hpp
+++ b/include/AModule.hpp
@@ -36,6 +36,7 @@ class AModule : public IModule {
SCROLL_DIR getScrollDir(GdkEventScroll *e);
bool tooltipEnabled() const;
+ std::vector pid_children_;
const std::string name_;
const Json::Value &config_;
Gtk::EventBox event_box_;
@@ -54,7 +55,6 @@ class AModule : public IModule {
const bool isTooltip;
const bool isExpand;
bool hasUserEvents_;
- std::vector pid_;
gdouble distance_scrolled_y_;
gdouble distance_scrolled_x_;
std::map eventActionMap_;
diff --git a/include/bar.hpp b/include/bar.hpp
index 9b407abf..9953b1f5 100644
--- a/include/bar.hpp
+++ b/include/bar.hpp
@@ -14,6 +14,7 @@
#include "AModule.hpp"
#include "group.hpp"
+#include "util/kill_signal.hpp"
#include "xdg-output-unstable-v1-client-protocol.h"
namespace waybar {
@@ -68,7 +69,11 @@ class Bar : public sigc::trackable {
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;
Json::Value config;
@@ -118,6 +123,9 @@ class Bar : public sigc::trackable {
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/config.hpp b/include/config.hpp
index 5256bb46..bf653c2a 100644
--- a/include/config.hpp
+++ b/include/config.hpp
@@ -35,6 +35,8 @@ class 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/modules/battery.hpp b/include/modules/battery.hpp
index 8e1a2ad2..c593e59b 100644
--- a/include/modules/battery.hpp
+++ b/include/modules/battery.hpp
@@ -35,6 +35,7 @@ class Battery : public ALabel {
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_;
@@ -43,6 +44,7 @@ class Battery : public ALabel {
int global_watch_fd_;
std::mutex battery_list_mutex_;
std::string old_status_;
+ std::string last_event_;
bool warnFirstTime_{true};
const Bar& bar_;
diff --git a/include/modules/cava.hpp b/include/modules/cava.hpp
deleted file mode 100644
index 1a88c7b7..00000000
--- a/include/modules/cava.hpp
+++ /dev/null
@@ -1,59 +0,0 @@
-#pragma once
-
-#include "ALabel.hpp"
-#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 {
-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};
- std::string format_silent_{""};
- 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/cava.hpp b/include/modules/cava/cava.hpp
new file mode 100644
index 00000000..6b13c4bd
--- /dev/null
+++ b/include/modules/cava/cava.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 onUpdate(const std::string& input) -> void;
+ auto onSilence() -> void;
+ auto doAction(const std::string& name) -> void override;
+
+ private:
+ std::shared_ptr backend_;
+ // Text to display
+ std::string label_text_{""};
+ bool hide_on_silence_{false};
+ std::string format_silent_{""};
+ int ascii_range_{0};
+ bool silence_{false};
+ // Cava method
+ void pause_resume();
+ // 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..d8a2ce06
--- /dev/null
+++ b/include/modules/cava/cava_backend.hpp
@@ -0,0 +1,74 @@
+#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();
+ // Signal accessor
+ using type_signal_update = sigc::signal;
+ type_signal_update signal_update();
+ using type_signal_silence = sigc::signal;
+ type_signal_silence signal_silence();
+
+ private:
+ CavaBackend(const Json::Value& config);
+ util::SleeperThread thread_;
+ util::SleeperThread read_thread_;
+ // Cava API to read audio source
+ ::cava::ptr input_source_;
+
+ 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{}};
+
+ std::chrono::seconds fetch_input_delay_{4};
+ // Delay to handle audio source
+ std::chrono::milliseconds frame_time_milsec_{1s};
+
+ 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);
+
+ // Signal
+ type_signal_update m_signal_update_;
+ type_signal_silence m_signal_silence_;
+};
+} // namespace waybar::modules::cava
diff --git a/include/modules/clock.hpp b/include/modules/clock.hpp
index 40b4f80e..c3548063 100644
--- a/include/modules/clock.hpp
+++ b/include/modules/clock.hpp
@@ -38,39 +38,41 @@ 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
- int cldShift_{1}; // calendar months shift factor
- 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 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();
diff --git a/include/modules/ext/workspace_manager.hpp b/include/modules/ext/workspace_manager.hpp
new file mode 100644
index 00000000..686c7fc7
--- /dev/null
+++ b/include/modules/ext/workspace_manager.hpp
@@ -0,0 +1,141 @@
+#pragma once
+
+#include
+#include
+#include
+#include
+
+#include