Fix inconsistancies with the systray toggle
Some checks failed
clang-format / lint (push) Has been cancelled
freebsd / build (push) Has been cancelled
linux / build (c++20, alpine) (push) Has been cancelled
linux / build (c++20, archlinux) (push) Has been cancelled
linux / build (c++20, debian) (push) Has been cancelled
linux / build (c++20, fedora) (push) Has been cancelled
linux / build (c++20, gentoo) (push) Has been cancelled
linux / build (c++20, opensuse) (push) Has been cancelled
Nix-Tests / nix-flake-check (push) Has been cancelled

This commit is contained in:
2026-02-09 02:45:58 -08:00
parent 8e5f7fec42
commit 0abbf221a2
6 changed files with 98 additions and 61 deletions

5
.dir-locals.el Normal file
View File

@@ -0,0 +1,5 @@
;;; Directory Local Variables -*- no-byte-compile: t -*-
;;; For more information see (info "(emacs) Directory Variables")
((nil . ((ff-search-directories . ("../include/*/" "../../include/*/"
"../src/*/" "../../src/*/")))))

View File

@@ -5,6 +5,8 @@
#include <gdk/gdkwayland.h> #include <gdk/gdkwayland.h>
#include <wayland-client.h> #include <wayland-client.h>
#include <map>
#include "bar.hpp" #include "bar.hpp"
#include "config.hpp" #include "config.hpp"
#include "util/css_reload_helper.hpp" #include "util/css_reload_helper.hpp"
@@ -17,35 +19,38 @@ namespace waybar {
class Client { class Client {
public: public:
static Client *inst(); static Client* inst();
int main(int argc, char *argv[]); int main(int argc, char* argv[]);
void reset(); void reset();
bool get_signal_state(int signum) const;
void toggle_signal_state(int signum);
Glib::RefPtr<Gtk::Application> gtk_app; Glib::RefPtr<Gtk::Application> gtk_app;
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 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;
Config config; Config config;
std::string bar_id; std::string bar_id;
private: private:
Client() = default; Client() = default;
const std::string getStyle(const std::string &style, std::optional<Appearance> appearance); 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;
struct waybar_output &getOutput(void *); struct waybar_output& getOutput(void*);
std::vector<Json::Value> getOutputConfigs(struct waybar_output &output); std::vector<Json::Value> getOutputConfigs(struct waybar_output& output);
static void handleGlobal(void *data, struct wl_registry *registry, uint32_t name, static void handleGlobal(void* data, struct wl_registry* registry, uint32_t name,
const char *interface, uint32_t version); const char* interface, uint32_t version);
static void handleGlobalRemove(void *data, struct wl_registry *registry, uint32_t name); static void handleGlobalRemove(void* data, struct wl_registry* registry, uint32_t name);
static void handleOutputDone(void *, struct zxdg_output_v1 *); static void handleOutputDone(void*, struct zxdg_output_v1*);
static void handleOutputName(void *, struct zxdg_output_v1 *, const char *); static void handleOutputName(void*, struct zxdg_output_v1*, const char*);
static void handleOutputDescription(void *, struct zxdg_output_v1 *, const char *); static void handleOutputDescription(void*, struct zxdg_output_v1*, const char*);
void handleMonitorAdded(Glib::RefPtr<Gdk::Monitor> monitor); void handleMonitorAdded(Glib::RefPtr<Gdk::Monitor> monitor);
void handleMonitorRemoved(Glib::RefPtr<Gdk::Monitor> monitor); void handleMonitorRemoved(Glib::RefPtr<Gdk::Monitor> monitor);
void handleDeferredMonitorRemoval(Glib::RefPtr<Gdk::Monitor> monitor); void handleDeferredMonitorRemoval(Glib::RefPtr<Gdk::Monitor> monitor);
@@ -56,6 +61,8 @@ class Client {
std::list<struct waybar_output> outputs_; std::list<struct waybar_output> outputs_;
std::unique_ptr<CssReloadHelper> m_cssReloadHelper; std::unique_ptr<CssReloadHelper> m_cssReloadHelper;
std::string m_cssFile; std::string m_cssFile;
std::map<int, bool> signal_toggle_state;
}; };
} // namespace waybar } // namespace waybar

View File

@@ -13,14 +13,14 @@ 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() override = default; ~Group() override = default;
auto update() -> void override; auto update() -> void override;
operator Gtk::Widget &() override; operator Gtk::Widget&() override;
auto refresh(int sig) -> void override; auto refresh(int sig) -> void override;
virtual Gtk::Box &getBox(); virtual Gtk::Box& getBox();
void addWidget(Gtk::Widget &widget); void addWidget(Gtk::Widget& widget);
protected: protected:
Gtk::Box box; Gtk::Box box;
@@ -31,12 +31,19 @@ class Group : public AModule {
bool click_to_reveal = false; bool click_to_reveal = false;
std::optional<int> toggle_signal; std::optional<int> toggle_signal;
std::string add_class_to_drawer_children; std::string add_class_to_drawer_children;
bool handleMouseEnter(GdkEventCrossing *const &ev) override; bool handleMouseEnter(GdkEventCrossing* const& ev) override;
bool handleMouseLeave(GdkEventCrossing *const &ev) override; bool handleMouseLeave(GdkEventCrossing* const& ev) override;
bool handleToggle(GdkEventButton *const &ev) override; bool handleToggle(GdkEventButton* const& ev) override;
void toggle(); void toggle();
void show_group(); void show_group();
void hide_group(); void hide_group();
void set_visible(bool v) {
if (v) {
show_group();
} else {
hide_group();
}
}
}; };
} // namespace waybar } // namespace waybar

