dwm: Add label-floating

This label is visible when the currently focused client is in floating mode and
detached from the layout. It uses the focused_state_change_event as well as the
focused_client_change_event to check if the focused client is floating and
updates m_is_floating accordingly which will enable/disbale the floating label
in the final output.

update_floating_label is called when the floating state of the client is not
known. The function queries dwm for the properties of the focused client and
sets m_is_floating accordingly.

This fixes issue #2.
This commit is contained in:
Mihir Lad 2020-07-22 18:35:26 -04:00
parent 3fa404e9ff
commit 02bd2e060d
3 changed files with 75 additions and 3 deletions

View File

@ -168,7 +168,7 @@ label-urgent-padding = 2
[module/dwm] [module/dwm]
type = internal/dwm type = internal/dwm
format = <label-tags> <label-layout> <label-title> format = <label-tags> <label-layout> <label-floating> <label-title>
enable-tags-click = false enable-tags-click = false
enable-layout-click = false enable-layout-click = false

View File

@ -56,7 +56,7 @@ namespace modules {
auto input(string&& cmd) -> bool override; auto input(string&& cmd) -> bool override;
private: private:
static constexpr const char* DEFAULT_FORMAT_TAGS{"<label-tags> <label-layout> <label-title>"}; static constexpr const char* DEFAULT_FORMAT_TAGS{"<label-tags> <label-layout> <label-floating> <label-title>"};
static constexpr const char* DEFAULT_STATE_LABEL{"%name%"}; static constexpr const char* DEFAULT_STATE_LABEL{"%name%"};
/** /**
@ -75,6 +75,11 @@ namespace modules {
*/ */
static constexpr const char* TAG_LABEL_LAYOUT{"<label-layout>"}; static constexpr const char* TAG_LABEL_LAYOUT{"<label-layout>"};
/**
* The floating label is shown when the selected window is floating
*/
static constexpr const char* TAG_LABEL_FLOATING{"<label-floating>"};
/** /**
* The title layout is replaced by the currently focused window title * The title layout is replaced by the currently focused window title
*/ */
@ -140,6 +145,14 @@ namespace modules {
*/ */
void on_focused_title_change(const dwmipc::FocusedTitleChangeEvent& ev); void on_focused_title_change(const dwmipc::FocusedTitleChangeEvent& ev);
/**
* Called by has_event when the state of the currently focused window
* changes. This updates the floating label.
*
* @param ev Event data
*/
void on_focused_state_change(const dwmipc::FocusedStateChangeEvent& ev);
/** /**
* Get a list of monitors from dwm, store them in m_monitors, and update the * Get a list of monitors from dwm, store them in m_monitors, and update the
* pointers to the active monitor and bar monitor. * pointers to the active monitor and bar monitor.
@ -159,6 +172,12 @@ namespace modules {
*/ */
void update_title_label(); void update_title_label();
/**
* Query dwm to determine if the currently focused client and update
* m_is_floating
*/
void update_floating_label();
/** /**
* Translate the tag's tag states to a state_t enum value * Translate the tag's tag states to a state_t enum value
* *
@ -246,6 +265,11 @@ namespace modules {
*/ */
bool m_layout_reverse{false}; bool m_layout_reverse{false};
/**
* If true, show floating label
*/
bool m_is_floating{false};
/** /**
* If the layout symbol is clicked on, it will set the layout represented by * If the layout symbol is clicked on, it will set the layout represented by
* this symbol. The default is monocle mode [M]. * this symbol. The default is monocle mode [M].
@ -288,6 +312,11 @@ namespace modules {
*/ */
label_t m_layout_label; label_t m_layout_label;
/**
* Shown when currently focused window is floating
*/
label_t m_floating_label;
/** /**
* Inserted between tags * Inserted between tags
*/ */

View File

@ -28,7 +28,7 @@ namespace modules {
m_ipc = factory_util::unique<dwmipc::Connection>(socket_path); m_ipc = factory_util::unique<dwmipc::Connection>(socket_path);
// Load configuration // Load configuration
m_formatter->add(DEFAULT_FORMAT, DEFAULT_FORMAT_TAGS, {TAG_LABEL_TAGS, TAG_LABEL_LAYOUT, TAG_LABEL_TITLE}); m_formatter->add(DEFAULT_FORMAT, DEFAULT_FORMAT_TAGS, {TAG_LABEL_TAGS, TAG_LABEL_LAYOUT, TAG_LABEL_FLOATING, TAG_LABEL_TITLE});
// Populate m_state_labels map with labels and their states // Populate m_state_labels map with labels and their states
if (m_formatter->has(TAG_LABEL_TAGS)) { if (m_formatter->has(TAG_LABEL_TAGS)) {
@ -50,6 +50,10 @@ namespace modules {
m_layout_label = load_optional_label(m_conf, name(), "label-layout", "%layout%"); m_layout_label = load_optional_label(m_conf, name(), "label-layout", "%layout%");
} }
if (m_formatter->has(TAG_LABEL_FLOATING)) {
m_floating_label = load_optional_label(m_conf, name(), "label-floating", "");
}
if (m_formatter->has(TAG_LABEL_TITLE)) { if (m_formatter->has(TAG_LABEL_TITLE)) {
m_title_label = load_optional_label(m_conf, name(), "label-title", "%title%"); m_title_label = load_optional_label(m_conf, name(), "label-title", "%title%");
} }
@ -74,6 +78,10 @@ namespace modules {
m_tags.emplace_back(t.tag_name, t.bit_mask, state, move(label)); m_tags.emplace_back(t.tag_name, t.bit_mask, state, move(label));
} }
if (m_floating_label) {
update_floating_label();
}
if (m_layout_label) { if (m_layout_label) {
auto layouts = m_ipc->get_layouts(); auto layouts = m_ipc->get_layouts();
m_layouts = m_ipc->get_layouts(); m_layouts = m_ipc->get_layouts();
@ -106,6 +114,14 @@ namespace modules {
m_ipc->subscribe(dwmipc::Event::FOCUSED_TITLE_CHANGE); m_ipc->subscribe(dwmipc::Event::FOCUSED_TITLE_CHANGE);
} }
if (m_floating_label) {
update_floating_label();
m_ipc->on_focused_state_change = [this](const dwmipc::FocusedStateChangeEvent& ev) {
this->on_focused_state_change(ev);
};
m_ipc->subscribe(dwmipc::Event::FOCUSED_STATE_CHANGE);
}
// This event is for keeping track of the currently focused monitor // This event is for keeping track of the currently focused monitor
m_ipc->on_monitor_focus_change = [this](const dwmipc::MonitorFocusChangeEvent& ev) { m_ipc->on_monitor_focus_change = [this](const dwmipc::MonitorFocusChangeEvent& ev) {
this->on_monitor_focus_change(ev); this->on_monitor_focus_change(ev);
@ -154,6 +170,11 @@ namespace modules {
auto dwm_module::build(builder* builder, const string& tag) const -> bool { auto dwm_module::build(builder* builder, const string& tag) const -> bool {
if (tag == TAG_LABEL_TITLE) { if (tag == TAG_LABEL_TITLE) {
builder->node(m_title_label); builder->node(m_title_label);
} else if (tag == TAG_LABEL_FLOATING) {
if (!m_is_floating) {
return true;
}
builder->node(m_floating_label);
} else if (tag == TAG_LABEL_LAYOUT) { } else if (tag == TAG_LABEL_LAYOUT) {
if (m_layout_click) { if (m_layout_click) {
// Toggle between secondary and default layout // Toggle between secondary and default layout
@ -353,6 +374,21 @@ namespace modules {
m_title_label->replace_token("%title%", new_title); m_title_label->replace_token("%title%", new_title);
} }
void dwm_module::update_floating_label() {
if (m_focused_client_id != 0) {
try {
m_is_floating = m_ipc->get_client(m_focused_client_id)->states.is_floating;
} catch (const dwmipc::SocketClosedError& err) {
m_log.err("%s: Disconnected from socket: %s", name(), err.what());
reconnect_dwm();
} catch (const dwmipc::IPCError& err) {
throw module_error(err.what());
}
} else {
m_is_floating = false;
}
}
auto dwm_module::reconnect_dwm() -> bool { auto dwm_module::reconnect_dwm() -> bool {
try { try {
if (!m_ipc->is_main_socket_connected()) { if (!m_ipc->is_main_socket_connected()) {
@ -401,10 +437,17 @@ namespace modules {
} }
} }
void dwm_module::on_focused_state_change(const dwmipc::FocusedStateChangeEvent& ev) {
if (ev.monitor_num == m_bar_mon->num && ev.client_window_id == m_focused_client_id) {
m_is_floating = ev.new_state.is_floating;
}
}
void dwm_module::on_client_focus_change(const dwmipc::ClientFocusChangeEvent& ev) { void dwm_module::on_client_focus_change(const dwmipc::ClientFocusChangeEvent& ev) {
if (ev.monitor_num == m_bar_mon->num) { if (ev.monitor_num == m_bar_mon->num) {
m_focused_client_id = ev.new_win_id; m_focused_client_id = ev.new_win_id;
update_title_label(); update_title_label();
update_floating_label();
} }
} }