diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index 706d21cc496..3d862e03345 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -437,6 +437,8 @@ void CWindow::moveToWorkspace(PHLWORKSPACE pWorkspace) { const auto OLDWORKSPACE = m_workspace; + bool previouslyEmpty = !pWorkspace->hasWindow(); + if (OLDWORKSPACE->isVisible()) { m_movingToWorkspaceAlpha->setValueAndWarp(1.F); *m_movingToWorkspaceAlpha = 0.F; @@ -462,6 +464,18 @@ void CWindow::moveToWorkspace(PHLWORKSPACE pWorkspace) { g_pEventManager->postEvent(SHyprIPCEvent{.event = "movewindow", .data = std::format("{:x},{}", rc(this), pWorkspace->m_name)}); g_pEventManager->postEvent(SHyprIPCEvent{.event = "movewindowv2", .data = std::format("{:x},{},{}", rc(this), pWorkspace->m_id, pWorkspace->m_name)}); EMIT_HOOK_EVENT("moveWindow", (std::vector{m_self.lock(), pWorkspace})); + + if (!OLDWORKSPACE->hasWindow()) { + g_pEventManager->postEvent(SHyprIPCEvent{.event = "depopulateworkspace", .data = OLDWORKSPACE->m_name}); + g_pEventManager->postEvent(SHyprIPCEvent{.event = "depopulateworkspacev2", .data = std::format("{},{}", OLDWORKSPACE->m_id, OLDWORKSPACE->m_name)}); + EMIT_HOOK_EVENT("depopulateWorkspace", OLDWORKSPACE); + } + + if (previouslyEmpty) { + g_pEventManager->postEvent(SHyprIPCEvent{.event = "populateworkspace", .data = pWorkspace->m_name}); + g_pEventManager->postEvent(SHyprIPCEvent{.event = "populateworkspacev2", .data = std::format("{},{}", pWorkspace->m_id, pWorkspace->m_name)}); + EMIT_HOOK_EVENT("populateWorkspace", pWorkspace); + } } if (const auto SWALLOWED = m_swallowed.lock()) { @@ -471,7 +485,7 @@ void CWindow::moveToWorkspace(PHLWORKSPACE pWorkspace) { } } - if (OLDWORKSPACE && g_pCompositor->isWorkspaceSpecial(OLDWORKSPACE->m_id) && OLDWORKSPACE->getWindows() == 0 && *PCLOSEONLASTSPECIAL) { + if (OLDWORKSPACE && g_pCompositor->isWorkspaceSpecial(OLDWORKSPACE->m_id) && !OLDWORKSPACE->hasWindow() && *PCLOSEONLASTSPECIAL) { if (const auto PMONITOR = OLDWORKSPACE->m_monitor.lock(); PMONITOR) PMONITOR->setSpecialWorkspace(nullptr); } @@ -526,10 +540,10 @@ void CWindow::onUnmap() { // if the special workspace now has 0 windows, it will be closed, and this // window will no longer pass render checks, cuz the workspace will be nuked. // throw it into the main one for the fadeout. - if (m_workspace->m_isSpecialWorkspace && m_workspace->getWindows() == 0) + if (m_workspace->m_isSpecialWorkspace && !m_workspace->hasWindow()) m_lastWorkspace = m_monitor->activeWorkspaceID(); - if (*PCLOSEONLASTSPECIAL && m_workspace && m_workspace->getWindows() == 0 && onSpecialWorkspace()) { + if (*PCLOSEONLASTSPECIAL && m_workspace && !m_workspace->hasWindow() && onSpecialWorkspace()) { const auto PMONITOR = m_monitor.lock(); if (PMONITOR && PMONITOR->m_activeSpecialWorkspace && PMONITOR->m_activeSpecialWorkspace == m_workspace) PMONITOR->setSpecialWorkspace(nullptr); diff --git a/src/desktop/Workspace.cpp b/src/desktop/Workspace.cpp index 7e1dcd5b6f1..64cb4f951ca 100644 --- a/src/desktop/Workspace.cpp +++ b/src/desktop/Workspace.cpp @@ -561,3 +561,7 @@ void CWorkspace::setPersistent(bool persistent) { bool CWorkspace::isPersistent() { return m_persistent; } + +bool CWorkspace::hasWindow() { + return std::ranges::any_of(g_pCompositor->m_windows, [this](const auto& w) { return w->workspaceID() == m_id && w->m_isMapped; }); +} diff --git a/src/desktop/Workspace.hpp b/src/desktop/Workspace.hpp index 72bc3a67e9d..1028304aeb7 100644 --- a/src/desktop/Workspace.hpp +++ b/src/desktop/Workspace.hpp @@ -82,6 +82,7 @@ class CWorkspace { void updateWindows(); void setPersistent(bool persistent); bool isPersistent(); + bool hasWindow(); struct { CSignalT<> destroy; diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp index 9a1c07d95d2..1c909cebe3d 100644 --- a/src/events/Windows.cpp +++ b/src/events/Windows.cpp @@ -66,7 +66,9 @@ void Events::listener_mapWindow(void* owner, void* data) { Desktop::focusState()->rawMonitorFocus(g_pCompositor->getMonitorFromVector({})); PMONITOR = Desktop::focusState()->monitor(); } - auto PWORKSPACE = PMONITOR->m_activeSpecialWorkspace ? PMONITOR->m_activeSpecialWorkspace : PMONITOR->m_activeWorkspace; + auto PWORKSPACE = PMONITOR->m_activeSpecialWorkspace ? PMONITOR->m_activeSpecialWorkspace : PMONITOR->m_activeWorkspace; + bool workspacePreviouslyEmpty = !PWORKSPACE->hasWindow(); + PWINDOW->m_monitor = PMONITOR; PWINDOW->m_workspace = PWORKSPACE; PWINDOW->m_isMapped = true; @@ -370,6 +372,10 @@ void Events::listener_mapWindow(void* owner, void* data) { // emit the IPC event before the layout might focus the window to avoid a focus event first g_pEventManager->postEvent(SHyprIPCEvent{"openwindow", std::format("{:x},{},{},{}", PWINDOW, PWORKSPACE->m_name, PWINDOW->m_class, PWINDOW->m_title)}); EMIT_HOOK_EVENT("openWindowEarly", PWINDOW); + if (workspacePreviouslyEmpty) { + g_pEventManager->postEvent(SHyprIPCEvent{"populateworkspace", PWORKSPACE->m_name}); + g_pEventManager->postEvent(SHyprIPCEvent{"populateworkspacev2", std::format("{},{}", PWORKSPACE->m_id, PWORKSPACE->m_name)}); + } if (PWINDOW->m_isFloating) { g_pLayoutManager->getCurrentLayout()->onWindowCreated(PWINDOW); @@ -510,6 +516,9 @@ void Events::listener_mapWindow(void* owner, void* data) { // emit the hook event here after basic stuff has been initialized EMIT_HOOK_EVENT("openWindow", PWINDOW); + if (workspacePreviouslyEmpty) { + EMIT_HOOK_EVENT("populateWorkspace", PWORKSPACE); + } // apply data from default decos. Borders, shadows. g_pDecorationPositioner->forceRecalcFor(PWINDOW); @@ -627,6 +636,12 @@ void Events::listener_unmapWindow(void* owner, void* data) { // do this after onWindowRemoved because otherwise it'll think the window is invalid PWINDOW->m_isMapped = false; + if (!PWINDOW->m_workspace->hasWindow()) { + g_pEventManager->postEvent(SHyprIPCEvent{"depopulateworkspace", PWINDOW->m_workspace->m_name}); + g_pEventManager->postEvent(SHyprIPCEvent{"depopulateworkspacev2", std::format("{},{}", PWINDOW->m_workspace->m_id, PWINDOW->m_workspace->m_name)}); + EMIT_HOOK_EVENT("depopulateWorkspace", PWINDOW->m_workspace); + } + // refocus on a new window if needed if (wasLastWindow) { static auto FOCUSONCLOSE = CConfigValue("input:focus_on_close"); @@ -644,7 +659,7 @@ void Events::listener_unmapWindow(void* owner, void* data) { g_pCompositor->setWindowFullscreenInternal(PWINDOWCANDIDATE, CURRENTFSMODE); } - if (!PWINDOWCANDIDATE && PWINDOW->m_workspace && PWINDOW->m_workspace->getWindows() == 0) + if (!PWINDOWCANDIDATE && PWINDOW->m_workspace && !PWINDOW->m_workspace->hasWindow()) g_pInputManager->refocus(); g_pInputManager->sendMotionEventsToFocused(); diff --git a/src/helpers/MiscFunctions.cpp b/src/helpers/MiscFunctions.cpp index 25b179e9deb..0686c5577e8 100644 --- a/src/helpers/MiscFunctions.cpp +++ b/src/helpers/MiscFunctions.cpp @@ -164,7 +164,7 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) { WORKSPACEID id = next ? Desktop::focusState()->monitor()->activeWorkspaceID() : 0; while (++id < LONG_MAX) { const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(id); - if (!invalidWSes.contains(id) && (!PWORKSPACE || PWORKSPACE->getWindows() == 0)) { + if (!invalidWSes.contains(id) && (!PWORKSPACE || !PWORKSPACE->hasWindow())) { result.id = id; return result; } diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 2fd7ba9902a..60e9bab983d 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -2262,7 +2262,7 @@ SDispatchResult CKeybindManager::circleNext(std::string arg) { if (!Desktop::focusState()->window()) { // if we have a clear focus, find the first window and get the next focusable. const auto PWS = Desktop::focusState()->monitor()->m_activeWorkspace; - if (PWS && PWS->getWindows() > 0) { + if (PWS && PWS->hasWindow()) { const auto PWINDOW = PWS->getFirstWindow(); switchToWindow(PWINDOW); } diff --git a/src/managers/input/UnifiedWorkspaceSwipeGesture.cpp b/src/managers/input/UnifiedWorkspaceSwipeGesture.cpp index 6dae1e63463..c00fe16037f 100644 --- a/src/managers/input/UnifiedWorkspaceSwipeGesture.cpp +++ b/src/managers/input/UnifiedWorkspaceSwipeGesture.cpp @@ -66,7 +66,7 @@ void CUnifiedWorkspaceSwipeGesture::update(double delta) { m_delta = std::clamp(m_delta, sc(-SWIPEDISTANCE), sc(SWIPEDISTANCE)); if ((m_workspaceBegin->m_id == workspaceIDLeft && *PSWIPENEW && (m_delta < 0)) || - (m_delta > 0 && m_workspaceBegin->getWindows() == 0 && workspaceIDRight <= m_workspaceBegin->m_id) || (m_delta < 0 && m_workspaceBegin->m_id <= workspaceIDLeft)) { + (m_delta > 0 && !m_workspaceBegin->hasWindow() && workspaceIDRight <= m_workspaceBegin->m_id) || (m_delta < 0 && m_workspaceBegin->m_id <= workspaceIDLeft)) { m_delta = 0; g_pHyprRenderer->damageMonitor(m_monitor.lock()); @@ -311,4 +311,4 @@ void CUnifiedWorkspaceSwipeGesture::end() { for (auto const& ls : Desktop::focusState()->monitor()->m_layerSurfaceLayers[2]) { *ls->m_alpha = pSwitchedTo->m_hasFullscreenWindow && pSwitchedTo->m_fullscreenMode == FSMODE_FULLSCREEN ? 0.f : 1.f; } -} \ No newline at end of file +}