From c942ce6dce7f01415f71e5207da69b6989d3818c Mon Sep 17 00:00:00 2001 From: thejch <66577496+thejch@users.noreply.github.com> Date: Sat, 16 Mar 2024 07:49:34 -0700 Subject: [PATCH] renderer: add better multi monitor animations (#5126) --- src/helpers/Box.cpp | 18 ++++++++++++++++ src/helpers/Box.hpp | 1 + src/managers/AnimationManager.cpp | 35 ++++++++++++++++++++++++++----- src/render/Renderer.cpp | 15 ++++++++++--- 4 files changed, 61 insertions(+), 8 deletions(-) diff --git a/src/helpers/Box.cpp b/src/helpers/Box.cpp index 59578f23..e9e0eeeb 100644 --- a/src/helpers/Box.cpp +++ b/src/helpers/Box.cpp @@ -116,6 +116,24 @@ CBox& CBox::noNegativeSize() { return *this; } +CBox& CBox::intersection(const CBox other) { + const float newTop = std::max(y, other.y); + const float newBottom = std::min(y + h, other.y + other.h); + const float newLeft = std::max(x, other.x); + const float newRight = std::min(x + w, other.x + other.w); + y = newTop; + x = newLeft; + w = newRight - newLeft; + h = newBottom - newTop; + + if (w <= 0 || h <= 0) { + w = 0; + h = 0; + } + + return *this; +} + CBox CBox::roundInternal() { float newW = x + w - std::floor(x); float newH = y + h - std::floor(y); diff --git a/src/helpers/Box.hpp b/src/helpers/Box.hpp index fd31a7b7..e38d6108 100644 --- a/src/helpers/Box.hpp +++ b/src/helpers/Box.hpp @@ -52,6 +52,7 @@ class CBox { CBox& addExtents(const SWindowDecorationExtents& e); CBox& expand(const double& value); CBox& noNegativeSize(); + CBox& intersection(const CBox other); CBox copy() const; diff --git a/src/managers/AnimationManager.cpp b/src/managers/AnimationManager.cpp index 072a377e..f9dfa6fa 100644 --- a/src/managers/AnimationManager.cpp +++ b/src/managers/AnimationManager.cpp @@ -86,8 +86,13 @@ void CAnimationManager::tick() { CBox WLRBOXPREV = {0, 0, 0, 0}; if (PWINDOW) { - WLRBOXPREV = PWINDOW->getFullWindowBoundingBox(); - PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID); + CBox bb = PWINDOW->getFullWindowBoundingBox(); + const auto PWINDOWWORKSPACE = g_pCompositor->getWorkspaceByID(PWINDOW->m_iWorkspaceID); + if (PWINDOWWORKSPACE) + bb.translate(PWINDOWWORKSPACE->m_vRenderOffset.value()); + WLRBOXPREV = bb; + + PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID); if (!PMONITOR) continue; animationsDisabled = animationsDisabled || PWINDOW->m_sAdditionalConfigData.forceNoAnims; @@ -95,13 +100,27 @@ void CAnimationManager::tick() { PMONITOR = g_pCompositor->getMonitorFromID(PWORKSPACE->m_iMonitorID); if (!PMONITOR) continue; - WLRBOXPREV = {(int)PMONITOR->vecPosition.x, (int)PMONITOR->vecPosition.y, (int)PMONITOR->vecSize.x, (int)PMONITOR->vecSize.y}; + WLRBOXPREV = {PMONITOR->vecPosition, PMONITOR->vecSize}; // TODO: just make this into a damn callback already vax... for (auto& w : g_pCompositor->m_vWindows) { if (!w->isHidden() && w->m_bIsMapped && w->m_bIsFloating) g_pHyprRenderer->damageWindow(w.get()); } + + // if a workspace window is on any monitor, damage it + for (auto& w : g_pCompositor->m_vWindows) { + for (auto& m : g_pCompositor->m_vMonitors) { + if (w->m_iWorkspaceID == PWORKSPACE->m_iID && g_pCompositor->windowValidMapped(w.get()) && g_pHyprRenderer->shouldRenderWindow(w.get(), m.get(), PWORKSPACE)) { + CBox bb = w->getFullWindowBoundingBox(); + bb.translate(PWORKSPACE->m_vRenderOffset.value()); + if (PWORKSPACE->m_bIsSpecialWorkspace) + bb.scaleFromCenter(1.1); // for some reason special ws windows getting border artifacts if you close it too quickly... + bb.intersection({m->vecPosition, m->vecSize}); + g_pHyprRenderer->damageBox(&bb); + } + } + } } else if (PLAYER) { WLRBOXPREV = CBox{PLAYER->realPosition.value(), PLAYER->realSize.value()}; PMONITOR = g_pCompositor->getMonitorFromVector(Vector2D(PLAYER->geometry.x, PLAYER->geometry.y) + Vector2D(PLAYER->geometry.width, PLAYER->geometry.height) / 2.f); @@ -175,7 +194,10 @@ void CAnimationManager::tick() { if (PWINDOW) { PWINDOW->updateWindowDecos(); - g_pHyprRenderer->damageWindow(PWINDOW); + auto bb = PWINDOW->getFullWindowBoundingBox(); + const auto PWINDOWWORKSPACE = g_pCompositor->getWorkspaceByID(PWINDOW->m_iWorkspaceID); + bb.translate(PWINDOWWORKSPACE->m_vRenderOffset.value()); + g_pHyprRenderer->damageBox(&bb); } else if (PWORKSPACE) { for (auto& w : g_pCompositor->m_vWindows) { if (!w->m_bIsMapped || w->isHidden()) @@ -222,7 +244,10 @@ void CAnimationManager::tick() { BORDERSIZE + ROUNDINGSIZE); // bottom // damage for new box - const CBox WLRBOXNEW = {PWINDOW->m_vRealPosition.value().x, PWINDOW->m_vRealPosition.value().y, PWINDOW->m_vRealSize.value().x, PWINDOW->m_vRealSize.value().y}; + CBox WLRBOXNEW = {PWINDOW->m_vRealPosition.value(), PWINDOW->m_vRealSize.value()}; + const auto PWINDOWWORKSPACE = g_pCompositor->getWorkspaceByID(PWINDOW->m_iWorkspaceID); + if (PWINDOWWORKSPACE) + WLRBOXNEW.translate(PWINDOWWORKSPACE->m_vRenderOffset.value()); g_pHyprRenderer->damageBox(WLRBOXNEW.x - BORDERSIZE, WLRBOXNEW.y - BORDERSIZE, WLRBOXNEW.width + 2 * BORDERSIZE, BORDERSIZE + ROUNDINGSIZE); // top g_pHyprRenderer->damageBox(WLRBOXNEW.x - BORDERSIZE, WLRBOXNEW.y - BORDERSIZE, BORDERSIZE + ROUNDINGSIZE, WLRBOXNEW.height + 2 * BORDERSIZE); // left g_pHyprRenderer->damageBox(WLRBOXNEW.x + WLRBOXNEW.width - ROUNDINGSIZE, WLRBOXNEW.y - BORDERSIZE, BORDERSIZE + ROUNDINGSIZE, diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 309e5742..cb60cd41 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -224,6 +224,15 @@ bool CHyprRenderer::shouldRenderWindow(CWindow* pWindow, CMonitor* pMonitor, CWo if (pMonitor->specialWorkspaceID == pWindow->m_iWorkspaceID) return true; + if (pWindow->m_vRealPosition.isBeingAnimated()) { + // render window if window and monitor intersect + // (when moving out of or through a monitor) + CBox windowBox = {pWindow->m_vRealPosition.value(), pWindow->m_vRealSize.value()}; + const CBox monitorBox = {pMonitor->vecPosition, pMonitor->vecSize}; + if (!windowBox.intersection(monitorBox).empty()) + return true; + } + return false; } @@ -363,7 +372,7 @@ void CHyprRenderer::renderWorkspaceWindows(CMonitor* pMonitor, CWorkspace* pWork continue; // render active window after all others of this pass - if (w.get() == g_pCompositor->m_pLastWindow && w->m_iWorkspaceID == pWorkspace->m_iID) { + if (w.get() == g_pCompositor->m_pLastWindow) { lastWindow = w.get(); continue; } @@ -404,7 +413,7 @@ void CHyprRenderer::renderWorkspaceWindows(CMonitor* pMonitor, CWorkspace* pWork if (!shouldRenderWindow(w.get(), pMonitor, pWorkspace)) continue; - if (w->m_iMonitorID == pWorkspace->m_iMonitorID && pWorkspace->m_bIsSpecialWorkspace != g_pCompositor->isWorkspaceSpecial(w->m_iWorkspaceID)) + if (pWorkspace->m_bIsSpecialWorkspace != g_pCompositor->isWorkspaceSpecial(w->m_iWorkspaceID)) continue; if (pWorkspace->m_bIsSpecialWorkspace && w->m_iMonitorID != pWorkspace->m_iMonitorID) @@ -781,7 +790,7 @@ void CHyprRenderer::renderAllClientsForWorkspace(CMonitor* pMonitor, CWorkspace* // special for (auto& ws : g_pCompositor->m_vWorkspaces) { - if (ws->m_iMonitorID == pMonitor->ID && ws->m_fAlpha.value() > 0.f && ws->m_bIsSpecialWorkspace) { + if (ws->m_fAlpha.value() > 0.f && ws->m_bIsSpecialWorkspace) { if (ws->m_bHasFullscreenWindow) renderWorkspaceWindowsFullscreen(pMonitor, ws.get(), time); else