diff options
| author | Vaxry <43317083+vaxerski@users.noreply.github.com> | 2023-11-11 14:37:17 +0000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-11-11 14:37:17 +0000 |
| commit | 9be6fbf5eae8c4b902b818881a4dc34f87bb630d (patch) | |
| tree | a5d440cd8f5d57a659df670548263eba1cd93a0a /src/render | |
| parent | 7345b1a1ea2671953df48c8a18524a7e556d383c (diff) | |
decorations: Decoration Positioner (#3800)
Diffstat (limited to 'src/render')
| -rw-r--r-- | src/render/OpenGL.cpp | 4 | ||||
| -rw-r--r-- | src/render/Renderer.cpp | 2 | ||||
| -rw-r--r-- | src/render/decorations/CHyprDropShadowDecoration.cpp | 64 | ||||
| -rw-r--r-- | src/render/decorations/CHyprDropShadowDecoration.hpp | 18 | ||||
| -rw-r--r-- | src/render/decorations/CHyprGroupBarDecoration.cpp | 105 | ||||
| -rw-r--r-- | src/render/decorations/CHyprGroupBarDecoration.hpp | 29 | ||||
| -rw-r--r-- | src/render/decorations/DecorationPositioner.cpp | 277 | ||||
| -rw-r--r-- | src/render/decorations/DecorationPositioner.hpp | 96 | ||||
| -rw-r--r-- | src/render/decorations/IHyprWindowDecoration.cpp | 17 | ||||
| -rw-r--r-- | src/render/decorations/IHyprWindowDecoration.hpp | 28 |
10 files changed, 487 insertions, 153 deletions
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,17 +10,16 @@ CHyprDropShadowDecoration::~CHyprDropShadowDecoration() { updateWindow(m_pWindow); } -SWindowDecorationExtents CHyprDropShadowDecoration::getWindowDecorationExtents() { - static auto* const PSHADOWS = &g_pConfigManager->getConfigValuePtr("decoration:drop_shadow")->intValue; - - if (*PSHADOWS != 1) - return {{}, {}}; +eDecorationType CHyprDropShadowDecoration::getDecorationType() { + return DECORATION_SHADOW; +} - return m_seExtents; +SDecorationPositioningInfo CHyprDropShadowDecoration::getPositioningInfo() { + return {DECORATION_POSITION_ABSOLUTE}; } -eDecorationType CHyprDropShadowDecoration::getDecorationType() { - return DECORATION_SHADOW; +void CHyprDropShadowDecoration::onPositioningReply(const SDecorationPositioningReply& reply) { + updateWindow(m_pWindow); } void CHyprDropShadowDecoration::damageEntire() { @@ -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; + + // get window box + windowBox.translate(-pMonitor->vecPosition).scale(pMonitor->scale).round(); + withDecos.translate(-pMonitor->vecPosition).scale(pMonitor->scale).round(); - windowBox.translate(-pMonitor->vecPosition).scale(pMonitor->scale); - windowBox.round(); + auto scaledDecoExtents = withDecos.extentsFrom(windowBox).round(); - windowBox.addExtents(SWindowDecorationExtents{m_eLastExtents * pMonitor->scale}.floor()).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<CWindow*> 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<std::unique_ptr<CTitleTex>> 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<CWindow*>(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<CDecorationPositioner::SWindowPositioningData>(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<CDecorationPositioner::SWindowPositioningData*> 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 <cstdint> +#include <memory> +#include <vector> +#include <unordered_map> +#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<CWindow*, SWindowData> m_mWindowDatas; + std::vector<std::unique_ptr<SWindowPositioningData>> m_vWindowPositioningDatas; + + SWindowPositioningData* getDataFor(IHyprWindowDecoration* pDecoration, CWindow* pWindow); + void onWindowUnmap(CWindow* pWindow); +}; + +inline std::unique_ptr<CDecorationPositioner> 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; }; |
