commit
89be55b00b
|
@ -1,4 +1,5 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
#include <atomic>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "modules/sway/ipc/client.hpp"
|
#include "modules/sway/ipc/client.hpp"
|
||||||
|
@ -30,18 +31,28 @@ class BarIpcClient {
|
||||||
private:
|
private:
|
||||||
void onInitialConfig(const struct Ipc::ipc_response& res);
|
void onInitialConfig(const struct Ipc::ipc_response& res);
|
||||||
void onIpcEvent(const struct Ipc::ipc_response&);
|
void onIpcEvent(const struct Ipc::ipc_response&);
|
||||||
|
void onCmd(const struct Ipc::ipc_response&);
|
||||||
void onConfigUpdate(const swaybar_config& config);
|
void onConfigUpdate(const swaybar_config& config);
|
||||||
void onVisibilityUpdate(bool visible_by_modifier);
|
void onVisibilityUpdate(bool visible_by_modifier);
|
||||||
|
void onModeUpdate(bool visible_by_modifier);
|
||||||
|
void onUrgencyUpdate(bool visible_by_urgency);
|
||||||
void update();
|
void update();
|
||||||
|
bool isModuleEnabled(std::string name);
|
||||||
|
|
||||||
Bar& bar_;
|
Bar& bar_;
|
||||||
util::JsonParser parser_;
|
util::JsonParser parser_;
|
||||||
Ipc ipc_;
|
Ipc ipc_;
|
||||||
|
|
||||||
swaybar_config bar_config_;
|
swaybar_config bar_config_;
|
||||||
|
std::string modifier_reset_;
|
||||||
|
bool visible_by_mode_ = false;
|
||||||
bool visible_by_modifier_ = false;
|
bool visible_by_modifier_ = false;
|
||||||
|
bool visible_by_urgency_ = false;
|
||||||
|
std::atomic<bool> modifier_no_action_ = false;
|
||||||
|
|
||||||
|
SafeSignal<bool> signal_mode_;
|
||||||
SafeSignal<bool> signal_visible_;
|
SafeSignal<bool> signal_visible_;
|
||||||
|
SafeSignal<bool> signal_urgency_;
|
||||||
SafeSignal<swaybar_config> signal_config_;
|
SafeSignal<swaybar_config> signal_config_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -77,6 +77,13 @@ Also a minimal example configuration can be found on the at the bottom of this m
|
||||||
Selects one of the preconfigured display modes. This is an equivalent of the sway-bar(5) *mode* command and supports the same values: *dock*, *hide*, *invisible*, *overlay*. ++
|
Selects one of the preconfigured display modes. This is an equivalent of the sway-bar(5) *mode* command and supports the same values: *dock*, *hide*, *invisible*, *overlay*. ++
|
||||||
Note: *hide* and *invisible* modes may be not as useful without Sway IPC.
|
Note: *hide* and *invisible* modes may be not as useful without Sway IPC.
|
||||||
|
|
||||||
|
modifier-reset ++
|
||||||
|
typeof: string ++
|
||||||
|
default: *press*
|
||||||
|
Defines the timing of modifier key to reset the bar visibility.
|
||||||
|
To reset the visibility of the bar with the press of the modifier key use *press*.
|
||||||
|
Use *release* to reset the visibility upon the release of the modifier key and only if no other action happened while the key was pressed. This prevents hiding the bar when the modifier is used to switch a workspace, change binding mode or start a keybinding.
|
||||||
|
|
||||||
*exclusive* ++
|
*exclusive* ++
|
||||||
typeof: bool ++
|
typeof: bool ++
|
||||||
default: *true* ++
|
default: *true* ++
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include <fmt/ostream.h>
|
#include <fmt/ostream.h>
|
||||||
#include <spdlog/spdlog.h>
|
#include <spdlog/spdlog.h>
|
||||||
|
|
||||||
|
#include <sstream>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
#include "bar.hpp"
|
#include "bar.hpp"
|
||||||
|
@ -19,11 +20,37 @@ BarIpcClient::BarIpcClient(waybar::Bar& bar) : bar_{bar} {
|
||||||
handle.disconnect();
|
handle.disconnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Json::Value subscribe_events{Json::arrayValue};
|
||||||
|
subscribe_events.append("bar_state_update");
|
||||||
|
subscribe_events.append("barconfig_update");
|
||||||
|
|
||||||
|
bool has_mode = isModuleEnabled("sway/mode");
|
||||||
|
bool has_workspaces = isModuleEnabled("sway/workspaces");
|
||||||
|
|
||||||
|
if (has_mode) {
|
||||||
|
subscribe_events.append("mode");
|
||||||
|
}
|
||||||
|
if (has_workspaces) {
|
||||||
|
subscribe_events.append("workspace");
|
||||||
|
}
|
||||||
|
if (has_mode || has_workspaces) {
|
||||||
|
subscribe_events.append("binding");
|
||||||
|
}
|
||||||
|
|
||||||
|
modifier_reset_ = bar.config.get("modifier-reset", "press").asString();
|
||||||
|
|
||||||
signal_config_.connect(sigc::mem_fun(*this, &BarIpcClient::onConfigUpdate));
|
signal_config_.connect(sigc::mem_fun(*this, &BarIpcClient::onConfigUpdate));
|
||||||
signal_visible_.connect(sigc::mem_fun(*this, &BarIpcClient::onVisibilityUpdate));
|
signal_visible_.connect(sigc::mem_fun(*this, &BarIpcClient::onVisibilityUpdate));
|
||||||
|
signal_urgency_.connect(sigc::mem_fun(*this, &BarIpcClient::onUrgencyUpdate));
|
||||||
|
signal_mode_.connect(sigc::mem_fun(*this, &BarIpcClient::onModeUpdate));
|
||||||
|
|
||||||
ipc_.subscribe(R"(["bar_state_update", "barconfig_update"])");
|
// Subscribe to non bar events to determine if the modifier key press is followed by another
|
||||||
|
// action.
|
||||||
|
std::ostringstream oss_events;
|
||||||
|
oss_events << subscribe_events;
|
||||||
|
ipc_.subscribe(oss_events.str());
|
||||||
ipc_.signal_event.connect(sigc::mem_fun(*this, &BarIpcClient::onIpcEvent));
|
ipc_.signal_event.connect(sigc::mem_fun(*this, &BarIpcClient::onIpcEvent));
|
||||||
|
ipc_.signal_cmd.connect(sigc::mem_fun(*this, &BarIpcClient::onCmd));
|
||||||
// Launch worker
|
// Launch worker
|
||||||
ipc_.setWorker([this] {
|
ipc_.setWorker([this] {
|
||||||
try {
|
try {
|
||||||
|
@ -34,6 +61,19 @@ BarIpcClient::BarIpcClient(waybar::Bar& bar) : bar_{bar} {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool BarIpcClient::isModuleEnabled(std::string name) {
|
||||||
|
for (const auto& section : {"modules-left", "modules-center", "modules-right"}) {
|
||||||
|
if (const auto& modules = bar_.config.get(section, {}); modules.isArray()) {
|
||||||
|
for (const auto& module : modules) {
|
||||||
|
if (module.asString().rfind(name, 0) == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
struct swaybar_config parseConfig(const Json::Value& payload) {
|
struct swaybar_config parseConfig(const Json::Value& payload) {
|
||||||
swaybar_config conf;
|
swaybar_config conf;
|
||||||
if (auto id = payload["id"]; id.isString()) {
|
if (auto id = payload["id"]; id.isString()) {
|
||||||
|
@ -61,23 +101,76 @@ void BarIpcClient::onInitialConfig(const struct Ipc::ipc_response& res) {
|
||||||
void BarIpcClient::onIpcEvent(const struct Ipc::ipc_response& res) {
|
void BarIpcClient::onIpcEvent(const struct Ipc::ipc_response& res) {
|
||||||
try {
|
try {
|
||||||
auto payload = parser_.parse(res.payload);
|
auto payload = parser_.parse(res.payload);
|
||||||
if (auto id = payload["id"]; id.isString() && id.asString() != bar_.bar_id) {
|
switch (res.type) {
|
||||||
spdlog::trace("swaybar ipc: ignore event for {}", id.asString());
|
case IPC_EVENT_WORKSPACE:
|
||||||
return;
|
if (payload.isMember("change")) {
|
||||||
}
|
// only check and send signal if the workspace update reason was because of a urgent
|
||||||
if (payload.isMember("visible_by_modifier")) {
|
// change
|
||||||
// visibility change for hidden bar
|
if (payload["change"] == "urgent") {
|
||||||
signal_visible_(payload["visible_by_modifier"].asBool());
|
auto urgent = payload["current"]["urgent"];
|
||||||
} else {
|
if (urgent.asBool()) {
|
||||||
// configuration update
|
// Event for a new urgency, update the visibly
|
||||||
auto config = parseConfig(payload);
|
signal_urgency_(true);
|
||||||
signal_config_(std::move(config));
|
} else if (!urgent.asBool() && visible_by_urgency_) {
|
||||||
|
// Event clearing an urgency, bar is visible, check if another workspace still has
|
||||||
|
// the urgency hint set
|
||||||
|
ipc_.sendCmd(IPC_GET_WORKSPACES);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
modifier_no_action_ = false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case IPC_EVENT_MODE:
|
||||||
|
if (payload.isMember("change")) {
|
||||||
|
signal_mode_(payload["change"] != "default");
|
||||||
|
modifier_no_action_ = false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case IPC_EVENT_BINDING:
|
||||||
|
modifier_no_action_ = false;
|
||||||
|
break;
|
||||||
|
case IPC_EVENT_BAR_STATE_UPDATE:
|
||||||
|
case IPC_EVENT_BARCONFIG_UPDATE:
|
||||||
|
if (auto id = payload["id"]; id.isString() && id.asString() != bar_.bar_id) {
|
||||||
|
spdlog::trace("swaybar ipc: ignore event for {}", id.asString());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (payload.isMember("visible_by_modifier")) {
|
||||||
|
// visibility change for hidden bar
|
||||||
|
signal_visible_(payload["visible_by_modifier"].asBool());
|
||||||
|
} else {
|
||||||
|
// configuration update
|
||||||
|
auto config = parseConfig(payload);
|
||||||
|
signal_config_(std::move(config));
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
} catch (const std::exception& e) {
|
} catch (const std::exception& e) {
|
||||||
spdlog::error("BarIpcClient::onEvent {}", e.what());
|
spdlog::error("BarIpcClient::onEvent {}", e.what());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BarIpcClient::onCmd(const struct Ipc::ipc_response& res) {
|
||||||
|
if (res.type == IPC_GET_WORKSPACES) {
|
||||||
|
try {
|
||||||
|
auto payload = parser_.parse(res.payload);
|
||||||
|
for (auto& ws : payload) {
|
||||||
|
if (ws["urgent"].asBool()) {
|
||||||
|
spdlog::debug("Found workspace {} with urgency set. Stopping search.", ws["name"]);
|
||||||
|
// Found one workspace with urgency set, signal bar visibility
|
||||||
|
signal_urgency_(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Command to get workspaces was sent after a change in workspaces was based on "urgent",
|
||||||
|
// if no workspace has this flag set to true, all flags must be cleared.
|
||||||
|
signal_urgency_(false);
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
spdlog::error("Bar: {}", e.what());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void BarIpcClient::onConfigUpdate(const swaybar_config& config) {
|
void BarIpcClient::onConfigUpdate(const swaybar_config& config) {
|
||||||
spdlog::info("config update for {}: id {}, mode {}, hidden_state {}", bar_.bar_id, config.id,
|
spdlog::info("config update for {}: id {}, mode {}, hidden_state {}", bar_.bar_id, config.id,
|
||||||
config.mode, config.hidden_state);
|
config.mode, config.hidden_state);
|
||||||
|
@ -85,14 +178,39 @@ void BarIpcClient::onConfigUpdate(const swaybar_config& config) {
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BarIpcClient::onModeUpdate(bool visible_by_mode) {
|
||||||
|
spdlog::debug("mode update for {}: {}", bar_.bar_id, visible_by_mode);
|
||||||
|
visible_by_mode_ = visible_by_mode;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
void BarIpcClient::onVisibilityUpdate(bool visible_by_modifier) {
|
void BarIpcClient::onVisibilityUpdate(bool visible_by_modifier) {
|
||||||
spdlog::debug("visiblity update for {}: {}", bar_.bar_id, visible_by_modifier);
|
spdlog::debug("visibility update for {}: {}", bar_.bar_id, visible_by_modifier);
|
||||||
visible_by_modifier_ = visible_by_modifier;
|
visible_by_modifier_ = visible_by_modifier;
|
||||||
|
if (visible_by_modifier) {
|
||||||
|
modifier_no_action_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear on either press or release depending on bar_.bar_config_.action value.
|
||||||
|
// For the check on release, make sure that the modifier key was not used for another action.
|
||||||
|
if (((modifier_reset_ == "press" && visible_by_modifier_) ||
|
||||||
|
(modifier_reset_ == "release" && !visible_by_modifier_ && modifier_no_action_))) {
|
||||||
|
// Clear the flags to hide the bar.
|
||||||
|
visible_by_urgency_ = false;
|
||||||
|
visible_by_mode_ = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BarIpcClient::onUrgencyUpdate(bool visible_by_urgency) {
|
||||||
|
spdlog::debug("urgency update for {}: {}", bar_.bar_id, visible_by_urgency);
|
||||||
|
visible_by_urgency_ = visible_by_urgency;
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
void BarIpcClient::update() {
|
void BarIpcClient::update() {
|
||||||
bool visible = visible_by_modifier_;
|
bool visible = visible_by_modifier_ || visible_by_mode_ || visible_by_urgency_;
|
||||||
if (bar_config_.mode == "invisible") {
|
if (bar_config_.mode == "invisible") {
|
||||||
visible = false;
|
visible = false;
|
||||||
} else if (bar_config_.mode != "hide" || bar_config_.hidden_state != "hide") {
|
} else if (bar_config_.mode != "hide" || bar_config_.hidden_state != "hide") {
|
||||||
|
|
Loading…
Reference in New Issue