decorations: Decoration Positioner (#3800)

This commit is contained in:
Vaxry 2023-11-11 14:37:17 +00:00 committed by GitHub
parent 7345b1a1ea
commit 9be6fbf5ea
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
27 changed files with 610 additions and 266 deletions

View file

@ -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<CPluginSystem>();
g_pConfigManager->handlePluginLoads();
Debug::log(LOG, "Creating the DecorationPositioner!");
g_pDecorationPositioner = std::make_unique<CDecorationPositioner>();
} 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) {

View file

@ -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()};
}
};

View file

@ -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<CHyprDropShadowDecoration>(this)); // put the shadow so it's the first deco (has to be rendered first)
addWindowDeco(std::make_unique<CHyprDropShadowDecoration>(this));
}
CWindow::~CWindow() {
@ -37,9 +37,7 @@ SWindowDecorationExtents CWindow::getFullWindowExtents() {
SWindowDecorationExtents maxExtents = {{BORDERSIZE + 2, BORDERSIZE + 2}, {BORDERSIZE + 2, BORDERSIZE + 2}};
for (auto& wd : m_dWindowDecorations) {
const auto EXTENTS = wd->getWindowDecorationExtents();
const auto EXTENTS = g_pDecorationPositioner->getWindowDecorationExtents(this);
if (EXTENTS.topLeft.x > maxExtents.topLeft.x)
maxExtents.topLeft.x = EXTENTS.topLeft.x;
@ -52,7 +50,6 @@ SWindowDecorationExtents CWindow::getFullWindowExtents() {
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,12 +141,7 @@ CBox CWindow::getWindowInputBox() {
SWindowDecorationExtents maxExtents = {{BORDERSIZE + 2, BORDERSIZE + 2}, {BORDERSIZE + 2, BORDERSIZE + 2}};
for (auto& wd : m_dWindowDecorations) {
if (!(wd->getDecorationFlags() & DECORATION_ALLOWS_MOUSE_INPUT))
continue;
const auto EXTENTS = wd->getWindowDecorationExtents();
const auto EXTENTS = g_pDecorationPositioner->getWindowDecorationExtents(this, true);
if (EXTENTS.topLeft.x > maxExtents.topLeft.x)
maxExtents.topLeft.x = EXTENTS.topLeft.x;
@ -162,7 +154,6 @@ CBox CWindow::getWindowInputBox() {
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<IHyprWindowDecoration> 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<CHyprGroupBarDecoration>(this));
updateWindowDecos();
addWindowDeco(std::make_unique<CHyprGroupBarDecoration>(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<CHyprGroupBarDecoration>(pWindow));
pWindow->addWindowDeco(std::make_unique<CHyprGroupBarDecoration>(pWindow));
if (!pWindow->m_sGroupData.pNextWindow) {
BEGINAT->m_sGroupData.pNextWindow = pWindow;

View file

@ -344,7 +344,9 @@ class CWindow {
CBox getWindowInputBox();
CBox getWindowMainSurfaceBox();
CBox getWindowIdealBoundingBoxIgnoreReserved();
void addWindowDeco(std::unique_ptr<IHyprWindowDecoration> deco);
void updateWindowDecos();
void removeWindowDeco(IHyprWindowDecoration* deco);
pid_t getPID();
IHyprWindowDecoration* getDecorationByType(eDecorationType);
void removeDecorationByType(eDecorationType);

View file

@ -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)}};
}

View file

@ -50,6 +50,9 @@ class CBox {
CBox& round();
CBox& transform(const wl_output_transform t, double w, double h);
CBox& addExtents(const SWindowDecorationExtents& e);
CBox& expand(const double& value);
SWindowDecorationExtents extentsFrom(const CBox&); // this is the big box
Vector2D middle() const;
Vector2D pos() const;

View file

@ -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<CRegion*>(&other)->pixman());
return *this;

View file

@ -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);

View file

@ -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));
}

View file

@ -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;
};

View file

@ -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<CHyprGroupBarDecoration>(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<CHyprGroupBarDecoration>(pWindow));
return;
}

