2020-07-17 04:35:15 +00:00
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include <dwmipcpp/connection.hpp>
|
|
|
|
|
|
|
|
#include "modules/meta/event_module.hpp"
|
2024-02-27 14:33:34 +00:00
|
|
|
#include "modules/meta/types.hpp"
|
2020-07-17 04:35:15 +00:00
|
|
|
|
|
|
|
POLYBAR_NS
|
|
|
|
|
|
|
|
namespace modules {
|
2020-12-20 00:17:42 +00:00
|
|
|
class dwm_module : public event_module<dwm_module> {
|
2020-07-17 04:35:15 +00:00
|
|
|
public:
|
2024-02-27 14:46:56 +00:00
|
|
|
explicit dwm_module(const bar_settings&, string, const config&);
|
2020-07-17 04:35:15 +00:00
|
|
|
|
|
|
|
using tag_mask_t = unsigned int;
|
2020-07-20 04:45:12 +00:00
|
|
|
using window_t = unsigned int;
|
2020-07-17 04:35:15 +00:00
|
|
|
|
2020-07-20 05:11:16 +00:00
|
|
|
/**
|
|
|
|
* Represents the relevant states a tag can have
|
|
|
|
*/
|
2020-07-17 04:35:15 +00:00
|
|
|
enum class state_t : uint8_t {
|
|
|
|
URGENT, ///< Tag is urgent, overrides all below
|
2020-07-30 01:22:02 +00:00
|
|
|
FOCUSED, ///< Monitor is selected and tag is selected, overrides all below
|
2020-07-17 04:35:15 +00:00
|
|
|
UNFOCUSED, ///< Monitor is not selected, but tag is selected
|
|
|
|
VISIBLE, ///< Tag is not selected, but occupied
|
2020-07-20 04:29:43 +00:00
|
|
|
EMPTY ///< Tag is unoccupied and unselected
|
2020-07-17 04:35:15 +00:00
|
|
|
};
|
|
|
|
|
2020-07-20 05:11:16 +00:00
|
|
|
/**
|
|
|
|
* Associates important properties of a tag
|
|
|
|
*/
|
2020-07-17 04:35:15 +00:00
|
|
|
struct tag_t {
|
2020-07-20 05:11:16 +00:00
|
|
|
/**
|
|
|
|
* Construct a tag_t object
|
|
|
|
*
|
|
|
|
* @param name Name of tag
|
|
|
|
* @param tag_mask_t Bit mask that represents this tag
|
|
|
|
* @param state Current state of the tag
|
|
|
|
* @param label Label to use for building tag on bar
|
|
|
|
*/
|
2020-07-20 04:45:12 +00:00
|
|
|
tag_t(string& name, tag_mask_t bit_mask, state_t state, label_t&& label)
|
2020-07-17 04:35:15 +00:00
|
|
|
: name(name), bit_mask(bit_mask), state(state), label(forward<label_t>(label)) {}
|
|
|
|
|
|
|
|
string name;
|
2020-07-20 04:45:12 +00:00
|
|
|
tag_mask_t bit_mask;
|
2020-07-17 04:35:15 +00:00
|
|
|
state_t state;
|
|
|
|
label_t label;
|
|
|
|
};
|
|
|
|
|
2024-02-27 14:33:34 +00:00
|
|
|
static constexpr auto TYPE = DWM_TYPE;
|
2020-12-20 00:17:42 +00:00
|
|
|
|
2020-07-30 01:34:19 +00:00
|
|
|
void stop() override;
|
|
|
|
bool has_event();
|
|
|
|
bool update();
|
|
|
|
bool build(builder* builder, const string& tag) const;
|
2020-07-17 04:35:15 +00:00
|
|
|
|
2020-12-20 00:17:42 +00:00
|
|
|
/**
|
|
|
|
* DWM command for changing the view to a tag with the specified bit mask
|
|
|
|
*/
|
|
|
|
static constexpr const char* EVENT_TAG_VIEW{"view"};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* DWM command for toggling the selected state of a tag with the specified
|
|
|
|
* bit mask
|
|
|
|
*/
|
|
|
|
static constexpr const char* EVENT_TAG_TOGGLE_VIEW{"toggleview"};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* DWM command for setting the layout to a layout specified by the address
|
|
|
|
*/
|
|
|
|
static constexpr const char* EVENT_LAYOUT_SET{"setlayoutsafe"};
|
|
|
|
|
2020-07-17 04:35:15 +00:00
|
|
|
protected:
|
2023-08-05 16:42:20 +00:00
|
|
|
bool generic_action(const string& action, const string& data);
|
2020-07-17 04:35:15 +00:00
|
|
|
|
|
|
|
private:
|
2020-07-22 22:35:26 +00:00
|
|
|
static constexpr const char* DEFAULT_FORMAT_TAGS{"<label-tags> <label-layout> <label-floating> <label-title>"};
|
2020-07-20 04:27:46 +00:00
|
|
|
static constexpr const char* DEFAULT_STATE_LABEL{"%name%"};
|
2020-07-17 04:35:15 +00:00
|
|
|
|
2023-08-05 16:42:20 +00:00
|
|
|
|
2020-07-20 05:11:16 +00:00
|
|
|
/**
|
2020-07-21 05:30:04 +00:00
|
|
|
* The tags label is replaced with the tags. Each tag is displayed using one
|
2020-07-20 05:11:16 +00:00
|
|
|
* of the following labels based on the tag state:
|
|
|
|
* * label-focused
|
|
|
|
* * label-unfocused
|
|
|
|
* * label-visible
|
|
|
|
* * label-urgent
|
|
|
|
* * label-empty
|
|
|
|
*/
|
2020-07-21 05:30:04 +00:00
|
|
|
static constexpr const char* TAG_LABEL_TAGS{"<label-tags>"};
|
2020-07-20 05:11:16 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* The layout label is replaced by the current layout symbol
|
|
|
|
*/
|
2020-07-17 04:35:15 +00:00
|
|
|
static constexpr const char* TAG_LABEL_LAYOUT{"<label-layout>"};
|
2020-07-20 05:11:16 +00:00
|
|
|
|
2020-07-22 22:35:26 +00:00
|
|
|
/**
|
|
|
|
* The floating label is shown when the selected window is floating
|
|
|
|
*/
|
|
|
|
static constexpr const char* TAG_LABEL_FLOATING{"<label-floating>"};
|
|
|
|
|
2020-07-20 05:11:16 +00:00
|
|
|
/**
|
|
|
|
* The title layout is replaced by the currently focused window title
|
|
|
|
*/
|
2020-07-17 04:35:15 +00:00
|
|
|
static constexpr const char* TAG_LABEL_TITLE{"<label-title>"};
|
|
|
|
|
2020-07-20 05:11:16 +00:00
|
|
|
/**
|
|
|
|
* Called by has_event on layout changes. This updates the layout label
|
|
|
|
*
|
|
|
|
* @param ev Event data
|
|
|
|
*/
|
2020-07-20 02:52:50 +00:00
|
|
|
void on_layout_change(const dwmipc::LayoutChangeEvent& ev);
|
2020-07-20 05:11:16 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Called by has_event when a new monitor is in focus. This updates
|
|
|
|
* m_active_mon to keep track of the currently active monitor.
|
|
|
|
*
|
|
|
|
* @param ev Event data
|
|
|
|
*/
|
2020-07-20 02:52:50 +00:00
|
|
|
void on_monitor_focus_change(const dwmipc::MonitorFocusChangeEvent& ev);
|
2020-07-20 05:11:16 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Called by has_event when any of the tag states change. This updates the
|
|
|
|
* m_tags array and their states/labels.
|
|
|
|
*
|
|
|
|
* @param ev Event data
|
|
|
|
*/
|
2020-07-20 02:52:50 +00:00
|
|
|
void on_tag_change(const dwmipc::TagChangeEvent& ev);
|
2020-07-20 05:11:16 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Called by has_event when a new client is in focus. This updates
|
|
|
|
* m_focused_client_id and updates the title label
|
|
|
|
*
|
|
|
|
* @param ev Event data
|
|
|
|
*/
|
2020-07-20 02:52:50 +00:00
|
|
|
void on_client_focus_change(const dwmipc::ClientFocusChangeEvent& ev);
|
2020-07-20 05:11:16 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Called by has_event when the title of the currently focused window
|
|
|
|
* changes. This updates the title label.
|
|
|
|
*
|
|
|
|
* @param ev Event data
|
|
|
|
*/
|
2020-07-20 02:52:50 +00:00
|
|
|
void on_focused_title_change(const dwmipc::FocusedTitleChangeEvent& ev);
|
2020-07-17 04:35:15 +00:00
|
|
|
|
2020-07-22 22:35:26 +00:00
|
|
|
/**
|
|
|
|
* 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);
|
|
|
|
|
2020-07-20 05:11:16 +00:00
|
|
|
/**
|
|
|
|
* Get a list of monitors from dwm, store them in m_monitors, and update the
|
|
|
|
* pointers to the active monitor and bar monitor.
|
|
|
|
*
|
|
|
|
* @param ev Event data
|
|
|
|
*/
|
2020-07-17 04:35:15 +00:00
|
|
|
void update_monitor_ref();
|
2020-07-20 05:11:16 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Update the labels for each tag based on their state
|
|
|
|
*/
|
2020-07-20 02:52:50 +00:00
|
|
|
void update_tag_labels();
|
2020-07-20 05:11:16 +00:00
|
|
|
|
2020-07-23 20:43:46 +00:00
|
|
|
/**
|
|
|
|
* Update the title label with the specified title
|
|
|
|
*
|
|
|
|
* @param title The title to use to update the label
|
|
|
|
*/
|
|
|
|
void update_title_label(const string& title);
|
|
|
|
|
2020-07-20 05:11:16 +00:00
|
|
|
/**
|
2020-07-21 04:42:58 +00:00
|
|
|
* Get the window title of the currently focused client from dwm and update
|
|
|
|
* the title label
|
2020-07-20 05:11:16 +00:00
|
|
|
*/
|
2020-07-21 04:42:58 +00:00
|
|
|
void update_title_label();
|
2020-07-20 02:52:50 +00:00
|
|
|
|
2020-07-22 22:35:26 +00:00
|
|
|
/**
|
|
|
|
* Query dwm to determine if the currently focused client and update
|
|
|
|
* m_is_floating
|
|
|
|
*/
|
|
|
|
void update_floating_label();
|
|
|
|
|
2020-07-23 20:43:46 +00:00
|
|
|
/**
|
|
|
|
* Update the layout label with the specified symbol
|
|
|
|
*
|
|
|
|
* @param symbol The symbol to use to update the label
|
|
|
|
*/
|
|
|
|
void update_layout_label(const string& symbol);
|
|
|
|
|
2020-07-20 05:11:16 +00:00
|
|
|
/**
|
|
|
|
* Translate the tag's tag states to a state_t enum value
|
|
|
|
*
|
|
|
|
* @param bit_mask Bit mask of the tag
|
|
|
|
*
|
|
|
|
* @return state_t enum value representing the state of the tag
|
|
|
|
*/
|
2020-07-30 01:34:19 +00:00
|
|
|
state_t get_state(tag_mask_t bit_mask) const;
|
2020-07-20 05:11:16 +00:00
|
|
|
|
2020-07-21 03:46:54 +00:00
|
|
|
/**
|
|
|
|
* Get the address to the layout represented by the symbol.
|
|
|
|
*/
|
2020-07-30 01:34:19 +00:00
|
|
|
const dwmipc::Layout* find_layout(const string& sym) const;
|
2020-07-21 03:46:54 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the address to the layout represented by the address.
|
|
|
|
*/
|
2020-07-30 01:34:19 +00:00
|
|
|
const dwmipc::Layout* find_layout(uintptr_t addr) const;
|
2020-07-21 03:46:54 +00:00
|
|
|
|
2020-07-21 22:36:29 +00:00
|
|
|
/**
|
|
|
|
* Get the address of the next layout in m_layouts.
|
|
|
|
*
|
|
|
|
* @param layout Address of the current layout
|
|
|
|
* @param wrap True to wrap around the array, false to return the same
|
|
|
|
* layout if the next layout does not exist.
|
|
|
|
*/
|
2020-07-30 01:34:19 +00:00
|
|
|
const dwmipc::Layout* next_layout(const dwmipc::Layout& layout, bool wrap) const;
|
2020-07-21 22:36:29 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the address of the previous layout in m_layouts.
|
|
|
|
*
|
|
|
|
* @param layout Address of the current layout
|
|
|
|
* @param wrap True to wrap around the array, false to return the same
|
|
|
|
* layout if the next layout does not exist.
|
|
|
|
*/
|
2020-07-30 01:34:19 +00:00
|
|
|
const dwmipc::Layout* prev_layout(const dwmipc::Layout& layout, bool wrap) const;
|
2020-07-21 22:36:29 +00:00
|
|
|
|
2020-12-20 00:17:42 +00:00
|
|
|
/**
|
2020-07-29 01:58:19 +00:00
|
|
|
* Get the address of the next tag in m_tags or return NULL if not applicable
|
|
|
|
*
|
|
|
|
* @param ignore_empty Ignore empty tags
|
|
|
|
*/
|
2020-08-08 23:19:40 +00:00
|
|
|
const tag_t* next_scrollable_tag(bool ignore_empty) const;
|
2020-07-29 01:58:19 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the address of the prev tag in m_tags or return NULL if not applicable
|
|
|
|
*
|
|
|
|
* @param ignore_empty Ignore empty tags
|
|
|
|
*/
|
2020-08-08 23:19:40 +00:00
|
|
|
const tag_t* prev_scrollable_tag(bool ignore_empty) const;
|
2020-07-29 01:58:19 +00:00
|
|
|
|
2020-07-20 05:11:16 +00:00
|
|
|
/**
|
|
|
|
* Attempt to connect to any disconnected dwm sockets. Catch errors.
|
|
|
|
*/
|
2020-07-30 01:34:19 +00:00
|
|
|
bool reconnect_dwm();
|
2020-07-17 04:35:15 +00:00
|
|
|
|
2020-07-20 05:11:16 +00:00
|
|
|
/**
|
|
|
|
* If true, enables the click handlers for the tags
|
|
|
|
*/
|
2020-07-21 22:36:29 +00:00
|
|
|
bool m_tags_click{true};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* If true, enables the click handlers for the layout label
|
|
|
|
*/
|
|
|
|
bool m_layout_click{true};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* If true, scrolling the layout cycle through available layouts
|
|
|
|
*/
|
|
|
|
bool m_layout_scroll{true};
|
|
|
|
|
2020-12-20 00:17:42 +00:00
|
|
|
/**
|
|
|
|
* If true, scrolling the bar cycles through the available tags
|
|
|
|
*/
|
2020-07-25 02:11:42 +00:00
|
|
|
bool m_tags_scroll{false};
|
2020-07-25 02:08:54 +00:00
|
|
|
|
2020-12-20 00:17:42 +00:00
|
|
|
/**
|
|
|
|
* If true, scrolling the bar cycles through the available tags backwards
|
|
|
|
*/
|
2020-08-08 23:19:40 +00:00
|
|
|
bool m_tags_scroll_reverse{false};
|
|
|
|
|
2020-12-20 00:17:42 +00:00
|
|
|
/**
|
|
|
|
* If true, wrap tag when scrolling
|
|
|
|
*/
|
2020-08-08 23:19:40 +00:00
|
|
|
bool m_tags_scroll_wrap{false};
|
|
|
|
|
2020-12-20 00:17:42 +00:00
|
|
|
/**
|
|
|
|
* If true, scrolling will view all tags regardless if occupied
|
|
|
|
*/
|
2020-07-29 01:58:19 +00:00
|
|
|
bool m_tags_scroll_empty{false};
|
|
|
|
|
2020-07-21 22:36:29 +00:00
|
|
|
/**
|
|
|
|
* If true, scrolling the layout will wrap around to the beginning
|
|
|
|
*/
|
|
|
|
bool m_layout_wrap{true};
|
2020-07-17 04:35:15 +00:00
|
|
|
|
2020-07-21 22:45:26 +00:00
|
|
|
/**
|
|
|
|
* If true, scrolling the layout will cycle layouts in the reverse direction
|
|
|
|
*/
|
|
|
|
bool m_layout_reverse{false};
|
|
|
|
|
2020-07-22 22:35:26 +00:00
|
|
|
/**
|
|
|
|
* If true, show floating label
|
|
|
|
*/
|
|
|
|
bool m_is_floating{false};
|
|
|
|
|
2020-07-21 03:46:54 +00:00
|
|
|
/**
|
|
|
|
* 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]"};
|
|
|
|
|
2020-07-30 00:37:15 +00:00
|
|
|
/**
|
|
|
|
* DWM socket path. Can be overriden by config.
|
|
|
|
*/
|
|
|
|
string m_socket_path{"/tmp/dwm.sock"};
|
|
|
|
|
2020-07-21 03:46:54 +00:00
|
|
|
/**
|
|
|
|
* 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;
|
|
|
|
|
2020-07-20 05:11:16 +00:00
|
|
|
/**
|
|
|
|
* Holds the address to the currently active monitor in the m_monitors array
|
|
|
|
*/
|
2020-07-20 02:52:50 +00:00
|
|
|
const dwmipc::Monitor* m_active_mon = nullptr;
|
2020-07-20 05:11:16 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Holds the address to the bar monitor in the m_monitors array
|
|
|
|
*/
|
2020-07-20 02:52:50 +00:00
|
|
|
const dwmipc::Monitor* m_bar_mon = nullptr;
|
2020-07-20 05:11:16 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* XID of the currently focused client
|
|
|
|
*/
|
2020-07-20 04:45:12 +00:00
|
|
|
window_t m_focused_client_id = 0;
|
2020-07-20 02:52:50 +00:00
|
|
|
|
2020-07-20 05:11:16 +00:00
|
|
|
/**
|
|
|
|
* Current layout symbol
|
|
|
|
*/
|
2020-07-17 04:35:15 +00:00
|
|
|
label_t m_layout_label;
|
2020-07-20 05:11:16 +00:00
|
|
|
|
2020-07-22 22:35:26 +00:00
|
|
|
/**
|
|
|
|
* Shown when currently focused window is floating
|
|
|
|
*/
|
|
|
|
label_t m_floating_label;
|
|
|
|
|
2020-07-20 05:11:16 +00:00
|
|
|
/**
|
|
|
|
* Inserted between tags
|
|
|
|
*/
|
2020-07-17 04:35:15 +00:00
|
|
|
label_t m_seperator_label;
|
2020-07-20 05:11:16 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Title of the currently focused window on the bar's monitor
|
|
|
|
*/
|
2020-07-17 04:35:15 +00:00
|
|
|
label_t m_title_label;
|
|
|
|
|
2021-07-16 00:24:16 +00:00
|
|
|
/**
|
|
|
|
* The default value displayed when m_title_label is false
|
|
|
|
*/
|
|
|
|
|
|
|
|
std::string m_title_label_default{"Desktop"};
|
|
|
|
|
2020-07-20 05:11:16 +00:00
|
|
|
/**
|
|
|
|
* Connection to DWM
|
|
|
|
*/
|
2020-07-20 02:52:50 +00:00
|
|
|
unique_ptr<dwmipc::Connection> m_ipc;
|
2020-07-20 05:11:16 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Vector of monitors returned by m_ipc->get_monitors
|
|
|
|
*/
|
2020-07-21 03:43:12 +00:00
|
|
|
shared_ptr<vector<dwmipc::Monitor>> m_monitors;
|
2020-07-20 05:11:16 +00:00
|
|
|
|
2020-07-21 03:46:54 +00:00
|
|
|
/**
|
|
|
|
* Vector of layouts returned by m_ipc->get_layouts
|
|
|
|
*/
|
|
|
|
shared_ptr<vector<dwmipc::Layout>> m_layouts;
|
|
|
|
|
2020-07-20 05:11:16 +00:00
|
|
|
/**
|
|
|
|
* Maps state_t enum values to their corresponding labels
|
|
|
|
*/
|
2020-07-17 04:35:15 +00:00
|
|
|
std::unordered_map<state_t, label_t> m_state_labels;
|
2020-07-20 05:11:16 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Vector of all tags
|
|
|
|
*/
|
2020-07-17 04:35:15 +00:00
|
|
|
vector<tag_t> m_tags;
|
|
|
|
};
|
|
|
|
} // namespace modules
|
|
|
|
|
|
|
|
POLYBAR_NS_END
|