Merge pull request #4395 from pol-rivero/workspace-taskbar-improvements
[hyprland/workspaces] Taskbar improvements
This commit is contained in:
@ -42,7 +42,6 @@ class Workspace {
|
|||||||
bool isPersistentConfig() const { return m_isPersistentConfig; };
|
bool isPersistentConfig() const { return m_isPersistentConfig; };
|
||||||
bool isPersistentRule() const { return m_isPersistentRule; };
|
bool isPersistentRule() const { return m_isPersistentRule; };
|
||||||
bool isVisible() const { return m_isVisible; };
|
bool isVisible() const { return m_isVisible; };
|
||||||
bool isEmpty() const { return m_windows == 0; };
|
|
||||||
bool isUrgent() const { return m_isUrgent; };
|
bool isUrgent() const { return m_isUrgent; };
|
||||||
|
|
||||||
bool handleClicked(GdkEventButton* bt) const;
|
bool handleClicked(GdkEventButton* bt) const;
|
||||||
@ -88,6 +87,7 @@ class Workspace {
|
|||||||
Gtk::Label m_labelBefore;
|
Gtk::Label m_labelBefore;
|
||||||
Gtk::Label m_labelAfter;
|
Gtk::Label m_labelAfter;
|
||||||
|
|
||||||
|
bool isEmpty() const;
|
||||||
void updateTaskbar(const std::string& workspace_icon);
|
void updateTaskbar(const std::string& workspace_icon);
|
||||||
bool handleClick(const GdkEventButton* event_button, WindowAddress const& addr) const;
|
bool handleClick(const GdkEventButton* event_button, WindowAddress const& addr) const;
|
||||||
bool shouldSkipWindow(const WindowRepr& window_repr) const;
|
bool shouldSkipWindow(const WindowRepr& window_repr) const;
|
||||||
|
@ -51,9 +51,13 @@ class Workspaces : public AModule, public EventHandler {
|
|||||||
auto taskbarFormatAfter() const -> std::string { return m_taskbarFormatAfter; }
|
auto taskbarFormatAfter() const -> std::string { return m_taskbarFormatAfter; }
|
||||||
auto taskbarIconSize() const -> int { return m_taskbarIconSize; }
|
auto taskbarIconSize() const -> int { return m_taskbarIconSize; }
|
||||||
auto taskbarOrientation() const -> Gtk::Orientation { return m_taskbarOrientation; }
|
auto taskbarOrientation() const -> Gtk::Orientation { return m_taskbarOrientation; }
|
||||||
|
auto taskbarReverseDirection() const -> bool { return m_taskbarReverseDirection; }
|
||||||
auto onClickWindow() const -> std::string { return m_onClickWindow; }
|
auto onClickWindow() const -> std::string { return m_onClickWindow; }
|
||||||
auto getIgnoredWindows() const -> std::vector<std::regex> { return m_ignoreWindows; }
|
auto getIgnoredWindows() const -> std::vector<std::regex> { return m_ignoreWindows; }
|
||||||
|
|
||||||
|
enum class ActiveWindowPosition { NONE, FIRST, LAST };
|
||||||
|
auto activeWindowPosition() const -> ActiveWindowPosition { return m_activeWindowPosition; }
|
||||||
|
|
||||||
std::string getRewrite(std::string window_class, std::string window_title);
|
std::string getRewrite(std::string window_class, std::string window_title);
|
||||||
std::string& getWindowSeparator() { return m_formatWindowSeparator; }
|
std::string& getWindowSeparator() { return m_formatWindowSeparator; }
|
||||||
bool isWorkspaceIgnored(std::string const& workspace_name);
|
bool isWorkspaceIgnored(std::string const& workspace_name);
|
||||||
@ -183,6 +187,14 @@ class Workspaces : public AModule, public EventHandler {
|
|||||||
std::string m_taskbarFormatAfter;
|
std::string m_taskbarFormatAfter;
|
||||||
int m_taskbarIconSize = 16;
|
int m_taskbarIconSize = 16;
|
||||||
Gtk::Orientation m_taskbarOrientation = Gtk::ORIENTATION_HORIZONTAL;
|
Gtk::Orientation m_taskbarOrientation = Gtk::ORIENTATION_HORIZONTAL;
|
||||||
|
bool m_taskbarReverseDirection = false;
|
||||||
|
util::EnumParser<ActiveWindowPosition> m_activeWindowEnumParser;
|
||||||
|
ActiveWindowPosition m_activeWindowPosition = ActiveWindowPosition::NONE;
|
||||||
|
std::map<std::string, ActiveWindowPosition> m_activeWindowPositionMap = {
|
||||||
|
{"NONE", ActiveWindowPosition::NONE},
|
||||||
|
{"FIRST", ActiveWindowPosition::FIRST},
|
||||||
|
{"LAST", ActiveWindowPosition::LAST},
|
||||||
|
};
|
||||||
std::string m_onClickWindow;
|
std::string m_onClickWindow;
|
||||||
std::string m_currentActiveWindowAddress;
|
std::string m_currentActiveWindowAddress;
|
||||||
|
|
||||||
|
@ -50,6 +50,21 @@ This setting is ignored if *workspace-taskbar.enable* is set to true.
|
|||||||
default: false ++
|
default: false ++
|
||||||
Enables the workspace taskbar mode.
|
Enables the workspace taskbar mode.
|
||||||
|
|
||||||
|
*update-active-window*: ++
|
||||||
|
typeof: bool ++
|
||||||
|
default: false ++
|
||||||
|
If true, the active/focused window will have an 'active' class. Could cause higher CPU usage due to more frequent redraws.
|
||||||
|
|
||||||
|
*reverse-direction*: ++
|
||||||
|
typeof: bool ++
|
||||||
|
default: false ++
|
||||||
|
If true, the taskbar windows will be added in reverse order (right to left if orientation is horizontal, bottom to top if vertical).
|
||||||
|
|
||||||
|
*active-window-position*: ++
|
||||||
|
typeof: "none" | "first" | "last" ++
|
||||||
|
default: "none" ++
|
||||||
|
If set to "first", the active window will be moved at the beginning of the taskbar. If set to "last", it will be moved at the end. It will only work if *update-active-window* is set to true.
|
||||||
|
|
||||||
*format*: ++
|
*format*: ++
|
||||||
typeof: string ++
|
typeof: string ++
|
||||||
default: {icon} ++
|
default: {icon} ++
|
||||||
@ -70,6 +85,19 @@ This setting is ignored if *workspace-taskbar.enable* is set to true.
|
|||||||
default: horizontal ++
|
default: horizontal ++
|
||||||
Direction in which the workspace taskbar is displayed.
|
Direction in which the workspace taskbar is displayed.
|
||||||
|
|
||||||
|
*ignore-list*: ++
|
||||||
|
typeof: array ++
|
||||||
|
default: [] ++
|
||||||
|
Regex patterns to match against window class or window title. If a window's class OR title matches any of the patterns, it will not be shown.
|
||||||
|
|
||||||
|
*on-click-window*: ++
|
||||||
|
typeof: string ++
|
||||||
|
default: "" ++
|
||||||
|
Command to run when a window is clicked. Available placeholders are: ++
|
||||||
|
- {address} Hyprland address of the clicked window. ++
|
||||||
|
- {button} Pressed button number, see https://api.gtkd.org/gdk.c.types.GdkEventButton.button.html. ++
|
||||||
|
See https://github.com/Alexays/Waybar/wiki/Module:-Hyprland#workspace-taskbars-example for a full example.
|
||||||
|
|
||||||
*show-special*: ++
|
*show-special*: ++
|
||||||
typeof: bool ++
|
typeof: bool ++
|
||||||
default: false ++
|
default: false ++
|
||||||
@ -216,4 +244,6 @@ Additional to workspace name matching, the following *format-icons* can be set.
|
|||||||
- *#workspaces button.special*
|
- *#workspaces button.special*
|
||||||
- *#workspaces button.urgent*
|
- *#workspaces button.urgent*
|
||||||
- *#workspaces button.hosting-monitor* (gets applied if workspace-monitor == waybar-monitor)
|
- *#workspaces button.hosting-monitor* (gets applied if workspace-monitor == waybar-monitor)
|
||||||
- *#workspaces .taskbar-window* (each window in the taskbar)
|
- *#workspaces .workspace-label*
|
||||||
|
- *#workspaces .taskbar-window* (each window in the taskbar, only if 'workspace-taskbar.enable' is true)
|
||||||
|
- *#workspaces .taskbar-window.active* (applied to the focused window, only if 'workspace-taskbar.update-active-window' is true)
|
||||||
|
@ -104,8 +104,25 @@ void Workspace::initializeWindowMap(const Json::Value &clients_data) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Workspace::setActiveWindow(WindowAddress const &addr) {
|
void Workspace::setActiveWindow(WindowAddress const &addr) {
|
||||||
for (auto &window : m_windowMap) {
|
std::optional<long> activeIdx;
|
||||||
window.setActive(window.address == addr);
|
for (size_t i = 0; i < m_windowMap.size(); ++i) {
|
||||||
|
auto &window = m_windowMap[i];
|
||||||
|
bool isActive = (window.address == addr);
|
||||||
|
window.setActive(isActive);
|
||||||
|
if (isActive) {
|
||||||
|
activeIdx = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto activeWindowPos = m_workspaceManager.activeWindowPosition();
|
||||||
|
if (activeIdx.has_value() && activeWindowPos != Workspaces::ActiveWindowPosition::NONE) {
|
||||||
|
auto window = std::move(m_windowMap[*activeIdx]);
|
||||||
|
m_windowMap.erase(m_windowMap.begin() + *activeIdx);
|
||||||
|
if (activeWindowPos == Workspaces::ActiveWindowPosition::FIRST) {
|
||||||
|
m_windowMap.insert(m_windowMap.begin(), std::move(window));
|
||||||
|
} else if (activeWindowPos == Workspaces::ActiveWindowPosition::LAST) {
|
||||||
|
m_windowMap.emplace_back(std::move(window));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -251,6 +268,17 @@ void Workspace::update(const std::string &workspace_icon) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Workspace::isEmpty() const {
|
||||||
|
auto ignore_list = m_workspaceManager.getIgnoredWindows();
|
||||||
|
if (ignore_list.empty()) {
|
||||||
|
return m_windows == 0;
|
||||||
|
}
|
||||||
|
// If there are windows but they are all ignored, consider the workspace empty
|
||||||
|
return std::all_of(
|
||||||
|
m_windowMap.begin(), m_windowMap.end(),
|
||||||
|
[this, &ignore_list](const auto &window_repr) { return shouldSkipWindow(window_repr); });
|
||||||
|
}
|
||||||
|
|
||||||
void Workspace::updateTaskbar(const std::string &workspace_icon) {
|
void Workspace::updateTaskbar(const std::string &workspace_icon) {
|
||||||
for (auto child : m_content.get_children()) {
|
for (auto child : m_content.get_children()) {
|
||||||
if (child != &m_labelBefore) {
|
if (child != &m_labelBefore) {
|
||||||
@ -259,9 +287,9 @@ void Workspace::updateTaskbar(const std::string &workspace_icon) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool isFirst = true;
|
bool isFirst = true;
|
||||||
for (const auto &window_repr : m_windowMap) {
|
auto processWindow = [&](const WindowRepr &window_repr) {
|
||||||
if (shouldSkipWindow(window_repr)) {
|
if (shouldSkipWindow(window_repr)) {
|
||||||
continue;
|
return; // skip
|
||||||
}
|
}
|
||||||
if (isFirst) {
|
if (isFirst) {
|
||||||
isFirst = false;
|
isFirst = false;
|
||||||
@ -270,6 +298,7 @@ void Workspace::updateTaskbar(const std::string &workspace_icon) {
|
|||||||
m_content.pack_start(*windowSeparator, false, false);
|
m_content.pack_start(*windowSeparator, false, false);
|
||||||
windowSeparator->show();
|
windowSeparator->show();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto window_box = Gtk::make_managed<Gtk::Box>(Gtk::ORIENTATION_HORIZONTAL);
|
auto window_box = Gtk::make_managed<Gtk::Box>(Gtk::ORIENTATION_HORIZONTAL);
|
||||||
window_box->set_tooltip_text(window_repr.window_title);
|
window_box->set_tooltip_text(window_repr.window_title);
|
||||||
window_box->get_style_context()->add_class("taskbar-window");
|
window_box->get_style_context()->add_class("taskbar-window");
|
||||||
@ -307,6 +336,16 @@ void Workspace::updateTaskbar(const std::string &workspace_icon) {
|
|||||||
|
|
||||||
m_content.pack_start(*event_box, true, false);
|
m_content.pack_start(*event_box, true, false);
|
||||||
event_box->show_all();
|
event_box->show_all();
|
||||||
|
};
|
||||||
|
|
||||||
|
if (m_workspaceManager.taskbarReverseDirection()) {
|
||||||
|
for (auto it = m_windowMap.rbegin(); it != m_windowMap.rend(); ++it) {
|
||||||
|
processWindow(*it);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (const auto &window_repr : m_windowMap) {
|
||||||
|
processWindow(window_repr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto formatAfter = m_workspaceManager.formatAfter();
|
auto formatAfter = m_workspaceManager.formatAfter();
|
||||||
|
@ -728,6 +728,7 @@ auto Workspaces::populateWorkspaceTaskbarConfig(const Json::Value &config) -> vo
|
|||||||
|
|
||||||
populateBoolConfig(workspaceTaskbar, "enable", m_enableTaskbar);
|
populateBoolConfig(workspaceTaskbar, "enable", m_enableTaskbar);
|
||||||
populateBoolConfig(workspaceTaskbar, "update-active-window", m_updateActiveWindow);
|
populateBoolConfig(workspaceTaskbar, "update-active-window", m_updateActiveWindow);
|
||||||
|
populateBoolConfig(workspaceTaskbar, "reverse-direction", m_taskbarReverseDirection);
|
||||||
|
|
||||||
if (workspaceTaskbar["format"].isString()) {
|
if (workspaceTaskbar["format"].isString()) {
|
||||||
/* The user defined a format string, use it */
|
/* The user defined a format string, use it */
|
||||||
@ -775,6 +776,18 @@ auto Workspaces::populateWorkspaceTaskbarConfig(const Json::Value &config) -> vo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (workspaceTaskbar["active-window-position"].isString()) {
|
||||||
|
auto posStr = workspaceTaskbar["active-window-position"].asString();
|
||||||
|
try {
|
||||||
|
m_activeWindowPosition =
|
||||||
|
m_activeWindowEnumParser.parseStringToEnum(posStr, m_activeWindowPositionMap);
|
||||||
|
} catch (const std::invalid_argument &e) {
|
||||||
|
spdlog::warn(
|
||||||
|
"Invalid string representation for active-window-position. Falling back to 'none'.");
|
||||||
|
m_activeWindowPosition = ActiveWindowPosition::NONE;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Workspaces::registerOrphanWindow(WindowCreationPayload create_window_payload) {
|
void Workspaces::registerOrphanWindow(WindowCreationPayload create_window_payload) {
|
||||||
|
@ -41,6 +41,7 @@ EnumType EnumParser<EnumType>::parseStringToEnum(const std::string& str,
|
|||||||
// Explicit instantiations for specific EnumType types you intend to use
|
// Explicit instantiations for specific EnumType types you intend to use
|
||||||
// Add explicit instantiations for all relevant EnumType types
|
// Add explicit instantiations for all relevant EnumType types
|
||||||
template struct EnumParser<modules::hyprland::Workspaces::SortMethod>;
|
template struct EnumParser<modules::hyprland::Workspaces::SortMethod>;
|
||||||
|
template struct EnumParser<modules::hyprland::Workspaces::ActiveWindowPosition>;
|
||||||
template struct EnumParser<util::KillSignalAction>;
|
template struct EnumParser<util::KillSignalAction>;
|
||||||
|
|
||||||
} // namespace waybar::util
|
} // namespace waybar::util
|
||||||
|
Reference in New Issue
Block a user