View file

@ -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<CHyprGroupBarDecoration>(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<CHyprGroupBarDecoration>(pWindow));
return;
}

View file

@ -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);
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;
}

View file

@ -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<CHyprGroupBarDecoration>(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<CHyprGroupBarDecoration>(pWindow));
}
void CKeybindManager::moveWindowOutOfGroup(CWindow* pWindow, const std::string& dir) {

View file

@ -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;
}

View file

@ -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<IHyprWindowDecoration> 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;
}
}

View file

@ -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<IHyprWindowDecoration> pDecoration);
/*
Removes a window decoration

View file

@ -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;

View file

@ -2105,7 +2105,7 @@ void CHyprRenderer::setOccludedForBackLayers(CRegion& region, CWorkspace* pWorks
box.scale(PMONITOR->scale);
rg.add(&box);
rg.add(box);
}
region.subtract(rg);

View file

@ -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();
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_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

View file

@ -7,7 +7,9 @@ class CHyprDropShadowDecoration : public IHyprWindowDecoration {
CHyprDropShadowDecoration(CWindow*);
virtual ~CHyprDropShadowDecoration();
virtual SWindowDecorationExtents getWindowDecorationExtents();
virtual SDecorationPositioningInfo getPositioningInfo();
virtual void onPositioningReply(const SDecorationPositioningReply& reply);
virtual void draw(CMonitor*, float a, const Vector2D& offset);
@ -28,5 +30,5 @@ class CHyprDropShadowDecoration : public IHyprWindowDecoration {
Vector2D m_vLastWindowSize;
CBox m_bLastWindowBox = {0};
SWindowDecorationExtents m_eLastExtents = {};
CBox m_bLastWindowBoxWithDecos = {0};
};

View file

@ -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)
@ -412,3 +402,8 @@ 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));
}

View file

@ -21,7 +21,9 @@ class CHyprGroupBarDecoration : public IHyprWindowDecoration {
CHyprGroupBarDecoration(CWindow*);
virtual ~CHyprGroupBarDecoration();
virtual SWindowDecorationExtents getWindowDecorationExtents();
virtual SDecorationPositioningInfo getPositioningInfo();
virtual void onPositioningReply(const SDecorationPositioningReply& reply);
virtual void draw(CMonitor*, float a, const Vector2D& offset);
@ -31,8 +33,6 @@ class CHyprGroupBarDecoration : public IHyprWindowDecoration {
virtual void damageEntire();
virtual SWindowDecorationExtents getWindowDecorationReservedArea();
virtual void onBeginWindowDragOnDeco(const Vector2D&);
virtual bool onEndWindowDragOnDeco(CWindow* pDraggedWindow, const Vector2D&);
@ -46,10 +46,9 @@ class CHyprGroupBarDecoration : public IHyprWindowDecoration {
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;

View file

@ -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;
}

View file

@ -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;

View file

@ -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&) {
;
}

View file

@ -2,6 +2,7 @@
#include "../../defines.hpp"
#include "../../helpers/Region.hpp"
#include "DecorationPositioner.hpp"
enum eDecorationType
{
@ -27,13 +28,16 @@ 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 onPositioningReply(const SDecorationPositioningReply& reply) = 0;
virtual void draw(CMonitor*, float a, const Vector2D& offset = Vector2D()) = 0;
@ -41,11 +45,7 @@ class IHyprWindowDecoration {
virtual void updateWindow(CWindow*) = 0;
virtual void damageEntire() = 0;
virtual SWindowDecorationExtents getWindowDecorationReservedArea();
virtual CRegion getWindowDecorationRegion();
virtual void damageEntire() = 0; // should be ignored by non-absolute decos
virtual void onBeginWindowDragOnDeco(const Vector2D&); // called when the user calls the "movewindow" mouse dispatcher on the deco
@ -59,4 +59,6 @@ class IHyprWindowDecoration {
private:
CWindow* m_pWindow = nullptr;
friend class CDecorationPositioner;
};