diff --git a/include/modules/hyprland/windowcreationpayload.hpp b/include/modules/hyprland/windowcreationpayload.hpp index 3bd30c8e..50b709f8 100644 --- a/include/modules/hyprland/windowcreationpayload.hpp +++ b/include/modules/hyprland/windowcreationpayload.hpp @@ -31,9 +31,11 @@ struct WindowRepr { std::string window_class; std::string window_title; std::string repr_rewrite; + bool isActive = false; public: bool empty() const { return address.empty(); } + void setActive(bool value) { isActive = value; } }; class WindowCreationPayload { @@ -48,6 +50,7 @@ class WindowCreationPayload { bool isEmpty(Workspaces& workspace_manager); bool reprIsReady() const { return std::holds_alternative(m_window); } WindowRepr repr(Workspaces& workspace_manager); + void setActive(bool value) { m_isActive = value; } std::string getWorkspaceName() const { return m_workspaceName; } WindowAddress getAddress() const { return m_windowAddress; } @@ -64,6 +67,7 @@ class WindowCreationPayload { WindowAddress m_windowAddress; std::string m_workspaceName; + bool m_isActive = false; int m_timeSpentUncreated = 0; }; diff --git a/include/modules/hyprland/workspace.hpp b/include/modules/hyprland/workspace.hpp index 4280cc39..f61ef00e 100644 --- a/include/modules/hyprland/workspace.hpp +++ b/include/modules/hyprland/workspace.hpp @@ -60,6 +60,7 @@ class Workspace { }; void insertWindow(WindowCreationPayload create_window_paylod); void initializeWindowMap(const Json::Value& clients_data); + void setActiveWindow(WindowAddress const& addr); bool onWindowOpened(WindowCreationPayload const& create_window_paylod); std::optional closeWindow(WindowAddress const& addr); diff --git a/include/modules/hyprland/workspaces.hpp b/include/modules/hyprland/workspaces.hpp index 757492be..02599dd5 100644 --- a/include/modules/hyprland/workspaces.hpp +++ b/include/modules/hyprland/workspaces.hpp @@ -103,6 +103,7 @@ class Workspaces : public AModule, public EventHandler { void onWindowMoved(std::string const& payload); void onWindowTitleEvent(std::string const& payload); + void onActiveWindowChanged(WindowAddress const& payload); void onConfigReloaded(); @@ -170,6 +171,7 @@ class Workspaces : public AModule, public EventHandler { IconLoader m_iconLoader; bool m_enableTaskbar = false; + bool m_updateActiveWindow = false; bool m_taskbarWithIcon = false; bool m_taskbarWithTitle = false; std::string m_taskbarFormatBefore; diff --git a/src/modules/hyprland/windowcreationpayload.cpp b/src/modules/hyprland/windowcreationpayload.cpp index 5e587d51..0cdf4a1a 100644 --- a/src/modules/hyprland/windowcreationpayload.cpp +++ b/src/modules/hyprland/windowcreationpayload.cpp @@ -97,9 +97,9 @@ WindowRepr WindowCreationPayload::repr(Workspaces &workspace_manager) { return std::get(m_window); } if (std::holds_alternative(m_window)) { - auto [window_class, window_title] = std::get(m_window); + auto const &[window_class, window_title] = std::get(m_window); return {m_windowAddress, window_class, window_title, - workspace_manager.getRewrite(window_class, window_title)}; + workspace_manager.getRewrite(window_class, window_title), m_isActive}; } // Unreachable spdlog::error("WorkspaceWindow::repr: Unreachable"); diff --git a/src/modules/hyprland/workspace.cpp b/src/modules/hyprland/workspace.cpp index 325fb83f..3350e302 100644 --- a/src/modules/hyprland/workspace.cpp +++ b/src/modules/hyprland/workspace.cpp @@ -103,6 +103,16 @@ void Workspace::initializeWindowMap(const Json::Value &clients_data) { } } +void Workspace::setActiveWindow(WindowAddress const &addr) { + for (auto &window : m_windowMap) { + if (window.address == addr) { + window.setActive(true); + } else { + window.setActive(false); + } + } +} + void Workspace::insertWindow(WindowCreationPayload create_window_paylod) { if (!create_window_paylod.isEmpty(m_workspaceManager)) { auto repr = create_window_paylod.repr(m_workspaceManager); @@ -259,6 +269,9 @@ void Workspace::updateTaskbar(const std::string &workspace_icon) { auto window_box = Gtk::make_managed(Gtk::ORIENTATION_HORIZONTAL); window_box->set_tooltip_text(window_repr.window_title); window_box->get_style_context()->add_class("taskbar-window"); + if (window_repr.isActive) { + window_box->get_style_context()->add_class("active"); + } auto event_box = Gtk::manage(new Gtk::EventBox()); event_box->add(*window_box); if (m_workspaceManager.onClickWindow() != "") { diff --git a/src/modules/hyprland/workspaces.cpp b/src/modules/hyprland/workspaces.cpp index a694e030..a6cd213e 100644 --- a/src/modules/hyprland/workspaces.cpp +++ b/src/modules/hyprland/workspaces.cpp @@ -341,6 +341,8 @@ void Workspaces::onEvent(const std::string &ev) { onWorkspaceRenamed(payload); } else if (eventName == "windowtitlev2") { onWindowTitleEvent(payload); + } else if (eventName == "activewindowv2") { + onActiveWindowChanged(payload); } else if (eventName == "configreloaded") { onConfigReloaded(); } @@ -561,9 +563,10 @@ void Workspaces::onWindowTitleEvent(std::string const &payload) { (*windowWorkspace)->insertWindow(std::move(wcp)); }; } else { - auto queuedWindow = std::ranges::find_if(m_windowsToCreate, [payload](auto &windowPayload) { - return windowPayload.getAddress() == payload; - }); + auto queuedWindow = + std::ranges::find_if(m_windowsToCreate, [&windowAddress](auto &windowPayload) { + return windowPayload.getAddress() == windowAddress; + }); // If the window was queued, rename it in the queue if (queuedWindow != m_windowsToCreate.end()) { @@ -586,6 +589,28 @@ void Workspaces::onWindowTitleEvent(std::string const &payload) { } } +void Workspaces::onActiveWindowChanged(WindowAddress const &activeWindowAddress) { + spdlog::trace("Active window changed: {}", activeWindowAddress); + + for (auto &[address, window] : m_orphanWindowMap) { + if (address == activeWindowAddress) { + window.setActive(true); + } else { + window.setActive(false); + } + } + for (auto const &workspace : m_workspaces) { + workspace->setActiveWindow(activeWindowAddress); + } + for (auto &window : m_windowsToCreate) { + if (window.getAddress() == activeWindowAddress) { + window.setActive(true); + } else { + window.setActive(false); + } + } +} + void Workspaces::onConfigReloaded() { spdlog::info("Hyprland config reloaded, reinitializing hyprland/workspaces module..."); init(); @@ -701,6 +726,7 @@ auto Workspaces::populateWorkspaceTaskbarConfig(const Json::Value &config) -> vo } populateBoolConfig(workspaceTaskbar, "enable", m_enableTaskbar); + populateBoolConfig(workspaceTaskbar, "update-active-window", m_updateActiveWindow); if (workspaceTaskbar["format"].isString()) { /* The user defined a format string, use it */ @@ -765,6 +791,12 @@ auto Workspaces::registerIpc() -> void { "rewrite rule uses the 'title' field."); m_ipc.registerForIPC("windowtitlev2", this); } + if (m_updateActiveWindow) { + spdlog::info( + "Registering for Hyprland's 'activewindowv2' events because 'update-active-window' is set " + "to true."); + m_ipc.registerForIPC("activewindowv2", this); + } } void Workspaces::removeWorkspacesToRemove() {