From bc16268d30a76ed154421452ec2384d42d302c19 Mon Sep 17 00:00:00 2001 From: Mihir Lad Date: Mon, 20 Jul 2020 23:46:54 -0400 Subject: [PATCH] dwm: Add click handlers to label-layout secondary-layout-symbol is the symbol of the layout to switch to when the layout symbol is left-clicked. This symbol is used to look up the memory address of the layout to set. The default is the monocle layout. setlayoutsafe is the dwm command name for setting layouts. The argument is the layout memory address. Left-clicking switches to the layout represented by secondary-layout-symbol, and right-clicking switches to the previous layout (specified by an argument of 0). To keep track of the different layouts, the layouts are retrieved in the constructor if the layout label is included and stored in m_layouts. m_current_layout is updated with the address of the current layout. m_default_layout is updated in the constructor to the first layout in the array which is the default layout in dwm. m_secondary_layout is updated to the address of the layout identified by secondary-layout-symbol. The builder adds click handlers (if layout label is included) to the layout symbol as described above. Left-clicking toggles between the secondary layout and the default layout. Right-clicking toggles between the previous layout and the current layout. find_layout are a pair of functions for finding a layout by address or symbol from the m_layouts array. --- config.cmake | 3 +++ include/modules/dwm.hpp | 49 ++++++++++++++++++++++++++++++++++++ src/modules/dwm.cpp | 55 +++++++++++++++++++++++++++++++++++------ 3 files changed, 100 insertions(+), 7 deletions(-) diff --git a/config.cmake b/config.cmake index d6ed90eb..ad66c49d 100644 --- a/config.cmake +++ b/config.cmake @@ -172,6 +172,9 @@ format = enable-click = false +; If enable-click = true, clicking the layout symbol will switch to this layout +secondary-layout-symbol = [M] + ; State ; Available tokens: ; %name% diff --git a/include/modules/dwm.hpp b/include/modules/dwm.hpp index 1e64bb2f..0c026e83 100644 --- a/include/modules/dwm.hpp +++ b/include/modules/dwm.hpp @@ -93,6 +93,18 @@ namespace modules { */ static constexpr const char* EVENT_TAG_RCLICK{"toggleview"}; + /** + * Event name is same as the IPC command name to set the layout to the + * secondary layout when the layout symbol is clicked + */ + static constexpr const char* EVENT_LAYOUT_LCLICK{"setlayoutsafe"}; + + /** + * Event name is same as the IPC command name to set the layout to the + * last layout. + */ + static constexpr const char* EVENT_LAYOUT_RCLICK{"setlayoutsafe"}; + /** * Called by has_event on layout changes. This updates the layout label * @@ -162,6 +174,16 @@ namespace modules { */ auto get_state(tag_mask_t bit_mask) const -> state_t; + /** + * Get the address to the layout represented by the symbol. + */ + auto find_layout(const string& sym) const -> const dwmipc::Layout*; + + /** + * Get the address to the layout represented by the address. + */ + auto find_layout(uintptr_t addr) const -> const dwmipc::Layout*; + /** * Check if the command matches the specified event name and if so, send a * command to dwm after parsing the command. @@ -193,6 +215,28 @@ namespace modules { */ bool m_click{true}; + /** + * If the layout symbol is clicked on, it will set the layout represented by + * this symbol. The default is monocle mode [M]. + */ + string m_secondary_layout_symbol{"[M]"}; + + /** + * Holds the address to the secondary layout specified by the secondary + * layout symbol + */ + const dwmipc::Layout* m_secondary_layout = nullptr; + + /** + * Holds the address to the current layout + */ + const dwmipc::Layout* m_current_layout = nullptr; + + /** + * Holds the address to the default layout + */ + const dwmipc::Layout* m_default_layout = nullptr; + /** * Holds the address to the currently active monitor in the m_monitors array */ @@ -233,6 +277,11 @@ namespace modules { */ shared_ptr> m_monitors; + /** + * Vector of layouts returned by m_ipc->get_layouts + */ + shared_ptr> m_layouts; + /** * Maps state_t enum values to their corresponding labels */ diff --git a/src/modules/dwm.cpp b/src/modules/dwm.cpp index 21bbf461..170fa336 100644 --- a/src/modules/dwm.cpp +++ b/src/modules/dwm.cpp @@ -56,6 +56,8 @@ namespace modules { m_click = m_conf.get(name(), "enable-click", m_click); + m_secondary_layout_symbol = m_conf.get(name(), "secondary-layout-symbol", m_secondary_layout_symbol); + try { update_monitor_ref(); @@ -68,11 +70,20 @@ namespace modules { m_tags.emplace_back(t.tag_name, t.bit_mask, state, move(label)); } - // This event is only needed to update the layout label if (m_layout_label) { auto layouts = m_ipc->get_layouts(); + m_layouts = m_ipc->get_layouts(); + // First layout is treated as default by dwm + m_default_layout = &m_layouts->at(0); + m_current_layout = find_layout(m_bar_mon->layout.address.cur); + m_secondary_layout = find_layout(m_secondary_layout_symbol); + if (m_secondary_layout == nullptr) { + throw module_error("Secondary layout symbol does not exist"); + } + // Initialize layout symbol m_layout_label->replace_token("%layout%", m_bar_mon->layout.symbol.cur); + // This event is only needed to update the layout label m_ipc->on_layout_change = [this](const dwmipc::LayoutChangeEvent& ev) { on_layout_change(ev); }; m_ipc->subscribe(dwmipc::Event::LAYOUT_CHANGE); } @@ -137,10 +148,21 @@ namespace modules { } auto dwm_module::build(builder* builder, const string& tag) const -> bool { - if (tag == TAG_LABEL_LAYOUT) { - builder->node(m_layout_label); - } else if (tag == TAG_LABEL_TITLE) { + if (tag == TAG_LABEL_TITLE) { builder->node(m_title_label); + } else if (tag == TAG_LABEL_LAYOUT) { + if (m_click) { + // Toggle between secondary and default layout + auto addr = (m_current_layout == m_default_layout ? m_secondary_layout : m_default_layout)->address; + builder->cmd(mousebtn::LEFT, build_cmd(EVENT_LAYOUT_LCLICK, to_string(addr))); + // Set previous layout + builder->cmd(mousebtn::RIGHT, build_cmd(EVENT_LAYOUT_RCLICK, "0")); + builder->node(m_layout_label); + builder->cmd_close(); + builder->cmd_close(); + } else { + builder->node(m_layout_label); + } } else if (tag == TAG_LABEL_STATE) { bool first = true; for (const auto& tag : m_tags) { @@ -168,7 +190,6 @@ namespace modules { } auto dwm_module::check_send_cmd(string cmd, const string& ev_name) -> bool { - std::cerr << cmd << std::endl; // cmd = - cmd.erase(0, strlen(EVENT_PREFIX)); @@ -176,7 +197,7 @@ namespace modules { if (cmd.compare(0, ev_name.size(), ev_name) == 0) { // Erase '-' cmd.erase(0, ev_name.size() + 1); - m_log.info("%s: Sending workspace %s command to ipc handler", ev_name, name()); + m_log.info("%s: Sending workspace %s command to ipc handler", name(), ev_name); try { m_ipc->run_command(ev_name, stoul(cmd)); @@ -196,7 +217,8 @@ namespace modules { return false; } - return check_send_cmd(cmd, EVENT_TAG_LCLICK) || check_send_cmd(cmd, EVENT_TAG_RCLICK); + return check_send_cmd(cmd, EVENT_TAG_LCLICK) || check_send_cmd(cmd, EVENT_TAG_RCLICK) || + check_send_cmd(cmd, EVENT_LAYOUT_LCLICK) || check_send_cmd(cmd, EVENT_LAYOUT_RCLICK); } auto dwm_module::get_state(tag_mask_t bit_mask) const -> state_t { @@ -247,6 +269,24 @@ namespace modules { } } + auto dwm_module::find_layout(const string& sym) const -> const dwmipc::Layout* { + for (const auto& lt : *m_layouts) { + if (lt.symbol == sym) { + return < + } + } + return nullptr; + } + + auto dwm_module::find_layout(const uintptr_t addr) const -> const dwmipc::Layout* { + for (const auto& lt : *m_layouts) { + if (lt.address == addr) { + return < + } + } + return nullptr; + } + void dwm_module::update_tag_labels() { for (auto& t : m_tags) { t.state = get_state(t.bit_mask); @@ -293,6 +333,7 @@ namespace modules { void dwm_module::on_layout_change(const dwmipc::LayoutChangeEvent& ev) { if (ev.monitor_num == m_bar_mon->num) { + m_current_layout = find_layout(ev.new_address); m_layout_label->reset_tokens(); m_layout_label->replace_token("%layout%", ev.new_symbol); }