From 9be6fbf5eae8c4b902b818881a4dc34f87bb630d Mon Sep 17 00:00:00 2001 From: Vaxry <43317083+vaxerski@users.noreply.github.com> Date: Sat, 11 Nov 2023 14:37:17 +0000 Subject: [PATCH] decorations: Decoration Positioner (#3800) --- src/Compositor.cpp | 7 +- src/SharedDefs.hpp | 4 +- src/Window.cpp | 92 +++--- src/Window.hpp | 2 + src/helpers/Box.cpp | 13 + src/helpers/Box.hpp | 35 ++- src/helpers/Region.cpp | 9 +- src/helpers/Region.hpp | 3 +- src/helpers/Vector2D.cpp | 4 + src/helpers/Vector2D.hpp | 1 + src/layout/DwindleLayout.cpp | 8 +- src/layout/MasterLayout.cpp | 8 +- src/managers/AnimationManager.cpp | 23 +- src/managers/KeybindManager.cpp | 8 +- src/managers/input/InputManager.cpp | 6 +- src/plugins/PluginAPI.cpp | 9 +- src/plugins/PluginAPI.hpp | 2 +- src/render/OpenGL.cpp | 4 +- src/render/Renderer.cpp | 2 +- .../decorations/CHyprDropShadowDecoration.cpp | 66 ++--- .../decorations/CHyprDropShadowDecoration.hpp | 18 +- .../decorations/CHyprGroupBarDecoration.cpp | 105 ++++--- .../decorations/CHyprGroupBarDecoration.hpp | 29 +- .../decorations/DecorationPositioner.cpp | 277 ++++++++++++++++++ .../decorations/DecorationPositioner.hpp | 96 ++++++ .../decorations/IHyprWindowDecoration.cpp | 17 -- .../decorations/IHyprWindowDecoration.hpp | 28 +- 27 files changed, 610 insertions(+), 266 deletions(-) create mode 100644 src/render/decorations/DecorationPositioner.cpp create mode 100644 src/render/decorations/DecorationPositioner.hpp diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 30e9fdb6..29d019c1 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -81,6 +81,7 @@ CCompositor::CCompositor() { CCompositor::~CCompositor() { cleanup(); + g_pDecorationPositioner.reset(); g_pPluginSystem.reset(); g_pHyprNotificationOverlay.reset(); g_pDebugOverlay.reset(); @@ -441,6 +442,9 @@ void CCompositor::initManagers(eManagersInitStage stage) { Debug::log(LOG, "Creating the PluginSystem!"); g_pPluginSystem = std::make_unique(); g_pConfigManager->handlePluginLoads(); + + Debug::log(LOG, "Creating the DecorationPositioner!"); + g_pDecorationPositioner = std::make_unique(); } break; default: UNREACHABLE(); } @@ -1920,8 +1924,7 @@ void CCompositor::updateWindowAnimatedDecorationValues(CWindow* pWindow) { pWindow->m_cRealShadowColor.setValueAndWarp(CColor(0, 0, 0, 0)); // no shadow } - for (auto& d : pWindow->m_dWindowDecorations) - d->updateWindow(pWindow); + pWindow->updateWindowDecos(); } int CCompositor::getNextAvailableMonitorID(std::string const& name) { diff --git a/src/SharedDefs.hpp b/src/SharedDefs.hpp index fb99caaa..4e4217d2 100644 --- a/src/SharedDefs.hpp +++ b/src/SharedDefs.hpp @@ -39,7 +39,7 @@ struct SWindowDecorationExtents { return SWindowDecorationExtents{topLeft * scale, bottomRight * scale}; } - SWindowDecorationExtents floor() { - return {topLeft.floor(), bottomRight.floor()}; + SWindowDecorationExtents round() { + return {topLeft.round(), bottomRight.round()}; } }; \ No newline at end of file diff --git a/src/Window.cpp b/src/Window.cpp index 7994b6cb..c1b79c2d 100644 --- a/src/Window.cpp +++ b/src/Window.cpp @@ -13,7 +13,7 @@ CWindow::CWindow() { m_cRealShadowColor.create(AVARTYPE_COLOR, g_pConfigManager->getAnimationPropertyConfig("fadeShadow"), (void*)this, AVARDAMAGE_SHADOW); m_fDimPercent.create(AVARTYPE_FLOAT, g_pConfigManager->getAnimationPropertyConfig("fadeDim"), (void*)this, AVARDAMAGE_ENTIRE); - m_dWindowDecorations.emplace_back(std::make_unique(this)); // put the shadow so it's the first deco (has to be rendered first) + addWindowDeco(std::make_unique(this)); } CWindow::~CWindow() { @@ -37,22 +37,19 @@ SWindowDecorationExtents CWindow::getFullWindowExtents() { SWindowDecorationExtents maxExtents = {{BORDERSIZE + 2, BORDERSIZE + 2}, {BORDERSIZE + 2, BORDERSIZE + 2}}; - for (auto& wd : m_dWindowDecorations) { + const auto EXTENTS = g_pDecorationPositioner->getWindowDecorationExtents(this); - const auto EXTENTS = wd->getWindowDecorationExtents(); + if (EXTENTS.topLeft.x > maxExtents.topLeft.x) + maxExtents.topLeft.x = EXTENTS.topLeft.x; - if (EXTENTS.topLeft.x > maxExtents.topLeft.x) - maxExtents.topLeft.x = EXTENTS.topLeft.x; + if (EXTENTS.topLeft.y > maxExtents.topLeft.y) + maxExtents.topLeft.y = EXTENTS.topLeft.y; - if (EXTENTS.topLeft.y > maxExtents.topLeft.y) - maxExtents.topLeft.y = EXTENTS.topLeft.y; + if (EXTENTS.bottomRight.x > maxExtents.bottomRight.x) + maxExtents.bottomRight.x = EXTENTS.bottomRight.x; - if (EXTENTS.bottomRight.x > maxExtents.bottomRight.x) - maxExtents.bottomRight.x = EXTENTS.bottomRight.x; - - if (EXTENTS.bottomRight.y > maxExtents.bottomRight.y) - maxExtents.bottomRight.y = EXTENTS.bottomRight.y; - } + if (EXTENTS.bottomRight.y > maxExtents.bottomRight.y) + maxExtents.bottomRight.y = EXTENTS.bottomRight.y; if (m_pWLSurface.exists() && !m_bIsX11) { CBox surfaceExtents = {0, 0, 0, 0}; @@ -144,25 +141,19 @@ CBox CWindow::getWindowInputBox() { SWindowDecorationExtents maxExtents = {{BORDERSIZE + 2, BORDERSIZE + 2}, {BORDERSIZE + 2, BORDERSIZE + 2}}; - for (auto& wd : m_dWindowDecorations) { + const auto EXTENTS = g_pDecorationPositioner->getWindowDecorationExtents(this, true); - if (!(wd->getDecorationFlags() & DECORATION_ALLOWS_MOUSE_INPUT)) - continue; + if (EXTENTS.topLeft.x > maxExtents.topLeft.x) + maxExtents.topLeft.x = EXTENTS.topLeft.x; - const auto EXTENTS = wd->getWindowDecorationExtents(); + if (EXTENTS.topLeft.y > maxExtents.topLeft.y) + maxExtents.topLeft.y = EXTENTS.topLeft.y; - if (EXTENTS.topLeft.x > maxExtents.topLeft.x) - maxExtents.topLeft.x = EXTENTS.topLeft.x; + if (EXTENTS.bottomRight.x > maxExtents.bottomRight.x) + maxExtents.bottomRight.x = EXTENTS.bottomRight.x; - if (EXTENTS.topLeft.y > maxExtents.topLeft.y) - maxExtents.topLeft.y = EXTENTS.topLeft.y; - - if (EXTENTS.bottomRight.x > maxExtents.bottomRight.x) - maxExtents.bottomRight.x = EXTENTS.bottomRight.x; - - if (EXTENTS.bottomRight.y > maxExtents.bottomRight.y) - maxExtents.bottomRight.y = EXTENTS.bottomRight.y; - } + if (EXTENTS.bottomRight.y > maxExtents.bottomRight.y) + maxExtents.bottomRight.y = EXTENTS.bottomRight.y; // Add extents to the real base BB and return CBox finalBox = {m_vRealPosition.vec().x - maxExtents.topLeft.x, m_vRealPosition.vec().y - maxExtents.topLeft.y, @@ -176,30 +167,19 @@ CBox CWindow::getWindowMainSurfaceBox() { } SWindowDecorationExtents CWindow::getFullWindowReservedArea() { - SWindowDecorationExtents extents; - - for (auto& wd : m_dWindowDecorations) { - const auto RESERVED = wd->getWindowDecorationReservedArea(); - - if (RESERVED.bottomRight == Vector2D{} && RESERVED.topLeft == Vector2D{}) - continue; - - extents.topLeft = extents.topLeft + RESERVED.topLeft; - extents.bottomRight = extents.bottomRight + RESERVED.bottomRight; - } - - return extents; + return g_pDecorationPositioner->getWindowDecorationReserved(this); } void CWindow::updateWindowDecos() { - for (auto& wd : m_dWindowDecorations) - wd->updateWindow(this); - bool recalc = false; + if (!m_bIsMapped || isHidden()) + return; + for (auto& wd : m_vDecosToRemove) { for (auto it = m_dWindowDecorations.begin(); it != m_dWindowDecorations.end(); it++) { if (it->get() == wd) { + g_pDecorationPositioner->uncacheDecoration(it->get()); it = m_dWindowDecorations.erase(it); recalc = true; if (it == m_dWindowDecorations.end()) @@ -208,10 +188,26 @@ void CWindow::updateWindowDecos() { } } + g_pDecorationPositioner->onWindowUpdate(this); + if (recalc) g_pLayoutManager->getCurrentLayout()->recalculateWindow(this); m_vDecosToRemove.clear(); + + for (auto& wd : m_dWindowDecorations) { + wd->updateWindow(this); + } +} + +void CWindow::addWindowDeco(std::unique_ptr deco) { + m_dWindowDecorations.emplace_back(std::move(deco)); + updateWindowDecos(); +} + +void CWindow::removeWindowDeco(IHyprWindowDecoration* deco) { + m_vDecosToRemove.push_back(deco); + updateWindowDecos(); } pid_t CWindow::getPID() { @@ -689,14 +685,14 @@ void CWindow::createGroup() { Debug::log(LOG, "createGroup: window:{:x},title:{} is denied as a group, ignored", (uintptr_t)this, this->m_szTitle); return; } + if (!m_sGroupData.pNextWindow) { m_sGroupData.pNextWindow = this; m_sGroupData.head = true; m_sGroupData.locked = false; m_sGroupData.deny = false; - m_dWindowDecorations.emplace_back(std::make_unique(this)); - updateWindowDecos(); + addWindowDeco(std::make_unique(this)); g_pLayoutManager->getCurrentLayout()->recalculateWindow(this); g_pCompositor->updateAllWindowsAnimatedDecorationValues(); @@ -835,6 +831,8 @@ void CWindow::setGroupCurrent(CWindow* pWindow) { g_pCompositor->setWindowFullscreen(pWindow, true, WORKSPACE->m_efFullscreenMode); g_pHyprRenderer->damageWindow(pWindow); + + pWindow->updateWindowDecos(); } void CWindow::insertWindowToGroup(CWindow* pWindow) { @@ -842,7 +840,7 @@ void CWindow::insertWindowToGroup(CWindow* pWindow) { const auto ENDAT = m_sGroupData.pNextWindow; if (!pWindow->getDecorationByType(DECORATION_GROUPBAR)) - pWindow->m_dWindowDecorations.emplace_back(std::make_unique(pWindow)); + pWindow->addWindowDeco(std::make_unique(pWindow)); if (!pWindow->m_sGroupData.pNextWindow) { BEGINAT->m_sGroupData.pNextWindow = pWindow; diff --git a/src/Window.hpp b/src/Window.hpp index 580b0a2a..4e1ab9c1 100644 --- a/src/Window.hpp +++ b/src/Window.hpp @@ -344,7 +344,9 @@ class CWindow { CBox getWindowInputBox(); CBox getWindowMainSurfaceBox(); CBox getWindowIdealBoundingBoxIgnoreReserved(); + void addWindowDeco(std::unique_ptr deco); void updateWindowDecos(); + void removeWindowDeco(IHyprWindowDecoration* deco); pid_t getPID(); IHyprWindowDecoration* getDecorationByType(eDecorationType); void removeDecorationByType(eDecorationType); diff --git a/src/helpers/Box.cpp b/src/helpers/Box.cpp index 55300f5f..29aa81fa 100644 --- a/src/helpers/Box.cpp +++ b/src/helpers/Box.cpp @@ -96,6 +96,15 @@ CBox& CBox::scaleFromCenter(double scale) { return *this; } +CBox& CBox::expand(const double& value) { + x -= value; + y -= value; + w += value * 2.0; + h += value * 2.0; + + return *this; +} + CBox CBox::roundInternal() { float newW = x + w - std::floor(x); float newH = y + h - std::floor(y); @@ -110,3 +119,7 @@ Vector2D CBox::pos() const { Vector2D CBox::size() const { return {w, h}; } + +SWindowDecorationExtents CBox::extentsFrom(const CBox& small) { + return {{small.x - x, small.y - y}, {w - small.w - (small.x - x), h - small.h - (small.y - y)}}; +} diff --git a/src/helpers/Box.hpp b/src/helpers/Box.hpp index 592bb417..cb07df06 100644 --- a/src/helpers/Box.hpp +++ b/src/helpers/Box.hpp @@ -39,26 +39,29 @@ class CBox { h = size.y; } - wlr_box wlr(); - wlr_box* pWlr(); + wlr_box wlr(); + wlr_box* pWlr(); - CBox& applyFromWlr(); - CBox& scale(double scale); - CBox& scaleFromCenter(double scale); - CBox& scale(const Vector2D& scale); - CBox& translate(const Vector2D& vec); - CBox& round(); - CBox& transform(const wl_output_transform t, double w, double h); - CBox& addExtents(const SWindowDecorationExtents& e); + CBox& applyFromWlr(); + CBox& scale(double scale); + CBox& scaleFromCenter(double scale); + CBox& scale(const Vector2D& scale); + CBox& translate(const Vector2D& vec); + CBox& round(); + CBox& transform(const wl_output_transform t, double w, double h); + CBox& addExtents(const SWindowDecorationExtents& e); + CBox& expand(const double& value); - Vector2D middle() const; - Vector2D pos() const; - Vector2D size() const; + SWindowDecorationExtents extentsFrom(const CBox&); // this is the big box - bool containsPoint(const Vector2D& vec) const; - bool empty() const; + Vector2D middle() const; + Vector2D pos() const; + Vector2D size() const; - double x = 0, y = 0; + bool containsPoint(const Vector2D& vec) const; + bool empty() const; + + double x = 0, y = 0; union { double w; double width; diff --git a/src/helpers/Region.cpp b/src/helpers/Region.cpp index fdf8a242..06b8536c 100644 --- a/src/helpers/Region.cpp +++ b/src/helpers/Region.cpp @@ -21,8 +21,8 @@ CRegion::CRegion(wlr_box* box) { pixman_region32_init_rect(&m_rRegion, box->x, box->y, box->width, box->height); } -CRegion::CRegion(CBox* box) { - pixman_region32_init_rect(&m_rRegion, box->x, box->y, box->w, box->h); +CRegion::CRegion(const CBox& box) { + pixman_region32_init_rect(&m_rRegion, box.x, box.y, box.w, box.h); } CRegion::CRegion(pixman_box32_t* box) { @@ -63,6 +63,11 @@ CRegion& CRegion::add(double x, double y, double w, double h) { return *this; } +CRegion& CRegion::add(const CBox& other) { + pixman_region32_union_rect(&m_rRegion, &m_rRegion, other.x, other.y, other.w, other.h); + return *this; +} + CRegion& CRegion::subtract(const CRegion& other) { pixman_region32_subtract(&m_rRegion, &m_rRegion, const_cast(&other)->pixman()); return *this; diff --git a/src/helpers/Region.hpp b/src/helpers/Region.hpp index 80153cff..1c6923df 100644 --- a/src/helpers/Region.hpp +++ b/src/helpers/Region.hpp @@ -17,7 +17,7 @@ class CRegion { /* Create from a wlr_box */ CRegion(wlr_box* box); /* Create from a CBox */ - CRegion(CBox* box); + CRegion(const CBox& box); /* Create from a pixman_box32_t */ CRegion(pixman_box32_t* box); @@ -40,6 +40,7 @@ class CRegion { CRegion& set(const CRegion& other); CRegion& add(const CRegion& other); CRegion& add(double x, double y, double w, double h); + CRegion& add(const CBox& other); CRegion& subtract(const CRegion& other); CRegion& intersect(const CRegion& other); CRegion& intersect(double x, double y, double w, double h); diff --git a/src/helpers/Vector2D.cpp b/src/helpers/Vector2D.cpp index ae2484b3..7bc6412d 100644 --- a/src/helpers/Vector2D.cpp +++ b/src/helpers/Vector2D.cpp @@ -28,6 +28,10 @@ Vector2D Vector2D::floor() const { return Vector2D(std::floor(x), std::floor(y)); } +Vector2D Vector2D::round() const { + return Vector2D(std::round(x), std::round(y)); +} + Vector2D Vector2D::clamp(const Vector2D& min, const Vector2D& max) const { return Vector2D(std::clamp(this->x, min.x, max.x < min.x ? INFINITY : max.x), std::clamp(this->y, min.y, max.y < min.y ? INFINITY : max.y)); } diff --git a/src/helpers/Vector2D.hpp b/src/helpers/Vector2D.hpp index 17415289..c79c967c 100644 --- a/src/helpers/Vector2D.hpp +++ b/src/helpers/Vector2D.hpp @@ -61,6 +61,7 @@ class Vector2D { Vector2D clamp(const Vector2D& min, const Vector2D& max = Vector2D()) const; Vector2D floor() const; + Vector2D round() const; bool inTriangle(const Vector2D& p1, const Vector2D& p2, const Vector2D& p3) const; }; diff --git a/src/layout/DwindleLayout.cpp b/src/layout/DwindleLayout.cpp index 6602c758..a01c3b8c 100644 --- a/src/layout/DwindleLayout.cpp +++ b/src/layout/DwindleLayout.cpp @@ -323,7 +323,7 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow, eDirection dire if (!(wd->getDecorationFlags() & DECORATION_ALLOWS_MOUSE_INPUT)) continue; - if (wd->getWindowDecorationRegion().containsPoint(MOUSECOORDS)) { + if (g_pDecorationPositioner->getWindowDecorationBox(wd.get()).containsPoint(MOUSECOORDS)) { if (!wd->onEndWindowDragOnDeco(pWindow, MOUSECOORDS)) return; break; @@ -334,9 +334,6 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow, eDirection dire // if it's a group, add the window if (OPENINGON->pWindow->m_sGroupData.pNextWindow // target is group && pWindow->canBeGroupedInto(OPENINGON->pWindow) && !m_vOverrideFocalPoint) { // we are not moving window - if (!pWindow->m_sGroupData.pNextWindow) - pWindow->m_dWindowDecorations.emplace_back(std::make_unique(pWindow)); - m_lDwindleNodesData.remove(*PNODE); static const auto* USECURRPOS = &g_pConfigManager->getConfigValuePtr("group:insert_after_current")->intValue; @@ -347,6 +344,9 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow, eDirection dire pWindow->updateWindowDecos(); recalculateWindow(pWindow); + if (!pWindow->getDecorationByType(DECORATION_GROUPBAR)) + pWindow->addWindowDeco(std::make_unique(pWindow)); + return; } diff --git a/src/layout/MasterLayout.cpp b/src/layout/MasterLayout.cpp index 57784786..d355a7d3 100644 --- a/src/layout/MasterLayout.cpp +++ b/src/layout/MasterLayout.cpp @@ -99,7 +99,7 @@ void CHyprMasterLayout::onWindowCreatedTiling(CWindow* pWindow, eDirection direc if (!(wd->getDecorationFlags() & DECORATION_ALLOWS_MOUSE_INPUT)) continue; - if (wd->getWindowDecorationRegion().containsPoint(MOUSECOORDS)) { + if (g_pDecorationPositioner->getWindowDecorationBox(wd.get()).containsPoint(MOUSECOORDS)) { if (!wd->onEndWindowDragOnDeco(pWindow, MOUSECOORDS)) return; break; @@ -111,9 +111,6 @@ void CHyprMasterLayout::onWindowCreatedTiling(CWindow* pWindow, eDirection direc if (OPENINGON && OPENINGON != PNODE && OPENINGON->pWindow->m_sGroupData.pNextWindow // target is group && pWindow->canBeGroupedInto(OPENINGON->pWindow)) { - if (!pWindow->m_sGroupData.pNextWindow) - pWindow->m_dWindowDecorations.emplace_back(std::make_unique(pWindow)); - m_lMasterNodesData.remove(*PNODE); static const auto* USECURRPOS = &g_pConfigManager->getConfigValuePtr("group:insert_after_current")->intValue; @@ -124,6 +121,9 @@ void CHyprMasterLayout::onWindowCreatedTiling(CWindow* pWindow, eDirection direc pWindow->updateWindowDecos(); recalculateWindow(pWindow); + if (!pWindow->getDecorationByType(DECORATION_GROUPBAR)) + pWindow->addWindowDeco(std::make_unique(pWindow)); + return; } diff --git a/src/managers/AnimationManager.cpp b/src/managers/AnimationManager.cpp index 1dc8e2c6..a5e1c47e 100644 --- a/src/managers/AnimationManager.cpp +++ b/src/managers/AnimationManager.cpp @@ -248,28 +248,9 @@ void CAnimationManager::tick() { case AVARDAMAGE_SHADOW: { RASSERT(PWINDOW, "Tried to AVARDAMAGE_SHADOW a non-window AVAR!"); - static auto* const PSHADOWIGNOREWINDOW = &g_pConfigManager->getConfigValuePtr("decoration:shadow_ignore_window")->intValue; + const auto PDECO = PWINDOW->getDecorationByType(DECORATION_SHADOW); - const auto PDECO = PWINDOW->getDecorationByType(DECORATION_SHADOW); - - if (PDECO) { - const auto EXTENTS = PDECO->getWindowDecorationExtents(); - - CBox dmg = {PWINDOW->m_vRealPosition.vec().x - EXTENTS.topLeft.x, PWINDOW->m_vRealPosition.vec().y - EXTENTS.topLeft.y, - PWINDOW->m_vRealSize.vec().x + EXTENTS.topLeft.x + EXTENTS.bottomRight.x, PWINDOW->m_vRealSize.vec().y + EXTENTS.topLeft.y + EXTENTS.bottomRight.y}; - - if (!*PSHADOWIGNOREWINDOW) { - // easy, damage the entire box - g_pHyprRenderer->damageBox(&dmg); - } else { - CRegion rg{dmg.x, dmg.y, dmg.width, dmg.height}; - CRegion wb{PWINDOW->m_vRealPosition.vec().x, PWINDOW->m_vRealPosition.vec().y, PWINDOW->m_vRealSize.vec().x, PWINDOW->m_vRealSize.vec().y}; - - rg.subtract(wb); - - g_pHyprRenderer->damageRegion(rg); - } - } + PDECO->damageEntire(); break; } diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 3bed027d..e4cac5f4 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -1845,7 +1845,7 @@ void CKeybindManager::mouse(std::string args) { if (!(wd->getDecorationFlags() & DECORATION_ALLOWS_MOUSE_INPUT)) continue; - if (wd->getWindowDecorationRegion().containsPoint(mouseCoords)) { + if (g_pDecorationPositioner->getWindowDecorationBox(wd.get()).containsPoint(mouseCoords)) { wd->onBeginWindowDragOnDeco(mouseCoords); break; } @@ -1964,9 +1964,6 @@ void CKeybindManager::moveWindowIntoGroup(CWindow* pWindow, CWindow* pWindowInDi if (pWindow->m_sGroupData.deny) return; - if (!pWindow->m_sGroupData.pNextWindow) - pWindow->m_dWindowDecorations.emplace_back(std::make_unique(pWindow)); - g_pLayoutManager->getCurrentLayout()->onWindowRemoved(pWindow); // This removes groupped property! static const auto* USECURRPOS = &g_pConfigManager->getConfigValuePtr("group:insert_after_current")->intValue; @@ -1978,6 +1975,9 @@ void CKeybindManager::moveWindowIntoGroup(CWindow* pWindow, CWindow* pWindowInDi g_pLayoutManager->getCurrentLayout()->recalculateWindow(pWindow); g_pCompositor->focusWindow(pWindow); g_pCompositor->warpCursorTo(pWindow->middle()); + + if (!pWindow->getDecorationByType(DECORATION_GROUPBAR)) + pWindow->addWindowDeco(std::make_unique(pWindow)); } void CKeybindManager::moveWindowOutOfGroup(CWindow* pWindow, const std::string& dir) { diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index 78ed3d71..d096ab32 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -588,7 +588,7 @@ void CInputManager::processMouseDownNormal(wlr_pointer_button_event* e) { if (!(wd->getDecorationFlags() & DECORATION_ALLOWS_MOUSE_INPUT)) continue; - if (wd->getWindowDecorationRegion().containsPoint(mouseCoords)) { + if (g_pDecorationPositioner->getWindowDecorationBox(wd.get()).containsPoint(mouseCoords)) { wd->onMouseButtonOnDeco(mouseCoords, e); return; } @@ -675,7 +675,7 @@ void CInputManager::onMouseWheel(wlr_pointer_axis_event* e) { const auto pWindow = g_pCompositor->vectorToWindowIdeal(MOUSECOORDS); if (*PGROUPBARSCROLLING && pWindow && !pWindow->m_bIsFullscreen && !pWindow->hasPopupAt(MOUSECOORDS) && pWindow->m_sGroupData.pNextWindow) { - const CBox box = pWindow->getDecorationByType(DECORATION_GROUPBAR)->getWindowDecorationRegion().getExtents(); + const CBox box = g_pDecorationPositioner->getWindowDecorationBox(pWindow->getDecorationByType(DECORATION_GROUPBAR)); if (box.containsPoint(MOUSECOORDS)) { if (e->delta > 0) pWindow->setGroupCurrent(pWindow->m_sGroupData.pNextWindow); @@ -1638,7 +1638,7 @@ void CInputManager::setCursorIconOnBorder(CWindow* w) { if (!(wd->getDecorationFlags() & DECORATION_ALLOWS_MOUSE_INPUT)) continue; - if (wd->getWindowDecorationRegion().containsPoint(mouseCoords)) { + if (g_pDecorationPositioner->getWindowDecorationBox(wd.get()).containsPoint(mouseCoords)) { onDeco = true; break; } diff --git a/src/plugins/PluginAPI.cpp b/src/plugins/PluginAPI.cpp index 1395728d..283472fa 100644 --- a/src/plugins/PluginAPI.cpp +++ b/src/plugins/PluginAPI.cpp @@ -111,7 +111,7 @@ APICALL bool HyprlandAPI::removeFunctionHook(HANDLE handle, CFunctionHook* hook) return g_pFunctionHookSystem->removeHook(hook); } -APICALL bool HyprlandAPI::addWindowDecoration(HANDLE handle, CWindow* pWindow, IHyprWindowDecoration* pDecoration) { +APICALL bool HyprlandAPI::addWindowDecoration(HANDLE handle, CWindow* pWindow, std::unique_ptr pDecoration) { auto* const PLUGIN = g_pPluginSystem->getPluginByHandle(handle); if (!PLUGIN) @@ -120,11 +120,10 @@ APICALL bool HyprlandAPI::addWindowDecoration(HANDLE handle, CWindow* pWindow, I if (!g_pCompositor->windowValidMapped(pWindow)) return false; - PLUGIN->registeredDecorations.push_back(pDecoration); + PLUGIN->registeredDecorations.push_back(pDecoration.get()); - pWindow->m_dWindowDecorations.emplace_back(pDecoration); + pWindow->addWindowDeco(std::move(pDecoration)); - pWindow->updateWindowDecos(); g_pLayoutManager->getCurrentLayout()->recalculateWindow(pWindow); return true; @@ -139,7 +138,7 @@ APICALL bool HyprlandAPI::removeWindowDecoration(HANDLE handle, IHyprWindowDecor for (auto& w : g_pCompositor->m_vWindows) { for (auto& d : w->m_dWindowDecorations) { if (d.get() == pDecoration) { - std::erase(w->m_dWindowDecorations, d); + w->removeWindowDeco(pDecoration); return true; } } diff --git a/src/plugins/PluginAPI.hpp b/src/plugins/PluginAPI.hpp index a3792fe9..12e7c128 100644 --- a/src/plugins/PluginAPI.hpp +++ b/src/plugins/PluginAPI.hpp @@ -221,7 +221,7 @@ namespace HyprlandAPI { returns: true on success. False otherwise. */ - APICALL bool addWindowDecoration(HANDLE handle, CWindow* pWindow, IHyprWindowDecoration* pDecoration); + APICALL bool addWindowDecoration(HANDLE handle, CWindow* pWindow, std::unique_ptr pDecoration); /* Removes a window decoration diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index 26f3c128..826854ed 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -497,7 +497,7 @@ void CHyprOpenGLImpl::renderRectWithBlur(CBox* box, const CColor& col, int round return; CRegion damage{m_RenderData.damage}; - damage.intersect(box); + damage.intersect(*box); CFramebuffer* POUTFB = blurMainFramebufferWithDamage(blurA, &damage); @@ -1392,7 +1392,7 @@ void CHyprOpenGLImpl::renderBorder(CBox* box, const CGradientValueData& grad, in if (borderSize < 1) return; - int scaledBorderSize = borderSize * m_RenderData.pMonitor->scale * m_RenderData.renderModif.scale; + int scaledBorderSize = std::round(borderSize * m_RenderData.pMonitor->scale * m_RenderData.renderModif.scale); // adjust box box->x -= scaledBorderSize; diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index a43d6a2d..98dcf7f5 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -2105,7 +2105,7 @@ void CHyprRenderer::setOccludedForBackLayers(CRegion& region, CWorkspace* pWorks box.scale(PMONITOR->scale); - rg.add(&box); + rg.add(box); } region.subtract(rg); diff --git a/src/render/decorations/CHyprDropShadowDecoration.cpp b/src/render/decorations/CHyprDropShadowDecoration.cpp index ac6c5b43..9f051ad3 100644 --- a/src/render/decorations/CHyprDropShadowDecoration.cpp +++ b/src/render/decorations/CHyprDropShadowDecoration.cpp @@ -10,19 +10,18 @@ CHyprDropShadowDecoration::~CHyprDropShadowDecoration() { updateWindow(m_pWindow); } -SWindowDecorationExtents CHyprDropShadowDecoration::getWindowDecorationExtents() { - static auto* const PSHADOWS = &g_pConfigManager->getConfigValuePtr("decoration:drop_shadow")->intValue; - - if (*PSHADOWS != 1) - return {{}, {}}; - - return m_seExtents; -} - eDecorationType CHyprDropShadowDecoration::getDecorationType() { return DECORATION_SHADOW; } +SDecorationPositioningInfo CHyprDropShadowDecoration::getPositioningInfo() { + return {DECORATION_POSITION_ABSOLUTE}; +} + +void CHyprDropShadowDecoration::onPositioningReply(const SDecorationPositioningReply& reply) { + updateWindow(m_pWindow); +} + void CHyprDropShadowDecoration::damageEntire() { static auto* const PSHADOWS = &g_pConfigManager->getConfigValuePtr("decoration:drop_shadow")->intValue; @@ -40,37 +39,11 @@ void CHyprDropShadowDecoration::updateWindow(CWindow* pWindow) { const auto WORKSPACEOFFSET = PWORKSPACE && !pWindow->m_bPinned ? PWORKSPACE->m_vRenderOffset.vec() : Vector2D(); - if (pWindow->m_vRealPosition.vec() + WORKSPACEOFFSET != m_vLastWindowPos || pWindow->m_vRealSize.vec() != m_vLastWindowSize) { - m_vLastWindowPos = pWindow->m_vRealPosition.vec() + WORKSPACEOFFSET; - m_vLastWindowSize = pWindow->m_vRealSize.vec(); + m_vLastWindowPos = pWindow->m_vRealPosition.vec() + WORKSPACEOFFSET; + m_vLastWindowSize = pWindow->m_vRealSize.vec(); - damageEntire(); - - const auto BORDER = m_pWindow->getRealBorderSize(); - - // calculate extents of decos with the DECORATION_PART_OF_MAIN_WINDOW flag - SWindowDecorationExtents maxExtents; - - for (auto& wd : m_pWindow->m_dWindowDecorations) { - // conveniently, this will also skip us. - if (!(wd->getDecorationFlags() & DECORATION_PART_OF_MAIN_WINDOW)) - continue; - - const auto EXTENTS = wd->getWindowDecorationExtents(); - - if (maxExtents.topLeft.x < EXTENTS.topLeft.x) - maxExtents.topLeft.x = EXTENTS.topLeft.x; - if (maxExtents.topLeft.y < EXTENTS.topLeft.y) - maxExtents.topLeft.y = EXTENTS.topLeft.y; - if (maxExtents.bottomRight.x < EXTENTS.bottomRight.x) - maxExtents.bottomRight.x = EXTENTS.bottomRight.x; - if (maxExtents.bottomRight.y < EXTENTS.bottomRight.y) - maxExtents.bottomRight.y = EXTENTS.bottomRight.y; - } - - m_bLastWindowBox = {m_vLastWindowPos.x, m_vLastWindowPos.y, m_vLastWindowSize.x, m_vLastWindowSize.y}; - m_eLastExtents = {{maxExtents.topLeft + Vector2D{BORDER, BORDER}}, {maxExtents.bottomRight + Vector2D{BORDER, BORDER}}}; - } + m_bLastWindowBox = {m_vLastWindowPos.x, m_vLastWindowPos.y, m_vLastWindowSize.x, m_vLastWindowSize.y}; + m_bLastWindowBoxWithDecos = g_pDecorationPositioner->getBoxWithIncludedDecos(pWindow); } void CHyprDropShadowDecoration::draw(CMonitor* pMonitor, float a, const Vector2D& offset) { @@ -102,8 +75,8 @@ void CHyprDropShadowDecoration::draw(CMonitor* pMonitor, float a, const Vector2D const auto ROUNDING = m_pWindow->rounding() + m_pWindow->getRealBorderSize(); // draw the shadow - CBox fullBox = {m_bLastWindowBox.x, m_bLastWindowBox.y, m_bLastWindowBox.width, m_bLastWindowBox.height}; - fullBox.addExtents(m_eLastExtents).translate(-pMonitor->vecPosition); + CBox fullBox = m_bLastWindowBoxWithDecos; + fullBox.translate(-pMonitor->vecPosition); fullBox.x -= *PSHADOWSIZE; fullBox.y -= *PSHADOWSIZE; fullBox.w += 2 * *PSHADOWSIZE; @@ -134,11 +107,16 @@ void CHyprDropShadowDecoration::draw(CMonitor* pMonitor, float a, const Vector2D if (*PSHADOWIGNOREWINDOW) { CBox windowBox = m_bLastWindowBox; + CBox withDecos = m_bLastWindowBoxWithDecos; - windowBox.translate(-pMonitor->vecPosition).scale(pMonitor->scale); - windowBox.round(); + // get window box + windowBox.translate(-pMonitor->vecPosition).scale(pMonitor->scale).round(); + withDecos.translate(-pMonitor->vecPosition).scale(pMonitor->scale).round(); - windowBox.addExtents(SWindowDecorationExtents{m_eLastExtents * pMonitor->scale}.floor()).round(); + auto scaledDecoExtents = withDecos.extentsFrom(windowBox).round(); + + // add extents + windowBox.addExtents(scaledDecoExtents).round(); if (windowBox.width < 1 || windowBox.height < 1) return; // prevent assert failed diff --git a/src/render/decorations/CHyprDropShadowDecoration.hpp b/src/render/decorations/CHyprDropShadowDecoration.hpp index d7ec043e..9f0f58a0 100644 --- a/src/render/decorations/CHyprDropShadowDecoration.hpp +++ b/src/render/decorations/CHyprDropShadowDecoration.hpp @@ -7,17 +7,19 @@ class CHyprDropShadowDecoration : public IHyprWindowDecoration { CHyprDropShadowDecoration(CWindow*); virtual ~CHyprDropShadowDecoration(); - virtual SWindowDecorationExtents getWindowDecorationExtents(); + virtual SDecorationPositioningInfo getPositioningInfo(); - virtual void draw(CMonitor*, float a, const Vector2D& offset); + virtual void onPositioningReply(const SDecorationPositioningReply& reply); - virtual eDecorationType getDecorationType(); + virtual void draw(CMonitor*, float a, const Vector2D& offset); - virtual void updateWindow(CWindow*); + virtual eDecorationType getDecorationType(); - virtual void damageEntire(); + virtual void updateWindow(CWindow*); - virtual eDecorationLayer getDecorationLayer(); + virtual void damageEntire(); + + virtual eDecorationLayer getDecorationLayer(); private: SWindowDecorationExtents m_seExtents; @@ -27,6 +29,6 @@ class CHyprDropShadowDecoration : public IHyprWindowDecoration { Vector2D m_vLastWindowPos; Vector2D m_vLastWindowSize; - CBox m_bLastWindowBox = {0}; - SWindowDecorationExtents m_eLastExtents = {}; + CBox m_bLastWindowBox = {0}; + CBox m_bLastWindowBoxWithDecos = {0}; }; \ No newline at end of file diff --git a/src/render/decorations/CHyprGroupBarDecoration.cpp b/src/render/decorations/CHyprGroupBarDecoration.cpp index 873186c0..625888da 100644 --- a/src/render/decorations/CHyprGroupBarDecoration.cpp +++ b/src/render/decorations/CHyprGroupBarDecoration.cpp @@ -6,6 +6,10 @@ // shared things to conserve VRAM static CTexture m_tGradientActive; static CTexture m_tGradientInactive; +constexpr int BAR_INDICATOR_HEIGHT = 3; +constexpr int BAR_PADDING_OUTER_VERT = 2; +constexpr int BAR_TEXT_PAD = 2; +constexpr int BAR_HORIZONTAL_PADDING = 2; CHyprGroupBarDecoration::CHyprGroupBarDecoration(CWindow* pWindow) : IHyprWindowDecoration(pWindow) { m_pWindow = pWindow; @@ -13,47 +17,33 @@ CHyprGroupBarDecoration::CHyprGroupBarDecoration(CWindow* pWindow) : IHyprWindow CHyprGroupBarDecoration::~CHyprGroupBarDecoration() {} -SWindowDecorationExtents CHyprGroupBarDecoration::getWindowDecorationExtents() { - return m_seExtents; +SDecorationPositioningInfo CHyprGroupBarDecoration::getPositioningInfo() { + const int BORDERSIZE = m_pWindow->getRealBorderSize(); + static auto* const PRENDERTITLES = &g_pConfigManager->getConfigValuePtr("group:groupbar:render_titles")->intValue; + static auto* const PTITLEFONTSIZE = &g_pConfigManager->getConfigValuePtr("group:groupbar:font_size")->intValue; + + SDecorationPositioningInfo info; + info.policy = DECORATION_POSITION_STICKY; + info.edges = DECORATION_EDGE_TOP; + info.priority = 3; + info.reserved = true; + info.desiredExtents = {{0, BORDERSIZE + BAR_PADDING_OUTER_VERT * 2 + BAR_INDICATOR_HEIGHT + (*PRENDERTITLES ? *PTITLEFONTSIZE : 0) + 2}, {0, 0}}; + return info; +} + +void CHyprGroupBarDecoration::onPositioningReply(const SDecorationPositioningReply& reply) { + m_bAssignedBox = reply.assignedGeometry; } eDecorationType CHyprGroupBarDecoration::getDecorationType() { return DECORATION_GROUPBAR; } -constexpr int BAR_INDICATOR_HEIGHT = 3; -constexpr int BAR_PADDING_OUTER_VERT = 2; -constexpr int BAR_TEXT_PAD = 2; -constexpr int BAR_HORIZONTAL_PADDING = 2; - // void CHyprGroupBarDecoration::updateWindow(CWindow* pWindow) { - damageEntire(); - - const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(pWindow->m_iWorkspaceID); - - const auto WORKSPACEOFFSET = PWORKSPACE && !pWindow->m_bPinned ? PWORKSPACE->m_vRenderOffset.vec() : Vector2D(); - - static auto* const PRENDERTITLES = &g_pConfigManager->getConfigValuePtr("group:groupbar:render_titles")->intValue; - static auto* const PTITLEFONTSIZE = &g_pConfigManager->getConfigValuePtr("group:groupbar:font_size")->intValue; - - if (pWindow->m_vRealPosition.vec() + WORKSPACEOFFSET != m_vLastWindowPos || pWindow->m_vRealSize.vec() != m_vLastWindowSize) { - // we draw 3px above the window's border with 3px - - const int BORDERSIZE = pWindow->getRealBorderSize(); - - m_seExtents.topLeft = Vector2D(0, BORDERSIZE + BAR_PADDING_OUTER_VERT * 2 + BAR_INDICATOR_HEIGHT + (*PRENDERTITLES ? *PTITLEFONTSIZE : 0) + 2); - m_seExtents.bottomRight = Vector2D(); - - m_vLastWindowPos = pWindow->m_vRealPosition.vec() + WORKSPACEOFFSET; - m_vLastWindowSize = pWindow->m_vRealSize.vec(); - - invalidateTextures(); - } - if (!m_pWindow->m_sGroupData.pNextWindow) { - m_pWindow->m_vDecosToRemove.push_back(this); + m_pWindow->removeWindowDeco(this); return; } @@ -70,15 +60,14 @@ void CHyprGroupBarDecoration::updateWindow(CWindow* pWindow) { damageEntire(); if (m_dwGroupMembers.size() == 0) { - m_pWindow->m_vDecosToRemove.push_back(this); + m_pWindow->removeWindowDeco(this); return; } } void CHyprGroupBarDecoration::damageEntire() { - 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_seExtents.topLeft.y}; - g_pHyprRenderer->damageBox(&dm); + auto box = assignedBoxGlobal(); + g_pHyprRenderer->damageBox(&box); } void CHyprGroupBarDecoration::draw(CMonitor* pMonitor, float a, const Vector2D& offset) { @@ -94,13 +83,19 @@ void CHyprGroupBarDecoration::draw(CMonitor* pMonitor, float a, const Vector2D& if (!m_pWindow->m_sSpecialRenderData.decorate) return; - m_fBarWidth = (m_vLastWindowSize.x - BAR_HORIZONTAL_PADDING * (barsToDraw - 1)) / barsToDraw; + const auto ASSIGNEDBOX = assignedBoxGlobal(); + + m_fBarWidth = (ASSIGNEDBOX.w - BAR_HORIZONTAL_PADDING * (barsToDraw - 1)) / barsToDraw; + + const auto DESIREDHEIGHT = BORDERSIZE + BAR_PADDING_OUTER_VERT * 2 + BAR_INDICATOR_HEIGHT + (*PRENDERTITLES ? *PTITLEFONTSIZE : 0) + 2; + if (DESIREDHEIGHT != ASSIGNEDBOX.h) + g_pDecorationPositioner->repositionDeco(this); int xoff = 0; for (int i = 0; i < barsToDraw; ++i) { - CBox rect = {m_vLastWindowPos.x + xoff - pMonitor->vecPosition.x + offset.x, - m_vLastWindowPos.y - BAR_PADDING_OUTER_VERT - BORDERSIZE - BAR_INDICATOR_HEIGHT - pMonitor->vecPosition.y + offset.y, m_fBarWidth, BAR_INDICATOR_HEIGHT}; + 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}; if (rect.width <= 0 || rect.height <= 0) break; @@ -123,6 +118,9 @@ void CHyprGroupBarDecoration::draw(CMonitor* pMonitor, float a, const Vector2D& // render title if necessary if (*PRENDERTITLES) { + CBox rect = {ASSIGNEDBOX.x + xoff - pMonitor->vecPosition.x + offset.x, ASSIGNEDBOX.y - pMonitor->vecPosition.y + offset.y + BAR_PADDING_OUTER_VERT, m_fBarWidth, + ASSIGNEDBOX.h - BAR_INDICATOR_HEIGHT - BAR_PADDING_OUTER_VERT * 2}; + CTitleTex* pTitleTex = textureFromTitle(m_dwGroupMembers[i]->m_szTitle); if (!pTitleTex) @@ -131,17 +129,15 @@ void CHyprGroupBarDecoration::draw(CMonitor* pMonitor, float a, const Vector2D& Vector2D{m_fBarWidth * pMonitor->scale, (*PTITLEFONTSIZE + 2 * BAR_TEXT_PAD) * pMonitor->scale})) .get(); - rect.height = (*PTITLEFONTSIZE + 2 * BAR_TEXT_PAD) * 0.8 * pMonitor->scale; - - rect.y -= rect.height; - rect.width = m_fBarWidth * pMonitor->scale; - refreshGradients(); - if (*PGRADIENTS) - g_pHyprOpenGL->renderTexture((m_dwGroupMembers[i] == g_pCompositor->m_pLastWindow ? m_tGradientActive : m_tGradientInactive), &rect, 1.0); + if (*PGRADIENTS) { + CBox rect2 = rect; + rect2.scale(pMonitor->scale); + g_pHyprOpenGL->renderTexture((m_dwGroupMembers[i] == g_pCompositor->m_pLastWindow ? m_tGradientActive : m_tGradientInactive), &rect2, 1.0); + } - rect.y -= (*PTITLEFONTSIZE + 2 * BAR_TEXT_PAD) * 0.2 * pMonitor->scale; + rect.y = ASSIGNEDBOX.y + ASSIGNEDBOX.h / 2.0 - (*PTITLEFONTSIZE + 2 * BAR_TEXT_PAD) / 2.0; rect.height = (*PTITLEFONTSIZE + 2 * BAR_TEXT_PAD) * pMonitor->scale; g_pHyprOpenGL->renderTexture(pTitleTex->tex, &rect, 1.f); @@ -154,12 +150,6 @@ void CHyprGroupBarDecoration::draw(CMonitor* pMonitor, float a, const Vector2D& invalidateTextures(); } -SWindowDecorationExtents CHyprGroupBarDecoration::getWindowDecorationReservedArea() { - static auto* const PRENDERTITLES = &g_pConfigManager->getConfigValuePtr("group:groupbar:render_titles")->intValue; - static auto* const PTITLEFONTSIZE = &g_pConfigManager->getConfigValuePtr("group:groupbar:font_size")->intValue; - return SWindowDecorationExtents{{0, BAR_INDICATOR_HEIGHT + BAR_PADDING_OUTER_VERT * 2 + (*PRENDERTITLES ? *PTITLEFONTSIZE : 0)}, {}}; -} - CTitleTex* CHyprGroupBarDecoration::textureFromTitle(const std::string& title) { for (auto& tex : m_sTitleTexs.titleTexs) { if (tex->szContent == title) @@ -307,7 +297,7 @@ bool CHyprGroupBarDecoration::onEndWindowDragOnDeco(CWindow* pDraggedWindow, con if (!pDraggedWindow->canBeGroupedInto(m_pWindow)) return true; - const float BARRELATIVEX = pos.x - m_vLastWindowPos.x - m_fBarWidth / 2; + const float BARRELATIVEX = pos.x - assignedBoxGlobal().x - m_fBarWidth / 2; const int WINDOWINDEX = BARRELATIVEX < 0 ? -1 : (BARRELATIVEX) / (m_fBarWidth + BAR_HORIZONTAL_PADDING); CWindow* pWindowInsertAfter = m_pWindow->getGroupWindowByIndex(WINDOWINDEX); @@ -363,7 +353,7 @@ void CHyprGroupBarDecoration::onMouseButtonOnDeco(const Vector2D& pos, wlr_point if (e->state != WLR_BUTTON_PRESSED) return; - const float BARRELATIVEX = pos.x - m_vLastWindowPos.x; + const float BARRELATIVEX = pos.x - assignedBoxGlobal().x; const int WINDOWINDEX = (BARRELATIVEX) / (m_fBarWidth + BAR_HORIZONTAL_PADDING); if (BARRELATIVEX - (m_fBarWidth + BAR_HORIZONTAL_PADDING) * WINDOWINDEX > m_fBarWidth) { @@ -382,7 +372,7 @@ void CHyprGroupBarDecoration::onMouseButtonOnDeco(const Vector2D& pos, wlr_point } void CHyprGroupBarDecoration::onBeginWindowDragOnDeco(const Vector2D& pos) { - const float BARRELATIVEX = pos.x - m_vLastWindowPos.x; + const float BARRELATIVEX = pos.x - assignedBoxGlobal().x; const int WINDOWINDEX = (BARRELATIVEX) / (m_fBarWidth + BAR_HORIZONTAL_PADDING); if (BARRELATIVEX - (m_fBarWidth + BAR_HORIZONTAL_PADDING) * WINDOWINDEX > m_fBarWidth) @@ -411,4 +401,9 @@ eDecorationLayer CHyprGroupBarDecoration::getDecorationLayer() { uint64_t CHyprGroupBarDecoration::getDecorationFlags() { return DECORATION_ALLOWS_MOUSE_INPUT; +} + +CBox CHyprGroupBarDecoration::assignedBoxGlobal() { + CBox box = m_bAssignedBox; + return box.translate(g_pDecorationPositioner->getEdgeDefinedPoint(DECORATION_EDGE_TOP, m_pWindow)); } \ No newline at end of file diff --git a/src/render/decorations/CHyprGroupBarDecoration.hpp b/src/render/decorations/CHyprGroupBarDecoration.hpp index 569fda21..52439942 100644 --- a/src/render/decorations/CHyprGroupBarDecoration.hpp +++ b/src/render/decorations/CHyprGroupBarDecoration.hpp @@ -21,35 +21,34 @@ class CHyprGroupBarDecoration : public IHyprWindowDecoration { CHyprGroupBarDecoration(CWindow*); virtual ~CHyprGroupBarDecoration(); - virtual SWindowDecorationExtents getWindowDecorationExtents(); + virtual SDecorationPositioningInfo getPositioningInfo(); - virtual void draw(CMonitor*, float a, const Vector2D& offset); + virtual void onPositioningReply(const SDecorationPositioningReply& reply); - virtual eDecorationType getDecorationType(); + virtual void draw(CMonitor*, float a, const Vector2D& offset); - virtual void updateWindow(CWindow*); + virtual eDecorationType getDecorationType(); - virtual void damageEntire(); + virtual void updateWindow(CWindow*); - virtual SWindowDecorationExtents getWindowDecorationReservedArea(); + virtual void damageEntire(); - virtual void onBeginWindowDragOnDeco(const Vector2D&); + virtual void onBeginWindowDragOnDeco(const Vector2D&); - virtual bool onEndWindowDragOnDeco(CWindow* pDraggedWindow, const Vector2D&); + virtual bool onEndWindowDragOnDeco(CWindow* pDraggedWindow, const Vector2D&); - virtual void onMouseButtonOnDeco(const Vector2D&, wlr_pointer_button_event*); + virtual void onMouseButtonOnDeco(const Vector2D&, wlr_pointer_button_event*); - virtual eDecorationLayer getDecorationLayer(); + virtual eDecorationLayer getDecorationLayer(); - virtual uint64_t getDecorationFlags(); + virtual uint64_t getDecorationFlags(); private: SWindowDecorationExtents m_seExtents; - CWindow* m_pWindow = nullptr; + CBox m_bAssignedBox = {0}; - Vector2D m_vLastWindowPos; - Vector2D m_vLastWindowSize; + CWindow* m_pWindow = nullptr; std::deque m_dwGroupMembers; @@ -60,6 +59,8 @@ class CHyprGroupBarDecoration : public IHyprWindowDecoration { void refreshGradients(); + CBox assignedBoxGlobal(); + struct STitleTexs { // STitleTexs* overriden = nullptr; // TODO: make shit shared in-group to decrease VRAM usage. std::deque> titleTexs; diff --git a/src/render/decorations/DecorationPositioner.cpp b/src/render/decorations/DecorationPositioner.cpp new file mode 100644 index 00000000..5a8a4275 --- /dev/null +++ b/src/render/decorations/DecorationPositioner.cpp @@ -0,0 +1,277 @@ +#include "DecorationPositioner.hpp" +#include "../../Compositor.hpp" + +CDecorationPositioner::CDecorationPositioner() { + g_pHookSystem->hookDynamic("closeWindow", [this](void* call, SCallbackInfo& info, std::any data) { + auto* const PWINDOW = std::any_cast(data); + this->onWindowUnmap(PWINDOW); + }); +} + +Vector2D CDecorationPositioner::getEdgeDefinedPoint(uint32_t edges, CWindow* pWindow) { + const bool TOP = edges & DECORATION_EDGE_TOP; + const bool BOTTOM = edges & DECORATION_EDGE_BOTTOM; + const bool LEFT = edges & DECORATION_EDGE_LEFT; + const bool RIGHT = edges & DECORATION_EDGE_RIGHT; + + const int EDGESNO = TOP + BOTTOM + LEFT + RIGHT; + + if (EDGESNO == 0 || EDGESNO > 2) { + Debug::log(ERR, "getEdgeDefinedPoint: invalid number of edges"); + return {}; + } + + CBox wb = pWindow->getWindowMainSurfaceBox(); + const auto BORDERSIZE = pWindow->getRealBorderSize(); + wb.expand(BORDERSIZE); + + if (EDGESNO == 1) { + if (TOP) + return wb.pos() + Vector2D{wb.size().x / 2.0, 0}; + else if (BOTTOM) + return wb.pos() + Vector2D{wb.size().x / 2.0, wb.size().y}; + else if (LEFT) + return wb.pos() + Vector2D{0, wb.size().y / 2.0}; + else if (RIGHT) + return wb.pos() + Vector2D{wb.size().x, wb.size().y / 2.0}; + UNREACHABLE(); + } else { + if (TOP && LEFT) + return wb.pos(); + if (TOP && RIGHT) + return wb.pos() + Vector2D{wb.size().x, 0}; + if (BOTTOM && RIGHT) + return wb.pos() + wb.size(); + if (BOTTOM && LEFT) + return wb.pos() + Vector2D{0, wb.size().y}; + UNREACHABLE(); + } + UNREACHABLE(); + return {}; +} + +void CDecorationPositioner::uncacheDecoration(IHyprWindowDecoration* deco) { + std::erase_if(m_vWindowPositioningDatas, [&](const auto& data) { return data->pDecoration == deco; }); +} + +void CDecorationPositioner::repositionDeco(IHyprWindowDecoration* deco) { + uncacheDecoration(deco); + onWindowUpdate(deco->m_pWindow); +} + +CDecorationPositioner::SWindowPositioningData* CDecorationPositioner::getDataFor(IHyprWindowDecoration* pDecoration, CWindow* pWindow) { + auto it = std::find_if(m_vWindowPositioningDatas.begin(), m_vWindowPositioningDatas.end(), [&](const auto& el) { return el->pDecoration == pDecoration; }); + + if (it != m_vWindowPositioningDatas.end()) + return it->get(); + + const auto DATA = m_vWindowPositioningDatas.emplace_back(std::make_unique(pWindow, pDecoration)).get(); + + DATA->positioningInfo = pDecoration->getPositioningInfo(); + + return DATA; +} + +void CDecorationPositioner::onWindowUpdate(CWindow* pWindow) { + if (!g_pCompositor->windowValidMapped(pWindow)) + return; + + auto* const WINDOWDATA = &m_mWindowDatas[pWindow]; + + // + std::vector datas; + for (auto& wd : pWindow->m_dWindowDecorations) { + datas.push_back(getDataFor(wd.get(), pWindow)); + } + + if (WINDOWDATA->lastWindowSize == pWindow->m_vRealSize.vec() /* position not changed */ + && + std::all_of(m_vWindowPositioningDatas.begin(), m_vWindowPositioningDatas.end(), [pWindow](const auto& data) { return pWindow != data->pWindow || !data->needsReposition; }) + /* all window datas are either not for this window or don't need a reposition */ + ) + return; + + WINDOWDATA->lastWindowSize = pWindow->m_vRealSize.vec(); + const bool EPHEMERAL = pWindow->m_vRealSize.isBeingAnimated(); + + std::sort(datas.begin(), datas.end(), [](const auto& a, const auto& b) { return a->positioningInfo.priority > b->positioningInfo.priority; }); + + CBox wb = pWindow->getWindowMainSurfaceBox(); + const auto BORDERSIZE = pWindow->getRealBorderSize(); + wb.expand(BORDERSIZE); + + // calc reserved + float reservedXL = 0, reservedYT = 0, reservedXR = 0, reservedYB = 0; + for (size_t i = 0; i < datas.size(); ++i) { + auto* const wd = datas[i]; + + if (!wd->positioningInfo.reserved) + continue; + + const bool TOP = wd->positioningInfo.edges & DECORATION_EDGE_TOP; + const bool BOTTOM = wd->positioningInfo.edges & DECORATION_EDGE_BOTTOM; + const bool LEFT = wd->positioningInfo.edges & DECORATION_EDGE_LEFT; + const bool RIGHT = wd->positioningInfo.edges & DECORATION_EDGE_RIGHT; + + if (LEFT) + reservedXL += wd->positioningInfo.desiredExtents.topLeft.x; + if (RIGHT) + reservedXR += wd->positioningInfo.desiredExtents.bottomRight.x; + if (TOP) + reservedYT += wd->positioningInfo.desiredExtents.topLeft.y; + if (BOTTOM) + reservedYB += wd->positioningInfo.desiredExtents.bottomRight.y; + } + + WINDOWDATA->reserved = {{reservedXL, reservedYT}, {reservedXR, reservedYB}}; + + float stickyOffsetXL = 0, stickyOffsetYT = 0, stickyOffsetXR = 0, stickyOffsetYB = 0; + + for (size_t i = 0; i < datas.size(); ++i) { + auto* const wd = datas[i]; + + wd->needsReposition = false; + + const bool TOP = wd->positioningInfo.edges & DECORATION_EDGE_TOP; + const bool BOTTOM = wd->positioningInfo.edges & DECORATION_EDGE_BOTTOM; + const bool LEFT = wd->positioningInfo.edges & DECORATION_EDGE_LEFT; + const bool RIGHT = wd->positioningInfo.edges & DECORATION_EDGE_RIGHT; + const int EDGESNO = TOP + BOTTOM + LEFT + RIGHT; + + if (wd->positioningInfo.policy == DECORATION_POSITION_ABSOLUTE) { + if (LEFT) + stickyOffsetXL += wd->positioningInfo.desiredExtents.topLeft.x; + if (RIGHT) + stickyOffsetXR += wd->positioningInfo.desiredExtents.bottomRight.x; + if (TOP) + stickyOffsetYT += wd->positioningInfo.desiredExtents.topLeft.y; + if (BOTTOM) + stickyOffsetYB += wd->positioningInfo.desiredExtents.bottomRight.y; + + wd->lastReply = {}; + wd->pDecoration->onPositioningReply({}); + continue; + } + + if (wd->positioningInfo.policy == DECORATION_POSITION_STICKY) { + if (EDGESNO != 1) { + wd->lastReply = {}; + wd->pDecoration->onPositioningReply({}); + continue; + } + + auto desiredSize = 0; + if (LEFT) + desiredSize = wd->positioningInfo.desiredExtents.topLeft.x; + else if (RIGHT) + desiredSize = wd->positioningInfo.desiredExtents.bottomRight.x; + else if (TOP) + desiredSize = wd->positioningInfo.desiredExtents.topLeft.y; + else + desiredSize = wd->positioningInfo.desiredExtents.bottomRight.y; + + const auto EDGEPOINT = getEdgeDefinedPoint(wd->positioningInfo.edges, pWindow); + + Vector2D pos, size; + + if (LEFT) { + pos = wb.pos() - EDGEPOINT - Vector2D{stickyOffsetXL, 0}; + pos.x -= desiredSize; + size = {desiredSize, wb.size().y}; + + stickyOffsetXL += desiredSize; + } else if (RIGHT) { + pos = wb.pos() + Vector2D{wb.size().x, 0} - EDGEPOINT + Vector2D{stickyOffsetXR, 0}; + size = {desiredSize, wb.size().y}; + + stickyOffsetXR += desiredSize; + } else if (TOP) { + pos = wb.pos() - EDGEPOINT - Vector2D{0, stickyOffsetYT}; + pos.y -= desiredSize; + size = {wb.size().x, desiredSize}; + + stickyOffsetYT += desiredSize; + } else { + pos = wb.pos() + Vector2D{0, wb.size().y} - EDGEPOINT - Vector2D{0, stickyOffsetYB}; + size = {wb.size().x, desiredSize}; + + stickyOffsetYB += desiredSize; + } + + wd->lastReply = {{pos, size}, EPHEMERAL}; + wd->pDecoration->onPositioningReply(wd->lastReply); + + continue; + } else { + // invalid + wd->lastReply = {}; + wd->pDecoration->onPositioningReply({}); + continue; + } + } + + WINDOWDATA->extents = {{stickyOffsetXL + reservedXL, stickyOffsetYT + reservedYT}, {stickyOffsetXR + reservedXR, stickyOffsetYB + reservedYB}}; +} + +void CDecorationPositioner::onWindowUnmap(CWindow* pWindow) { + std::erase_if(m_vWindowPositioningDatas, [&](const auto& data) { return data->pWindow == pWindow; }); + m_mWindowDatas.erase(pWindow); +} + +SWindowDecorationExtents CDecorationPositioner::getWindowDecorationReserved(CWindow* pWindow) { + return m_mWindowDatas[pWindow].reserved; +} + +SWindowDecorationExtents CDecorationPositioner::getWindowDecorationExtents(CWindow* pWindow, bool inputOnly) { + if (!inputOnly) + return m_mWindowDatas[pWindow].extents; + + // TODO: + return m_mWindowDatas[pWindow].extents; +} + +CBox CDecorationPositioner::getBoxWithIncludedDecos(CWindow* pWindow) { + CBox accum = pWindow->getWindowMainSurfaceBox().expand(pWindow->getRealBorderSize()); + + for (auto& data : m_vWindowPositioningDatas) { + if (data->pWindow != pWindow) + continue; + + if (!(data->pDecoration->getDecorationFlags() & DECORATION_PART_OF_MAIN_WINDOW)) + continue; + + CBox decoBox; + + if (data->positioningInfo.policy == DECORATION_POSITION_ABSOLUTE) { + decoBox = data->pWindow->getWindowMainSurfaceBox(); + decoBox.addExtents(data->positioningInfo.desiredExtents); + } else { + decoBox = data->lastReply.assignedGeometry; + const auto EDGEPOINT = getEdgeDefinedPoint(data->positioningInfo.edges, pWindow); + decoBox.translate(EDGEPOINT); + } + + SWindowDecorationExtents extentsToAdd; + + if (decoBox.x < accum.x) + extentsToAdd.topLeft.x = accum.x - decoBox.x; + if (decoBox.y < accum.y) + extentsToAdd.topLeft.y = accum.y - decoBox.y; + if (decoBox.x + decoBox.w > accum.x + accum.w) + extentsToAdd.bottomRight.x = accum.x + accum.w - (decoBox.x + decoBox.w); + if (decoBox.y + decoBox.h > accum.y + accum.h) + extentsToAdd.bottomRight.y = accum.y + accum.h - (decoBox.y + decoBox.h); + + accum.addExtents(extentsToAdd); + } + + return accum; +} + +CBox CDecorationPositioner::getWindowDecorationBox(IHyprWindowDecoration* deco) { + const auto DATA = getDataFor(deco, deco->m_pWindow); + + CBox box = DATA->lastReply.assignedGeometry; + box.translate(getEdgeDefinedPoint(DATA->positioningInfo.edges, deco->m_pWindow)); + return box; +} \ No newline at end of file diff --git a/src/render/decorations/DecorationPositioner.hpp b/src/render/decorations/DecorationPositioner.hpp new file mode 100644 index 00000000..c85bc217 --- /dev/null +++ b/src/render/decorations/DecorationPositioner.hpp @@ -0,0 +1,96 @@ +#pragma once + +#include +#include +#include +#include +#include "../../helpers/Box.hpp" + +class CWindow; +class IHyprWindowDecoration; + +enum eDecorationPositioningPolicy +{ + DECORATION_POSITION_ABSOLUTE = 0, /* Decoration does not interfere with anything else */ + DECORATION_POSITION_STICKY, /* Decoration is stuck to some edge of a window */ +}; + +enum eDecorationEdges +{ + DECORATION_EDGE_TOP = 1 << 0, + DECORATION_EDGE_BOTTOM = 1 << 1, + DECORATION_EDGE_LEFT = 1 << 2, + DECORATION_EDGE_RIGHT = 1 << 3 +}; + +/* +Request the positioner to position a decoration + +DECORATION_POSITION_ABSOLUTE: + - desiredExtents may contain the extents to be used when reserved is set. Edges has to have the edges used. +DECORATION_POSITION_STICKY: + - one edge allowed + - priority allowed + - desiredExtents contains the desired extents. Any other edge than the one selected is ignored. + - reserved is allowed +*/ +struct SDecorationPositioningInfo { + eDecorationPositioningPolicy policy = DECORATION_POSITION_ABSOLUTE; + uint32_t edges = 0; // enum eDecorationEdges + uint32_t priority = 10; // priority, decos will be evaluated high -> low + SWindowDecorationExtents desiredExtents; + bool reserved = false; // if true, geometry will use reserved area +}; + +/* +A reply from the positioner. This may be sent multiple times, if anything changes. + +DECORATION_POSITION_ABSOLUTE: + - assignedGeometry is empty +DECORATION_POSITION_STICKY: + - assignedGeometry is relative to the edge's center point + - ephemeral is sent +*/ +struct SDecorationPositioningReply { + CBox assignedGeometry; + bool ephemeral = false; // if true, means it's a result of an animation and will change soon. +}; + +class CDecorationPositioner { + public: + CDecorationPositioner(); + + Vector2D getEdgeDefinedPoint(uint32_t edges, CWindow* pWindow); + + // called on resize, or insert/removal of a new deco + void onWindowUpdate(CWindow* pWindow); + void uncacheDecoration(IHyprWindowDecoration* deco); + SWindowDecorationExtents getWindowDecorationReserved(CWindow* pWindow); + SWindowDecorationExtents getWindowDecorationExtents(CWindow* pWindow, bool inputOnly = false); + CBox getBoxWithIncludedDecos(CWindow* pWindow); + void repositionDeco(IHyprWindowDecoration* deco); + CBox getWindowDecorationBox(IHyprWindowDecoration* deco); + + private: + struct SWindowPositioningData { + CWindow* pWindow = nullptr; + IHyprWindowDecoration* pDecoration = nullptr; + SDecorationPositioningInfo positioningInfo; + SDecorationPositioningReply lastReply; + bool needsReposition = true; + }; + + struct SWindowData { + Vector2D lastWindowSize = {}; + SWindowDecorationExtents reserved = {}; + SWindowDecorationExtents extents = {}; + }; + + std::unordered_map m_mWindowDatas; + std::vector> m_vWindowPositioningDatas; + + SWindowPositioningData* getDataFor(IHyprWindowDecoration* pDecoration, CWindow* pWindow); + void onWindowUnmap(CWindow* pWindow); +}; + +inline std::unique_ptr g_pDecorationPositioner; \ No newline at end of file diff --git a/src/render/decorations/IHyprWindowDecoration.cpp b/src/render/decorations/IHyprWindowDecoration.cpp index d2b9b0f9..7a4906b5 100644 --- a/src/render/decorations/IHyprWindowDecoration.cpp +++ b/src/render/decorations/IHyprWindowDecoration.cpp @@ -8,23 +8,6 @@ IHyprWindowDecoration::IHyprWindowDecoration(CWindow* pWindow) { IHyprWindowDecoration::~IHyprWindowDecoration() {} -SWindowDecorationExtents IHyprWindowDecoration::getWindowDecorationReservedArea() { - return SWindowDecorationExtents{}; -} - -CRegion IHyprWindowDecoration::getWindowDecorationRegion() { - const SWindowDecorationExtents RESERVED = getWindowDecorationReservedArea(); - const int BORDERSIZE = m_pWindow->getRealBorderSize(); - return CRegion(m_pWindow->m_vRealPosition.vec().x - (BORDERSIZE + RESERVED.topLeft.x) * (int)(RESERVED.topLeft.x != 0), - m_pWindow->m_vRealPosition.vec().y - (BORDERSIZE + RESERVED.topLeft.y) * (int)(RESERVED.topLeft.y != 0), - m_pWindow->m_vRealSize.vec().x + (BORDERSIZE + RESERVED.topLeft.x) * (int)(RESERVED.topLeft.x != 0) + - (BORDERSIZE + RESERVED.bottomRight.x) * (int)(RESERVED.bottomRight.x != 0), - m_pWindow->m_vRealSize.vec().y + (BORDERSIZE + RESERVED.topLeft.y) * (int)(RESERVED.topLeft.y != 0) + - (BORDERSIZE + RESERVED.bottomRight.y) * (int)(RESERVED.bottomRight.y != 0)) - .subtract(CRegion(m_pWindow->m_vRealPosition.vec().x - BORDERSIZE, m_pWindow->m_vRealPosition.vec().y - BORDERSIZE, m_pWindow->m_vRealSize.vec().x + 2 * BORDERSIZE, - m_pWindow->m_vRealSize.vec().y + 2 * BORDERSIZE)); -} - void IHyprWindowDecoration::onBeginWindowDragOnDeco(const Vector2D&) { ; } diff --git a/src/render/decorations/IHyprWindowDecoration.hpp b/src/render/decorations/IHyprWindowDecoration.hpp index 47945b38..15890f44 100644 --- a/src/render/decorations/IHyprWindowDecoration.hpp +++ b/src/render/decorations/IHyprWindowDecoration.hpp @@ -2,6 +2,7 @@ #include "../../defines.hpp" #include "../../helpers/Region.hpp" +#include "DecorationPositioner.hpp" enum eDecorationType { @@ -27,36 +28,37 @@ enum eDecorationFlags class CWindow; class CMonitor; +class CDecorationPositioner; class IHyprWindowDecoration { public: IHyprWindowDecoration(CWindow*); virtual ~IHyprWindowDecoration() = 0; - virtual SWindowDecorationExtents getWindowDecorationExtents() = 0; + virtual SDecorationPositioningInfo getPositioningInfo() = 0; - virtual void draw(CMonitor*, float a, const Vector2D& offset = Vector2D()) = 0; + virtual void onPositioningReply(const SDecorationPositioningReply& reply) = 0; - virtual eDecorationType getDecorationType() = 0; + virtual void draw(CMonitor*, float a, const Vector2D& offset = Vector2D()) = 0; - virtual void updateWindow(CWindow*) = 0; + virtual eDecorationType getDecorationType() = 0; - virtual void damageEntire() = 0; + virtual void updateWindow(CWindow*) = 0; - virtual SWindowDecorationExtents getWindowDecorationReservedArea(); + virtual void damageEntire() = 0; // should be ignored by non-absolute decos - virtual CRegion getWindowDecorationRegion(); + virtual void onBeginWindowDragOnDeco(const Vector2D&); // called when the user calls the "movewindow" mouse dispatcher on the deco - virtual void onBeginWindowDragOnDeco(const Vector2D&); // called when the user calls the "movewindow" mouse dispatcher on the deco + virtual bool onEndWindowDragOnDeco(CWindow* pDraggedWindow, const Vector2D&); // returns true if the window should be placed by the layout - virtual bool onEndWindowDragOnDeco(CWindow* pDraggedWindow, const Vector2D&); // returns true if the window should be placed by the layout + virtual void onMouseButtonOnDeco(const Vector2D&, wlr_pointer_button_event*); - virtual void onMouseButtonOnDeco(const Vector2D&, wlr_pointer_button_event*); + virtual eDecorationLayer getDecorationLayer(); - virtual eDecorationLayer getDecorationLayer(); - - virtual uint64_t getDecorationFlags(); + virtual uint64_t getDecorationFlags(); private: CWindow* m_pWindow = nullptr; + + friend class CDecorationPositioner; };