refactor(workspaces): listen ipc event

This commit is contained in:
Alexis 2018-08-13 21:23:43 +02:00
parent 68f9ea3065
commit ea9a08d473
5 changed files with 146 additions and 116 deletions

View File

@ -4,6 +4,7 @@
#include "bar.hpp"
#include "client.hpp"
#include "util/chrono.hpp"
#include "util/json.hpp"
#include "IModule.hpp"
namespace waybar::modules {
@ -15,13 +16,16 @@ namespace waybar::modules {
operator Gtk::Widget &();
private:
void _addWorkspace(Json::Value node);
Json::Value _getWorkspaces();
Json::Value _getWorkspaces(const std::string data);
Bar &_bar;
waybar::util::SleeperThread _thread;
Gtk::Box _box;
util::JsonParser _parser;
std::mutex _mutex;
std::unordered_map<int, Gtk::Button> _buttons;
int _ipcSocketfd;
int _ipcEventSocketfd;
Json::Value _workspaces;
int _ipcfd;
int _ipcEventfd;
};
}

34
include/util/json.hpp Normal file
View File

@ -0,0 +1,34 @@
#pragma once
#include <json/json.h>
namespace waybar::util {
struct JsonParser {
JsonParser()
: _reader(_builder.newCharReader())
{}
Json::Value parse(const std::string data)
{
Json::Value root;
std::string err;
bool res =
_reader->parse(data.c_str(), data.c_str() + data.size(), &root, &err);
if (!res)
throw std::runtime_error(err);
return root;
}
~JsonParser()
{
delete _reader;
}
private:
Json::CharReaderBuilder _builder;
Json::CharReader *_reader;
};
}

View File

@ -1,6 +1,7 @@
#include "bar.hpp"
#include "client.hpp"
#include "factory.hpp"
#include "util/json.hpp"
waybar::Bar::Bar(Client &client, std::unique_ptr<struct wl_output *> &&p_output)
: client(client), window{Gtk::WindowType::WINDOW_TOPLEVEL},
@ -125,19 +126,13 @@ auto waybar::Bar::toggle() -> void
auto waybar::Bar::_setupConfig() -> void
{
Json::Value root;
Json::CharReaderBuilder builder;
Json::CharReader* reader = builder.newCharReader();
std::string err;
util::JsonParser parser;
std::ifstream file(client.configFile);
if (!file.is_open())
throw std::runtime_error("Can't open config file");
std::string str((std::istreambuf_iterator<char>(file)),
std::istreambuf_iterator<char>());
bool res = reader->parse(str.c_str(), str.c_str() + str.size(), &_config, &err);
delete reader;
if (!res)
throw std::runtime_error(err);
_config = parser.parse(str);
}
auto waybar::Bar::_setupCss() -> void

View File

