Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Idempotent bar show/hide via configurable user kill signals #3930

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions include/bar.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -118,6 +123,9 @@ class Bar : public sigc::trackable {
std::unique_ptr<BarIpcClient> _ipc_client;
#endif
std::vector<std::shared_ptr<waybar::AModule>> modules_all_;

waybar::util::KillSignalAction onSigusr1 = util::SIGNALACTION_DEFAULT_SIGUSR1;
waybar::util::KillSignalAction onSigusr2 = util::SIGNALACTION_DEFAULT_SIGUSR2;
};

} // namespace waybar
26 changes: 26 additions & 0 deletions include/util/kill_signal.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#pragma once

#include <json/value.h>

#include <cstdint>

namespace waybar::util {

enum class KillSignalAction : std::uint8_t {
TOGGLE,
RELOAD,
SHOW,
HIDE,
NOOP,
};
const std::map<std::string, KillSignalAction> userKillSignalActions = {
{"TOGGLE", KillSignalAction::TOGGLE},
{"RELOAD", KillSignalAction::RELOAD},
{"SHOW", KillSignalAction::SHOW},
{"HIDE", KillSignalAction::HIDE},
{"NOOP", KillSignalAction::NOOP}};

const KillSignalAction SIGNALACTION_DEFAULT_SIGUSR1 = KillSignalAction::TOGGLE;
const KillSignalAction SIGNALACTION_DEFAULT_SIGUSR2 = KillSignalAction::RELOAD;

}; // namespace waybar::util
40 changes: 38 additions & 2 deletions man/waybar.5.scd.in
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,20 @@ The visual display elements for waybar use a CSS stylesheet, see *waybar-styles(
default: *false* ++
Option to enable reloading the css style if a modification is detected on the style sheet file or any imported css files.

*on_sigusr1* ++
typeof: string ++
default: *toggle* ++
Action that is performed when receiving SIGUSR1 kill signal. ++
Possible values: *show*, *hide*, *toggle*, *reload*, *noop*. ++
Default value: *toggle*.

*on_sigusr2* ++
typeof: string ++
default: *reload* ++
Action that is performed when receiving SIGUSR2 kill signal. ++
Possible values: *show*, *hide*, *toggle*, *reload*, *noop*. ++
Default value: *reload*.

# MODULE FORMAT

You can use PangoMarkupFormat (See https://developer.gnome.org/pango/stable/PangoMarkupFormat.html#PangoMarkupFormat).
Expand Down Expand Up @@ -206,14 +220,36 @@ A minimal *config* file could look like this:
Waybar accepts the following signals:

*SIGUSR1*
Toggles the bar visibility (hides if shown, shows if hidden)
By default toggles the bar visibility (hides if shown, shows if hidden)
*SIGUSR2*
Reloads (resets) the bar
By default reloads (resets) the bar
*SIGINT*
Quits the bar

For example, to toggle the bar programmatically, you can invoke `killall -SIGUSR1 waybar`.

## User signal configuration

Config parameters *on_sigusr1* and *on_sigusr2* change what happens when bars receive
*SIGUSR1* and *SIGUSR2* signals.

This means that commands `killall -SIGUSR1 waybar` and `killall -SIGUSR2 waybar`
can perform user-configured action.

It also means that if an external script has the PID of the bar then it can
perform more complex `show`/`hide`/`reload` logic for each instance of Waybar.
One can find the PID e.g. by doing `pgrep -a waybar` which could then match
by config name or other parameters.

## Kill parameter meanings

*show* Switches state to visible (per bar).
*hide* Switches state to hidden (per bar).
*toggle* Switches state between visible and hidden (per bar).
*reload* Reloads all waybars of current waybar process (basically equivalent to
restarting with updated config which sets initial visibility values).
*noop* Does nothing when the kill signal is received.

# MULTI OUTPUT CONFIGURATION

## Limit a configuration to some outputs
Expand Down
33 changes: 33 additions & 0 deletions src/bar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
#include "client.hpp"
#include "factory.hpp"
#include "group.hpp"
#include "util/enum.hpp"
#include "util/kill_signal.hpp"

#ifdef HAVE_SWAY
#include "modules/sway/bar.hpp"
Expand Down Expand Up @@ -277,6 +279,32 @@ waybar::Bar::Bar(struct waybar_output* w_output, const Json::Value& w_config)
}
#endif

waybar::util::EnumParser<util::KillSignalAction> m_signalActionEnumParser;
const auto& configSigusr1 = config["on_sigusr1"];
if (configSigusr1.isString()) {
auto strSigusr1 = configSigusr1.asString();
try {
onSigusr1 =
m_signalActionEnumParser.parseStringToEnum(strSigusr1, util::userKillSignalActions);
} catch (const std::invalid_argument& e) {
onSigusr1 = util::SIGNALACTION_DEFAULT_SIGUSR1;
spdlog::warn(
"Invalid string representation for on_sigusr1. Falling back to default mode (toggle).");
}
}
const auto& configSigusr2 = config["on_sigusr2"];
if (configSigusr2.isString()) {
auto strSigusr2 = configSigusr2.asString();
try {
onSigusr2 =
m_signalActionEnumParser.parseStringToEnum(strSigusr2, util::userKillSignalActions);
} catch (const std::invalid_argument& e) {
onSigusr2 = util::SIGNALACTION_DEFAULT_SIGUSR2;
spdlog::warn(
"Invalid string representation for on_sigusr2. Falling back to default mode (reload).");
}
}

setupWidgets();
window.show_all();

Expand Down Expand Up @@ -422,6 +450,8 @@ void waybar::Bar::setVisible(bool value) {
}

void waybar::Bar::toggle() { setVisible(!visible); }
void waybar::Bar::show() { setVisible(true); }
void waybar::Bar::hide() { setVisible(false); }

// Converting string to button code rn as to avoid doing it later
void waybar::Bar::setupAltFormatKeyForModule(const std::string& module_name) {
Expand Down Expand Up @@ -479,6 +509,9 @@ void waybar::Bar::handleSignal(int signal) {
}
}

waybar::util::KillSignalAction waybar::Bar::getOnSigusr1Action() { return this->onSigusr1; }
waybar::util::KillSignalAction waybar::Bar::getOnSigusr2Action() { return this->onSigusr2; }

void waybar::Bar::getModules(const Factory& factory, const std::string& pos,
waybar::Group* group = nullptr) {
auto module_list = group != nullptr ? config[pos]["modules"] : config[pos];
Expand Down
48 changes: 38 additions & 10 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@
#include <list>
#include <mutex>

#include "bar.hpp"
#include "client.hpp"
#include "util/backend_common.hpp"

std::mutex reap_mtx;
std::list<pid_t> reap;
Expand Down Expand Up @@ -70,21 +72,47 @@ void startSignalThread() {
}
}

waybar::util::KillSignalAction getActionForBar(waybar::Bar* bar, int signal) {
switch (signal) {
case SIGUSR1:
return bar->getOnSigusr1Action();
case SIGUSR2:
return bar->getOnSigusr2Action();
default:
return waybar::util::KillSignalAction::NOOP;
}
}

void handleUserSignal(int signal) {
for (auto& bar : waybar::Client::inst()->bars) {
switch (getActionForBar(bar.get(), signal)) {
case waybar::util::KillSignalAction::HIDE:
bar->hide();
break;
case waybar::util::KillSignalAction::SHOW:
bar->show();
break;
case waybar::util::KillSignalAction::TOGGLE:
bar->toggle();
break;
case waybar::util::KillSignalAction::RELOAD:
spdlog::info("Reloading...");
reload = true;
waybar::Client::inst()->reset();
return;
case waybar::util::KillSignalAction::NOOP:
break;
}
}
}

int main(int argc, char* argv[]) {
try {
auto* client = waybar::Client::inst();

std::signal(SIGUSR1, [](int /*signal*/) {
for (auto& bar : waybar::Client::inst()->bars) {
bar->toggle();
}
});
std::signal(SIGUSR1, [](int /*signal*/) { handleUserSignal(SIGUSR1); });

std::signal(SIGUSR2, [](int /*signal*/) {
spdlog::info("Reloading...");
reload = true;
waybar::Client::inst()->reset();
});
std::signal(SIGUSR2, [](int /*signal*/) { handleUserSignal(SIGUSR2); });

std::signal(SIGINT, [](int /*signal*/) {
spdlog::info("Quitting.");
Expand Down
1 change: 1 addition & 0 deletions src/util/enum.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,5 +41,6 @@ EnumType EnumParser<EnumType>::parseStringToEnum(const std::string& str,
// Explicit instantiations for specific EnumType types you intend to use
// Add explicit instantiations for all relevant EnumType types
template struct EnumParser<modules::hyprland::Workspaces::SortMethod>;
template struct EnumParser<util::KillSignalAction>;

} // namespace waybar::util