diff --git a/src/Window.cpp b/src/Window.cpp index 5bb1738e..cc76aed2 100644 --- a/src/Window.cpp +++ b/src/Window.cpp @@ -13,4 +13,7 @@ CWindow::~CWindow() { g_pCompositor->m_pLastFocus = nullptr; g_pCompositor->m_pLastWindow = nullptr; } + + for (auto& wd : m_dWindowDecorations) + delete wd; } \ No newline at end of file diff --git a/src/Window.hpp b/src/Window.hpp index 253600b2..0dd105bb 100644 --- a/src/Window.hpp +++ b/src/Window.hpp @@ -4,6 +4,8 @@ #include "events/Events.hpp" #include "helpers/SubsurfaceTree.hpp" #include "helpers/AnimatedVariable.hpp" +#include "render/decorations/IHyprWindowDecoration.hpp" +#include struct SWindowSpecialRenderData { float alpha = 1.f; @@ -88,6 +90,9 @@ public: // For hidden windows and stuff bool m_bHidden = false; + // Window decorations + std::deque m_dWindowDecorations; + // Special render data, rules, etc SWindowSpecialRenderData m_sSpecialRenderData; SWindowAdditionalConfigData m_sAdditionalConfigData; diff --git a/src/layout/DwindleLayout.cpp b/src/layout/DwindleLayout.cpp index ef312abd..0f41265b 100644 --- a/src/layout/DwindleLayout.cpp +++ b/src/layout/DwindleLayout.cpp @@ -275,6 +275,10 @@ void CHyprDwindleLayout::onWindowCreated(CWindow* pWindow) { if (OPENINGON->pGroupParent) { // means we opened on a group + + // add the group deco + pWindow->m_dWindowDecorations.emplace_back(new CHyprGroupBarDecoration(pWindow)); + PNODE->pGroupParent = OPENINGON->pGroupParent; PNODE->pGroupParent->groupMembers.push_back(PNODE); PNODE->pGroupParent->groupMemberActive = PNODE->pGroupParent->groupMembers.size() - 1; @@ -693,6 +697,10 @@ void CHyprDwindleLayout::toggleWindowGroup(CWindow* pWindow) { for (auto& node : PGROUPPARENT->groupMembers) { node->pGroupParent = nullptr; node->pWindow->m_cRealBorderColor.setValueAndWarp(INACTIVEBORDERCOL); // no anim here because they pop in + + for (auto& wd : node->pWindow->m_dWindowDecorations) { + wd->updateWindow(node->pWindow); + } } PGROUPPARENT->groupMembers.clear(); @@ -725,6 +733,8 @@ void CHyprDwindleLayout::toggleWindowGroup(CWindow* pWindow) { c->pGroupParent = PPARENT; c->pWindow->m_cRealBorderColor = GROUPINACTIVEBORDERCOL; + c->pWindow->m_dWindowDecorations.push_back(new CHyprGroupBarDecoration(c->pWindow)); + if (c->pWindow == g_pCompositor->m_pLastWindow) c->pWindow->m_cRealBorderColor = CColor(g_pConfigManager->getInt("dwindle:col.group_border_active")); } @@ -735,6 +745,31 @@ void CHyprDwindleLayout::toggleWindowGroup(CWindow* pWindow) { } } +std::deque CHyprDwindleLayout::getGroupMembers(CWindow* pWindow) { + + std::deque result; + + if (!g_pCompositor->windowExists(pWindow)) + return result; // reject with empty + + // get the node + const auto PNODE = getNodeFromWindow(pWindow); + + if (!PNODE) + return result; // reject with empty + + const auto PGROUPPARENT = PNODE->pGroupParent; + + if (!PGROUPPARENT) + return result; // reject with empty + + for (auto& node : PGROUPPARENT->groupMembers) { + result.push_back(node->pWindow); + } + + return result; +} + void CHyprDwindleLayout::switchGroupWindow(CWindow* pWindow, bool forward) { if (!g_pCompositor->windowValidMapped(pWindow)) return; // reject @@ -760,6 +795,12 @@ void CHyprDwindleLayout::switchGroupWindow(CWindow* pWindow, bool forward) { PNODE->pGroupParent->recalcSizePosRecursive(); + for (auto& gm : PNODE->pGroupParent->groupMembers) { + for (auto& deco : gm->pWindow->m_dWindowDecorations) { + deco->updateWindow(gm->pWindow); + } + } + // focus g_pCompositor->focusWindow(PNODE->pGroupParent->groupMembers[PNODE->pGroupParent->groupMemberActive]->pWindow); } @@ -850,7 +891,7 @@ void CHyprDwindleLayout::alterSplitRatioBy(CWindow* pWindow, float ratio) { PNODE->pParent->recalcSizePosRecursive(); } -void CHyprDwindleLayout::layoutMessage(SLayoutMessageHeader header, std::string message) { +std::any CHyprDwindleLayout::layoutMessage(SLayoutMessageHeader header, std::string message) { if (message == "togglegroup") toggleWindowGroup(header.pWindow); else if (message == "changegroupactivef") @@ -859,6 +900,12 @@ void CHyprDwindleLayout::layoutMessage(SLayoutMessageHeader header, std::string switchGroupWindow(header.pWindow, false); else if (message == "togglesplit") toggleSplit(header.pWindow); + else if (message == "groupinfo") { + auto res = getGroupMembers(g_pCompositor->m_pLastWindow); + return res; + } + + return ""; } void CHyprDwindleLayout::toggleSplit(CWindow* pWindow) { @@ -870,4 +917,8 @@ void CHyprDwindleLayout::toggleSplit(CWindow* pWindow) { PNODE->pParent->splitTop = !PNODE->pParent->splitTop; PNODE->pParent->recalcSizePosRecursive(); +} + +std::string CHyprDwindleLayout::getLayoutName() { + return "dwindle"; } \ No newline at end of file diff --git a/src/layout/DwindleLayout.hpp b/src/layout/DwindleLayout.hpp index 91d3a820..4abd04ef 100644 --- a/src/layout/DwindleLayout.hpp +++ b/src/layout/DwindleLayout.hpp @@ -3,6 +3,7 @@ #include "IHyprLayout.hpp" #include #include +#include "../render/decorations/CHyprGroupBarDecoration.hpp" class CHyprDwindleLayout; @@ -50,10 +51,11 @@ public: virtual void onMouseMove(const Vector2D&); virtual void onWindowCreatedFloating(CWindow*); virtual void fullscreenRequestForWindow(CWindow*); - virtual void layoutMessage(SLayoutMessageHeader, std::string); + virtual std::any layoutMessage(SLayoutMessageHeader, std::string); virtual SWindowRenderLayoutHints requestRenderHints(CWindow*); virtual void switchWindows(CWindow*, CWindow*); virtual void alterSplitRatioBy(CWindow*, float); + virtual std::string getLayoutName(); private: @@ -73,6 +75,7 @@ public: void toggleWindowGroup(CWindow*); void switchGroupWindow(CWindow*, bool forward); void toggleSplit(CWindow*); + std::deque getGroupMembers(CWindow*); friend struct SDwindleNodeData; }; \ No newline at end of file diff --git a/src/layout/IHyprLayout.hpp b/src/layout/IHyprLayout.hpp index 71f30e3d..01e3e04a 100644 --- a/src/layout/IHyprLayout.hpp +++ b/src/layout/IHyprLayout.hpp @@ -74,9 +74,10 @@ public: /* Called when a dispatcher requests a custom message - The layout is free to ignore. + The layout is free to ignore. + std::any is the reply. Can be empty. */ - virtual void layoutMessage(SLayoutMessageHeader, std::string) = 0; + virtual std::any layoutMessage(SLayoutMessageHeader, std::string) = 0; /* Required to be handled, but may return just SWindowRenderLayoutHints() @@ -96,4 +97,9 @@ public: on a window */ virtual void alterSplitRatioBy(CWindow*, float) = 0; + + /* + Called when something wants the current layout's name + */ + virtual std::string getLayoutName() = 0; }; \ No newline at end of file diff --git a/src/managers/AnimationManager.cpp b/src/managers/AnimationManager.cpp index 5c417cb2..0df6a3bf 100644 --- a/src/managers/AnimationManager.cpp +++ b/src/managers/AnimationManager.cpp @@ -140,8 +140,12 @@ void CAnimationManager::tick() { case AVARDAMAGE_ENTIRE: { g_pHyprRenderer->damageBox(&WLRBOXPREV); - if (PWINDOW) + if (PWINDOW) { g_pHyprRenderer->damageWindow(PWINDOW); + for (auto& wd : PWINDOW->m_dWindowDecorations) { + wd->updateWindow(PWINDOW); + } + } break; } case AVARDAMAGE_BORDER: { diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index fc3f5702..86ab125d 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -109,6 +109,10 @@ void CHyprRenderer::renderWindow(CWindow* pWindow, SMonitor* pMonitor, timespec* g_pHyprOpenGL->m_pCurrentWindow = pWindow; + // render window decorations first + for (auto& wd : pWindow->m_dWindowDecorations) + wd->draw(pMonitor); + wlr_surface_for_each_surface(g_pXWaylandManager->getWindowSurface(pWindow), renderSurface, &renderdata); if (pWindow->m_bIsX11) { diff --git a/src/render/decorations/CHyprGroupBarDecoration.cpp b/src/render/decorations/CHyprGroupBarDecoration.cpp new file mode 100644 index 00000000..eca14973 --- /dev/null +++ b/src/render/decorations/CHyprGroupBarDecoration.cpp @@ -0,0 +1,99 @@ +#include "CHyprGroupBarDecoration.hpp" +#include "../../Compositor.hpp" + +CHyprGroupBarDecoration::CHyprGroupBarDecoration(CWindow* pWindow) { + m_pWindow = pWindow; + updateWindow(pWindow); +} + +CHyprGroupBarDecoration::~CHyprGroupBarDecoration() { + +} + +SWindowDecorationExtents CHyprGroupBarDecoration::getWindowDecorationExtents() { + return m_seExtents; +} + +eDecorationType CHyprGroupBarDecoration::getDecorationType() { + return DECORATION_GROUPBAR; +} + +void CHyprGroupBarDecoration::updateWindow(CWindow* pWindow) { + damageEntire(); + + const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID); + + if (pWindow->m_vRealPosition.vec() != m_vLastWindowPos || pWindow->m_vRealSize.vec() != m_vLastWindowSize) { + // we draw 3px above the window's border with 3px + const auto BORDERSIZE = g_pConfigManager->getInt("general:border_size"); + + m_seExtents.topLeft = Vector2D(0, BORDERSIZE + 3 + 3); + m_seExtents.bottomRight = Vector2D(); + + m_vLastWindowPos = pWindow->m_vRealPosition.vec(); + m_vLastWindowSize = pWindow->m_vRealSize.vec(); + } + + // let's check if the window group is different. + + if (g_pLayoutManager->getCurrentLayout()->getLayoutName() != "dwindle") { + // ???? + for (auto it = pWindow->m_dWindowDecorations.begin(); it != pWindow->m_dWindowDecorations.end(); it++) { + if ((*it) == this) { + pWindow->m_dWindowDecorations.erase(it); + delete this; + return; + } + } + } + + // get the group info + SLayoutMessageHeader header; + header.pWindow = g_pCompositor->m_pLastWindow; + + m_dwGroupMembers = std::any_cast>(g_pLayoutManager->getCurrentLayout()->layoutMessage(header, "groupinfo")); + + damageEntire(); + + if (m_dwGroupMembers.size() == 0) { + // remove + for (auto it = pWindow->m_dWindowDecorations.begin(); it != pWindow->m_dWindowDecorations.end(); it++) { + if ((*it) == this) { + pWindow->m_dWindowDecorations.erase(it); + delete this; + return; + } + } + } +} + +void CHyprGroupBarDecoration::damageEntire() { + wlr_box 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); +} + +void CHyprGroupBarDecoration::draw(SMonitor* pMonitor) { + // get how many bars we will draw + int barsToDraw = m_dwGroupMembers.size(); + + if (barsToDraw < 1 || m_pWindow->m_bHidden || !g_pCompositor->windowValidMapped(m_pWindow)) + return; + + const int PAD = 2; //2px + + const int BARW = (m_vLastWindowSize.x - PAD * (barsToDraw - 1)) / barsToDraw; + + int xoff = 0; + + for (int i = 0; i < barsToDraw; ++i) { + wlr_box rect = {m_vLastWindowPos.x + xoff - pMonitor->vecPosition.x, m_vLastWindowPos.y - m_seExtents.topLeft.y - pMonitor->vecPosition.y, BARW, 3}; + + if (rect.width <= 0 || rect.height <= 0) + break; + + CColor color = m_dwGroupMembers[i] == g_pCompositor->m_pLastWindow ? CColor(g_pConfigManager->getInt("dwindle:col.group_border_active")) : CColor(g_pConfigManager->getInt("dwindle:col.group_border")); + g_pHyprOpenGL->renderRect(&rect, color); + + xoff += PAD + BARW; + } +} \ No newline at end of file diff --git a/src/render/decorations/CHyprGroupBarDecoration.hpp b/src/render/decorations/CHyprGroupBarDecoration.hpp new file mode 100644 index 00000000..74a597a6 --- /dev/null +++ b/src/render/decorations/CHyprGroupBarDecoration.hpp @@ -0,0 +1,30 @@ +#pragma once + +#include "IHyprWindowDecoration.hpp" +#include + +class CHyprGroupBarDecoration : public IHyprWindowDecoration { +public: + CHyprGroupBarDecoration(CWindow*); + virtual ~CHyprGroupBarDecoration(); + + virtual SWindowDecorationExtents getWindowDecorationExtents(); + + virtual void draw(SMonitor*); + + virtual eDecorationType getDecorationType(); + + virtual void updateWindow(CWindow*); + + virtual void damageEntire(); + +private: + SWindowDecorationExtents m_seExtents; + + CWindow* m_pWindow = nullptr; + + Vector2D m_vLastWindowPos; + Vector2D m_vLastWindowSize; + + std::deque m_dwGroupMembers; +}; \ No newline at end of file diff --git a/src/render/decorations/IHyprWindowDecoration.cpp b/src/render/decorations/IHyprWindowDecoration.cpp new file mode 100644 index 00000000..ada71985 --- /dev/null +++ b/src/render/decorations/IHyprWindowDecoration.cpp @@ -0,0 +1,7 @@ +#include "IHyprWindowDecoration.hpp" + +#include "../../Window.hpp" + +IHyprWindowDecoration::~IHyprWindowDecoration() { + +} \ No newline at end of file diff --git a/src/render/decorations/IHyprWindowDecoration.hpp b/src/render/decorations/IHyprWindowDecoration.hpp new file mode 100644 index 00000000..0815273d --- /dev/null +++ b/src/render/decorations/IHyprWindowDecoration.hpp @@ -0,0 +1,31 @@ +#pragma once + +#include "../../defines.hpp" + +enum eDecorationType { + DECORATION_NONE = -1, + DECORATION_GROUPBAR +}; + +struct SWindowDecorationExtents { + Vector2D topLeft; + Vector2D bottomRight; +}; + +class CWindow; +struct SMonitor; + +class IHyprWindowDecoration { +public: + virtual ~IHyprWindowDecoration() = 0; + + virtual SWindowDecorationExtents getWindowDecorationExtents() = 0; + + virtual void draw(SMonitor*) = 0; + + virtual eDecorationType getDecorationType() = 0; + + virtual void updateWindow(CWindow*) = 0; + + virtual void damageEntire() = 0; +}; \ No newline at end of file