polybar-dwm/include/modules/i3.hpp

273 lines
7.8 KiB
C++
Raw Normal View History

#pragma once
2016-05-19 14:41:06 +00:00
2016-10-12 01:57:22 +00:00
#include <i3ipc++/ipc.hpp>
2016-05-19 14:41:06 +00:00
#include "config.hpp"
2016-10-12 01:57:22 +00:00
#include "components/config.hpp"
2016-06-15 03:32:35 +00:00
#include "drawtypes/iconset.hpp"
2016-05-19 14:41:06 +00:00
#include "drawtypes/label.hpp"
2016-06-15 03:32:35 +00:00
#include "modules/meta.hpp"
2016-10-12 01:57:22 +00:00
#include "utils/i3.hpp"
#include "utils/io.hpp"
2016-06-15 03:32:35 +00:00
LEMONBUDDY_NS
namespace modules {
2016-10-12 01:57:22 +00:00
// meta types {{{
2016-06-15 03:32:35 +00:00
enum class i3_flag {
WORKSPACE_NONE,
WORKSPACE_FOCUSED,
WORKSPACE_UNFOCUSED,
WORKSPACE_VISIBLE,
WORKSPACE_URGENT,
};
2016-05-19 14:41:06 +00:00
2016-06-15 03:32:35 +00:00
struct i3_workspace {
2016-10-12 01:57:22 +00:00
int index;
i3_flag flag;
label_t label;
i3_workspace(int index_, i3_flag flag_, label_t&& label_)
: index(index_), flag(flag_), label(forward<decltype(label_)>(label_)) {}
2016-05-19 14:41:06 +00:00
2016-06-15 03:32:35 +00:00
operator bool() {
2016-10-12 01:57:22 +00:00
return label && *label;
2016-06-15 03:32:35 +00:00
}
};
using i3_workspace_t = unique_ptr<i3_workspace>;
2016-10-12 01:57:22 +00:00
// }}}
2016-06-15 03:32:35 +00:00
class i3_module : public event_module<i3_module> {
public:
using event_module::event_module;
~i3_module() {
2016-10-12 01:57:22 +00:00
// Shutdown ipc connection {{{
2016-06-15 03:32:35 +00:00
try {
2016-10-12 01:57:22 +00:00
shutdown(m_ipc.get_event_socket_fd(), SHUT_RD);
shutdown(m_ipc.get_main_socket_fd(), SHUT_RD);
} catch (const std::exception& err) {
2016-06-15 03:32:35 +00:00
}
2016-05-19 14:41:06 +00:00
2016-10-12 01:57:22 +00:00
// }}}
}
void setup() {
// Load configuration values {{{
GET_CONFIG_VALUE(name(), m_indexsort, "index-sort");
2016-10-12 01:57:22 +00:00
GET_CONFIG_VALUE(name(), m_pinworkspaces, "pin-workspaces");
GET_CONFIG_VALUE(name(), m_strip_wsnumbers, "strip-wsnumbers");
2016-10-12 01:57:22 +00:00
GET_CONFIG_VALUE(name(), m_wsname_maxlen, "wsname-maxlen");
// }}}
// Add formats and create components {{{
2016-06-15 03:32:35 +00:00
m_formatter->add(DEFAULT_FORMAT, TAG_LABEL_STATE, {TAG_LABEL_STATE});
if (m_formatter->has(TAG_LABEL_STATE)) {
m_statelabels.insert(make_pair(i3_flag::WORKSPACE_FOCUSED,
get_optional_config_label(m_conf, name(), "label-focused", DEFAULT_WS_LABEL)));
m_statelabels.insert(make_pair(i3_flag::WORKSPACE_UNFOCUSED,
get_optional_config_label(m_conf, name(), "label-unfocused", DEFAULT_WS_LABEL)));
m_statelabels.insert(make_pair(i3_flag::WORKSPACE_VISIBLE,
get_optional_config_label(m_conf, name(), "label-visible", DEFAULT_WS_LABEL)));
m_statelabels.insert(make_pair(i3_flag::WORKSPACE_URGENT,
get_optional_config_label(m_conf, name(), "label-urgent", DEFAULT_WS_LABEL)));
}
m_icons = iconset_t{new iconset()};
m_icons->add(
DEFAULT_WS_ICON, icon_t{new icon(m_conf.get<string>(name(), DEFAULT_WS_ICON, ""))});
2016-10-12 01:57:22 +00:00
// }}}
// Add formats and create components {{{
for (auto workspace : m_conf.get_list<string>(name(), "ws-icon", {})) {
2016-06-15 03:32:35 +00:00
auto vec = string_util::split(workspace, ';');
if (vec.size() == 2)
m_icons->add(vec[0], icon_t{new icon{vec[1]}});
}
2016-10-12 01:57:22 +00:00
// }}}
// Subscribe to ipc events {{{
try {
m_ipc.subscribe(i3ipc::ET_WORKSPACE);
m_ipc.prepare_to_event_handling();
} catch (std::runtime_error& e) {
throw module_error(e.what());
}
// }}}
2016-06-15 03:32:35 +00:00
}
bool has_event() {
2016-10-12 01:57:22 +00:00
// Wait for ipc events {{{
try {
m_ipc.handle_event();
return true;
} catch (const std::exception& err) {
if (enabled()) {
m_log.err("%s: Error while handling ipc event, stopping module...", name());
m_log.err("%s: %s", name(), err.what());
stop();
}
2016-06-15 03:32:35 +00:00
return false;
2016-10-12 01:57:22 +00:00
}
// }}}
2016-06-15 03:32:35 +00:00
}
bool update() {
2016-10-12 01:57:22 +00:00
// Refresh workspace data {{{
2016-06-15 03:32:35 +00:00
2016-10-12 01:57:22 +00:00
m_workspaces.clear();
i3_util::connection_t ipc;
2016-06-15 03:32:35 +00:00
try {
2016-10-12 01:57:22 +00:00
auto workspaces = ipc.get_workspaces();
vector<shared_ptr<i3ipc::workspace_t>> sorted = workspaces;
2016-10-12 01:57:22 +00:00
string focused_output;
2016-06-15 03:32:35 +00:00
2016-10-12 01:57:22 +00:00
for (auto&& workspace : workspaces)
if (workspace->focused) {
focused_output = workspace->output;
2016-06-15 03:32:35 +00:00
break;
}
2016-05-19 14:41:06 +00:00
if (m_indexsort) {
using ws_t = shared_ptr<i3ipc::workspace_t>;
// clang-format off
sort(sorted.begin(), sorted.end(), [](ws_t ws1, ws_t ws2){
return ws1->num < ws2->num;
});
// clang-format on
}
for (auto&& workspace : sorted) {
2016-10-12 01:57:22 +00:00
if (m_pinworkspaces && workspace->output != m_bar.monitor->name)
2016-06-15 03:32:35 +00:00
continue;
2016-05-19 14:41:06 +00:00
2016-06-15 03:32:35 +00:00
auto flag = i3_flag::WORKSPACE_NONE;
2016-10-12 01:57:22 +00:00
if (workspace->focused)
2016-06-15 03:32:35 +00:00
flag = i3_flag::WORKSPACE_FOCUSED;
2016-10-12 01:57:22 +00:00
else if (workspace->urgent)
2016-06-15 03:32:35 +00:00
flag = i3_flag::WORKSPACE_URGENT;
2016-10-12 01:57:22 +00:00
else if (!workspace->visible || (workspace->visible && workspace->output != focused_output))
2016-06-15 03:32:35 +00:00
flag = i3_flag::WORKSPACE_UNFOCUSED;
2016-10-12 01:57:22 +00:00
else
flag = i3_flag::WORKSPACE_VISIBLE;
2016-05-19 14:41:06 +00:00
2016-10-12 01:57:22 +00:00
string wsname{workspace->name};
if (m_strip_wsnumbers) {
auto index = string_util::split(wsname, ':');
if (index.size() == 2) {
wsname = index[1];
}
}
2016-10-12 01:57:22 +00:00
if (m_wsname_maxlen > 0 && wsname.length() > m_wsname_maxlen)
wsname.erase(m_wsname_maxlen);
2016-05-19 14:41:06 +00:00
2016-10-12 01:57:22 +00:00
auto icon = m_icons->get(workspace->name, DEFAULT_WS_ICON);
2016-06-15 03:32:35 +00:00
auto label = m_statelabels.find(flag)->second->clone();
2016-10-12 01:57:22 +00:00
label->replace_token("%output%", workspace->output);
label->replace_token("%name%", wsname);
2016-06-15 03:32:35 +00:00
label->replace_token("%icon%", icon->m_text);
2016-10-12 01:57:22 +00:00
label->replace_token("%index%", to_string(workspace->num));
m_workspaces.emplace_back(make_unique<i3_workspace>(workspace->num, flag, std::move(label)));
2016-06-15 03:32:35 +00:00
}
2016-10-12 01:57:22 +00:00
return true;
} catch (const std::exception& err) {
m_log.err("%s: %s", name(), err.what());
return false;
2016-06-15 03:32:35 +00:00
}
2016-10-12 01:57:22 +00:00
// }}}
2016-06-15 03:32:35 +00:00
}
bool build(builder* builder, string tag) {
2016-10-12 01:57:22 +00:00
// Output workspace info {{{
2016-06-15 03:32:35 +00:00
if (tag != TAG_LABEL_STATE)
return false;
2016-06-15 03:32:35 +00:00
for (auto&& ws : m_workspaces) {
builder->cmd(mousebtn::SCROLL_DOWN, EVENT_SCROLL_DOWN);
builder->cmd(mousebtn::SCROLL_UP, EVENT_SCROLL_UP);
2016-10-12 01:57:22 +00:00
builder->cmd(mousebtn::LEFT, string{EVENT_CLICK} + to_string(ws.get()->index));
2016-06-15 03:32:35 +00:00
builder->node(ws.get()->label);
builder->cmd_close(true);
2016-06-29 09:06:33 +00:00
}
2016-06-15 03:32:35 +00:00
return true;
2016-10-12 01:57:22 +00:00
// }}}
2016-06-15 03:32:35 +00:00
}
bool handle_event(string cmd) {
2016-10-12 01:57:22 +00:00
// Send ipc commands {{{
if (cmd.compare(0, 2, EVENT_PREFIX) != 0)
return false;
2016-10-12 01:57:22 +00:00
try {
i3_util::connection_t ipc;
if (cmd.compare(0, strlen(EVENT_CLICK), EVENT_CLICK) == 0) {
m_log.info("%s: Sending workspace focus command to ipc handler", name());
ipc.send_command("workspace number " + cmd.substr(strlen(EVENT_CLICK)));
} else if (cmd.compare(0, strlen(EVENT_SCROLL_DOWN), EVENT_SCROLL_DOWN) == 0) {
m_log.info("%s: Sending workspace prev command to ipc handler", name());
ipc.send_command("workspace next_on_output");
} else if (cmd.compare(0, strlen(EVENT_SCROLL_UP), EVENT_SCROLL_UP) == 0) {
m_log.info("%s: Sending workspace next command to ipc handler", name());
ipc.send_command("workspace prev_on_output");
}
2016-10-12 01:57:22 +00:00
} catch (const std::exception& err) {
m_log.err("%s: %s", name(), err.what());
}
return true;
2016-10-12 01:57:22 +00:00
// }}}
}
bool receive_events() const {
return true;
}
2016-06-15 03:32:35 +00:00
private:
static constexpr auto DEFAULT_WS_ICON = "ws-icon-default";
2016-06-15 03:32:35 +00:00
static constexpr auto DEFAULT_WS_LABEL = "%icon% %name%";
static constexpr auto TAG_LABEL_STATE = "<label-state>";
static constexpr auto EVENT_PREFIX = "i3";
2016-10-12 02:14:28 +00:00
static constexpr auto EVENT_CLICK = "i3-wsfocus-";
static constexpr auto EVENT_SCROLL_UP = "i3-wsnext";
static constexpr auto EVENT_SCROLL_DOWN = "i3-wsprev";
2016-06-15 03:32:35 +00:00
map<i3_flag, label_t> m_statelabels;
vector<i3_workspace_t> m_workspaces;
iconset_t m_icons;
bool m_indexsort = false;
2016-10-12 01:57:22 +00:00
bool m_pinworkspaces = false;
bool m_strip_wsnumbers = false;
2016-10-12 01:57:22 +00:00
size_t m_wsname_maxlen = 0;
i3_util::connection_t m_ipc;
2016-05-19 14:41:06 +00:00
};
}
2016-06-15 03:32:35 +00:00
LEMONBUDDY_NS_END