summaryrefslogtreecommitdiff
path: root/src/desktop/view/Window.cpp
diff options
context:
space:
mode:
authorVaxry <43317083+vaxerski@users.noreply.github.com>2026-02-21 21:30:39 +0000
committerGitHub <noreply@github.com>2026-02-21 21:30:39 +0000
commit723870337f299d4c80aa0048144f3a1ca1c885bd (patch)
treeca3279ae5dbc841f676c64d2f58f895de13cd3bf /src/desktop/view/Window.cpp
parent51f8849e541f0a8150ac3a43fa928c1e299daf18 (diff)
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.
Diffstat (limited to 'src/desktop/view/Window.cpp')
-rw-r--r--src/desktop/view/Window.cpp544
1 files changed, 133 insertions, 411 deletions
diff --git a/src/desktop/view/Window.cpp b/src/desktop/view/Window.cpp
index 7e1131b1..d94ee79a 100644
--- a/src/desktop/view/Window.cpp
+++ b/src/desktop/view/Window.cpp
@@ -3,6 +3,8 @@
#include <hyprutils/animation/AnimatedVariable.hpp>
#include <re2/re2.h>
+#include "Group.hpp"
+
#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
#include <sys/types.h>
#include <sys/sysctl.h>
@@ -37,12 +39,15 @@
#include "../../helpers/math/Expression.hpp"
#include "../../managers/XWaylandManager.hpp"
#include "../../render/Renderer.hpp"
-#include "../../managers/LayoutManager.hpp"
#include "../../managers/HookSystemManager.hpp"
#include "../../managers/EventManager.hpp"
#include "../../managers/input/InputManager.hpp"
#include "../../managers/PointerManager.hpp"
#include "../../managers/animation/DesktopAnimationManager.hpp"
+#include "../../layout/space/Space.hpp"
+#include "../../layout/LayoutManager.hpp"
+#include "../../layout/target/WindowTarget.hpp"
+#include "../../layout/target/WindowGroupTarget.hpp"
#include <hyprutils/string/String.hpp>
@@ -57,6 +62,9 @@ using namespace Desktop::View;
static uint64_t windowIDCounter = 0x18000000;
//
+#define COMMA ,
+//
+
PHLWINDOW CWindow::create(SP<CXWaylandSurface> surface) {
PHLWINDOW pWindow = SP<CWindow>(new CWindow(surface));
@@ -79,6 +87,8 @@ PHLWINDOW CWindow::create(SP<CXWaylandSurface> surface) {
pWindow->addWindowDeco(makeUnique<CHyprDropShadowDecoration>(pWindow));
pWindow->addWindowDeco(makeUnique<CHyprBorderDecoration>(pWindow));
+ pWindow->m_target = Layout::CWindowTarget::create(pWindow);
+
return pWindow;
}
@@ -104,6 +114,8 @@ PHLWINDOW CWindow::create(SP<CXDGSurfaceResource> resource) {
pWindow->addWindowDeco(makeUnique<CHyprDropShadowDecoration>(pWindow));
pWindow->addWindowDeco(makeUnique<CHyprBorderDecoration>(pWindow));
+ pWindow->m_target = Layout::CWindowTarget::create(pWindow);
+
pWindow->wlSurface()->assign(pWindow->m_xdgSurface->m_surface.lock(), pWindow);
return pWindow;
@@ -263,23 +275,24 @@ CBox CWindow::getWindowIdealBoundingBoxIgnoreReserved() {
return CBox{sc<int>(POS.x), sc<int>(POS.y), sc<int>(SIZE.x), sc<int>(SIZE.y)};
}
- // get work area
- const auto WORKAREA = g_pLayoutManager->getCurrentLayout()->workAreaOnWorkspace(m_workspace);
- const auto RESERVED = CReservedArea{PMONITOR->logicalBox(), WORKAREA};
+ // fucker fucking fuck
+ const auto WORKAREA = m_workspace->m_space->workArea();
+ const auto& RESERVED = PMONITOR->m_reservedArea;
- if (DELTALESSTHAN(POS.y - PMONITOR->m_position.y, RESERVED.top(), 1)) {
- POS.y = PMONITOR->m_position.y;
- SIZE.y += RESERVED.top();
- }
- if (DELTALESSTHAN(POS.x - PMONITOR->m_position.x, RESERVED.left(), 1)) {
- POS.x = PMONITOR->m_position.x;
+ if (DELTALESSTHAN(POS.x, WORKAREA.x, 1)) {
+ POS.x -= RESERVED.left();
SIZE.x += RESERVED.left();
}
- if (DELTALESSTHAN(POS.x + SIZE.x - PMONITOR->m_position.x, PMONITOR->m_size.x - RESERVED.right(), 1))
+ if (DELTALESSTHAN(POS.y, WORKAREA.y, 1)) {
+ POS.y -= RESERVED.top();
+ SIZE.y += RESERVED.top();
+ }
+
+ if (DELTALESSTHAN(POS.x + SIZE.x, WORKAREA.x + WORKAREA.width, 1))
SIZE.x += RESERVED.right();
- if (DELTALESSTHAN(POS.y + SIZE.y - PMONITOR->m_position.y, PMONITOR->m_size.y - RESERVED.bottom(), 1))
+ if (DELTALESSTHAN(POS.y + SIZE.y, WORKAREA.y + WORKAREA.height, 1))
SIZE.y += RESERVED.bottom();
return CBox{sc<int>(POS.x), sc<int>(POS.y), sc<int>(SIZE.x), sc<int>(SIZE.y)};
@@ -357,14 +370,18 @@ void CWindow::addWindowDeco(UP<IHyprWindowDecoration> deco) {
m_windowDecorations.emplace_back(std::move(deco));
g_pDecorationPositioner->forceRecalcFor(m_self.lock());
updateWindowDecos();
- g_pLayoutManager->getCurrentLayout()->recalculateWindow(m_self.lock());
+
+ if (layoutTarget())
+ layoutTarget()->recalc();
}
void CWindow::removeWindowDeco(IHyprWindowDecoration* deco) {
m_decosToRemove.push_back(deco);
g_pDecorationPositioner->forceRecalcFor(m_self.lock());
updateWindowDecos();
- g_pLayoutManager->getCurrentLayout()->recalculateWindow(m_self.lock());
+
+ if (layoutTarget())
+ layoutTarget()->recalc();
}
void CWindow::uncacheWindowDecos() {
@@ -495,11 +512,9 @@ void CWindow::moveToWorkspace(PHLWORKSPACE pWorkspace) {
OLDWORKSPACE->updateWindows();
OLDWORKSPACE->updateWindowData();
- g_pLayoutManager->getCurrentLayout()->recalculateMonitor(OLDWORKSPACE->monitorID());
pWorkspace->updateWindows();
pWorkspace->updateWindowData();
- g_pLayoutManager->getCurrentLayout()->recalculateMonitor(monitorID());
g_pCompositor->updateAllWindowsAnimatedDecorationValues();
@@ -591,7 +606,7 @@ void CWindow::onUnmap() {
m_workspace->updateWindows();
m_workspace->updateWindowData();
}
- g_pLayoutManager->getCurrentLayout()->recalculateMonitor(monitorID());
+
g_pCompositor->updateAllWindowsAnimatedDecorationValues();
m_workspace.reset();
@@ -723,311 +738,6 @@ bool CWindow::hasPopupAt(const Vector2D& pos) {
return popup && popup->wlSurface()->resource();
}
-void CWindow::applyGroupRules() {
- if ((m_groupRules & GROUP_SET && m_firstMap) || m_groupRules & GROUP_SET_ALWAYS)
- createGroup();
-
- if (m_groupData.pNextWindow.lock() && ((m_groupRules & GROUP_LOCK && m_firstMap) || m_groupRules & GROUP_LOCK_ALWAYS))
- getGroupHead()->m_groupData.locked = true;
-}
-
-void CWindow::createGroup() {
- if (m_groupData.deny) {
- Log::logger->log(Log::DEBUG, "createGroup: window:{:x},title:{} is denied as a group, ignored", rc<uintptr_t>(this), this->m_title);
- return;
- }
-
- if (m_groupData.pNextWindow.expired()) {
- m_groupData.pNextWindow = m_self;
- m_groupData.head = true;
- m_groupData.locked = false;
- m_groupData.deny = false;
-
- addWindowDeco(makeUnique<CHyprGroupBarDecoration>(m_self.lock()));
-
- if (m_workspace) {
- m_workspace->updateWindows();
- m_workspace->updateWindowData();
- }
- g_pLayoutManager->getCurrentLayout()->recalculateMonitor(monitorID());
- g_pCompositor->updateAllWindowsAnimatedDecorationValues();
-
- g_pEventManager->postEvent(SHyprIPCEvent{.event = "togglegroup", .data = std::format("1,{:x}", rc<uintptr_t>(this))});
- }
-
- m_ruleApplicator->propertiesChanged(Desktop::Rule::RULE_PROP_GROUP | Desktop::Rule::RULE_PROP_ON_WORKSPACE);
-}
-
-void CWindow::destroyGroup() {
- if (m_groupData.pNextWindow == m_self) {
- if (m_groupRules & GROUP_SET_ALWAYS) {
- Log::logger->log(Log::DEBUG, "destoryGroup: window:{:x},title:{} has rule [group set always], ignored", rc<uintptr_t>(this), this->m_title);
- return;
- }
- m_groupData.pNextWindow.reset();
- m_groupData.head = false;
- updateWindowDecos();
- if (m_workspace) {
- m_workspace->updateWindows();
- m_workspace->updateWindowData();
- }
- g_pLayoutManager->getCurrentLayout()->recalculateMonitor(monitorID());
- g_pCompositor->updateAllWindowsAnimatedDecorationValues();
-
- g_pEventManager->postEvent(SHyprIPCEvent{.event = "togglegroup", .data = std::format("0,{:x}", rc<uintptr_t>(this))});
- m_ruleApplicator->propertiesChanged(Desktop::Rule::RULE_PROP_GROUP | Desktop::Rule::RULE_PROP_ON_WORKSPACE);
- return;
- }
-
- std::string addresses;
- PHLWINDOW curr = m_self.lock();
- std::vector<PHLWINDOW> members;
- do {
- const auto PLASTWIN = curr;
- curr = curr->m_groupData.pNextWindow.lock();
- PLASTWIN->m_groupData.pNextWindow.reset();
- curr->setHidden(false);
- members.push_back(curr);
-
- addresses += std::format("{:x},", rc<uintptr_t>(curr.get()));
- } while (curr.get() != this);
-
- for (auto const& w : members) {
- if (w->m_groupData.head)
- g_pLayoutManager->getCurrentLayout()->onWindowRemoved(curr);
- w->m_groupData.head = false;
- }
-
- const bool GROUPSLOCKEDPREV = g_pKeybindManager->m_groupsLocked;
- g_pKeybindManager->m_groupsLocked = true;
- for (auto const& w : members) {
- g_pLayoutManager->getCurrentLayout()->onWindowCreated(w);
- w->m_ruleApplicator->propertiesChanged(Desktop::Rule::RULE_PROP_GROUP | Desktop::Rule::RULE_PROP_ON_WORKSPACE);
- w->updateWindowDecos();
- }
- g_pKeybindManager->m_groupsLocked = GROUPSLOCKEDPREV;
-
- if (m_workspace) {
- m_workspace->updateWindows();
- m_workspace->updateWindowData();
- }
- g_pLayoutManager->getCurrentLayout()->recalculateMonitor(monitorID());
- g_pCompositor->updateAllWindowsAnimatedDecorationValues();
-
- if (!addresses.empty())
- addresses.pop_back();
-
- m_ruleApplicator->propertiesChanged(Desktop::Rule::RULE_PROP_GROUP | Desktop::Rule::RULE_PROP_ON_WORKSPACE);
- g_pEventManager->postEvent(SHyprIPCEvent{.event = "togglegroup", .data = std::format("0,{}", addresses)});
-}
-
-PHLWINDOW CWindow::getGroupHead() {
- PHLWINDOW curr = m_self.lock();
- while (!curr->m_groupData.head)
- curr = curr->m_groupData.pNextWindow.lock();
- return curr;
-}
-
-PHLWINDOW CWindow::getGroupTail() {
- PHLWINDOW curr = m_self.lock();
- while (!curr->m_groupData.pNextWindow->m_groupData.head)
- curr = curr->m_groupData.pNextWindow.lock();
- return curr;
-}
-
-PHLWINDOW CWindow::getGroupCurrent() {
- PHLWINDOW curr = m_self.lock();
- while (curr->isHidden())
- curr = curr->m_groupData.pNextWindow.lock();
- return curr;
-}
-
-int CWindow::getGroupSize() {
- int size = 1;
- PHLWINDOW curr = m_self.lock();
- while (curr->m_groupData.pNextWindow != m_self) {
- curr = curr->m_groupData.pNextWindow.lock();
- size++;
- }
- return size;
-}
-
-bool CWindow::canBeGroupedInto(PHLWINDOW pWindow) {
- static auto ALLOWGROUPMERGE = CConfigValue<Hyprlang::INT>("group:merge_groups_on_drag");
- bool isGroup = m_groupData.pNextWindow;
- bool disallowDragIntoGroup = g_pInputManager->m_wasDraggingWindow && isGroup && !sc<bool>(*ALLOWGROUPMERGE);
- return !g_pKeybindManager->m_groupsLocked // global group lock disengaged
- && ((m_groupRules & GROUP_INVADE && m_firstMap) // window ignore local group locks, or
- || (!pWindow->getGroupHead()->m_groupData.locked // target unlocked
- && !(m_groupData.pNextWindow.lock() && getGroupHead()->m_groupData.locked))) // source unlocked or isn't group
- && !m_groupData.deny // source is not denied entry
- && !(m_groupRules & GROUP_BARRED && m_firstMap) // group rule doesn't prevent adding window
- && !disallowDragIntoGroup; // config allows groups to be merged
-}
-
-PHLWINDOW CWindow::getGroupWindowByIndex(int index) {
- const int SIZE = getGroupSize();
- index = ((index % SIZE) + SIZE) % SIZE;
- PHLWINDOW curr = getGroupHead();
- while (index > 0) {
- curr = curr->m_groupData.pNextWindow.lock();
- index--;
- }
- return curr;
-}
-
-bool CWindow::hasInGroup(PHLWINDOW w) {
- PHLWINDOW curr = m_groupData.pNextWindow.lock();
- while (curr && curr != m_self) {
- if (curr == w)
- return true;
- curr = curr->m_groupData.pNextWindow.lock();
- }
- return false;
-}
-
-void CWindow::setGroupCurrent(PHLWINDOW pWindow) {
- PHLWINDOW curr = m_groupData.pNextWindow.lock();
- bool isMember = false;
- while (curr.get() != this) {
- if (curr == pWindow) {
- isMember = true;
- break;
- }
- curr = curr->m_groupData.pNextWindow.lock();
- }
-
- if (!isMember && pWindow.get() != this)
- return;
-
- const auto PCURRENT = getGroupCurrent();
- const bool FULLSCREEN = PCURRENT->isFullscreen();
- const auto WORKSPACE = PCURRENT->m_workspace;
- const auto MODE = PCURRENT->m_fullscreenState.internal;
-
- const auto CURRENTISFOCUS = PCURRENT == Desktop::focusState()->window();
-
- const auto PWINDOWSIZE = PCURRENT->m_realSize->value();
- const auto PWINDOWPOS = PCURRENT->m_realPosition->value();
- const auto PWINDOWSIZEGOAL = PCURRENT->m_realSize->goal();
- const auto PWINDOWPOSGOAL = PCURRENT->m_realPosition->goal();
- const auto PWINDOWLASTFLOATINGSIZE = PCURRENT->m_lastFloatingSize;
- const auto PWINDOWLASTFLOATINGPOSITION = PCURRENT->m_lastFloatingPosition;
-
- if (FULLSCREEN)
- g_pCompositor->setWindowFullscreenInternal(PCURRENT, FSMODE_NONE);
-
- PCURRENT->setHidden(true);
- pWindow->setHidden(false); // can remove m_pLastWindow
-
- g_pLayoutManager->getCurrentLayout()->replaceWindowDataWith(PCURRENT, pWindow);
-
- if (PCURRENT->m_isFloating) {
- pWindow->m_realPosition->setValueAndWarp(PWINDOWPOSGOAL);
- pWindow->m_realSize->setValueAndWarp(PWINDOWSIZEGOAL);
- pWindow->sendWindowSize();
- }
-
- pWindow->m_realPosition->setValue(PWINDOWPOS);
- pWindow->m_realSize->setValue(PWINDOWSIZE);
-
- if (FULLSCREEN)
- g_pCompositor->setWindowFullscreenInternal(pWindow, MODE);
-
- pWindow->m_lastFloatingSize = PWINDOWLASTFLOATINGSIZE;
- pWindow->m_lastFloatingPosition = PWINDOWLASTFLOATINGPOSITION;
-
- g_pCompositor->updateAllWindowsAnimatedDecorationValues();
-
- if (CURRENTISFOCUS)
- Desktop::focusState()->rawWindowFocus(pWindow);
-
- g_pHyprRenderer->damageWindow(pWindow);
-
- pWindow->m_ruleApplicator->propertiesChanged(Desktop::Rule::RULE_PROP_GROUP | Desktop::Rule::RULE_PROP_ON_WORKSPACE);
- m_ruleApplicator->propertiesChanged(Desktop::Rule::RULE_PROP_GROUP | Desktop::Rule::RULE_PROP_ON_WORKSPACE);
- pWindow->updateWindowDecos();
-}
-
-void CWindow::insertWindowToGroup(PHLWINDOW pWindow) {
- const auto BEGINAT = m_self.lock();
- const auto ENDAT = m_groupData.pNextWindow.lock();
-
- if (!pWindow->m_groupData.pNextWindow.lock()) {
- BEGINAT->m_groupData.pNextWindow = pWindow;
- pWindow->m_groupData.pNextWindow = ENDAT;
- pWindow->m_groupData.head = false;
- pWindow->addWindowDeco(makeUnique<CHyprGroupBarDecoration>(pWindow));
- return;
- }
-
- const auto SHEAD = pWindow->getGroupHead();
- const auto STAIL = pWindow->getGroupTail();
-
- SHEAD->m_groupData.head = false;
- BEGINAT->m_groupData.pNextWindow = SHEAD;
- STAIL->m_groupData.pNextWindow = ENDAT;
-
- pWindow->m_ruleApplicator->propertiesChanged(Desktop::Rule::RULE_PROP_GROUP | Desktop::Rule::RULE_PROP_ON_WORKSPACE);
- m_ruleApplicator->propertiesChanged(Desktop::Rule::RULE_PROP_GROUP | Desktop::Rule::RULE_PROP_ON_WORKSPACE);
- pWindow->updateWindowDecos();
-}
-
-PHLWINDOW CWindow::getGroupPrevious() {
- PHLWINDOW curr = m_groupData.pNextWindow.lock();
-
- while (curr != m_self && curr->m_groupData.pNextWindow != m_self)
- curr = curr->m_groupData.pNextWindow.lock();
-
- return curr;
-}
-
-void CWindow::switchWithWindowInGroup(PHLWINDOW pWindow) {
- if (!m_groupData.pNextWindow.lock() || !pWindow->m_groupData.pNextWindow.lock())
- return;
-
- if (m_groupData.pNextWindow.lock() == pWindow) { // A -> this -> pWindow -> B >> A -> pWindow -> this -> B
- getGroupPrevious()->m_groupData.pNextWindow = pWindow;
- m_groupData.pNextWindow = pWindow->m_groupData.pNextWindow;
- pWindow->m_groupData.pNextWindow = m_self;
-
- } else if (pWindow->m_groupData.pNextWindow == m_self) { // A -> pWindow -> this -> B >> A -> this -> pWindow -> B
- pWindow->getGroupPrevious()->m_groupData.pNextWindow = m_self;
- pWindow->m_groupData.pNextWindow = m_groupData.pNextWindow;
- m_groupData.pNextWindow = pWindow;
-
- } else { // A -> this -> B | C -> pWindow -> D >> A -> pWindow -> B | C -> this -> D
- std::swap(m_groupData.pNextWindow, pWindow->m_groupData.pNextWindow);
- std::swap(getGroupPrevious()->m_groupData.pNextWindow, pWindow->getGroupPrevious()->m_groupData.pNextWindow);
- }
-
- std::swap(m_groupData.head, pWindow->m_groupData.head);
- std::swap(m_groupData.locked, pWindow->m_groupData.locked);
-
- pWindow->m_ruleApplicator->propertiesChanged(Desktop::Rule::RULE_PROP_GROUP | Desktop::Rule::RULE_PROP_ON_WORKSPACE);
- m_ruleApplicator->propertiesChanged(Desktop::Rule::RULE_PROP_GROUP | Desktop::Rule::RULE_PROP_ON_WORKSPACE);
- pWindow->updateWindowDecos();
-}
-
-void CWindow::updateGroupOutputs() {
- if (m_groupData.pNextWindow.expired())
- return;
-
- PHLWINDOW curr = m_groupData.pNextWindow.lock();
-
- const auto WS = m_workspace;
-
- while (curr.get() != this) {
- curr->m_monitor = m_monitor;
- curr->moveToWorkspace(WS);
-
- *curr->m_realPosition = m_realPosition->goal();
- *curr->m_realSize = m_realSize->goal();
-
- curr = curr->m_groupData.pNextWindow.lock();
- }
-}
-
Vector2D CWindow::middle() {
return m_realPosition->goal() + m_realSize->goal() / 2.f;
}
@@ -1148,7 +858,7 @@ void CWindow::setAnimationsToMove() {
void CWindow::onWorkspaceAnimUpdate() {
// clip box for animated offsets
- if (!m_isFloating || m_pinned || isFullscreen() || m_draggingTiled) {
+ if (!m_isFloating || m_pinned || isFullscreen()) {
m_floatingOffset = Vector2D(0, 0);
return;
}
@@ -1326,7 +1036,7 @@ void CWindow::activate(bool force) {
if (m_isFloating)
g_pCompositor->changeWindowZOrder(m_self.lock(), true);
- Desktop::focusState()->fullWindowFocus(m_self.lock());
+ Desktop::focusState()->fullWindowFocus(m_self.lock(), FOCUS_REASON_DESKTOP_STATE_CHANGE);
warpCursor();
}
@@ -1378,7 +1088,8 @@ void CWindow::onUpdateMeta() {
if (m_self == Desktop::focusState()->window()) { // if it's the active, let's post an event to update others
g_pEventManager->postEvent(SHyprIPCEvent{.event = "activewindow", .data = m_class + "," + m_title});
g_pEventManager->postEvent(SHyprIPCEvent{.event = "activewindowv2", .data = std::format("{:x}", rc<uintptr_t>(this))});
- EMIT_HOOK_EVENT("activeWindow", m_self.lock());
+
+ // no need for a hook event
}
Log::logger->log(Log::DEBUG, "Window {:x} set title to {}", rc<uintptr_t>(this), m_title);
@@ -1392,7 +1103,8 @@ void CWindow::onUpdateMeta() {
if (m_self == Desktop::focusState()->window()) { // if it's the active, let's post an event to update others
g_pEventManager->postEvent(SHyprIPCEvent{.event = "activewindow", .data = m_class + "," + m_title});
g_pEventManager->postEvent(SHyprIPCEvent{.event = "activewindowv2", .data = std::format("{:x}", rc<uintptr_t>(this))});
- EMIT_HOOK_EVENT("activeWindow", m_self.lock());
+
+ // no need for a hook event
}
Log::logger->log(Log::DEBUG, "Window {:x} set class to {}", rc<uintptr_t>(this), m_class);
@@ -1472,7 +1184,7 @@ void CWindow::onX11ConfigureRequest(CBox box) {
g_pHyprRenderer->damageWindow(m_self.lock());
- if (!m_isFloating || isFullscreen() || g_pInputManager->m_currentlyDraggedWindow == m_self) {
+ if (!m_isFloating || isFullscreen() || g_layoutManager->dragController()->target() == m_self) {
sendWindowSize(true);
g_pInputManager->refocus();
g_pHyprRenderer->damageWindow(m_self.lock());
@@ -1689,20 +1401,17 @@ void CWindow::setContentType(NContentType::eContentType contentType) {
}
void CWindow::deactivateGroupMembers() {
- auto curr = getGroupHead();
- while (curr) {
- if (curr != m_self.lock()) {
+ if (!m_group)
+ return;
+ for (const auto& w : m_group->windows()) {
+ if (w != m_self.lock()) {
// we don't want to deactivate unfocused xwayland windows
// because X is weird, keep the behavior for wayland windows
// also its not really needed for xwayland windows
// ref: #9760 #9294
- if (!curr->m_isX11 && curr->m_xdgSurface && curr->m_xdgSurface->m_toplevel)
- curr->m_xdgSurface->m_toplevel->setActive(false);
+ if (!w->m_isX11 && w->m_xdgSurface && w->m_xdgSurface->m_toplevel)
+ w->m_xdgSurface->m_toplevel->setActive(false);
}
-
- curr = curr->m_groupData.pNextWindow.lock();
- if (curr == getGroupHead())
- break;
}
}
@@ -1827,21 +1536,13 @@ void CWindow::updateDecorationValues() {
const bool IS_SHADOWED_BY_MODAL = m_xdgSurface && m_xdgSurface->m_toplevel && m_xdgSurface->m_toplevel->anyChildModal();
- // border
- const auto RENDERDATA = g_pLayoutManager->getCurrentLayout()->requestRenderHints(m_self.lock());
- if (RENDERDATA.isBorderGradient)
- setBorderColor(*RENDERDATA.borderGradient);
- else {
- const bool GROUPLOCKED = m_groupData.pNextWindow.lock() ? getGroupHead()->m_groupData.locked : false;
- if (m_self == Desktop::focusState()->window()) {
- const auto* const ACTIVECOLOR =
- !m_groupData.pNextWindow.lock() ? (!m_groupData.deny ? ACTIVECOL : NOGROUPACTIVECOL) : (GROUPLOCKED ? GROUPACTIVELOCKEDCOL : GROUPACTIVECOL);
- setBorderColor(m_ruleApplicator->activeBorderColor().valueOr(*ACTIVECOLOR));
- } else {
- const auto* const INACTIVECOLOR =
- !m_groupData.pNextWindow.lock() ? (!m_groupData.deny ? INACTIVECOL : NOGROUPINACTIVECOL) : (GROUPLOCKED ? GROUPINACTIVELOCKEDCOL : GROUPINACTIVECOL);
- setBorderColor(m_ruleApplicator->inactiveBorderColor().valueOr(*INACTIVECOLOR));
- }
+ const bool GROUPLOCKED = m_group ? m_group->locked() : false;
+ if (m_self == Desktop::focusState()->window()) {
+ const auto* const ACTIVECOLOR = !m_group ? (!(m_groupRules & GROUP_DENY) ? ACTIVECOL : NOGROUPACTIVECOL) : (GROUPLOCKED ? GROUPACTIVELOCKEDCOL : GROUPACTIVECOL);
+ setBorderColor(m_ruleApplicator->activeBorderColor().valueOr(*ACTIVECOLOR));
+ } else {
+ const auto* const INACTIVECOLOR = !m_group ? (!(m_groupRules & GROUP_DENY) ? INACTIVECOL : NOGROUPINACTIVECOL) : (GROUPLOCKED ? GROUPINACTIVELOCKEDCOL : GROUPINACTIVECOL);
+ setBorderColor(m_ruleApplicator->inactiveBorderColor().valueOr(*INACTIVECOLOR));
}
// opacity
@@ -1929,6 +1630,7 @@ void CWindow::mapWindow() {
static auto PDIMSTRENGTH = CConfigValue<Hyprlang::FLOAT>("decoration:dim_strength");
static auto PNEWTAKESOVERFS = CConfigValue<Hyprlang::INT>("misc:on_focus_under_fullscreen");
static auto PINITIALWSTRACKING = CConfigValue<Hyprlang::INT>("misc:initial_workspace_tracking");
+ static auto PAUTOGROUP = CConfigValue<Hyprlang::INT>("group:auto_group");
const auto LAST_FOCUS_WINDOW = Desktop::focusState()->window();
const bool IS_LAST_IN_FS = LAST_FOCUS_WINDOW ? LAST_FOCUS_WINDOW->m_fullscreenState.internal != FSMODE_NONE : false;
@@ -2053,8 +1755,8 @@ void CWindow::mapWindow() {
requestedFSMonitor = MONITOR_INVALID;
}
- m_isFloating = m_ruleApplicator->static_.floating.value_or(m_isFloating);
- m_isPseudotiled = m_ruleApplicator->static_.pseudo.value_or(m_isPseudotiled);
+ m_isFloating = m_ruleApplicator->static_.floating.value_or(m_isFloating);
+ m_target->setPseudo(m_ruleApplicator->static_.pseudo.value_or(m_target->isPseudo()));
m_noInitialFocus = m_ruleApplicator->static_.noInitialFocus.value_or(m_noInitialFocus);
m_pinned = m_ruleApplicator->static_.pin.value_or(m_pinned);
@@ -2109,7 +1811,7 @@ void CWindow::mapWindow() {
} else if (v == "barred") {
m_groupRules |= Desktop::View::GROUP_BARRED;
} else if (v == "deny") {
- m_groupData.deny = true;
+ m_groupRules |= Desktop::View::GROUP_DENY;
} else if (v == "override") {
// Clear existing rules
m_groupRules = Desktop::View::GROUP_OVERRIDE;
@@ -2213,9 +1915,9 @@ void CWindow::mapWindow() {
m_isFloating = true;
if (PWORKSPACE->m_defaultPseudo) {
- m_isPseudotiled = true;
CBox desiredGeometry = g_pXWaylandManager->getGeometryForWindow(m_self.lock());
- m_pseudoSize = Vector2D(desiredGeometry.width, desiredGeometry.height);
+ m_target->setPseudoSize(Vector2D{desiredGeometry.width, desiredGeometry.height});
+ m_target->setPseudo(true);
}
updateWindowData();
@@ -2230,43 +1932,29 @@ void CWindow::mapWindow() {
g_pEventManager->postEvent(SHyprIPCEvent{"openwindow", std::format("{:x},{},{},{}", m_self.lock(), PWORKSPACE->m_name, m_class, m_title)});
EMIT_HOOK_EVENT("openWindowEarly", m_self.lock());
- if (m_isFloating) {
- g_pLayoutManager->getCurrentLayout()->onWindowCreated(m_self.lock());
- m_createdOverFullscreen = true;
-
- if (!m_ruleApplicator->static_.size.empty()) {
- const auto COMPUTED = calculateExpression(m_ruleApplicator->static_.size);
- if (!COMPUTED)
- Log::logger->log(Log::ERR, "failed to parse {} as an expression", m_ruleApplicator->static_.size);
- else {
- *m_realSize = *COMPUTED;
- setHidden(false);
- }
- }
+ if (*PAUTOGROUP // auto_group enabled
+ && Desktop::focusState()->window() // focused window exists
+ && canBeGroupedInto(Desktop::focusState()->window()->m_group) // we can group
+ && Desktop::focusState()->window()->m_workspace == m_workspace // workspaces match, we're not opening on another ws
+ && !isModal() && !(parent() && m_isFloating) && !isX11OverrideRedirect() // not a modal, floating child or X11 OR
+ ) {
+ // add to group if we are focused on one
+ Desktop::focusState()->window()->m_group->add(m_self.lock());
+ } else
+ g_layoutManager->newTarget(m_target, m_workspace->m_space);
- if (!m_ruleApplicator->static_.position.empty()) {
- const auto COMPUTED = calculateExpression(m_ruleApplicator->static_.position);
- if (!COMPUTED)
- Log::logger->log(Log::ERR, "failed to parse {} as an expression", m_ruleApplicator->static_.position);
- else {
- *m_realPosition = *COMPUTED + PMONITOR->m_position;
- setHidden(false);
- }
- }
+ if (!m_group && (m_groupRules & GROUP_SET))
+ m_group = CGroup::create({m_self});
- if (m_ruleApplicator->static_.center.value_or(false)) {
- const auto WORKAREA = PMONITOR->logicalBoxMinusReserved();
- *m_realPosition = WORKAREA.middle() - m_realSize->goal() / 2.f;
- }
+ if (m_isFloating) {
+ m_createdOverFullscreen = true;
// set the pseudo size to the GOAL of our current size
// because the windows are animated on RealSize
- m_pseudoSize = m_realSize->goal();
+ m_target->setPseudoSize(m_realSize->goal());
g_pCompositor->changeWindowZOrder(m_self.lock(), true);
} else {
- g_pLayoutManager->getCurrentLayout()->onWindowCreated(m_self.lock());
-
bool setPseudo = false;
if (!m_ruleApplicator->static_.size.empty()) {
@@ -2274,14 +1962,14 @@ void CWindow::mapWindow() {
if (!COMPUTED)
Log::logger->log(Log::ERR, "failed to parse {} as an expression", m_ruleApplicator->static_.size);
else {
- setPseudo = true;
- m_pseudoSize = *COMPUTED;
+ setPseudo = true;
+ m_target->setPseudoSize(*COMPUTED);
setHidden(false);
}
}
if (!setPseudo)
- m_pseudoSize = m_realSize->goal() - Vector2D(10, 10);
+ m_target->setPseudoSize(m_realSize->goal() - Vector2D(10, 10));
}
const auto PFOCUSEDWINDOWPREV = Desktop::focusState()->window();
@@ -2311,13 +1999,13 @@ void CWindow::mapWindow() {
(!PFORCEFOCUS || PFORCEFOCUS == m_self.lock()) && !g_pInputManager->isConstrained()) {
// this window should gain focus: if it's grouped, preserve fullscreen state.
- const bool SAME_GROUP = hasInGroup(LAST_FOCUS_WINDOW);
+ const bool SAME_GROUP = m_group && m_group->has(LAST_FOCUS_WINDOW);
if (IS_LAST_IN_FS && SAME_GROUP) {
- Desktop::focusState()->rawWindowFocus(m_self.lock());
+ Desktop::focusState()->rawWindowFocus(m_self.lock(), FOCUS_REASON_NEW_WINDOW);
g_pCompositor->setWindowFullscreenInternal(m_self.lock(), LAST_FS_MODE);
} else
- Desktop::focusState()->fullWindowFocus(m_self.lock());
+ Desktop::focusState()->fullWindowFocus(m_self.lock(), FOCUS_REASON_NEW_WINDOW);
m_activeInactiveAlpha->setValueAndWarp(*PACTIVEALPHA);
m_dimPercent->setValueAndWarp(m_ruleApplicator->noDim().valueOrDefault() ? 0.f : *PDIMSTRENGTH);
@@ -2358,18 +2046,16 @@ void CWindow::mapWindow() {
if (workspaceSilent) {
if (validMapped(PFOCUSEDWINDOWPREV)) {
- Desktop::focusState()->rawWindowFocus(PFOCUSEDWINDOWPREV);
+ Desktop::focusState()->rawWindowFocus(PFOCUSEDWINDOWPREV, FOCUS_REASON_NEW_WINDOW);
PFOCUSEDWINDOWPREV->updateWindowDecos(); // need to for some reason i cba to find out why
} else if (!PFOCUSEDWINDOWPREV)
- Desktop::focusState()->rawWindowFocus(nullptr);
+ Desktop::focusState()->rawWindowFocus(nullptr, FOCUS_REASON_NEW_WINDOW);
}
// swallow
if (SWALLOWER) {
- g_pLayoutManager->getCurrentLayout()->onWindowRemoved(SWALLOWER);
- g_pHyprRenderer->damageWindow(SWALLOWER);
+ g_layoutManager->removeTarget(SWALLOWER->layoutTarget());
SWALLOWER->setHidden(true);
- g_pLayoutManager->getCurrentLayout()->recalculateMonitor(monitorID());
}
m_firstMap = false;
@@ -2382,7 +2068,7 @@ void CWindow::mapWindow() {
// apply data from default decos. Borders, shadows.
g_pDecorationPositioner->forceRecalcFor(m_self.lock());
updateWindowDecos();
- g_pLayoutManager->getCurrentLayout()->recalculateWindow(m_self.lock());
+ layoutTarget()->recalc();
// do animations
g_pDesktopAnimationManager->startAnimation(m_self.lock(), CDesktopAnimationManager::ANIMATION_TYPE_IN);
@@ -2454,10 +2140,10 @@ void CWindow::unmapWindow() {
m_swallowed->m_currentlySwallowed = false;
m_swallowed->setHidden(false);
- if (m_groupData.pNextWindow.lock())
+ if (m_group)
m_swallowed->m_groupSwallowed = true; // flag for the swallowed window to be created into the group where it belongs when auto_group = false.
- g_pLayoutManager->getCurrentLayout()->onWindowCreated(m_swallowed.lock());
+ g_layoutManager->newTarget(m_swallowed->layoutTarget(), m_workspace->m_space);
}
m_swallowed->m_groupSwallowed = false;
@@ -2466,7 +2152,7 @@ void CWindow::unmapWindow() {
bool wasLastWindow = false;
PHLWINDOW nextInGroup = [this] -> PHLWINDOW {
- if (!m_groupData.pNextWindow)
+ if (!m_group)
return nullptr;
// walk the history to find a suitable window
@@ -2475,7 +2161,7 @@ void CWindow::unmapWindow() {
if (!w || !w->m_isMapped || w == m_self)
continue;
- if (!hasInGroup(w.lock()))
+ if (!m_group->has(w.lock()))
continue;
return w.lock();
@@ -2491,7 +2177,7 @@ void CWindow::unmapWindow() {
g_pInputManager->releaseAllMouseButtons();
}
- if (m_self.lock() == g_pInputManager->m_currentlyDraggedWindow.lock())
+ if (m_self.lock() == g_layoutManager->dragController()->target())
CKeybindManager::changeMouseBindMode(MBIND_INVALID);
// remove the fullscreen window status from workspace if we closed it
@@ -2500,7 +2186,10 @@ void CWindow::unmapWindow() {
if (PWORKSPACE->m_hasFullscreenWindow && isFullscreen())
PWORKSPACE->m_hasFullscreenWindow = false;
- g_pLayoutManager->getCurrentLayout()->onWindowRemoved(m_self.lock());
+ if (m_group)
+ m_group->remove(m_self.lock());
+
+ g_layoutManager->removeTarget(m_target);
g_pHyprRenderer->damageWindow(m_self.lock());
@@ -2516,17 +2205,20 @@ void CWindow::unmapWindow() {
if (*FOCUSONCLOSE)
candidate = (g_pCompositor->vectorToWindowUnified(g_pInputManager->getMouseCoordsInternal(),
Desktop::View::RESERVED_EXTENTS | Desktop::View::INPUT_EXTENTS | Desktop::View::ALLOW_FLOATING));
- else
- candidate = g_pLayoutManager->getCurrentLayout()->getNextWindowCandidate(m_self.lock());
+ else {
+ const auto CAND = g_layoutManager->getNextCandidate(m_workspace->m_space, layoutTarget());
+ if (CAND)
+ candidate = CAND->window();
+ }
}
Log::logger->log(Log::DEBUG, "On closed window, new focused candidate is {}", candidate);
if (candidate != Desktop::focusState()->window() && candidate) {
if (candidate == nextInGroup)
- Desktop::focusState()->rawWindowFocus(candidate);
+ Desktop::focusState()->rawWindowFocus(candidate, FOCUS_REASON_DESKTOP_STATE_CHANGE);
else
- Desktop::focusState()->fullWindowFocus(candidate);
+ Desktop::focusState()->fullWindowFocus(candidate, FOCUS_REASON_DESKTOP_STATE_CHANGE);
if ((*PEXITRETAINSFS || candidate == nextInGroup) && CURRENTWINDOWFSSTATE)
g_pCompositor->setWindowFullscreenInternal(candidate, CURRENTFSMODE);
@@ -2541,7 +2233,8 @@ void CWindow::unmapWindow() {
if (m_self.lock() == Desktop::focusState()->window() || !Desktop::focusState()->window()) {
g_pEventManager->postEvent(SHyprIPCEvent{"activewindow", ","});
g_pEventManager->postEvent(SHyprIPCEvent{"activewindowv2", ""});
- EMIT_HOOK_EVENT("activeWindow", PHLWINDOW{nullptr});
+
+ EMIT_HOOK_EVENT("activeWindow", Desktop::View::SWindowActiveEvent{nullptr COMMA FOCUS_REASON_OTHER});
}
} else {
Log::logger->log(Log::DEBUG, "Unmapped was not focused, ignoring a refocus.");
@@ -2573,7 +2266,13 @@ void CWindow::commitWindow() {
// try to calculate static rules already for any floats
m_ruleApplicator->readStaticRules(true);
- Vector2D predSize = g_pLayoutManager->getCurrentLayout()->predictSizeForNewWindow(m_self.lock());
+ const Vector2D predSize = !m_ruleApplicator->static_.floating.value_or(false) // no float rule
+ && !m_isFloating // not floating
+ && !parent() // no parents
+ && !g_pXWaylandManager->shouldBeFloated(m_self.lock(), true) // should not be floated
+ ?
+ g_layoutManager->predictSizeForNewTiledTarget().value_or(Vector2D{}) :
+ Vector2D{};
Log::logger->log(Log::DEBUG, "Layout predicts size {} for {}", predSize, m_self.lock());
@@ -2634,7 +2333,7 @@ void CWindow::destroyWindow() {
m_listeners = {};
- g_pLayoutManager->getCurrentLayout()->onWindowRemoved(m_self.lock());
+ g_layoutManager->removeTarget(m_target);
m_readyToDelete = true;
@@ -2664,7 +2363,7 @@ void CWindow::activateX11() {
if (!m_xwaylandSurface->wantsFocus())
return;
- Desktop::focusState()->fullWindowFocus(m_self.lock());
+ Desktop::focusState()->fullWindowFocus(m_self.lock(), FOCUS_REASON_DESKTOP_STATE_CHANGE);
return;
}
@@ -2764,3 +2463,26 @@ std::optional<Vector2D> CWindow::maxSize() {
return maxSize;
}
+
+SP<Layout::ITarget> CWindow::layoutTarget() {
+ return m_group ? m_group->m_target : m_target;
+}
+
+bool CWindow::canBeGroupedInto(SP<CGroup> group) {
+ if (!group)
+ return false;
+
+ if (isX11OverrideRedirect())
+ return false;
+
+ static auto ALLOWGROUPMERGE = CConfigValue<Hyprlang::INT>("group:merge_groups_on_drag");
+ bool isGroup = m_group;
+ bool disallowDragIntoGroup = g_layoutManager->dragController()->wasDraggingWindow() && isGroup && !sc<bool>(*ALLOWGROUPMERGE);
+ return !g_pKeybindManager->m_groupsLocked // global group lock disengaged
+ && ((m_groupRules & GROUP_INVADE && m_firstMap) // window ignore local group locks, or
+ || (!group->locked() // target unlocked
+ && !(m_group && m_group->locked()))) // source unlocked or isn't group
+ && !(m_groupRules & GROUP_DENY) // source is not denied entry
+ && !(m_groupRules & GROUP_BARRED && m_firstMap) // group rule doesn't prevent adding window
+ && !disallowDragIntoGroup; // config allows groups to be merged
+}