2020-10-20 02:34:48 +00:00
|
|
|
#include "modules/sway/bar.hpp"
|
|
|
|
|
|
|
|
#include <fmt/ostream.h>
|
|
|
|
#include <spdlog/spdlog.h>
|
|
|
|
|
2021-11-23 16:46:58 +00:00
|
|
|
#include <stdexcept>
|
|
|
|
|
2020-10-20 02:34:48 +00:00
|
|
|
#include "bar.hpp"
|
|
|
|
#include "modules/sway/ipc/ipc.hpp"
|
|
|
|
|
|
|
|
namespace waybar::modules::sway {
|
|
|
|
|
|
|
|
BarIpcClient::BarIpcClient(waybar::Bar& bar) : bar_{bar} {
|
|
|
|
{
|
|
|
|
sigc::connection handle =
|
|
|
|
ipc_.signal_cmd.connect(sigc::mem_fun(*this, &BarIpcClient::onInitialConfig));
|
|
|
|
ipc_.sendCmd(IPC_GET_BAR_CONFIG, bar_.bar_id);
|
|
|
|
|
|
|
|
handle.disconnect();
|
|
|
|
}
|
|
|
|
|
|
|
|
signal_config_.connect(sigc::mem_fun(*this, &BarIpcClient::onConfigUpdate));
|
|
|
|
signal_visible_.connect(sigc::mem_fun(*this, &BarIpcClient::onVisibilityUpdate));
|
2022-04-06 13:53:49 +00:00
|
|
|
signal_urgency_.connect(sigc::mem_fun(*this, &BarIpcClient::onUrgencyUpdate));
|
2022-04-09 11:49:22 +00:00
|
|
|
signal_mode_.connect(sigc::mem_fun(*this, &BarIpcClient::onModeUpdate));
|
2020-10-20 02:34:48 +00:00
|
|
|
|
2022-04-09 11:18:03 +00:00
|
|
|
// Subscribe to non bar events to determine if the modifier key press is followed by another
|
|
|
|
// action.
|
|
|
|
ipc_.subscribe(R"(["bar_state_update", "barconfig_update", "workspace", "mode", "binding"])");
|
2020-10-20 02:34:48 +00:00
|
|
|
ipc_.signal_event.connect(sigc::mem_fun(*this, &BarIpcClient::onIpcEvent));
|
2022-04-06 13:53:49 +00:00
|
|
|
ipc_.signal_cmd.connect(sigc::mem_fun(*this, &BarIpcClient::onCmd));
|
2020-10-20 02:34:48 +00:00
|
|
|
// Launch worker
|
|
|
|
ipc_.setWorker([this] {
|
|
|
|
try {
|
|
|
|
ipc_.handleEvent();
|
|
|
|
} catch (const std::exception& e) {
|
|
|
|
spdlog::error("BarIpcClient::handleEvent {}", e.what());
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
struct swaybar_config parseConfig(const Json::Value& payload) {
|
|
|
|
swaybar_config conf;
|
|
|
|
if (auto id = payload["id"]; id.isString()) {
|
|
|
|
conf.id = id.asString();
|
|
|
|
}
|
|
|
|
if (auto mode = payload["mode"]; mode.isString()) {
|
|
|
|
conf.mode = mode.asString();
|
|
|
|
}
|
|
|
|
if (auto hs = payload["hidden_state"]; hs.isString()) {
|
|
|
|
conf.hidden_state = hs.asString();
|
|
|
|
}
|
|
|
|
return conf;
|
|
|
|
}
|
|
|
|
|
|
|
|
void BarIpcClient::onInitialConfig(const struct Ipc::ipc_response& res) {
|
2021-11-23 16:46:58 +00:00
|
|
|
auto payload = parser_.parse(res.payload);
|
|
|
|
if (auto success = payload.get("success", true); !success.asBool()) {
|
|
|
|
auto err = payload.get("error", "Unknown error");
|
|
|
|
throw std::runtime_error(err.asString());
|
2020-10-20 02:34:48 +00:00
|
|
|
}
|
2021-11-23 16:46:58 +00:00
|
|
|
auto config = parseConfig(payload);
|
|
|
|
onConfigUpdate(config);
|
2020-10-20 02:34:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void BarIpcClient::onIpcEvent(const struct Ipc::ipc_response& res) {
|
|
|
|
try {
|
|
|
|
auto payload = parser_.parse(res.payload);
|
2022-04-06 13:53:49 +00:00
|
|
|
switch (res.type) {
|
|
|
|
case IPC_EVENT_WORKSPACE:
|
|
|
|
if (payload.isMember("change")) {
|
|
|
|
// only check and send signal if the workspace update reason was because of a urgent
|
|
|
|
// change
|
|
|
|
if (payload["change"] == "urgent") {
|
|
|
|
auto urgent = payload["current"]["urgent"];
|
|
|
|
if (urgent.asBool()) {
|
|
|
|
// Event for a new urgency, update the visibly
|
|
|
|
signal_urgency_(true);
|
|
|
|
} 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);
|
|
|
|
}
|
|
|
|
}
|
2022-04-09 11:18:03 +00:00
|
|
|
modifier_no_action_ = false;
|
2022-04-06 13:53:49 +00:00
|
|
|
}
|
|
|
|
break;
|
2022-04-09 11:18:03 +00:00
|
|
|
case IPC_EVENT_MODE:
|
2022-04-09 11:49:22 +00:00
|
|
|
if (payload.isMember("change")) {
|
|
|
|
signal_mode_(payload["change"] != "default");
|
|
|
|
modifier_no_action_ = false;
|
|
|
|
}
|
|
|
|
break;
|
2022-04-09 11:18:03 +00:00
|
|
|
case IPC_EVENT_BINDING:
|
|
|
|
modifier_no_action_ = false;
|
|
|
|
break;
|
2022-04-06 13:53:49 +00:00
|
|
|
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;
|
2020-10-20 02:34:48 +00:00
|
|
|
}
|
|
|
|
} catch (const std::exception& e) {
|
|
|
|
spdlog::error("BarIpcClient::onEvent {}", e.what());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-06 13:53:49 +00:00
|
|
|
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());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-20 02:34:48 +00:00
|
|
|
void BarIpcClient::onConfigUpdate(const swaybar_config& config) {
|
2022-04-06 06:37:19 +00:00
|
|
|
spdlog::info("config update for {}: id {}, mode {}, hidden_state {}", bar_.bar_id, config.id,
|
|
|
|
config.mode, config.hidden_state);
|
2021-09-15 15:39:51 +00:00
|
|
|
bar_config_ = config;
|
2020-10-20 02:35:55 +00:00
|
|
|
update();
|
2020-10-20 02:34:48 +00:00
|
|
|
}
|
|
|
|
|
2022-04-09 11:49:22 +00:00
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
2020-10-20 02:34:48 +00:00
|
|
|
void BarIpcClient::onVisibilityUpdate(bool visible_by_modifier) {
|
2022-04-06 13:53:49 +00:00
|
|
|
spdlog::debug("visibility update for {}: {}", bar_.bar_id, visible_by_modifier);
|
2020-10-20 02:35:55 +00:00
|
|
|
visible_by_modifier_ = visible_by_modifier;
|
2022-04-09 11:18:03 +00:00
|
|
|
if (visible_by_modifier) {
|
|
|
|
modifier_no_action_ = true;
|
|
|
|
}
|
|
|
|
if (!visible_by_modifier_ && modifier_no_action_) {
|
|
|
|
// Modifier key was pressed and released without a different action.
|
|
|
|
// This signals an acknowledgment and should hide the bar again.
|
|
|
|
// Hide the bar and clear the urgency flag.
|
|
|
|
visible_by_urgency_ = false;
|
2022-04-09 11:49:22 +00:00
|
|
|
visible_by_mode_ = false;
|
2022-04-09 11:18:03 +00:00
|
|
|
}
|
|
|
|
|
2020-10-20 02:35:55 +00:00
|
|
|
update();
|
|
|
|
}
|
|
|
|
|
2022-04-06 13:53:49 +00:00
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
2020-10-20 02:35:55 +00:00
|
|
|
void BarIpcClient::update() {
|
2022-04-09 11:49:22 +00:00
|
|
|
bool visible = visible_by_modifier_ || visible_by_mode_ || visible_by_urgency_;
|
2020-10-20 02:35:55 +00:00
|
|
|
if (bar_config_.mode == "invisible") {
|
|
|
|
visible = false;
|
|
|
|
} else if (bar_config_.mode != "hide" || bar_config_.hidden_state != "hide") {
|
|
|
|
visible = true;
|
|
|
|
}
|
|
|
|
bar_.setMode(visible ? bar_config_.mode : Bar::MODE_INVISIBLE);
|
2020-10-20 02:34:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace waybar::modules::sway
|