From 16a9c16d9f99bd8be9f1bb15442b001fdf2ea759 Mon Sep 17 00:00:00 2001 From: thejch <66577496+thejch@users.noreply.github.com> Date: Sat, 30 Mar 2024 18:14:26 -0700 Subject: [PATCH] renderer/animations: Fix various inaccurate damage tracking issues and offsets (#5297) --- src/desktop/Window.cpp | 38 ++++++++ src/desktop/Window.hpp | 4 + src/desktop/Workspace.cpp | 10 ++ src/helpers/Box.cpp | 25 ++--- src/helpers/Box.hpp | 2 +- src/managers/AnimationManager.cpp | 94 +++++++----------- src/render/Renderer.cpp | 97 ++++++++----------- src/render/Renderer.hpp | 4 +- .../decorations/CHyprBorderDecoration.cpp | 34 ++++++- .../decorations/CHyprBorderDecoration.hpp | 2 +- .../decorations/CHyprDropShadowDecoration.cpp | 42 +++++++- .../decorations/CHyprDropShadowDecoration.hpp | 2 +- .../decorations/CHyprGroupBarDecoration.cpp | 18 ++-- .../decorations/CHyprGroupBarDecoration.hpp | 2 +- .../decorations/IHyprWindowDecoration.hpp | 2 +- 15 files changed, 229 insertions(+), 147 deletions(-) diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index 1336456a..891fd652 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -1165,6 +1165,44 @@ void CWindow::setAnimationsToMove() { m_bAnimatingIn = false; } +void CWindow::onWorkspaceAnimUpdate() { + // clip box for animated offsets + if (!m_bIsFloating || m_bPinned || m_bIsFullscreen) { + m_vFloatingOffset = Vector2D(0, 0); + return; + } + + Vector2D offset; + const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(m_iWorkspaceID); + if (!PWORKSPACE) + return; + + const auto PWSMON = g_pCompositor->getMonitorFromID(PWORKSPACE->m_iMonitorID); + if (!PWSMON) + return; + + const auto WINBB = getFullWindowBoundingBox(); + if (PWORKSPACE->m_vRenderOffset.value().x != 0) { + const auto PROGRESS = PWORKSPACE->m_vRenderOffset.value().x / PWSMON->vecSize.x; + + if (WINBB.x < PWSMON->vecPosition.x) + offset.x += (PWSMON->vecPosition.x - WINBB.x) * PROGRESS; + + if (WINBB.x + WINBB.width > PWSMON->vecPosition.x + PWSMON->vecSize.x) + offset.x += (WINBB.x + WINBB.width - PWSMON->vecPosition.x - PWSMON->vecSize.x) * PROGRESS; + } else if (PWORKSPACE->m_vRenderOffset.value().y != 0) { + const auto PROGRESS = PWORKSPACE->m_vRenderOffset.value().y / PWSMON->vecSize.y; + + if (WINBB.y < PWSMON->vecPosition.y) + offset.y += (PWSMON->vecPosition.y - WINBB.y) * PROGRESS; + + if (WINBB.y + WINBB.height > PWSMON->vecPosition.y + PWSMON->vecSize.y) + offset.y += (WINBB.y + WINBB.height - PWSMON->vecPosition.y - PWSMON->vecSize.y) * PROGRESS; + } + + m_vFloatingOffset = offset; +} + int CWindow::popupsCount() { if (m_bIsX11) return 1; diff --git a/src/desktop/Window.hpp b/src/desktop/Window.hpp index d8b4012d..bc1820a0 100644 --- a/src/desktop/Window.hpp +++ b/src/desktop/Window.hpp @@ -237,6 +237,9 @@ class CWindow { Vector2D m_vLastFloatingSize; Vector2D m_vLastFloatingPosition; + // for floating window offset in workspace animations + Vector2D m_vFloatingOffset = Vector2D(0, 0); + // this is used for pseudotiling bool m_bIsPseudotiled = false; Vector2D m_vPseudoSize = Vector2D(0, 0); @@ -421,6 +424,7 @@ class CWindow { void updateGroupOutputs(); void switchWithWindowInGroup(CWindow* pWindow); void setAnimationsToMove(); + void onWorkspaceAnimUpdate(); private: // For hidden windows and stuff diff --git a/src/desktop/Workspace.cpp b/src/desktop/Workspace.cpp index 05843b59..a0c14bba 100644 --- a/src/desktop/Workspace.cpp +++ b/src/desktop/Workspace.cpp @@ -49,6 +49,16 @@ void CWorkspace::startAnim(bool in, bool left, bool instant) { const auto ANIMSTYLE = m_fAlpha.m_pConfig->pValues->internalStyle; static auto PWORKSPACEGAP = CConfigValue("general:gaps_workspaces"); + // set floating windows offset callbacks + m_vRenderOffset.setUpdateCallback([&](void*) { + for (auto& w : g_pCompositor->m_vWindows) { + if (!g_pCompositor->windowValidMapped(w.get()) || w->m_iWorkspaceID != m_iID) + continue; + + w->onWorkspaceAnimUpdate(); + }; + }); + if (ANIMSTYLE.starts_with("slidefade")) { const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID); float movePerc = 100.f; diff --git a/src/helpers/Box.cpp b/src/helpers/Box.cpp index e9e0eeeb..8470b509 100644 --- a/src/helpers/Box.cpp +++ b/src/helpers/Box.cpp @@ -106,6 +106,11 @@ CBox& CBox::expand(const double& value) { w += value * 2.0; h += value * 2.0; + if (w <= 0 || h <= 0) { + w = 0; + h = 0; + } + return *this; } @@ -116,22 +121,20 @@ CBox& CBox::noNegativeSize() { return *this; } -CBox& CBox::intersection(const CBox other) { - const float newTop = std::max(y, other.y); +CBox CBox::intersection(const CBox other) const { + const float newX = std::max(x, other.x); + const float newY = 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; + float newW = newRight - newX; + float newH = newBottom - newY; - if (w <= 0 || h <= 0) { - w = 0; - h = 0; + if (newW <= 0 || newH <= 0) { + newW = 0; + newH = 0; } - return *this; + return {newX, newY, newW, newH}; } CBox CBox::roundInternal() { diff --git a/src/helpers/Box.hpp b/src/helpers/Box.hpp index e38d6108..98ba8d47 100644 --- a/src/helpers/Box.hpp +++ b/src/helpers/Box.hpp @@ -52,9 +52,9 @@ class CBox { CBox& addExtents(const SWindowDecorationExtents& e); CBox& expand(const double& value); CBox& noNegativeSize(); - CBox& intersection(const CBox other); CBox copy() const; + CBox intersection(const CBox other) const; SWindowDecorationExtents extentsFrom(const CBox&); // this is the big box diff --git a/src/managers/AnimationManager.cpp b/src/managers/AnimationManager.cpp index 93608383..fc768b77 100644 --- a/src/managers/AnimationManager.cpp +++ b/src/managers/AnimationManager.cpp @@ -87,11 +87,15 @@ void CAnimationManager::tick() { CBox WLRBOXPREV = {0, 0, 0, 0}; if (PWINDOW) { - CBox bb = PWINDOW->getFullWindowBoundingBox(); - const auto PWINDOWWORKSPACE = g_pCompositor->getWorkspaceByID(PWINDOW->m_iWorkspaceID); - if (PWINDOWWORKSPACE) - bb.translate(PWINDOWWORKSPACE->m_vRenderOffset.value()); - WLRBOXPREV = bb; + if (av->m_eDamagePolicy == AVARDAMAGE_ENTIRE) { + g_pHyprRenderer->damageWindow(PWINDOW); + } else if (av->m_eDamagePolicy == AVARDAMAGE_BORDER) { + const auto PDECO = PWINDOW->getDecorationByType(DECORATION_BORDER); + PDECO->damageEntire(); + } else if (av->m_eDamagePolicy == AVARDAMAGE_SHADOW) { + const auto PDECO = PWINDOW->getDecorationByType(DECORATION_SHADOW); + PDECO->damageEntire(); + } PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID); if (!PMONITOR) @@ -101,25 +105,35 @@ void CAnimationManager::tick() { PMONITOR = g_pCompositor->getMonitorFromID(PWORKSPACE->m_iMonitorID); if (!PMONITOR) continue; - WLRBOXPREV = {PMONITOR->vecPosition, PMONITOR->vecSize}; + + // dont damage the whole monitor on workspace change, unless it's a special workspace, because dim/blur etc + if (PWORKSPACE->m_bIsSpecialWorkspace) + g_pHyprRenderer->damageMonitor(PMONITOR); // 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 (!g_pCompositor->windowValidMapped(w.get()) || w->m_iWorkspaceID != PWORKSPACE->m_iID) + continue; + + if (w->m_bIsFloating && !w->m_bPinned) { + // still doing the full damage hack for floating because sometimes when the window + // goes through multiple monitors the last rendered frame is missing damage somehow?? + const CBox windowBoxNoOffset = w->getFullWindowBoundingBox(); + const CBox monitorBox = {PMONITOR->vecPosition, PMONITOR->vecSize}; + if (windowBoxNoOffset.intersection(monitorBox) != windowBoxNoOffset) // on edges between multiple monitors + g_pHyprRenderer->damageWindow(w.get(), true); + } + + if (PWORKSPACE->m_bIsSpecialWorkspace) + g_pHyprRenderer->damageWindow(w.get(), true); // hack for special too because it can cross multiple monitors } - // if a special workspace window is on any monitor, damage it + // damage any workspace window that is on any monitor for (auto& w : g_pCompositor->m_vWindows) { - for (auto& m : g_pCompositor->m_vMonitors) { - if (w->m_iWorkspaceID == PWORKSPACE->m_iID && PWORKSPACE->m_bIsSpecialWorkspace && g_pCompositor->windowValidMapped(w.get()) && - g_pHyprRenderer->shouldRenderWindow(w.get(), m.get(), PWORKSPACE)) { - CBox bb = w->getFullWindowBoundingBox(); - bb.translate(PWORKSPACE->m_vRenderOffset.value()); - bb.intersection({m->vecPosition, m->vecSize}); - g_pHyprRenderer->damageBox(&bb); - } - } + if (!g_pCompositor->windowValidMapped(w.get()) || w->m_iWorkspaceID != PWORKSPACE->m_iID || w->m_bPinned) + continue; + + g_pHyprRenderer->damageWindow(w.get()); } } else if (PLAYER) { WLRBOXPREV = CBox{PLAYER->realPosition.value(), PLAYER->realSize.value()}; @@ -194,26 +208,13 @@ void CAnimationManager::tick() { if (PWINDOW) { PWINDOW->updateWindowDecos(); - auto bb = PWINDOW->getFullWindowBoundingBox(); - const auto PWINDOWWORKSPACE = g_pCompositor->getWorkspaceByID(PWINDOW->m_iWorkspaceID); - if (PWINDOWWORKSPACE) - bb.translate(PWINDOWWORKSPACE->m_vRenderOffset.value()); - g_pHyprRenderer->damageBox(&bb); + g_pHyprRenderer->damageWindow(PWINDOW); } else if (PWORKSPACE) { for (auto& w : g_pCompositor->m_vWindows) { - if (!w->m_bIsMapped || w->isHidden()) - continue; - - if (w->m_iWorkspaceID != PWORKSPACE->m_iID) + if (!g_pCompositor->windowValidMapped(w.get()) || w->m_iWorkspaceID != PWORKSPACE->m_iID) continue; w->updateWindowDecos(); - - if (w->m_bIsFloating) { - auto bb = w->getFullWindowBoundingBox(); - bb.translate(PWORKSPACE->m_vRenderOffset.value()); - g_pHyprRenderer->damageBox(&bb); - } } } else if (PLAYER) { if (PLAYER->layer == ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND || PLAYER->layer == ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM) @@ -229,31 +230,8 @@ void CAnimationManager::tick() { case AVARDAMAGE_BORDER: { RASSERT(PWINDOW, "Tried to AVARDAMAGE_BORDER a non-window AVAR!"); - // TODO: move this to the border class - - // damage only the border. - const auto ROUNDING = PWINDOW->rounding(); - const auto ROUNDINGSIZE = ROUNDING + 1; - const auto BORDERSIZE = PWINDOW->getRealBorderSize(); - - // damage for old box - g_pHyprRenderer->damageBox(WLRBOXPREV.x - BORDERSIZE, WLRBOXPREV.y - BORDERSIZE, WLRBOXPREV.width + 2 * BORDERSIZE, BORDERSIZE + ROUNDINGSIZE); // top - g_pHyprRenderer->damageBox(WLRBOXPREV.x - BORDERSIZE, WLRBOXPREV.y - BORDERSIZE, BORDERSIZE + ROUNDINGSIZE, WLRBOXPREV.height + 2 * BORDERSIZE); // left - g_pHyprRenderer->damageBox(WLRBOXPREV.x + WLRBOXPREV.width - ROUNDINGSIZE, WLRBOXPREV.y - BORDERSIZE, BORDERSIZE + ROUNDINGSIZE, - WLRBOXPREV.height + 2 * BORDERSIZE); // right - g_pHyprRenderer->damageBox(WLRBOXPREV.x, WLRBOXPREV.y + WLRBOXPREV.height - ROUNDINGSIZE, WLRBOXPREV.width + 2 * BORDERSIZE, - BORDERSIZE + ROUNDINGSIZE); // bottom - - // damage for new box - 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, - WLRBOXNEW.height + 2 * BORDERSIZE); // right - g_pHyprRenderer->damageBox(WLRBOXNEW.x, WLRBOXNEW.y + WLRBOXNEW.height - ROUNDINGSIZE, WLRBOXNEW.width + 2 * BORDERSIZE, BORDERSIZE + ROUNDINGSIZE); // bottom + const auto PDECO = PWINDOW->getDecorationByType(DECORATION_BORDER); + PDECO->damageEntire(); break; } diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 960add70..18110256 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -211,7 +211,7 @@ static void renderSurface(struct wlr_surface* surface, int x, int y, void* data) g_pHyprOpenGL->m_RenderData.useNearestNeighbor = NEARESTNEIGHBORSET; } -bool CHyprRenderer::shouldRenderWindow(CWindow* pWindow, CMonitor* pMonitor, CWorkspace* pWorkspace) { +bool CHyprRenderer::shouldRenderWindow(CWindow* pWindow, CMonitor* pMonitor) { CBox geometry = pWindow->getFullWindowBoundingBox(); if (!wlr_output_layout_intersects(g_pCompositor->m_sWLROutputLayout, pMonitor->output, geometry.pWlr())) @@ -234,9 +234,12 @@ bool CHyprRenderer::shouldRenderWindow(CWindow* pWindow, CMonitor* pMonitor, CWo } } - if (pWindow->m_iWorkspaceID == pWorkspace->m_iID && pWorkspace->m_iMonitorID == pMonitor->ID) + if (pWindow->m_iMonitorID == pMonitor->ID) return true; + if (!g_pCompositor->isWorkspaceVisible(pWindow->m_iWorkspaceID) && pWindow->m_iMonitorID != pMonitor->ID) + return false; + // if not, check if it maybe is active on a different monitor. if (g_pCompositor->isWorkspaceVisible(pWindow->m_iWorkspaceID) && pWindow->m_bIsFloating /* tiled windows can't be multi-ws */) return !pWindow->m_bIsFullscreen; // Do not draw fullscreen windows on other monitors @@ -244,12 +247,20 @@ bool CHyprRenderer::shouldRenderWindow(CWindow* pWindow, CMonitor* pMonitor, CWo if (pMonitor->specialWorkspaceID == pWindow->m_iWorkspaceID) return true; + // if window is tiled and it's flying in, don't render on other mons (for slide) + if (!pWindow->m_bIsFloating && pWindow->m_vRealPosition.isBeingAnimated() && pWindow->m_bAnimatingIn && pWindow->m_iMonitorID != pMonitor->ID) + return false; + if (pWindow->m_vRealPosition.isBeingAnimated()) { if (PWINDOWWORKSPACE && !PWINDOWWORKSPACE->m_bIsSpecialWorkspace && PWINDOWWORKSPACE->m_vRenderOffset.isBeingAnimated()) return false; // render window if window and monitor intersect // (when moving out of or through a monitor) - CBox windowBox = pWindow->getFullWindowBoundingBox(); + CBox windowBox = pWindow->getFullWindowBoundingBox(); + if (PWINDOWWORKSPACE && PWINDOWWORKSPACE->m_vRenderOffset.isBeingAnimated()) + windowBox.translate(PWINDOWWORKSPACE->m_vRenderOffset.value()); + windowBox.translate(pWindow->m_vFloatingOffset); + const CBox monitorBox = {pMonitor->vecPosition, pMonitor->vecSize}; if (!windowBox.intersection(monitorBox).empty()) return true; @@ -292,7 +303,7 @@ void CHyprRenderer::renderWorkspaceWindowsFullscreen(CMonitor* pMonitor, CWorksp // loop over the tiled windows that are fading out for (auto& w : g_pCompositor->m_vWindows) { - if (!shouldRenderWindow(w.get(), pMonitor, pWorkspace)) + if (!shouldRenderWindow(w.get(), pMonitor)) continue; if (w->m_fAlpha.value() == 0.f) @@ -309,7 +320,7 @@ void CHyprRenderer::renderWorkspaceWindowsFullscreen(CMonitor* pMonitor, CWorksp // and floating ones too for (auto& w : g_pCompositor->m_vWindows) { - if (!shouldRenderWindow(w.get(), pMonitor, pWorkspace)) + if (!shouldRenderWindow(w.get(), pMonitor)) continue; if (w->m_fAlpha.value() == 0.f) @@ -345,7 +356,7 @@ void CHyprRenderer::renderWorkspaceWindowsFullscreen(CMonitor* pMonitor, CWorksp if (w->m_iMonitorID == pWorkspace->m_iMonitorID && pWorkspace->m_bIsSpecialWorkspace != g_pCompositor->isWorkspaceSpecial(w->m_iWorkspaceID)) continue; - if (shouldRenderWindow(w.get(), pMonitor, pWorkspace)) + if (shouldRenderWindow(w.get(), pMonitor)) renderWindow(w.get(), pMonitor, time, pWorkspace->m_efFullscreenMode != FULLSCREEN_FULL, RENDER_PASS_ALL); if (w->m_iWorkspaceID != pWorkspace->m_iID) @@ -388,7 +399,7 @@ void CHyprRenderer::renderWorkspaceWindows(CMonitor* pMonitor, CWorkspace* pWork if (w->m_bIsFloating) continue; // floating are in the second pass - if (!shouldRenderWindow(w.get(), pMonitor, pWorkspace)) + if (!shouldRenderWindow(w.get(), pMonitor)) continue; if (pWorkspace->m_bIsSpecialWorkspace != g_pCompositor->isWorkspaceSpecial(w->m_iWorkspaceID)) @@ -418,7 +429,7 @@ void CHyprRenderer::renderWorkspaceWindows(CMonitor* pMonitor, CWorkspace* pWork if (pWorkspace->m_bIsSpecialWorkspace != g_pCompositor->isWorkspaceSpecial(w->m_iWorkspaceID)) continue; - if (!shouldRenderWindow(w.get(), pMonitor, pWorkspace)) + if (!shouldRenderWindow(w.get(), pMonitor)) continue; // render the bad boy @@ -433,7 +444,7 @@ void CHyprRenderer::renderWorkspaceWindows(CMonitor* pMonitor, CWorkspace* pWork if (!w->m_bIsFloating || w->m_bPinned) continue; - if (!shouldRenderWindow(w.get(), pMonitor, pWorkspace)) + if (!shouldRenderWindow(w.get(), pMonitor)) continue; if (pWorkspace->m_bIsSpecialWorkspace != g_pCompositor->isWorkspaceSpecial(w->m_iWorkspaceID)) @@ -510,47 +521,16 @@ void CHyprRenderer::renderWindow(CWindow* pWindow, CMonitor* pMonitor, timespec* g_pHyprOpenGL->renderRect(&monbox, CColor(0, 0, 0, *PDIMAROUND * renderdata.alpha * renderdata.fadeAlpha)); } - // clip box for animated offsets - const Vector2D PREOFFSETPOS = {renderdata.x, renderdata.y}; - if (!ignorePosition && pWindow->m_bIsFloating && !pWindow->m_bPinned && !pWindow->m_bIsFullscreen) { - Vector2D offset; - - if (PWORKSPACE->m_vRenderOffset.value().x != 0) { - const auto PWSMON = g_pCompositor->getMonitorFromID(PWORKSPACE->m_iMonitorID); - const auto PROGRESS = PWORKSPACE->m_vRenderOffset.value().x / PWSMON->vecSize.x; - const auto WINBB = pWindow->getFullWindowBoundingBox(); - - if (WINBB.x < PWSMON->vecPosition.x) { - offset.x = (PWSMON->vecPosition.x - WINBB.x) * PROGRESS; - } else if (WINBB.x + WINBB.width > PWSMON->vecPosition.x + PWSMON->vecSize.x) { - offset.x = (WINBB.x + WINBB.width - PWSMON->vecPosition.x - PWSMON->vecSize.x) * PROGRESS; - } - } else if (PWORKSPACE->m_vRenderOffset.value().y != 0) { - const auto PWSMON = g_pCompositor->getMonitorFromID(PWORKSPACE->m_iMonitorID); - const auto PROGRESS = PWORKSPACE->m_vRenderOffset.value().y / PWSMON->vecSize.y; - const auto WINBB = pWindow->getFullWindowBoundingBox(); - - if (WINBB.y < PWSMON->vecPosition.y) { - offset.y = (PWSMON->vecPosition.y - WINBB.y) * PROGRESS; - } else if (WINBB.y + WINBB.height > PWSMON->vecPosition.y + PWSMON->vecSize.y) { - offset.y = (WINBB.y + WINBB.width - PWSMON->vecPosition.y - PWSMON->vecSize.y) * PROGRESS; - } - } - - renderdata.x += offset.x; - renderdata.y += offset.y; - } + renderdata.x += pWindow->m_vFloatingOffset.x; + renderdata.y += pWindow->m_vFloatingOffset.y; // if window is floating and we have a slide animation, clip it to its full bb if (!ignorePosition && pWindow->m_bIsFloating && !pWindow->m_bIsFullscreen && PWORKSPACE->m_vRenderOffset.isBeingAnimated() && !pWindow->m_bPinned) { - CRegion rg = pWindow->getFullWindowBoundingBox().translate(-pMonitor->vecPosition + PWORKSPACE->m_vRenderOffset.value()).scale(pMonitor->scale); + CRegion rg = + pWindow->getFullWindowBoundingBox().translate(-pMonitor->vecPosition + PWORKSPACE->m_vRenderOffset.value() + pWindow->m_vFloatingOffset).scale(pMonitor->scale); g_pHyprOpenGL->m_RenderData.clipBox = rg.getExtents(); } - // if window is tiled and it's flying in, don't render on other mons (for slide) - if (!ignorePosition && !pWindow->m_bIsFloating && pWindow->m_vRealPosition.isBeingAnimated() && pWindow->m_bAnimatingIn && pWindow->m_iMonitorID != pMonitor->ID) - return; - // render window decorations first, if not fullscreen full if (mode == RENDER_PASS_ALL || mode == RENDER_PASS_MAIN) { @@ -569,14 +549,14 @@ void CHyprRenderer::renderWindow(CWindow* pWindow, CMonitor* pMonitor, timespec* if (wd->getDecorationLayer() != DECORATION_LAYER_BOTTOM) continue; - wd->draw(pMonitor, renderdata.alpha * renderdata.fadeAlpha, Vector2D{renderdata.x, renderdata.y} - PREOFFSETPOS); + wd->draw(pMonitor, renderdata.alpha * renderdata.fadeAlpha); } for (auto& wd : pWindow->m_dWindowDecorations) { if (wd->getDecorationLayer() != DECORATION_LAYER_UNDER) continue; - wd->draw(pMonitor, renderdata.alpha * renderdata.fadeAlpha, Vector2D{renderdata.x, renderdata.y} - PREOFFSETPOS); + wd->draw(pMonitor, renderdata.alpha * renderdata.fadeAlpha); } } @@ -601,7 +581,7 @@ void CHyprRenderer::renderWindow(CWindow* pWindow, CMonitor* pMonitor, timespec* if (wd->getDecorationLayer() != DECORATION_LAYER_OVER) continue; - wd->draw(pMonitor, renderdata.alpha * renderdata.fadeAlpha, Vector2D{renderdata.x, renderdata.y} - PREOFFSETPOS); + wd->draw(pMonitor, renderdata.alpha * renderdata.fadeAlpha); } } @@ -662,7 +642,7 @@ void CHyprRenderer::renderWindow(CWindow* pWindow, CMonitor* pMonitor, timespec* if (wd->getDecorationLayer() != DECORATION_LAYER_OVERLAY) continue; - wd->draw(pMonitor, renderdata.alpha * renderdata.fadeAlpha, Vector2D{renderdata.x, renderdata.y} - PREOFFSETPOS); + wd->draw(pMonitor, renderdata.alpha * renderdata.fadeAlpha); } } } @@ -861,7 +841,7 @@ void CHyprRenderer::renderAllClientsForWorkspace(CMonitor* pMonitor, CWorkspace* if (!w->m_bPinned || !w->m_bIsFloating) continue; - if (!shouldRenderWindow(w.get(), pMonitor, pWorkspace)) + if (!shouldRenderWindow(w.get(), pMonitor)) continue; // render the bad boy @@ -1739,15 +1719,22 @@ void CHyprRenderer::damageSurface(wlr_surface* pSurface, double x, double y, dou damageBox.pixman()->extents.x2 - damageBox.pixman()->extents.x1, damageBox.pixman()->extents.y2 - damageBox.pixman()->extents.y1); } -void CHyprRenderer::damageWindow(CWindow* pWindow) { +void CHyprRenderer::damageWindow(CWindow* pWindow, bool forceFull) { if (g_pCompositor->m_bUnsafeState) return; - CBox damageBox = pWindow->getFullWindowBoundingBox(); + CBox windowBox = pWindow->getFullWindowBoundingBox(); + const auto PWINDOWWORKSPACE = g_pCompositor->getWorkspaceByID(pWindow->m_iWorkspaceID); + if (PWINDOWWORKSPACE && PWINDOWWORKSPACE->m_vRenderOffset.isBeingAnimated() && !pWindow->m_bPinned) + windowBox.translate(PWINDOWWORKSPACE->m_vRenderOffset.value()); + windowBox.translate(pWindow->m_vFloatingOffset); + for (auto& m : g_pCompositor->m_vMonitors) { - CBox fixedDamageBox = {damageBox.x - m->vecPosition.x, damageBox.y - m->vecPosition.y, damageBox.width, damageBox.height}; - fixedDamageBox.scale(m->scale); - m->addDamage(&fixedDamageBox); + if (g_pHyprRenderer->shouldRenderWindow(pWindow, m.get()) || forceFull) { // only damage if window is rendered on monitor + CBox fixedDamageBox = {windowBox.x - m->vecPosition.x, windowBox.y - m->vecPosition.y, windowBox.width, windowBox.height}; + fixedDamageBox.scale(m->scale); + m->addDamage(&fixedDamageBox); + } } for (auto& wd : pWindow->m_dWindowDecorations) @@ -1756,7 +1743,7 @@ void CHyprRenderer::damageWindow(CWindow* pWindow) { static auto PLOGDAMAGE = CConfigValue("debug:log_damage"); if (*PLOGDAMAGE) - Debug::log(LOG, "Damage: Window ({}): xy: {}, {} wh: {}, {}", pWindow->m_szTitle, damageBox.x, damageBox.y, damageBox.width, damageBox.height); + Debug::log(LOG, "Damage: Window ({}): xy: {}, {} wh: {}, {}", pWindow->m_szTitle, windowBox.x, windowBox.y, windowBox.width, windowBox.height); } void CHyprRenderer::damageMonitor(CMonitor* pMonitor) { diff --git a/src/render/Renderer.hpp b/src/render/Renderer.hpp index 0a684af3..613706a5 100644 --- a/src/render/Renderer.hpp +++ b/src/render/Renderer.hpp @@ -46,14 +46,14 @@ class CHyprRenderer { void outputMgrApplyTest(wlr_output_configuration_v1*, bool); void arrangeLayersForMonitor(const int&); void damageSurface(wlr_surface*, double, double, double scale = 1.0); - void damageWindow(CWindow*); + void damageWindow(CWindow*, bool forceFull = false); void damageBox(CBox*); void damageBox(const int& x, const int& y, const int& w, const int& h); void damageRegion(const CRegion&); void damageMonitor(CMonitor*); void damageMirrorsWith(CMonitor*, const CRegion&); bool applyMonitorRule(CMonitor*, SMonitorRule*, bool force = false); - bool shouldRenderWindow(CWindow*, CMonitor*, CWorkspace*); + bool shouldRenderWindow(CWindow*, CMonitor*); bool shouldRenderWindow(CWindow*); void ensureCursorRenderingMode(); bool shouldRenderCursor(); diff --git a/src/render/decorations/CHyprBorderDecoration.cpp b/src/render/decorations/CHyprBorderDecoration.cpp index ea40ee65..4981d2ea 100644 --- a/src/render/decorations/CHyprBorderDecoration.cpp +++ b/src/render/decorations/CHyprBorderDecoration.cpp @@ -45,14 +45,14 @@ CBox CHyprBorderDecoration::assignedBoxGlobal() { return box.translate(WORKSPACEOFFSET); } -void CHyprBorderDecoration::draw(CMonitor* pMonitor, float a, const Vector2D& offset) { +void CHyprBorderDecoration::draw(CMonitor* pMonitor, float a) { if (doesntWantBorders()) return; if (m_bAssignedGeometry.width < m_seExtents.topLeft.x + 1 || m_bAssignedGeometry.height < m_seExtents.topLeft.y + 1) return; - CBox windowBox = assignedBoxGlobal().translate(-pMonitor->vecPosition + offset).expand(-m_pWindow->getRealBorderSize()).scale(pMonitor->scale).round(); + CBox windowBox = assignedBoxGlobal().translate(-pMonitor->vecPosition + m_pWindow->m_vFloatingOffset).expand(-m_pWindow->getRealBorderSize()).scale(pMonitor->scale).round(); if (windowBox.width < 1 || windowBox.height < 1) return; @@ -87,7 +87,35 @@ void CHyprBorderDecoration::updateWindow(CWindow*) { } void CHyprBorderDecoration::damageEntire() { - ; // ignored, done in animationManager. todo, move. + if (!g_pCompositor->windowValidMapped(m_pWindow)) + return; + + auto surfaceBox = m_pWindow->getWindowMainSurfaceBox(); + const auto ROUNDING = m_pWindow->rounding(); + const auto ROUNDINGSIZE = ROUNDING - M_SQRT1_2 * ROUNDING + 1; + const auto BORDERSIZE = m_pWindow->getRealBorderSize(); + + const auto PWINDOWWORKSPACE = g_pCompositor->getWorkspaceByID(m_pWindow->m_iWorkspaceID); + if (PWINDOWWORKSPACE && PWINDOWWORKSPACE->m_vRenderOffset.isBeingAnimated() && !m_pWindow->m_bPinned) + surfaceBox.translate(PWINDOWWORKSPACE->m_vRenderOffset.value()); + surfaceBox.translate(m_pWindow->m_vFloatingOffset); + + CBox surfaceBoxExpandedBorder = surfaceBox; + surfaceBoxExpandedBorder.expand(BORDERSIZE); + CBox surfaceBoxShrunkRounding = surfaceBox; + surfaceBoxShrunkRounding.expand(-ROUNDINGSIZE); + + CRegion borderRegion(surfaceBoxExpandedBorder); + borderRegion.subtract(surfaceBoxShrunkRounding); + + for (auto& m : g_pCompositor->m_vMonitors) { + if (!g_pHyprRenderer->shouldRenderWindow(m_pWindow, m.get())) { + const CRegion monitorRegion({m->vecPosition, m->vecSize}); + borderRegion.subtract(monitorRegion); + } + } + + g_pHyprRenderer->damageRegion(borderRegion); } eDecorationLayer CHyprBorderDecoration::getDecorationLayer() { diff --git a/src/render/decorations/CHyprBorderDecoration.hpp b/src/render/decorations/CHyprBorderDecoration.hpp index 9c0bcc33..9b9df7ab 100644 --- a/src/render/decorations/CHyprBorderDecoration.hpp +++ b/src/render/decorations/CHyprBorderDecoration.hpp @@ -11,7 +11,7 @@ class CHyprBorderDecoration : public IHyprWindowDecoration { virtual void onPositioningReply(const SDecorationPositioningReply& reply); - virtual void draw(CMonitor*, float a, const Vector2D& offset); + virtual void draw(CMonitor*, float a); virtual eDecorationType getDecorationType(); diff --git a/src/render/decorations/CHyprDropShadowDecoration.cpp b/src/render/decorations/CHyprDropShadowDecoration.cpp index 588b23a4..99d08828 100644 --- a/src/render/decorations/CHyprDropShadowDecoration.cpp +++ b/src/render/decorations/CHyprDropShadowDecoration.cpp @@ -41,9 +41,37 @@ void CHyprDropShadowDecoration::damageEntire() { if (*PSHADOWS != 1) return; // disabled - CBox dm = {m_vLastWindowPos.x - m_seExtents.topLeft.x, m_vLastWindowPos.y - m_seExtents.topLeft.y, m_vLastWindowSize.x + m_seExtents.topLeft.x + m_seExtents.bottomRight.x, - m_vLastWindowSize.y + m_seExtents.topLeft.y + m_seExtents.bottomRight.y}; - g_pHyprRenderer->damageBox(&dm); + CBox shadowBox = {m_pWindow->m_vRealPosition.value().x - m_seExtents.topLeft.x, m_pWindow->m_vRealPosition.value().y - m_seExtents.topLeft.y, + m_pWindow->m_vRealSize.value().x + m_seExtents.topLeft.x + m_seExtents.bottomRight.x, + m_pWindow->m_vRealSize.value().y + m_seExtents.topLeft.y + m_seExtents.bottomRight.y}; + + const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(m_pWindow->m_iWorkspaceID); + if (PWORKSPACE && PWORKSPACE->m_vRenderOffset.isBeingAnimated() && !m_pWindow->m_bPinned) + shadowBox.translate(PWORKSPACE->m_vRenderOffset.value()); + shadowBox.translate(m_pWindow->m_vFloatingOffset); + + static auto PSHADOWIGNOREWINDOW = CConfigValue("decoration:shadow_ignore_window"); + const auto ROUNDING = m_pWindow->rounding(); + const auto ROUNDINGSIZE = ROUNDING - M_SQRT1_2 * ROUNDING + 1; + + CRegion shadowRegion(shadowBox); + if (*PSHADOWIGNOREWINDOW) { + CBox surfaceBox = m_pWindow->getWindowMainSurfaceBox(); + if (PWORKSPACE && PWORKSPACE->m_vRenderOffset.isBeingAnimated() && !m_pWindow->m_bPinned) + surfaceBox.translate(PWORKSPACE->m_vRenderOffset.value()); + surfaceBox.translate(m_pWindow->m_vFloatingOffset); + surfaceBox.expand(-ROUNDINGSIZE); + shadowRegion.subtract(CRegion(surfaceBox)); + } + + for (auto& m : g_pCompositor->m_vMonitors) { + if (!g_pHyprRenderer->shouldRenderWindow(m_pWindow, m.get())) { + const CRegion monitorRegion({m->vecPosition, m->vecSize}); + shadowRegion.subtract(monitorRegion); + } + } + + g_pHyprRenderer->damageRegion(shadowRegion); } void CHyprDropShadowDecoration::updateWindow(CWindow* pWindow) { @@ -54,7 +82,7 @@ void CHyprDropShadowDecoration::updateWindow(CWindow* pWindow) { m_bLastWindowBoxWithDecos = g_pDecorationPositioner->getBoxWithIncludedDecos(pWindow); } -void CHyprDropShadowDecoration::draw(CMonitor* pMonitor, float a, const Vector2D& offset) { +void CHyprDropShadowDecoration::draw(CMonitor* pMonitor, float a) { if (!g_pCompositor->windowValidMapped(m_pWindow)) return; @@ -98,12 +126,13 @@ void CHyprDropShadowDecoration::draw(CMonitor* pMonitor, float a, const Vector2D // scale the box in relation to the center of the box fullBox.scaleFromCenter(SHADOWSCALE).translate(*PSHADOWOFFSET); + updateWindow(m_pWindow); m_vLastWindowPos += WORKSPACEOFFSET; m_seExtents = {{m_vLastWindowPos.x - fullBox.x - pMonitor->vecPosition.x + 2, m_vLastWindowPos.y - fullBox.y - pMonitor->vecPosition.y + 2}, {fullBox.x + fullBox.width + pMonitor->vecPosition.x - m_vLastWindowPos.x - m_vLastWindowSize.x + 2, fullBox.y + fullBox.height + pMonitor->vecPosition.y - m_vLastWindowPos.y - m_vLastWindowSize.y + 2}}; - fullBox.translate(offset); + fullBox.translate(m_pWindow->m_vFloatingOffset); if (fullBox.width < 1 || fullBox.height < 1) return; // don't draw invisible shadows @@ -125,6 +154,9 @@ void CHyprDropShadowDecoration::draw(CMonitor* pMonitor, float a, const Vector2D windowBox.translate(-pMonitor->vecPosition + WORKSPACEOFFSET); withDecos.translate(-pMonitor->vecPosition + WORKSPACEOFFSET); + windowBox.translate(m_pWindow->m_vFloatingOffset); + withDecos.translate(m_pWindow->m_vFloatingOffset); + auto scaledExtentss = withDecos.extentsFrom(windowBox); scaledExtentss = scaledExtentss * pMonitor->scale; scaledExtentss = scaledExtentss.round(); diff --git a/src/render/decorations/CHyprDropShadowDecoration.hpp b/src/render/decorations/CHyprDropShadowDecoration.hpp index 3b389550..fcc5f873 100644 --- a/src/render/decorations/CHyprDropShadowDecoration.hpp +++ b/src/render/decorations/CHyprDropShadowDecoration.hpp @@ -11,7 +11,7 @@ class CHyprDropShadowDecoration : public IHyprWindowDecoration { virtual void onPositioningReply(const SDecorationPositioningReply& reply); - virtual void draw(CMonitor*, float a, const Vector2D& offset); + virtual void draw(CMonitor*, float a); virtual eDecorationType getDecorationType(); diff --git a/src/render/decorations/CHyprGroupBarDecoration.cpp b/src/render/decorations/CHyprGroupBarDecoration.cpp index a03d97f9..ce683ac1 100644 --- a/src/render/decorations/CHyprGroupBarDecoration.cpp +++ b/src/render/decorations/CHyprGroupBarDecoration.cpp @@ -83,10 +83,11 @@ void CHyprGroupBarDecoration::updateWindow(CWindow* pWindow) { void CHyprGroupBarDecoration::damageEntire() { auto box = assignedBoxGlobal(); + box.translate(m_pWindow->m_vFloatingOffset); g_pHyprRenderer->damageBox(&box); } -void CHyprGroupBarDecoration::draw(CMonitor* pMonitor, float a, const Vector2D& offset) { +void CHyprGroupBarDecoration::draw(CMonitor* pMonitor, float a) { // get how many bars we will draw int barsToDraw = m_dwGroupMembers.size(); @@ -110,8 +111,9 @@ void CHyprGroupBarDecoration::draw(CMonitor* pMonitor, float a, const Vector2D& int xoff = 0; for (int i = 0; i < barsToDraw; ++i) { - CBox rect = {ASSIGNEDBOX.x + xoff - pMonitor->vecPosition.x + offset.x, - ASSIGNEDBOX.y + ASSIGNEDBOX.h - BAR_INDICATOR_HEIGHT - BAR_PADDING_OUTER_VERT - pMonitor->vecPosition.y + offset.y, m_fBarWidth, BAR_INDICATOR_HEIGHT}; + CBox rect = {ASSIGNEDBOX.x + xoff - pMonitor->vecPosition.x + m_pWindow->m_vFloatingOffset.x, + ASSIGNEDBOX.y + ASSIGNEDBOX.h - BAR_INDICATOR_HEIGHT - BAR_PADDING_OUTER_VERT - pMonitor->vecPosition.y + m_pWindow->m_vFloatingOffset.y, m_fBarWidth, + BAR_INDICATOR_HEIGHT}; if (rect.width <= 0 || rect.height <= 0) break; @@ -135,7 +137,8 @@ void CHyprGroupBarDecoration::draw(CMonitor* pMonitor, float a, const Vector2D& color.a *= a; g_pHyprOpenGL->renderRect(&rect, color); - rect = {ASSIGNEDBOX.x + xoff - pMonitor->vecPosition.x + offset.x, ASSIGNEDBOX.y - pMonitor->vecPosition.y + offset.y + BAR_PADDING_OUTER_VERT, m_fBarWidth, + rect = {ASSIGNEDBOX.x + xoff - pMonitor->vecPosition.x + m_pWindow->m_vFloatingOffset.x, + ASSIGNEDBOX.y - pMonitor->vecPosition.y + m_pWindow->m_vFloatingOffset.y + BAR_PADDING_OUTER_VERT, m_fBarWidth, ASSIGNEDBOX.h - BAR_INDICATOR_HEIGHT - BAR_PADDING_OUTER_VERT * 2}; rect.scale(pMonitor->scale); @@ -505,9 +508,8 @@ CBox CHyprGroupBarDecoration::assignedBoxGlobal() { const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(m_pWindow->m_iWorkspaceID); - if (!PWORKSPACE) - return box; + if (PWORKSPACE && PWORKSPACE->m_vRenderOffset.isBeingAnimated() && !m_pWindow->m_bPinned) + box.translate(PWORKSPACE->m_vRenderOffset.value()); - const auto WORKSPACEOFFSET = PWORKSPACE && !m_pWindow->m_bPinned ? PWORKSPACE->m_vRenderOffset.value() : Vector2D(); - return box.translate(WORKSPACEOFFSET); + return box; } diff --git a/src/render/decorations/CHyprGroupBarDecoration.hpp b/src/render/decorations/CHyprGroupBarDecoration.hpp index 04f5123b..24635f6e 100644 --- a/src/render/decorations/CHyprGroupBarDecoration.hpp +++ b/src/render/decorations/CHyprGroupBarDecoration.hpp @@ -27,7 +27,7 @@ class CHyprGroupBarDecoration : public IHyprWindowDecoration { virtual void onPositioningReply(const SDecorationPositioningReply& reply); - virtual void draw(CMonitor*, float a, const Vector2D& offset); + virtual void draw(CMonitor*, float a); virtual eDecorationType getDecorationType(); diff --git a/src/render/decorations/IHyprWindowDecoration.hpp b/src/render/decorations/IHyprWindowDecoration.hpp index d3d1a5dd..10426439 100644 --- a/src/render/decorations/IHyprWindowDecoration.hpp +++ b/src/render/decorations/IHyprWindowDecoration.hpp @@ -39,7 +39,7 @@ class IHyprWindowDecoration { virtual void onPositioningReply(const SDecorationPositioningReply& reply) = 0; - virtual void draw(CMonitor*, float a, const Vector2D& offset = Vector2D()) = 0; + virtual void draw(CMonitor*, float a) = 0; virtual eDecorationType getDecorationType() = 0;