diff --git a/.gitmodules b/.gitmodules index 1f20a3d2..6757f493 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,7 +1,7 @@ [submodule "lib/i3ipcpp"] path = lib/i3ipcpp url = https://github.com/jaagr/i3ipcpp - branch = v0.5.1 + branch = v0.6.0 [submodule "lib/xpp"] path = lib/xpp url = https://github.com/jaagr/xpp diff --git a/include/modules/i3.hpp b/include/modules/i3.hpp index b5ee8cff..6d214255 100644 --- a/include/modules/i3.hpp +++ b/include/modules/i3.hpp @@ -11,33 +11,27 @@ POLYBAR_NS namespace modules { - // meta types {{{ - - enum class i3_flag { - WORKSPACE_NONE, - WORKSPACE_FOCUSED, - WORKSPACE_UNFOCUSED, - WORKSPACE_VISIBLE, - WORKSPACE_URGENT, - }; - - struct i3_workspace { - int index; - i3_flag flag; - label_t label; - - i3_workspace(int index_, i3_flag flag_, label_t&& label_) - : index(index_), flag(flag_), label(forward(label_)) {} - - operator bool(); - }; - - using i3_workspace_t = unique_ptr; - - // }}} - class i3_module : public event_module { public: + enum class state { + NONE, + FOCUSED, + UNFOCUSED, + VISIBLE, + URGENT, + }; + + struct workspace { + explicit workspace(int index, state state_, label_t&& label) + : index(index), state(state_), label(forward(label)) {} + + operator bool(); + + int index; + state state; + label_t label; + }; + using event_module::event_module; void setup(); @@ -51,19 +45,26 @@ namespace modules { } private: - static constexpr auto DEFAULT_WS_ICON = "ws-icon-default"; - static constexpr auto DEFAULT_WS_LABEL = "%icon% %name%"; - static constexpr auto TAG_LABEL_STATE = ""; + static constexpr const char* DEFAULT_TAGS{" "}; + static constexpr const char* DEFAULT_MODE{"default"}; + static constexpr const char* DEFAULT_WS_ICON{"ws-icon-default"}; + static constexpr const char* DEFAULT_WS_LABEL{"%icon% %name%"}; - static constexpr auto EVENT_PREFIX = "i3"; - static constexpr auto EVENT_CLICK = "i3-wsfocus-"; - static constexpr auto EVENT_SCROLL_UP = "i3-wsnext"; - static constexpr auto EVENT_SCROLL_DOWN = "i3-wsprev"; + static constexpr const char* TAG_LABEL_STATE{""}; + static constexpr const char* TAG_LABEL_MODE{""}; - map m_statelabels; - vector m_workspaces; + static constexpr const char* EVENT_PREFIX{"i3"}; + static constexpr const char* EVENT_CLICK{"i3-wsfocus-"}; + static constexpr const char* EVENT_SCROLL_UP{"i3-wsnext"}; + static constexpr const char* EVENT_SCROLL_DOWN{"i3-wsprev"}; + + map m_statelabels; + vector> m_workspaces; iconset_t m_icons; + label_t m_modelabel; + bool m_modeactive{false}; + bool m_click = true; bool m_scroll = true; bool m_indexsort = false; @@ -71,7 +72,7 @@ namespace modules { bool m_strip_wsnumbers = false; size_t m_wsname_maxlen = 0; - i3_util::connection_t m_ipc; + unique_ptr m_ipc; }; } diff --git a/lib/i3ipcpp b/lib/i3ipcpp index a9654243..8d78ec8c 160000 --- a/lib/i3ipcpp +++ b/lib/i3ipcpp @@ -1 +1 @@ -Subproject commit a96542431949cb5d429df1078d9ba3ad28be371b +Subproject commit 8d78ec8cb08f66874082a8d9166793e478682d97 diff --git a/src/modules/i3.cpp b/src/modules/i3.cpp index ea010f0f..4ac22249 100644 --- a/src/modules/i3.cpp +++ b/src/modules/i3.cpp @@ -1,9 +1,9 @@ #include -#include "modules/i3.hpp" - #include "drawtypes/iconset.hpp" #include "drawtypes/label.hpp" +#include "modules/i3.hpp" +#include "utils/file.hpp" #include "modules/meta/base.inl" #include "modules/meta/event_module.inl" @@ -14,11 +14,19 @@ namespace modules { template class module; template class event_module; - i3_workspace::operator bool() { + i3_module::workspace::operator bool() { return label && *label; } - void i3_module::setup() { // {{{ + void i3_module::setup() { + auto socket_path = i3ipc::get_socketpath(); + + if (!file_util::exists(socket_path)) { + throw module_error("Could not find socket: " + (socket_path.empty() ? "" : socket_path)); + } + + m_ipc = make_unique(); + // Load configuration values GET_CONFIG_VALUE(name(), m_click, "enable-click"); GET_CONFIG_VALUE(name(), m_scroll, "enable-scroll"); @@ -28,17 +36,21 @@ namespace modules { GET_CONFIG_VALUE(name(), m_wsname_maxlen, "wsname-maxlen"); // Add formats and create components - m_formatter->add(DEFAULT_FORMAT, TAG_LABEL_STATE, {TAG_LABEL_STATE}); + m_formatter->add(DEFAULT_FORMAT, DEFAULT_TAGS, {TAG_LABEL_STATE, TAG_LABEL_MODE}); if (m_formatter->has(TAG_LABEL_STATE)) { - m_statelabels.insert(make_pair( - i3_flag::WORKSPACE_FOCUSED, load_optional_label(m_conf, name(), "label-focused", DEFAULT_WS_LABEL))); - m_statelabels.insert(make_pair( - i3_flag::WORKSPACE_UNFOCUSED, load_optional_label(m_conf, name(), "label-unfocused", DEFAULT_WS_LABEL))); - m_statelabels.insert(make_pair( - i3_flag::WORKSPACE_VISIBLE, load_optional_label(m_conf, name(), "label-visible", DEFAULT_WS_LABEL))); m_statelabels.insert( - make_pair(i3_flag::WORKSPACE_URGENT, load_optional_label(m_conf, name(), "label-urgent", DEFAULT_WS_LABEL))); + 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%"); } m_icons = make_shared(); @@ -52,29 +64,44 @@ namespace modules { } try { - m_ipc.subscribe(i3ipc::ET_WORKSPACE); - m_ipc.prepare_to_event_handling(); - } catch (std::exception& err) { + 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) { throw module_error(err.what()); } - } // }}} + } - void i3_module::stop() { // {{{ + void i3_module::stop() { try { - m_log.info("%s: Disconnecting from sockets", name()); - shutdown(m_ipc.get_event_socket_fd(), SHUT_RDWR); - shutdown(m_ipc.get_main_socket_fd(), SHUT_RDWR); + 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); + } } catch (...) { } event_module::stop(); - } // }}} + } - bool i3_module::has_event() { // {{{ - return m_ipc.handle_event(); - } // }}} + bool i3_module::has_event() { + try { + m_ipc->handle_event(); + return true; + } catch (const exception& err) { + return false; + } + } - bool i3_module::update() { // {{{ + bool i3_module::update() { m_workspaces.clear(); i3_util::connection_t ipc; @@ -83,9 +110,9 @@ namespace modules { vector> sorted = workspaces; string focused_output; - for (auto&& workspace : workspaces) { - if (workspace->focused) { - focused_output = workspace->output; + for (auto&& ws : workspaces) { + if (ws->focused) { + focused_output = ws->output; break; } } @@ -99,23 +126,23 @@ namespace modules { // clang-format on } - for (auto&& workspace : sorted) { - if (m_pinworkspaces && workspace->output != m_bar.monitor->name) { + for (auto&& ws : sorted) { + if (m_pinworkspaces && ws->output != m_bar.monitor->name) { continue; } - auto flag = i3_flag::WORKSPACE_NONE; - if (workspace->focused) { - flag = i3_flag::WORKSPACE_FOCUSED; - } else if (workspace->urgent) { - flag = i3_flag::WORKSPACE_URGENT; - } else if (!workspace->visible || (workspace->visible && workspace->output != focused_output)) { - flag = i3_flag::WORKSPACE_UNFOCUSED; + auto state = state::NONE; + if (ws->focused) { + state = state::FOCUSED; + } else if (ws->urgent) { + state = state::URGENT; + } else if (!ws->visible || (ws->visible && ws->output != focused_output)) { + state = state::UNFOCUSED; } else { - flag = i3_flag::WORKSPACE_VISIBLE; + state = state::VISIBLE; } - string wsname{workspace->name}; + string wsname{ws->name}; // Remove workspace numbers "0:" if (m_strip_wsnumbers) { @@ -130,53 +157,55 @@ namespace modules { wsname.erase(m_wsname_maxlen); } - auto icon = m_icons->get(workspace->name, DEFAULT_WS_ICON); - auto label = m_statelabels.find(flag)->second->clone(); + auto icon = m_icons->get(ws->name, DEFAULT_WS_ICON); + auto label = m_statelabels.find(state)->second->clone(); label->reset_tokens(); - label->replace_token("%output%", workspace->output); + label->replace_token("%output%", ws->output); label->replace_token("%name%", wsname); label->replace_token("%icon%", icon->get()); - label->replace_token("%index%", to_string(workspace->num)); - m_workspaces.emplace_back(make_unique(workspace->num, flag, move(label))); + label->replace_token("%index%", to_string(ws->num)); + m_workspaces.emplace_back(make_unique(ws->num, state, move(label))); } return true; - } catch (const std::exception& err) { + } catch (const exception& err) { m_log.err("%s: %s", name(), err.what()); return false; } - } // }}} + } - bool i3_module::build(builder* builder, const string& tag) const { // {{{ - if (tag != TAG_LABEL_STATE) { + 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); + } + + 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); + } + } + + if (m_scroll) { + builder->cmd_close(); + builder->cmd_close(); + } + } else { return false; } - if (m_scroll) { - builder->cmd(mousebtn::SCROLL_DOWN, EVENT_SCROLL_DOWN); - builder->cmd(mousebtn::SCROLL_UP, EVENT_SCROLL_UP); - } - - 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); - } - } - - if (m_scroll) { - builder->cmd_close(); - builder->cmd_close(); - } - return true; - } // }}} + } - bool i3_module::handle_event(string cmd) { // {{{ + bool i3_module::handle_event(string cmd) { if (cmd.compare(0, 2, EVENT_PREFIX) != 0) { return false; } @@ -194,12 +223,12 @@ namespace modules { m_log.info("%s: Sending workspace next command to ipc handler", name()); ipc.send_command("workspace prev_on_output"); } - } catch (const std::exception& err) { + } catch (const exception& err) { m_log.err("%s: %s", name(), err.what()); } return true; - } // }}} + } } POLYBAR_NS_END