@ -48,10 +48,11 @@ int ipc_open_socket(std::string socket_path) {
}
struct ipc_response ipc_recv_response(int socketfd) {
struct ipc_response response;
char data[ipc_header_size];
uint32_t *data32 = (uint32_t *)(data + sizeof(ipc_magic));
size_t total = 0;
while (total < ipc_header_size) {
ssize_t received = recv(socketfd, data + total, ipc_header_size - total, 0);
if (received <= 0) {
@ -60,8 +61,6 @@ struct ipc_response ipc_recv_response(int socketfd) {
total += received;
}
struct ipc_response response;
total = 0;
response.size = data32[0];
response.type = data32[1];
@ -86,14 +85,10 @@ std::string ipc_single_command(int socketfd, uint32_t type, const char *payload,
data32[0] = *len;
data32[1] = type;
if (send(socketfd, data, ipc_header_size, 0) == -1) {
if (send(socketfd, data, ipc_header_size, 0) == -1)
throw std::runtime_error("Unable to send IPC header");
}
if (send(socketfd, payload, *len, 0) == -1) {
if (send(socketfd, payload, *len, 0) == -1)
throw std::runtime_error("Unable to send IPC payload");
}
struct ipc_response resp = ipc_recv_response(socketfd);
*len = resp.size;
return resp.payload;

View File

@ -6,47 +6,60 @@ waybar::modules::Workspaces::Workspaces(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\" ]";
_ipcfd = ipc_open_socket(socketPath);
_ipcEventfd = ipc_open_socket(socketPath);
const char *subscribe = "[ \"workspace\" ]";
uint32_t len = strlen(subscribe);
ipc_single_command(_ipcEventSocketfd, IPC_SUBSCRIBE, subscribe, &len);
ipc_single_command(_ipcEventfd, IPC_SUBSCRIBE, subscribe, &len);
_thread = [this] {
try {
if (_bar.outputName.empty()) {
// Wait for the name of the output
while (_bar.outputName.empty())
_thread.sleep_for(chrono::milliseconds(150));
} else
ipc_recv_response(_ipcEventfd);
uint32_t len = 0;
auto str = ipc_single_command(_ipcfd, IPC_GET_WORKSPACES, nullptr, &len);
std::lock_guard<std::mutex> lock(_mutex);
_workspaces = _getWorkspaces(str);
Glib::signal_idle().connect_once(sigc::mem_fun(*this, &Workspaces::update));
_thread.sleep_for(chrono::milliseconds(250));
} catch (const std::exception& e) {
std::cerr << e.what() << std::endl;
}
};
}
auto waybar::modules::Workspaces::update() -> void
{
if (_bar.outputName.empty()) return;
Json::Value workspaces = _getWorkspaces();
std::lock_guard<std::mutex> lock(_mutex);
bool needReorder = false;
for (auto it = _buttons.begin(); it != _buttons.end(); ++it) {
auto ws = std::find_if(workspaces.begin(), workspaces.end(),
auto ws = std::find_if(_workspaces.begin(), _workspaces.end(),
[it](auto node) -> bool { return node["num"].asInt() == it->first; });
if (ws == workspaces.end()) {
if (ws == _workspaces.end()) {
it = _buttons.erase(it);
needReorder = true;
}
}
for (auto node : workspaces) {
for (auto node : _workspaces) {
if (_bar.outputName != node["output"].asString())
continue;
auto it = _buttons.find(node["num"].asInt());
if (it == _buttons.end() && _bar.outputName == node["output"].asString()) {
if (it == _buttons.end()) {
_addWorkspace(node);
needReorder = true;
} else {
auto styleContext = it->second.get_style_context();
auto &button = it->second;
bool isCurrent = node["focused"].asBool();
if (!isCurrent) {
styleContext->remove_class("current");
button.get_style_context()->remove_class("current");
} else if (isCurrent) {
styleContext->add_class("current");
button.get_style_context()->add_class("current");
}
if (needReorder)
_box.reorder_child(it->second, node["num"].asInt() - 1);
it->second.show();
_box.reorder_child(button, node["num"].asInt() - 1);
button.show();
}
}
}
@ -61,7 +74,7 @@ void waybar::modules::Workspaces::_addWorkspace(Json::Value node)
try {
auto value = fmt::format("workspace \"{}\"", pair.first->first);
uint32_t size = value.size();
ipc_single_command(_ipcSocketfd, IPC_COMMAND, value.c_str(), &size);
ipc_single_command(_ipcfd, IPC_COMMAND, value.c_str(), &size);
} catch (const std::exception& e) {
std::cerr << e.what() << std::endl;
}
@ -73,27 +86,16 @@ void waybar::modules::Workspaces::_addWorkspace(Json::Value node)
button.show();
}
Json::Value waybar::modules::Workspaces::_getWorkspaces()
Json::Value waybar::modules::Workspaces::_getWorkspaces(const std::string data)
{
uint32_t len = 0;
Json::Value root;
Json::CharReaderBuilder builder;
Json::CharReader* reader = builder.newCharReader();
Json::Value res;
try {
std::string str = ipc_single_command(_ipcSocketfd, IPC_GET_WORKSPACES,
nullptr, &len);
std::string err;
bool res =
reader->parse(str.c_str(), str.c_str() + str.size(), &root, &err);
delete reader;
if (!res) {
std::cerr << err << std::endl;
return root;
}
res = _parser.parse(data);
} catch (const std::exception& e) {
std::cerr << e.what() << std::endl;
}
return root;
return res;
}
waybar::modules::Workspaces::operator Gtk::Widget &() {