1
0
Fork 0
mirror of https://github.com/polybar/polybar.git synced 2024-11-11 13:50:56 -05:00
polybar/src/modules/i3.cpp

238 lines
7.5 KiB
C++
Raw Normal View History

2016-11-02 15:22:45 -04:00
#include <sys/socket.h>
#include "drawtypes/iconset.hpp"
#include "drawtypes/label.hpp"
2016-11-30 12:23:11 -05:00
#include "modules/i3.hpp"
2016-12-09 03:02:47 -05:00
#include "utils/factory.hpp"
2016-11-30 12:23:11 -05:00
#include "utils/file.hpp"
2016-11-20 17:04:31 -05:00
#include "modules/meta/base.inl"
2016-11-19 00:22:44 -05:00
POLYBAR_NS
2016-11-02 15:22:45 -04:00
namespace modules {
2016-11-20 17:04:31 -05:00
template class module<i3_module>;
i3_module::i3_module(const bar_settings& bar, string name_) : event_module<i3_module>(bar, move(name_)) {
2016-11-30 12:23:11 -05:00
auto socket_path = i3ipc::get_socketpath();
if (!file_util::exists(socket_path)) {
throw module_error("Could not find socket: " + (socket_path.empty() ? "<empty>" : socket_path));
}
2016-12-09 03:02:47 -05:00
m_ipc = factory_util::unique<i3ipc::connection>();
2016-11-30 12:23:11 -05:00
// Load configuration values
m_click = m_conf.get(name(), "enable-click", m_click);
m_scroll = m_conf.get(name(), "enable-scroll", m_scroll);
m_revscroll = m_conf.get(name(), "reverse-scroll", m_revscroll);
m_wrap = m_conf.get(name(), "wrapping-scroll", m_wrap);
m_indexsort = m_conf.get(name(), "index-sort", m_indexsort);
m_pinworkspaces = m_conf.get(name(), "pin-workspaces", m_pinworkspaces);
m_strip_wsnumbers = m_conf.get(name(), "strip-wsnumbers", m_strip_wsnumbers);
m_fuzzy_match = m_conf.get(name(), "fuzzy-match", m_fuzzy_match);
2016-12-13 22:45:20 -05:00
m_conf.warn_deprecated(name(), "wsname-maxlen", "%name:min:max%");
2016-11-02 15:22:45 -04:00
// Add formats and create components
2016-11-30 12:23:11 -05:00
m_formatter->add(DEFAULT_FORMAT, DEFAULT_TAGS, {TAG_LABEL_STATE, TAG_LABEL_MODE});
2016-11-02 15:22:45 -04:00
if (m_formatter->has(TAG_LABEL_STATE)) {
m_statelabels.insert(
2016-11-30 12:23:11 -05:00
make_pair(state::FOCUSED, load_optional_label(m_conf, name(), "label-focused", DEFAULT_WS_LABEL)));
m_statelabels.insert(
make_pair(state::UNFOCUSED, load_optional_label(m_conf, name(), "label-unfocused", DEFAULT_WS_LABEL)));
m_statelabels.insert(
make_pair(state::VISIBLE, load_optional_label(m_conf, name(), "label-visible", DEFAULT_WS_LABEL)));
m_statelabels.insert(
make_pair(state::URGENT, load_optional_label(m_conf, name(), "label-urgent", DEFAULT_WS_LABEL)));
}
if (m_formatter->has(TAG_LABEL_MODE)) {
m_modelabel = load_optional_label(m_conf, name(), "label-mode", "%mode%");
2016-11-02 15:22:45 -04:00
}
m_icons = factory_util::shared<iconset>();
m_icons->add(DEFAULT_WS_ICON, factory_util::shared<label>(m_conf.get(name(), DEFAULT_WS_ICON, ""s)));
2016-11-02 15:22:45 -04:00
2016-11-25 07:55:15 -05:00
for (const auto& workspace : m_conf.get_list<string>(name(), "ws-icon", {})) {
2016-11-02 15:22:45 -04:00
auto vec = string_util::split(workspace, ';');
2016-11-25 07:55:15 -05:00
if (vec.size() == 2) {
m_icons->add(vec[0], factory_util::shared<label>(vec[1]));
2016-11-25 07:55:15 -05:00
}
2016-11-02 15:22:45 -04:00
}
try {
2016-11-30 12:23:11 -05:00
if (m_modelabel) {
m_ipc->on_mode_event = [this](const i3ipc::mode_t& mode) {
m_modeactive = (mode.change != DEFAULT_MODE);
if (m_modeactive) {
m_modelabel->reset_tokens();
m_modelabel->replace_token("%mode%", mode.change);
}
};
}
m_ipc->subscribe(i3ipc::ET_WORKSPACE | i3ipc::ET_MODE);
} catch (const exception& err) {
2016-11-02 15:22:45 -04:00
throw module_error(err.what());
}
2016-11-30 12:23:11 -05:00
}
2016-11-02 15:22:45 -04:00
i3_module::workspace::operator bool() {
return label && *label;
}
2016-11-30 12:23:11 -05:00
void i3_module::stop() {
2016-11-02 15:22:45 -04:00
try {
2016-11-30 12:23:11 -05:00
if (m_ipc) {
m_log.info("%s: Disconnecting from socket", name());
shutdown(m_ipc->get_event_socket_fd(), SHUT_RDWR);
shutdown(m_ipc->get_main_socket_fd(), SHUT_RDWR);
}
2016-11-02 15:22:45 -04:00
} catch (...) {
}
event_module::stop();
2016-11-30 12:23:11 -05:00
}
2016-11-02 15:22:45 -04:00
2016-11-30 12:23:11 -05:00
bool i3_module::has_event() {
try {
m_ipc->handle_event();
return true;
} catch (const exception& err) {
return false;
}
}
2016-11-02 15:22:45 -04:00
2016-11-30 12:23:11 -05:00
bool i3_module::update() {
2016-11-02 15:22:45 -04:00
m_workspaces.clear();
i3_util::connection_t ipc;
try {
2016-12-13 22:42:21 -05:00
vector<shared_ptr<i3_util::workspace_t>> workspaces;
2016-11-02 15:22:45 -04:00
2016-12-13 22:42:21 -05:00
if (m_pinworkspaces) {
workspaces = i3_util::workspaces(ipc, m_bar.monitor->name);
} else {
workspaces = i3_util::workspaces(ipc);
2016-11-25 07:55:15 -05:00
}
2016-11-02 15:22:45 -04:00
if (m_indexsort) {
2016-12-13 22:42:21 -05:00
sort(workspaces.begin(), workspaces.end(), i3_util::ws_numsort);
2016-11-02 15:22:45 -04:00
}
2016-12-13 22:42:21 -05:00
for (auto&& ws : workspaces) {
state ws_state{state::NONE};
2016-11-02 15:22:45 -04:00
2016-11-30 12:23:11 -05:00
if (ws->focused) {
2016-11-30 21:35:54 -05:00
ws_state = state::FOCUSED;
2016-11-30 12:23:11 -05:00
} else if (ws->urgent) {
2016-11-30 21:35:54 -05:00
ws_state = state::URGENT;
2016-12-13 22:42:21 -05:00
} else if (!ws->visible || (ws->visible && ws->output != m_bar.monitor->name)) {
2016-11-30 21:35:54 -05:00
ws_state = state::UNFOCUSED;
2016-11-25 07:55:15 -05:00
} else {
2016-11-30 21:35:54 -05:00
ws_state = state::VISIBLE;
2016-11-25 07:55:15 -05:00
}
2016-11-02 15:22:45 -04:00
2016-12-13 22:42:21 -05:00
string ws_name{ws->name};
2016-11-02 15:22:45 -04:00
// Remove workspace numbers "0:"
2016-11-25 07:55:15 -05:00
if (m_strip_wsnumbers) {
2016-12-13 22:42:21 -05:00
ws_name.erase(0, string_util::find_nth(ws_name, 0, ":", 1) + 1);
2016-11-25 07:55:15 -05:00
}
2016-11-02 15:22:45 -04:00
// Trim leading and trailing whitespace
ws_name = string_util::trim(move(ws_name), ' ');
2016-11-02 15:22:45 -04:00
auto icon = m_icons->get(ws->name, DEFAULT_WS_ICON, m_fuzzy_match);
2016-11-30 21:35:54 -05:00
auto label = m_statelabels.find(ws_state)->second->clone();
2016-11-02 15:22:45 -04:00
label->reset_tokens();
2016-11-30 12:23:11 -05:00
label->replace_token("%output%", ws->output);
2016-12-13 22:42:21 -05:00
label->replace_token("%name%", ws_name);
2016-11-02 15:22:45 -04:00
label->replace_token("%icon%", icon->get());
2016-11-30 12:23:11 -05:00
label->replace_token("%index%", to_string(ws->num));
2016-12-09 03:02:47 -05:00
m_workspaces.emplace_back(factory_util::unique<workspace>(ws->num, ws_state, move(label)));
2016-11-02 15:22:45 -04:00
}
return true;
2016-11-30 12:23:11 -05:00
} catch (const exception& err) {
2016-11-02 15:22:45 -04:00
m_log.err("%s: %s", name(), err.what());
return false;
}
2016-11-30 12:23:11 -05:00
}
2016-11-02 15:22:45 -04:00
2016-11-30 12:23:11 -05:00
bool i3_module::build(builder* builder, const string& tag) const {
if (tag == TAG_LABEL_MODE && m_modeactive) {
builder->node(m_modelabel);
} else if (tag == TAG_LABEL_STATE && !m_workspaces.empty()) {
if (m_scroll) {
builder->cmd(mousebtn::SCROLL_DOWN, EVENT_SCROLL_DOWN);
builder->cmd(mousebtn::SCROLL_UP, EVENT_SCROLL_UP);
}
2016-11-02 15:22:45 -04:00
2016-11-30 12:23:11 -05:00
for (auto&& ws : m_workspaces) {
if (m_click) {
builder->cmd(mousebtn::LEFT, string{EVENT_CLICK} + to_string(ws->index));
builder->node(ws->label);
builder->cmd_close();
} else {
builder->node(ws->label);
}
}
2016-11-02 15:22:45 -04:00
2016-11-30 12:23:11 -05:00
if (m_scroll) {
builder->cmd_close();
builder->cmd_close();
}
2016-11-30 12:23:11 -05:00
} else {
return false;
}
return true;
2016-11-30 12:23:11 -05:00
}
2016-11-02 15:22:45 -04:00
2016-12-23 14:43:52 -05:00
bool i3_module::input(string&& cmd) {
if (cmd.find(EVENT_PREFIX) != 0) {
return false;
}
2016-11-02 15:22:45 -04:00
try {
2016-12-14 21:30:41 -05:00
using namespace i3_util;
string scrolldir;
2016-12-14 21:30:41 -05:00
const connection_t conn{};
2016-11-02 15:22:45 -04:00
if (cmd.compare(0, strlen(EVENT_CLICK), EVENT_CLICK) == 0) {
2016-12-23 14:43:52 -05:00
cmd.erase(0, strlen(EVENT_CLICK));
if (focused_workspace(conn)->num != atoi(cmd.c_str())) {
m_log.info("%s: Sending workspace focus command to ipc handler", name());
2016-12-23 14:43:52 -05:00
conn.send_command("workspace number " + cmd);
}
2016-11-02 15:22:45 -04:00
} else if (cmd.compare(0, strlen(EVENT_SCROLL_UP), EVENT_SCROLL_UP) == 0) {
scrolldir = m_revscroll ? "prev" : "next";
2016-12-14 13:04:33 -05:00
} else if (cmd.compare(0, strlen(EVENT_SCROLL_DOWN), EVENT_SCROLL_DOWN) == 0) {
scrolldir = m_revscroll ? "next" : "prev";
} else {
return false;
2016-11-02 15:22:45 -04:00
}
2016-12-14 21:30:41 -05:00
const string& mon_name{m_bar.monitor->name};
if (scrolldir == "next" && (m_wrap || *workspaces(conn, mon_name).back() != *focused_workspace(conn))) {
m_log.info("%s: Sending workspace next command to ipc handler", name());
2016-12-14 21:30:41 -05:00
conn.send_command("workspace next_on_output");
} else if (scrolldir == "prev" && (m_wrap || *workspaces(conn, mon_name).front() != *focused_workspace(conn))) {
m_log.info("%s: Sending workspace prev command to ipc handler", name());
2016-12-14 21:30:41 -05:00
conn.send_command("workspace prev_on_output");
}
2016-11-30 12:23:11 -05:00
} catch (const exception& err) {
2016-11-02 15:22:45 -04:00
m_log.err("%s: %s", name(), err.what());
}
return true;
2016-11-30 12:23:11 -05:00
}
2016-11-02 15:22:45 -04:00
}
2016-11-19 00:22:44 -05:00
POLYBAR_NS_END