View File

@@ -4,6 +4,7 @@
#include <spdlog/spdlog.h> #include <spdlog/spdlog.h>
#include <iostream> #include <iostream>
#include <stdexcept>
#include <utility> #include <utility>
#include "gtkmm/icontheme.h" #include "gtkmm/icontheme.h"
@@ -11,60 +12,60 @@
#include "util/clara.hpp" #include "util/clara.hpp"
#include "util/format.hpp" #include "util/format.hpp"
waybar::Client *waybar::Client::inst() { waybar::Client* waybar::Client::inst() {
static auto *c = new Client(); static auto* c = new Client();
return c; return c;
} }
void waybar::Client::handleGlobal(void *data, struct wl_registry *registry, uint32_t name, void waybar::Client::handleGlobal(void* data, struct wl_registry* registry, uint32_t name,
const char *interface, uint32_t version) { const char* interface, uint32_t version) {
auto *client = static_cast<Client *>(data); auto* client = static_cast<Client*>(data);
if (strcmp(interface, zxdg_output_manager_v1_interface.name) == 0 && if (strcmp(interface, zxdg_output_manager_v1_interface.name) == 0 &&
version >= ZXDG_OUTPUT_V1_NAME_SINCE_VERSION) { version >= ZXDG_OUTPUT_V1_NAME_SINCE_VERSION) {
client->xdg_output_manager = static_cast<struct zxdg_output_manager_v1 *>(wl_registry_bind( client->xdg_output_manager = static_cast<struct zxdg_output_manager_v1*>(wl_registry_bind(
registry, name, &zxdg_output_manager_v1_interface, ZXDG_OUTPUT_V1_NAME_SINCE_VERSION)); registry, name, &zxdg_output_manager_v1_interface, ZXDG_OUTPUT_V1_NAME_SINCE_VERSION));
} else if (strcmp(interface, zwp_idle_inhibit_manager_v1_interface.name) == 0) { } else if (strcmp(interface, zwp_idle_inhibit_manager_v1_interface.name) == 0) {
client->idle_inhibit_manager = static_cast<struct zwp_idle_inhibit_manager_v1 *>( client->idle_inhibit_manager = static_cast<struct zwp_idle_inhibit_manager_v1*>(
wl_registry_bind(registry, name, &zwp_idle_inhibit_manager_v1_interface, 1)); wl_registry_bind(registry, name, &zwp_idle_inhibit_manager_v1_interface, 1));
} }
} }
void waybar::Client::handleGlobalRemove(void *data, struct wl_registry * /*registry*/, void waybar::Client::handleGlobalRemove(void* data, struct wl_registry* /*registry*/,
uint32_t name) { uint32_t name) {
// Nothing here // Nothing here
} }
void waybar::Client::handleOutput(struct waybar_output &output) { void waybar::Client::handleOutput(struct waybar_output& output) {
static const struct zxdg_output_v1_listener xdgOutputListener = { static const struct zxdg_output_v1_listener xdgOutputListener = {
.logical_position = [](void *, struct zxdg_output_v1 *, int32_t, int32_t) {}, .logical_position = [](void*, struct zxdg_output_v1*, int32_t, int32_t) {},
.logical_size = [](void *, struct zxdg_output_v1 *, int32_t, int32_t) {}, .logical_size = [](void*, struct zxdg_output_v1*, int32_t, int32_t) {},
.done = &handleOutputDone, .done = &handleOutputDone,
.name = &handleOutputName, .name = &handleOutputName,
.description = &handleOutputDescription, .description = &handleOutputDescription,
}; };
// owned by output->monitor; no need to destroy // owned by output->monitor; no need to destroy
auto *wl_output = gdk_wayland_monitor_get_wl_output(output.monitor->gobj()); auto* wl_output = gdk_wayland_monitor_get_wl_output(output.monitor->gobj());
output.xdg_output.reset(zxdg_output_manager_v1_get_xdg_output(xdg_output_manager, wl_output)); output.xdg_output.reset(zxdg_output_manager_v1_get_xdg_output(xdg_output_manager, wl_output));
zxdg_output_v1_add_listener(output.xdg_output.get(), &xdgOutputListener, &output); zxdg_output_v1_add_listener(output.xdg_output.get(), &xdgOutputListener, &output);
} }
struct waybar::waybar_output &waybar::Client::getOutput(void *addr) { struct waybar::waybar_output& waybar::Client::getOutput(void* addr) {
auto it = std::find_if(outputs_.begin(), outputs_.end(), auto it = std::find_if(outputs_.begin(), outputs_.end(),
[&addr](const auto &output) { return &output == addr; }); [&addr](const auto& output) { return &output == addr; });
if (it == outputs_.end()) { if (it == outputs_.end()) {
throw std::runtime_error("Unable to find valid output"); throw std::runtime_error("Unable to find valid output");
} }
return *it; return *it;
} }
std::vector<Json::Value> waybar::Client::getOutputConfigs(struct waybar_output &output) { std::vector<Json::Value> waybar::Client::getOutputConfigs(struct waybar_output& output) {
return config.getOutputConfigs(output.name, output.identifier); return config.getOutputConfigs(output.name, output.identifier);
} }
void waybar::Client::handleOutputDone(void *data, struct zxdg_output_v1 * /*xdg_output*/) { void waybar::Client::handleOutputDone(void* data, struct zxdg_output_v1* /*xdg_output*/) {
auto *client = waybar::Client::inst(); auto* client = waybar::Client::inst();
try { try {
auto &output = client->getOutput(data); auto& output = client->getOutput(data);
/** /**
* Multiple .done events may arrive in batch. In this case libwayland would queue * Multiple .done events may arrive in batch. In this case libwayland would queue
* xdg_output.destroy and dispatch all pending events, triggering this callback several times * xdg_output.destroy and dispatch all pending events, triggering this callback several times
@@ -80,44 +81,44 @@ void waybar::Client::handleOutputDone(void *data, struct zxdg_output_v1 * /*xdg_
auto configs = client->getOutputConfigs(output); auto configs = client->getOutputConfigs(output);
if (!configs.empty()) { if (!configs.empty()) {
for (const auto &config : configs) { for (const auto& config : configs) {
client->bars.emplace_back(std::make_unique<Bar>(&output, config)); client->bars.emplace_back(std::make_unique<Bar>(&output, config));
} }
} }
} }
} catch (const std::exception &e) { } catch (const std::exception& e) {
spdlog::warn("caught exception in zxdg_output_v1_listener::done: {}", e.what()); spdlog::warn("caught exception in zxdg_output_v1_listener::done: {}", e.what());
} }
} }
void waybar::Client::handleOutputName(void *data, struct zxdg_output_v1 * /*xdg_output*/, void waybar::Client::handleOutputName(void* data, struct zxdg_output_v1* /*xdg_output*/,
const char *name) { const char* name) {
auto *client = waybar::Client::inst(); auto* client = waybar::Client::inst();
try { try {
auto &output = client->getOutput(data); auto& output = client->getOutput(data);
output.name = name; output.name = name;
} catch (const std::exception &e) { } catch (const std::exception& e) {
spdlog::warn("caught exception in zxdg_output_v1_listener::name: {}", e.what()); spdlog::warn("caught exception in zxdg_output_v1_listener::name: {}", e.what());
} }
} }
void waybar::Client::handleOutputDescription(void *data, struct zxdg_output_v1 * /*xdg_output*/, void waybar::Client::handleOutputDescription(void* data, struct zxdg_output_v1* /*xdg_output*/,
const char *description) { const char* description) {
auto *client = waybar::Client::inst(); auto* client = waybar::Client::inst();
try { try {
auto &output = client->getOutput(data); auto& output = client->getOutput(data);
// Description format: "identifier (name)" // Description format: "identifier (name)"
auto s = std::string(description); auto s = std::string(description);
auto pos = s.find(" ("); auto pos = s.find(" (");
output.identifier = pos != std::string::npos ? s.substr(0, pos) : s; output.identifier = pos != std::string::npos ? s.substr(0, pos) : s;
} catch (const std::exception &e) { } catch (const std::exception& e) {
spdlog::warn("caught exception in zxdg_output_v1_listener::description: {}", e.what()); spdlog::warn("caught exception in zxdg_output_v1_listener::description: {}", e.what());
} }
} }
void waybar::Client::handleMonitorAdded(Glib::RefPtr<Gdk::Monitor> monitor) { void waybar::Client::handleMonitorAdded(Glib::RefPtr<Gdk::Monitor> monitor) {
auto &output = outputs_.emplace_back(); auto& output = outputs_.emplace_back();
output.monitor = std::move(monitor); output.monitor = std::move(monitor);
handleOutput(output); handleOutput(output);
} }
@@ -146,10 +147,10 @@ void waybar::Client::handleDeferredMonitorRemoval(Glib::RefPtr<Gdk::Monitor> mon
++it; ++it;
} }
} }
outputs_.remove_if([&monitor](const auto &output) { return output.monitor == monitor; }); outputs_.remove_if([&monitor](const auto& output) { return output.monitor == monitor; });
} }
const std::string waybar::Client::getStyle(const std::string &style, const std::string waybar::Client::getStyle(const std::string& style,
std::optional<Appearance> appearance = std::nullopt) { std::optional<Appearance> appearance = std::nullopt) {
auto gtk_settings = Gtk::Settings::get_default(); auto gtk_settings = Gtk::Settings::get_default();
std::optional<std::string> css_file; std::optional<std::string> css_file;
@@ -182,7 +183,7 @@ const std::string waybar::Client::getStyle(const std::string &style,
return css_file.value(); return css_file.value();
}; };
auto waybar::Client::setupCss(const std::string &css_file) -> void { auto waybar::Client::setupCss(const std::string& css_file) -> void {
css_provider_ = Gtk::CssProvider::create(); css_provider_ = Gtk::CssProvider::create();
style_context_ = Gtk::StyleContext::create(); style_context_ = Gtk::StyleContext::create();
@@ -221,7 +222,7 @@ void waybar::Client::bindInterfaces() {
sigc::mem_fun(*this, &Client::handleMonitorRemoved)); sigc::mem_fun(*this, &Client::handleMonitorRemoved));
} }
int waybar::Client::main(int argc, char *argv[]) { int waybar::Client::main(int argc, char* argv[]) {
bool show_help = false; bool show_help = false;
bool show_version = false; bool show_version = false;
std::string config_opt; std::string config_opt;
@@ -282,7 +283,7 @@ int waybar::Client::main(int argc, char *argv[]) {
if (m_config.isObject() && m_config["reload_style_on_change"].asBool()) { if (m_config.isObject() && m_config["reload_style_on_change"].asBool()) {
m_cssReloadHelper->monitorChanges(); m_cssReloadHelper->monitorChanges();
} else if (m_config.isArray()) { } else if (m_config.isArray()) {
for (const auto &conf : m_config) { for (const auto& conf : m_config) {
if (conf["reload_style_on_change"].asBool()) { if (conf["reload_style_on_change"].asBool()) {
m_cssReloadHelper->monitorChanges(); m_cssReloadHelper->monitorChanges();
break; break;
@@ -290,6 +291,8 @@ int waybar::Client::main(int argc, char *argv[]) {
} }
} }
signal_toggle_state.clear();
bindInterfaces(); bindInterfaces();
gtk_app->hold(); gtk_app->hold();
gtk_app->run(); gtk_app->run();
@@ -303,3 +306,16 @@ void waybar::Client::reset() {
// delete signal handler for css changes // delete signal handler for css changes
portal->signal_appearance_changed().clear(); portal->signal_appearance_changed().clear();
} }
bool waybar::Client::get_signal_state(int signum) const {
try {
return signal_toggle_state.at(signum);
} catch (const std::out_of_range&) {
// default signal states to false
return false;
}
}
void waybar::Client::toggle_signal_state(int signum) {
signal_toggle_state[signum] = !get_signal_state(signum);
}

View File

@@ -4,6 +4,7 @@
#include <util/command.hpp> #include <util/command.hpp>
#include "client.hpp"
#include "gtkmm/enums.h" #include "gtkmm/enums.h"
#include "gtkmm/widget.h" #include "gtkmm/widget.h"
@@ -134,7 +135,7 @@ auto Group::update() -> void {
void Group::refresh(int sig) { void Group::refresh(int sig) {
if (toggle_signal.has_value() && sig == SIGRTMIN + toggle_signal.value()) { if (toggle_signal.has_value() && sig == SIGRTMIN + toggle_signal.value()) {
toggle(); set_visible(waybar::Client::inst()->get_signal_state(sig));
} }
} }

View File

@@ -117,6 +117,7 @@ void handleUserSignal(int signal, bool& reload) {
// `true` or `false`, respectively, into `reload`. // `true` or `false`, respectively, into `reload`.
static void handleSignalMainThread(int signum, bool& reload) { static void handleSignalMainThread(int signum, bool& reload) {
if (signum >= SIGRTMIN + 1 && signum <= SIGRTMAX) { if (signum >= SIGRTMIN + 1 && signum <= SIGRTMAX) {
waybar::Client::inst()->toggle_signal_state(signum);
for (auto& bar : waybar::Client::inst()->bars) { for (auto& bar : waybar::Client::inst()->bars) {
bar->handleSignal(signum); bar->handleSignal(signum);
} }