2018-08-15 18:17:17 +00:00
|
|
|
#include "modules/sway/workspaces.hpp"
|
|
|
|
#include "modules/sway/ipc/client.hpp"
|
2018-08-08 21:54:58 +00:00
|
|
|
|
2018-08-15 18:17:17 +00:00
|
|
|
waybar::modules::sway::Workspaces::Workspaces(Bar &bar, Json::Value config)
|
2018-08-15 12:48:08 +00:00
|
|
|
: _bar(bar), _config(config), _scrolling(false)
|
2018-08-08 21:54:58 +00:00
|
|
|
{
|
2018-08-15 12:48:08 +00:00
|
|
|
_box.set_name("workspaces");
|
2018-08-13 12:05:13 +00:00
|
|
|
std::string socketPath = get_socketpath();
|
2018-08-13 19:23:43 +00:00
|
|
|
_ipcfd = ipc_open_socket(socketPath);
|
|
|
|
_ipcEventfd = ipc_open_socket(socketPath);
|
|
|
|
const char *subscribe = "[ \"workspace\" ]";
|
2018-08-13 12:05:13 +00:00
|
|
|
uint32_t len = strlen(subscribe);
|
2018-08-13 19:23:43 +00:00
|
|
|
ipc_single_command(_ipcEventfd, IPC_SUBSCRIBE, subscribe, &len);
|
2018-08-10 21:21:21 +00:00
|
|
|
_thread = [this] {
|
2018-08-13 19:23:43 +00:00
|
|
|
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;
|
|
|
|
std::lock_guard<std::mutex> lock(_mutex);
|
2018-08-13 21:43:35 +00:00
|
|
|
auto str = ipc_single_command(_ipcfd, IPC_GET_WORKSPACES, nullptr, &len);
|
2018-08-15 18:17:17 +00:00
|
|
|
_workspaces = _parser.parse(str);
|
|
|
|
Glib::signal_idle()
|
|
|
|
.connect_once(sigc::mem_fun(*this, &Workspaces::update));
|
2018-08-13 19:23:43 +00:00
|
|
|
} catch (const std::exception& e) {
|
|
|
|
std::cerr << e.what() << std::endl;
|
|
|
|
}
|
2018-08-09 18:22:01 +00:00
|
|
|
};
|
2018-08-08 21:54:58 +00:00
|
|
|
}
|
|
|
|
|
2018-08-15 18:17:17 +00:00
|
|
|
auto waybar::modules::sway::Workspaces::update() -> void
|
2018-08-08 21:54:58 +00:00
|
|
|
{
|
2018-08-13 19:23:43 +00:00
|
|
|
std::lock_guard<std::mutex> lock(_mutex);
|
2018-08-10 16:02:12 +00:00
|
|
|
bool needReorder = false;
|
2018-08-15 12:30:01 +00:00
|
|
|
for (auto it = _buttons.begin(); it != _buttons.end();) {
|
2018-08-13 19:23:43 +00:00
|
|
|
auto ws = std::find_if(_workspaces.begin(), _workspaces.end(),
|
2018-08-08 21:54:58 +00:00
|
|
|
[it](auto node) -> bool { return node["num"].asInt() == it->first; });
|
2018-08-13 19:23:43 +00:00
|
|
|
if (ws == _workspaces.end()) {
|
2018-08-10 21:21:21 +00:00
|
|
|
it = _buttons.erase(it);
|
2018-08-10 16:02:12 +00:00
|
|
|
needReorder = true;
|
2018-08-15 12:30:01 +00:00
|
|
|
} else
|
|
|
|
++it;
|
2018-08-08 21:54:58 +00:00
|
|
|
}
|
2018-08-13 19:23:43 +00:00
|
|
|
for (auto node : _workspaces) {
|
|
|
|
if (_bar.outputName != node["output"].asString())
|
|
|
|
continue;
|
2018-08-08 21:54:58 +00:00
|
|
|
auto it = _buttons.find(node["num"].asInt());
|
2018-08-13 19:23:43 +00:00
|
|
|
if (it == _buttons.end()) {
|
2018-08-08 21:54:58 +00:00
|
|
|
_addWorkspace(node);
|
2018-08-10 16:02:12 +00:00
|
|
|
needReorder = true;
|
2018-08-08 21:54:58 +00:00
|
|
|
} else {
|
2018-08-13 19:23:43 +00:00
|
|
|
auto &button = it->second;
|
2018-08-15 12:30:01 +00:00
|
|
|
if (node["focused"].asBool())
|
2018-08-15 13:03:51 +00:00
|
|
|
button.get_style_context()->add_class("focused");
|
2018-08-15 12:30:01 +00:00
|
|
|
else
|
2018-08-15 13:03:51 +00:00
|
|
|
button.get_style_context()->remove_class("focused");
|
|
|
|
if (node["visible"].asBool())
|
|
|
|
button.get_style_context()->add_class("visible");
|
|
|
|
else
|
|
|
|
button.get_style_context()->remove_class("visible");
|
|
|
|
if (node["urgent"].asBool())
|
|
|
|
button.get_style_context()->add_class("urgent");
|
|
|
|
else
|
|
|
|
button.get_style_context()->remove_class("urgent");
|
2018-08-10 16:02:12 +00:00
|
|
|
if (needReorder)
|
2018-08-14 09:26:06 +00:00
|
|
|
_box.reorder_child(button, node["num"].asInt());
|
2018-08-13 19:23:43 +00:00
|
|
|
button.show();
|
2018-08-08 21:54:58 +00:00
|
|
|
}
|
|
|
|
}
|
2018-08-14 09:26:06 +00:00
|
|
|
if (_scrolling)
|
|
|
|
_scrolling = false;
|
2018-08-08 21:54:58 +00:00
|
|
|
}
|
|
|
|
|
2018-08-15 18:17:17 +00:00
|
|
|
void waybar::modules::sway::Workspaces::_addWorkspace(Json::Value node)
|
2018-08-08 21:54:58 +00:00
|
|
|
{
|
2018-08-15 12:58:55 +00:00
|
|
|
auto icon = _getIcon(node["name"].asString());
|
|
|
|
auto pair = _buttons.emplace(node["num"].asInt(), icon);
|
2018-08-08 21:54:58 +00:00
|
|
|
auto &button = pair.first->second;
|
2018-08-15 12:58:55 +00:00
|
|
|
if (icon != node["name"].asString())
|
|
|
|
button.get_style_context()->add_class("icon");
|
2018-08-10 21:21:21 +00:00
|
|
|
_box.pack_start(button, false, false, 0);
|
2018-08-08 21:54:58 +00:00
|
|
|
button.set_relief(Gtk::RELIEF_NONE);
|
|
|
|
button.signal_clicked().connect([this, pair] {
|
2018-08-11 00:09:39 +00:00
|
|
|
try {
|
2018-08-13 21:43:35 +00:00
|
|
|
std::lock_guard<std::mutex> lock(_mutex);
|
2018-08-11 00:09:39 +00:00
|
|
|
auto value = fmt::format("workspace \"{}\"", pair.first->first);
|
|
|
|
uint32_t size = value.size();
|
2018-08-13 19:23:43 +00:00
|
|
|
ipc_single_command(_ipcfd, IPC_COMMAND, value.c_str(), &size);
|
2018-08-11 00:09:39 +00:00
|
|
|
} catch (const std::exception& e) {
|
|
|
|
std::cerr << e.what() << std::endl;
|
|
|
|
}
|
2018-08-08 21:54:58 +00:00
|
|
|
});
|
2018-08-14 09:26:06 +00:00
|
|
|
button.add_events(Gdk::SCROLL_MASK | Gdk::SMOOTH_SCROLL_MASK);
|
|
|
|
button.signal_scroll_event()
|
|
|
|
.connect(sigc::mem_fun(*this, &Workspaces::_handleScroll));
|
|
|
|
_box.reorder_child(button, node["num"].asInt());
|
|
|
|
if (node["focused"].asBool())
|
2018-08-15 13:03:51 +00:00
|
|
|
button.get_style_context()->add_class("focused");
|
|
|
|
if (node["visible"].asBool())
|
|
|
|
button.get_style_context()->add_class("visible");
|
|
|
|
if (node["urgent"].asBool())
|
|
|
|
button.get_style_context()->add_class("urgent");
|
2018-08-08 21:54:58 +00:00
|
|
|
button.show();
|
|
|
|
}
|
|
|
|
|
2018-08-15 18:17:17 +00:00
|
|
|
std::string waybar::modules::sway::Workspaces::_getIcon(std::string name)
|
2018-08-15 12:48:08 +00:00
|
|
|
{
|
|
|
|
if (_config["format-icons"][name])
|
|
|
|
return _config["format-icons"][name].asString();
|
|
|
|
if (_config["format-icons"]["default"])
|
|
|
|
return _config["format-icons"]["default"].asString();
|
|
|
|
return name;
|
|
|
|
}
|
|
|
|
|
2018-08-15 18:17:17 +00:00
|
|
|
bool waybar::modules::sway::Workspaces::_handleScroll(GdkEventScroll *e)
|
2018-08-14 09:26:06 +00:00
|
|
|
{
|
|
|
|
std::lock_guard<std::mutex> lock(_mutex);
|
|
|
|
// Avoid concurrent scroll event
|
|
|
|
if (_scrolling)
|
|
|
|
return false;
|
|
|
|
_scrolling = true;
|
|
|
|
int id = -1;
|
|
|
|
uint16_t idx = 0;
|
|
|
|
for (; idx < _workspaces.size(); idx += 1)
|
|
|
|
if (_workspaces[idx]["focused"].asBool()) {
|
|
|
|
id = _workspaces[idx]["num"].asInt();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (id == -1) {
|
|
|
|
_scrolling = false;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (e->direction == GDK_SCROLL_UP)
|
|
|
|
id = _getNextWorkspace();
|
|
|
|
if (e->direction == GDK_SCROLL_DOWN)
|
|
|
|
id = _getPrevWorkspace();
|
|
|
|
if (e->direction == GDK_SCROLL_SMOOTH) {
|
|
|
|
gdouble delta_x, delta_y;
|
|
|
|
gdk_event_get_scroll_deltas ((const GdkEvent *) e, &delta_x, &delta_y);
|
|
|
|
if (delta_y < 0)
|
|
|
|
id = _getNextWorkspace();
|
|
|
|
else if (delta_y > 0)
|
|
|
|
id = _getPrevWorkspace();
|
|
|
|
}
|
|
|
|
if (id == _workspaces[idx]["num"].asInt()) {
|
|
|
|
_scrolling = false;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
auto value = fmt::format("workspace \"{}\"", id);
|
|
|
|
uint32_t size = value.size();
|
|
|
|
ipc_single_command(_ipcfd, IPC_COMMAND, value.c_str(), &size);
|
|
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(150));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-08-15 18:17:17 +00:00
|
|
|
int waybar::modules::sway::Workspaces::_getPrevWorkspace()
|
2018-08-14 09:26:06 +00:00
|
|
|
{
|
|
|
|
int current = -1;
|
|
|
|
for (uint16_t i = 0; i != _workspaces.size(); i += 1)
|
|
|
|
if (_workspaces[i]["focused"].asBool()) {
|
|
|
|
current = _workspaces[i]["num"].asInt();
|
|
|
|
if (i > 0)
|
|
|
|
return _workspaces[i - 1]["num"].asInt();
|
|
|
|
return _workspaces[_workspaces.size() - 1]["num"].asInt();
|
|
|
|
}
|
|
|
|
return current;
|
|
|
|
}
|
|
|
|
|
2018-08-15 18:17:17 +00:00
|
|
|
int waybar::modules::sway::Workspaces::_getNextWorkspace()
|
2018-08-14 09:26:06 +00:00
|
|
|
{
|
|
|
|
int current = -1;
|
|
|
|
for (uint16_t i = 0; i != _workspaces.size(); i += 1)
|
|
|
|
if (_workspaces[i]["focused"].asBool()) {
|
|
|
|
current = _workspaces[i]["num"].asInt();
|
|
|
|
if (i + 1U < _workspaces.size())
|
|
|
|
return _workspaces[i + 1]["num"].asInt();
|
|
|
|
return _workspaces[0]["num"].asInt();
|
|
|
|
}
|
|
|
|
return current;
|
|
|
|
}
|
|
|
|
|
2018-08-15 18:17:17 +00:00
|
|
|
waybar::modules::sway::Workspaces::operator Gtk::Widget &() {
|
2018-08-10 21:21:21 +00:00
|
|
|
return _box;
|
2018-08-08 21:54:58 +00:00
|
|
|
}
|