layout: rethonk layouts from the ground up (#12890)

Rewrites layouts to be much smaller, and deal with much less annoying
BS. Improves the overall architecture, unifies handling of pseudotiling,
and various other improvements.
This commit is contained in:
Vaxry 2026-02-21 21:30:39 +00:00 committed by GitHub
parent 51f8849e54
commit 723870337f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
82 changed files with 8431 additions and 5527 deletions

View file

@ -2,13 +2,15 @@
#include "../../Compositor.hpp"
#include "../../config/ConfigValue.hpp"
#include "../../desktop/state/FocusState.hpp"
#include "managers/LayoutManager.hpp"
#include "../../desktop/view/Group.hpp"
#include <ranges>
#include <pango/pangocairo.h>
#include "../pass/TexPassElement.hpp"
#include "../pass/RectPassElement.hpp"
#include "../Renderer.hpp"
#include "../../managers/input/InputManager.hpp"
#include "../../layout/LayoutManager.hpp"
#include "../../layout/supplementary/DragController.hpp"
// shared things to conserve VRAM
static SP<CTexture> m_tGradientActive = makeShared<CTexture>();
@ -65,19 +67,14 @@ eDecorationType CHyprGroupBarDecoration::getDecorationType() {
//
void CHyprGroupBarDecoration::updateWindow(PHLWINDOW pWindow) {
if (m_window->m_groupData.pNextWindow.expired()) {
if (!m_window->m_group) {
m_window->removeWindowDeco(this);
return;
}
m_dwGroupMembers.clear();
PHLWINDOW head = pWindow->getGroupHead();
m_dwGroupMembers.emplace_back(head);
PHLWINDOW curr = head->m_groupData.pNextWindow.lock();
while (curr != head) {
m_dwGroupMembers.emplace_back(curr);
curr = curr->m_groupData.pNextWindow.lock();
for (const auto& w : m_window->m_group->windows()) {
m_dwGroupMembers.emplace_back(w);
}
damageEntire();
@ -158,7 +155,7 @@ void CHyprGroupBarDecoration::draw(PHLMONITOR pMonitor, float const& a) {
rect.scale(pMonitor->m_scale).round();
const bool GROUPLOCKED = m_window->getGroupHead()->m_groupData.locked || g_pKeybindManager->m_groupsLocked;
const bool GROUPLOCKED = m_window->m_group->locked() || g_pKeybindManager->m_groupsLocked;
const auto* const PCOLACTIVE = GROUPLOCKED ? GROUPCOLACTIVELOCKED : GROUPCOLACTIVE;
const auto* const PCOLINACTIVE = GROUPLOCKED ? GROUPCOLINACTIVELOCKED : GROUPCOLINACTIVE;
@ -204,6 +201,7 @@ void CHyprGroupBarDecoration::draw(PHLMONITOR pMonitor, float const& a) {
data.tex = GRADIENTTEX;
data.blur = blur;
data.box = rect;
data.a = a;
if (*PGRADIENTROUNDING) {
data.round = *PGRADIENTROUNDING;
data.roundingPower = *PGRADIENTROUNDINGPOWER;
@ -391,7 +389,7 @@ bool CHyprGroupBarDecoration::onBeginWindowDragOnDeco(const Vector2D& pos) {
static auto PSTACKED = CConfigValue<Hyprlang::INT>("group:groupbar:stacked");
static auto POUTERGAP = CConfigValue<Hyprlang::INT>("group:groupbar:gaps_out");
static auto PINNERGAP = CConfigValue<Hyprlang::INT>("group:groupbar:gaps_in");
if (m_window.lock() == m_window->m_groupData.pNextWindow.lock())
if (m_window->m_group->size() == 1)
return false;
const float BARRELATIVEX = pos.x - assignedBoxGlobal().x;
@ -404,95 +402,33 @@ bool CHyprGroupBarDecoration::onBeginWindowDragOnDeco(const Vector2D& pos) {
if (*PSTACKED && (BARRELATIVEY - (m_barHeight + *POUTERGAP) * WINDOWINDEX < *POUTERGAP))
return false;
PHLWINDOW pWindow = m_window->getGroupWindowByIndex(WINDOWINDEX);
PHLWINDOW pWindow = m_window->m_group->fromIndex(WINDOWINDEX);
// hack
g_pLayoutManager->getCurrentLayout()->onWindowRemoved(pWindow);
if (!pWindow->m_isFloating) {
const bool GROUPSLOCKEDPREV = g_pKeybindManager->m_groupsLocked;
g_pKeybindManager->m_groupsLocked = true;
g_pLayoutManager->getCurrentLayout()->onWindowCreated(pWindow);
g_pKeybindManager->m_groupsLocked = GROUPSLOCKEDPREV;
}
const auto& GROUP = m_window->m_group;
g_pInputManager->m_currentlyDraggedWindow = pWindow;
// remove the window from the group
GROUP->remove(pWindow);
// start a move drag on it
g_layoutManager->dragController()->dragBegin(pWindow->layoutTarget(), MBIND_MOVE);
if (!g_pCompositor->isWindowActive(pWindow))
Desktop::focusState()->rawWindowFocus(pWindow);
Desktop::focusState()->rawWindowFocus(pWindow, Desktop::FOCUS_REASON_CLICK);
return true;
}
bool CHyprGroupBarDecoration::onEndWindowDragOnDeco(const Vector2D& pos, PHLWINDOW pDraggedWindow) {
static auto PSTACKED = CConfigValue<Hyprlang::INT>("group:groupbar:stacked");
static auto PDRAGINTOGROUP = CConfigValue<Hyprlang::INT>("group:drag_into_group");
static auto PMERGEFLOATEDINTOTILEDONGROUPBAR = CConfigValue<Hyprlang::INT>("group:merge_floated_into_tiled_on_groupbar");
static auto PMERGEGROUPSONGROUPBAR = CConfigValue<Hyprlang::INT>("group:merge_groups_on_groupbar");
static auto POUTERGAP = CConfigValue<Hyprlang::INT>("group:groupbar:gaps_out");
static auto PINNERGAP = CConfigValue<Hyprlang::INT>("group:groupbar:gaps_in");
const bool FLOATEDINTOTILED = !m_window->m_isFloating && !pDraggedWindow->m_draggingTiled;
const bool FLOATEDINTOTILED = !m_window->m_isFloating && !g_layoutManager->dragController()->draggingTiled();
g_pInputManager->m_wasDraggingWindow = false;
if (!pDraggedWindow->canBeGroupedInto(m_window.lock()) || (*PDRAGINTOGROUP != 1 && *PDRAGINTOGROUP != 2) || (FLOATEDINTOTILED && !*PMERGEFLOATEDINTOTILEDONGROUPBAR) ||
(!*PMERGEGROUPSONGROUPBAR && pDraggedWindow->m_groupData.pNextWindow.lock() && m_window->m_groupData.pNextWindow.lock())) {
g_pInputManager->m_wasDraggingWindow = true;
if (!pDraggedWindow->canBeGroupedInto(m_window->m_group) || (*PDRAGINTOGROUP != 1 && *PDRAGINTOGROUP != 2) || (FLOATEDINTOTILED && !*PMERGEFLOATEDINTOTILEDONGROUPBAR) ||
(!*PMERGEGROUPSONGROUPBAR && pDraggedWindow->m_group))
return false;
}
const float BARRELATIVE = *PSTACKED ? pos.y - assignedBoxGlobal().y - (m_barHeight + *POUTERGAP) / 2 : pos.x - assignedBoxGlobal().x - m_barWidth / 2;
const float BARSIZE = *PSTACKED ? m_barHeight + *POUTERGAP : m_barWidth + *PINNERGAP;
const int WINDOWINDEX = BARRELATIVE < 0 ? -1 : BARRELATIVE / BARSIZE;
PHLWINDOW pWindowInsertAfter = m_window->getGroupWindowByIndex(WINDOWINDEX);
PHLWINDOW pWindowInsertEnd = pWindowInsertAfter->m_groupData.pNextWindow.lock();
PHLWINDOW pDraggedHead = pDraggedWindow->m_groupData.pNextWindow.lock() ? pDraggedWindow->getGroupHead() : pDraggedWindow;
if (!pDraggedWindow->m_groupData.pNextWindow.expired()) {
// stores group data
std::vector<PHLWINDOW> members;
PHLWINDOW curr = pDraggedHead;
const bool WASLOCKED = pDraggedHead->m_groupData.locked;
do {
members.push_back(curr);
curr = curr->m_groupData.pNextWindow.lock();
} while (curr != members[0]);
// removes all windows
for (const PHLWINDOW& w : members) {
w->m_groupData.pNextWindow.reset();
w->m_groupData.head = false;
w->m_groupData.locked = false;
g_pLayoutManager->getCurrentLayout()->onWindowRemoved(w);
}
// restores the group
for (auto it = members.begin(); it != members.end(); ++it) {
(*it)->m_isFloating = pWindowInsertAfter->m_isFloating; // match the floating state of group members
*(*it)->m_realSize = pWindowInsertAfter->m_realSize->goal(); // match the size of group members
*(*it)->m_realPosition = pWindowInsertAfter->m_realPosition->goal(); // match the position of group members
if (std::next(it) != members.end())
(*it)->m_groupData.pNextWindow = *std::next(it);
else
(*it)->m_groupData.pNextWindow = members[0];
}
members[0]->m_groupData.head = true;
members[0]->m_groupData.locked = WASLOCKED;
} else
g_pLayoutManager->getCurrentLayout()->onWindowRemoved(pDraggedWindow);
pDraggedWindow->m_isFloating = pWindowInsertAfter->m_isFloating; // match the floating state of the window
pWindowInsertAfter->insertWindowToGroup(pDraggedWindow);
if (WINDOWINDEX == -1)
std::swap(pDraggedHead->m_groupData.head, pWindowInsertEnd->m_groupData.head);
m_window->setGroupCurrent(pDraggedWindow);
pDraggedWindow->applyGroupRules();
pDraggedWindow->updateWindowDecos();
g_pLayoutManager->getCurrentLayout()->recalculateWindow(pDraggedWindow);
m_window->m_group->add(pDraggedWindow);
if (!pDraggedWindow->getDecorationByType(DECORATION_GROUPBAR))
pDraggedWindow->addWindowDeco(makeUnique<CHyprGroupBarDecoration>(pDraggedWindow));
@ -519,7 +455,7 @@ bool CHyprGroupBarDecoration::onMouseButtonOnDeco(const Vector2D& pos, const IPo
if (e.state == WL_POINTER_BUTTON_STATE_PRESSED)
pressedCursorPos = pos;
else if (e.state == WL_POINTER_BUTTON_STATE_RELEASED && pressedCursorPos == pos)
g_pXWaylandManager->sendCloseWindow(m_window->getGroupWindowByIndex(WINDOWINDEX));
g_pXWaylandManager->sendCloseWindow(m_window->m_group->fromIndex(WINDOWINDEX));
return true;
}
@ -532,17 +468,17 @@ bool CHyprGroupBarDecoration::onMouseButtonOnDeco(const Vector2D& pos, const IPo
const auto STACKPAD = *PSTACKED && (BARRELATIVEY - (m_barHeight + *POUTERGAP) * WINDOWINDEX < *POUTERGAP);
if (TABPAD || STACKPAD) {
if (!g_pCompositor->isWindowActive(m_window.lock()))
Desktop::focusState()->rawWindowFocus(m_window.lock());
Desktop::focusState()->rawWindowFocus(m_window.lock(), Desktop::FOCUS_REASON_CLICK);
return true;
}
PHLWINDOW pWindow = m_window->getGroupWindowByIndex(WINDOWINDEX);
PHLWINDOW pWindow = m_window->m_group->fromIndex(WINDOWINDEX);
if (pWindow != m_window)
pWindow->setGroupCurrent(pWindow);
pWindow->m_group->setCurrent(pWindow);
if (!g_pCompositor->isWindowActive(pWindow) && *PFOLLOWMOUSE != 3)
Desktop::focusState()->rawWindowFocus(pWindow);
Desktop::focusState()->rawWindowFocus(pWindow, Desktop::FOCUS_REASON_CLICK);
if (pWindow->m_isFloating)
g_pCompositor->changeWindowZOrder(pWindow, true);
@ -553,13 +489,13 @@ bool CHyprGroupBarDecoration::onMouseButtonOnDeco(const Vector2D& pos, const IPo
bool CHyprGroupBarDecoration::onScrollOnDeco(const Vector2D& pos, const IPointer::SAxisEvent e) {
static auto PGROUPBARSCROLLING = CConfigValue<Hyprlang::INT>("group:groupbar:scrolling");
if (!*PGROUPBARSCROLLING || m_window->m_groupData.pNextWindow.expired())
if (!*PGROUPBARSCROLLING || !m_window->m_group)
return false;
if (e.delta > 0)
m_window->setGroupCurrent(m_window->m_groupData.pNextWindow.lock());
m_window->m_group->moveCurrent(true);
else
m_window->setGroupCurrent(m_window->getGroupPrevious());
m_window->m_group->moveCurrent(false);
return true;
}

View file

@ -1,7 +1,7 @@
#include "DecorationPositioner.hpp"
#include "../../desktop/view/Window.hpp"
#include "../../managers/HookSystemManager.hpp"
#include "../../managers/LayoutManager.hpp"
#include "../../layout/target/Target.hpp"
CDecorationPositioner::CDecorationPositioner() {
static auto P = g_pHookSystem->hookDynamic("closeWindow", [this](void* call, SCallbackInfo& info, std::any data) {
@ -278,7 +278,7 @@ void CDecorationPositioner::onWindowUpdate(PHLWINDOW pWindow) {
if (WINDOWDATA->extents != SBoxExtents{{stickyOffsetXL + reservedXL, stickyOffsetYT + reservedYT}, {stickyOffsetXR + reservedXR, stickyOffsetYB + reservedYB}}) {
WINDOWDATA->extents = {{stickyOffsetXL + reservedXL, stickyOffsetYT + reservedYT}, {stickyOffsetXR + reservedXR, stickyOffsetYB + reservedYB}};
g_pLayoutManager->getCurrentLayout()->recalculateWindow(pWindow);
pWindow->layoutTarget()->recalc();
}
}