Waybar/src/modules/workspaces.cpp

95 lines
2.9 KiB
C++

#include "modules/workspaces.hpp"
#include "ipc/client.hpp"
waybar::modules::Workspaces::Workspaces(Bar &bar)
: _bar(bar)
{
_box.get_style_context()->add_class("workspaces");
std::string socketPath = get_socketpath();
_ipcSocketfd = ipc_open_socket(socketPath);
_ipcEventSocketfd = ipc_open_socket(socketPath);
const char *subscribe = "[ \"workspace\", \"mode\" ]";
uint32_t len = strlen(subscribe);
ipc_single_command(_ipcEventSocketfd, IPC_SUBSCRIBE, subscribe, &len);
_thread = [this] {
Glib::signal_idle().connect_once([this] {
update();
});
_thread.sleep_for(chrono::milliseconds(250));
};
}
auto waybar::modules::Workspaces::update() -> void
{
if (_bar.outputName.empty()) return;
Json::Value workspaces = _getWorkspaces();
bool needReorder = false;
for (auto it = _buttons.begin(); it != _buttons.end(); ++it) {
auto ws = std::find_if(workspaces.begin(), workspaces.end(),
[it](auto node) -> bool { return node["num"].asInt() == it->first; });
if (ws == workspaces.end()) {
it = _buttons.erase(it);
needReorder = true;
}
}
for (auto node : workspaces) {
auto it = _buttons.find(node["num"].asInt());
if (it == _buttons.end() && _bar.outputName == node["output"].asString()) {
_addWorkspace(node);
needReorder = true;
} else {
auto styleContext = it->second.get_style_context();
bool isCurrent = node["focused"].asBool();
if (!isCurrent) {
styleContext->remove_class("current");
} else if (isCurrent) {
styleContext->add_class("current");
}
if (needReorder)
_box.reorder_child(it->second, node["num"].asInt() - 1);
it->second.show();
}
}
}
void waybar::modules::Workspaces::_addWorkspace(Json::Value node)
{
auto pair = _buttons.emplace(node["num"].asInt(), node["name"].asString());
auto &button = pair.first->second;
_box.pack_start(button, false, false, 0);
button.set_relief(Gtk::RELIEF_NONE);
button.signal_clicked().connect([this, pair] {
auto value = fmt::format("workspace \"{}\"", pair.first->first);
uint32_t size = value.size();
ipc_single_command(_ipcSocketfd, IPC_COMMAND, value.c_str(), &size);
});
_box.reorder_child(button, node["num"].asInt() - 1);
if (node["focused"].asBool()) {
button.get_style_context()->add_class("current");
}
button.show();
}
Json::Value waybar::modules::Workspaces::_getWorkspaces()
{
uint32_t len = 0;
Json::Value root;
Json::CharReaderBuilder builder;
Json::CharReader* reader = builder.newCharReader();
std::string err;
std::string str = ipc_single_command(_ipcSocketfd, IPC_GET_WORKSPACES,
nullptr, &len);
bool res = reader->parse(str.c_str(), str.c_str() + str.size(), &root, &err);
delete reader;
if (!res) {
std::cerr << err << std::endl;
return nullptr;
}
return root;
}
waybar::modules::Workspaces::operator Gtk::Widget &() {
return _box;
}