summaryrefslogtreecommitdiff
path: root/src/layout/IHyprLayout.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/layout/IHyprLayout.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/layout/IHyprLayout.cpp')
-rw-r--r--src/layout/IHyprLayout.cpp1062
1 files changed, 0 insertions, 1062 deletions
diff --git a/src/layout/IHyprLayout.cpp b/src/layout/IHyprLayout.cpp
deleted file mode 100644
index f434b580..00000000
--- a/src/layout/IHyprLayout.cpp
+++ /dev/null
@@ -1,1062 +0,0 @@
-#include "IHyprLayout.hpp"
-#include "../defines.hpp"
-#include "../Compositor.hpp"
-#include "../render/decorations/CHyprGroupBarDecoration.hpp"
-#include "../config/ConfigValue.hpp"
-#include "../config/ConfigManager.hpp"
-#include "../desktop/view/Window.hpp"
-#include "../desktop/state/FocusState.hpp"
-#include "../protocols/XDGShell.hpp"
-#include "../protocols/core/Compositor.hpp"
-#include "../xwayland/XSurface.hpp"
-#include "../render/Renderer.hpp"
-#include "../managers/LayoutManager.hpp"
-#include "../managers/EventManager.hpp"
-#include "../managers/HookSystemManager.hpp"
-#include "../managers/cursor/CursorShapeOverrideController.hpp"
-#include "../desktop/rule/windowRule/WindowRule.hpp"
-
-void IHyprLayout::onWindowCreated(PHLWINDOW pWindow, eDirection direction) {
- CBox desiredGeometry = g_pXWaylandManager->getGeometryForWindow(pWindow);
-
- const bool HASPERSISTENTSIZE = pWindow->m_ruleApplicator->persistentSize().valueOrDefault();
-
- const auto STOREDSIZE = HASPERSISTENTSIZE ? g_pConfigManager->getStoredFloatingSize(pWindow) : std::nullopt;
-
- if (STOREDSIZE.has_value()) {
- Log::logger->log(Log::DEBUG, "using stored size {}x{} for new window {}::{}", STOREDSIZE->x, STOREDSIZE->y, pWindow->m_class, pWindow->m_title);
- pWindow->m_lastFloatingSize = STOREDSIZE.value();
- } else if (desiredGeometry.width <= 5 || desiredGeometry.height <= 5) {
- const auto PMONITOR = pWindow->m_monitor.lock();
- pWindow->m_lastFloatingSize = PMONITOR->m_size / 2.f;
- } else
- pWindow->m_lastFloatingSize = Vector2D(desiredGeometry.width, desiredGeometry.height);
-
- pWindow->m_pseudoSize = pWindow->m_lastFloatingSize;
-
- bool autoGrouped = IHyprLayout::onWindowCreatedAutoGroup(pWindow);
- if (autoGrouped)
- return;
-
- if (pWindow->m_isFloating)
- onWindowCreatedFloating(pWindow);
- else
- onWindowCreatedTiling(pWindow, direction);
-
- if (!g_pXWaylandManager->shouldBeFloated(pWindow)) // do not apply group rules to child windows
- pWindow->applyGroupRules();
-}
-
-void IHyprLayout::onWindowRemoved(PHLWINDOW pWindow) {
- if (pWindow->isFullscreen())
- g_pCompositor->setWindowFullscreenInternal(pWindow, FSMODE_NONE);
-
- if (!pWindow->m_groupData.pNextWindow.expired()) {
- if (pWindow->m_groupData.pNextWindow.lock() == pWindow) {
- pWindow->m_groupData.pNextWindow.reset();
- pWindow->updateWindowDecos();
- } else {
- // find last window and update
- PHLWINDOW PWINDOWPREV = pWindow->getGroupPrevious();
- const auto WINDOWISVISIBLE = pWindow->getGroupCurrent() == pWindow;
-
- if (WINDOWISVISIBLE)
- PWINDOWPREV->setGroupCurrent(pWindow->m_groupData.head ? pWindow->m_groupData.pNextWindow.lock() : PWINDOWPREV);
-
- PWINDOWPREV->m_groupData.pNextWindow = pWindow->m_groupData.pNextWindow;
-
- pWindow->m_groupData.pNextWindow.reset();
-
- if (pWindow->m_groupData.head) {
- std::swap(PWINDOWPREV->m_groupData.pNextWindow->m_groupData.head, pWindow->m_groupData.head);
- std::swap(PWINDOWPREV->m_groupData.pNextWindow->m_groupData.locked, pWindow->m_groupData.locked);
- }
-
- if (pWindow == m_lastTiledWindow)
- m_lastTiledWindow.reset();
-
- pWindow->setHidden(false);
-
- pWindow->updateWindowDecos();
- PWINDOWPREV->getGroupCurrent()->updateWindowDecos();
- pWindow->updateDecorationValues();
-
- return;
- }
- }
-
- if (pWindow->m_isFloating) {
- onWindowRemovedFloating(pWindow);
- } else {
- onWindowRemovedTiling(pWindow);
- }
-
- if (pWindow == m_lastTiledWindow)
- m_lastTiledWindow.reset();
-}
-
-void IHyprLayout::onWindowRemovedFloating(PHLWINDOW pWindow) {
- ; // no-op
-}
-
-void IHyprLayout::onWindowCreatedFloating(PHLWINDOW pWindow) {
-
- CBox desiredGeometry = g_pXWaylandManager->getGeometryForWindow(pWindow);
- const auto PMONITOR = pWindow->m_monitor.lock();
-
- if (pWindow->m_isX11) {
- Vector2D xy = {desiredGeometry.x, desiredGeometry.y};
- xy = g_pXWaylandManager->xwaylandToWaylandCoords(xy);
- desiredGeometry.x = xy.x;
- desiredGeometry.y = xy.y;
- } else if (pWindow->m_ruleApplicator->persistentSize().valueOrDefault()) {
- desiredGeometry.w = pWindow->m_lastFloatingSize.x;
- desiredGeometry.h = pWindow->m_lastFloatingSize.y;
- }
-
- static auto PXWLFORCESCALEZERO = CConfigValue<Hyprlang::INT>("xwayland:force_zero_scaling");
-
- if (!PMONITOR) {
- Log::logger->log(Log::ERR, "{:m} has an invalid monitor in onWindowCreatedFloating!!!", pWindow);
- return;
- }
-
- if (desiredGeometry.width <= 5 || desiredGeometry.height <= 5) {
- const auto PWINDOWSURFACE = pWindow->wlSurface()->resource();
- *pWindow->m_realSize = PWINDOWSURFACE->m_current.size;
-
- if ((desiredGeometry.width <= 1 || desiredGeometry.height <= 1) && pWindow->m_isX11 &&
- pWindow->isX11OverrideRedirect()) { // XDG windows should be fine. TODO: check for weird atoms?
- pWindow->setHidden(true);
- return;
- }
-
- // reject any windows with size <= 5x5
- if (pWindow->m_realSize->goal().x <= 5 || pWindow->m_realSize->goal().y <= 5)
- *pWindow->m_realSize = PMONITOR->m_size / 2.f;
-
- if (pWindow->m_isX11 && pWindow->isX11OverrideRedirect()) {
-
- if (pWindow->m_xwaylandSurface->m_geometry.x != 0 && pWindow->m_xwaylandSurface->m_geometry.y != 0)
- *pWindow->m_realPosition = g_pXWaylandManager->xwaylandToWaylandCoords(pWindow->m_xwaylandSurface->m_geometry.pos());
- else
- *pWindow->m_realPosition = Vector2D(PMONITOR->m_position.x + (PMONITOR->m_size.x - pWindow->m_realSize->goal().x) / 2.f,
- PMONITOR->m_position.y + (PMONITOR->m_size.y - pWindow->m_realSize->goal().y) / 2.f);
- } else {
- *pWindow->m_realPosition = Vector2D(PMONITOR->m_position.x + (PMONITOR->m_size.x - pWindow->m_realSize->goal().x) / 2.f,
- PMONITOR->m_position.y + (PMONITOR->m_size.y - pWindow->m_realSize->goal().y) / 2.f);
- }
- } else {
- // we respect the size.
- *pWindow->m_realSize = Vector2D(desiredGeometry.width, desiredGeometry.height);
-
- // check if it's on the correct monitor!
- Vector2D middlePoint = Vector2D(desiredGeometry.x, desiredGeometry.y) + Vector2D(desiredGeometry.width, desiredGeometry.height) / 2.f;
-
- // check if it's visible on any monitor (only for XDG)
- bool visible = pWindow->m_isX11;
-
- if (!visible) {
- visible = g_pCompositor->isPointOnAnyMonitor(Vector2D(desiredGeometry.x, desiredGeometry.y)) &&
- g_pCompositor->isPointOnAnyMonitor(Vector2D(desiredGeometry.x + desiredGeometry.width, desiredGeometry.y)) &&
- g_pCompositor->isPointOnAnyMonitor(Vector2D(desiredGeometry.x, desiredGeometry.y + desiredGeometry.height)) &&
- g_pCompositor->isPointOnAnyMonitor(Vector2D(desiredGeometry.x + desiredGeometry.width, desiredGeometry.y + desiredGeometry.height));
- }
-
- // TODO: detect a popup in a more consistent way.
- bool centeredOnParent = false;
- if ((desiredGeometry.x == 0 && desiredGeometry.y == 0) || !visible || !pWindow->m_isX11) {
- // if the pos isn't set, fall back to the center placement if it's not a child
- auto pos = PMONITOR->m_position + PMONITOR->m_size / 2.F - desiredGeometry.size() / 2.F;
-
- // otherwise middle of parent if available
- if (!pWindow->m_isX11) {
- if (const auto PARENT = pWindow->parent(); PARENT) {
- *pWindow->m_realPosition = PARENT->m_realPosition->goal() + PARENT->m_realSize->goal() / 2.F - desiredGeometry.size() / 2.F;
- pWindow->m_workspace = PARENT->m_workspace;
- pWindow->m_monitor = PARENT->m_monitor;
- centeredOnParent = true;
- }
- }
- if (!centeredOnParent)
- *pWindow->m_realPosition = pos;
- } else {
- // if it is, we respect where it wants to put itself, but apply monitor offset if outside
- // most of these are popups
-
- if (const auto POPENMON = g_pCompositor->getMonitorFromVector(middlePoint); POPENMON->m_id != PMONITOR->m_id)
- *pWindow->m_realPosition = Vector2D(desiredGeometry.x, desiredGeometry.y) - POPENMON->m_position + PMONITOR->m_position;
- else
- *pWindow->m_realPosition = Vector2D(desiredGeometry.x, desiredGeometry.y);
- }
- }
-
- if (*PXWLFORCESCALEZERO && pWindow->m_isX11)
- *pWindow->m_realSize = pWindow->m_realSize->goal() / PMONITOR->m_scale;
-
- if (pWindow->m_X11DoesntWantBorders || (pWindow->m_isX11 && pWindow->isX11OverrideRedirect())) {
- pWindow->m_realPosition->warp();
- pWindow->m_realSize->warp();
- }
-
- if (!pWindow->isX11OverrideRedirect())
- g_pCompositor->changeWindowZOrder(pWindow, true);
- else {
- pWindow->m_pendingReportedSize = pWindow->m_realSize->goal();
- pWindow->m_reportedSize = pWindow->m_pendingReportedSize;
- }
-}
-
-bool IHyprLayout::onWindowCreatedAutoGroup(PHLWINDOW pWindow) {
- static auto PAUTOGROUP = CConfigValue<Hyprlang::INT>("group:auto_group");
- const PHLWINDOW OPENINGON = Desktop::focusState()->window() && Desktop::focusState()->window()->m_workspace == pWindow->m_workspace ?
- Desktop::focusState()->window() :
- (pWindow->m_workspace ? pWindow->m_workspace->getFirstWindow() : nullptr);
- const bool FLOATEDINTOTILED = pWindow->m_isFloating && OPENINGON && !OPENINGON->m_isFloating;
- const bool SWALLOWING = pWindow->m_swallowed || pWindow->m_groupSwallowed;
-
- if ((*PAUTOGROUP || SWALLOWING) // continue if auto_group is enabled or if dealing with window swallowing.
- && OPENINGON // this shouldn't be 0, but honestly, better safe than sorry.
- && OPENINGON != pWindow // prevent freeze when the "group set" window rule makes the new window to be already a group.
- && OPENINGON->m_groupData.pNextWindow.lock() // check if OPENINGON is a group.
- && pWindow->canBeGroupedInto(OPENINGON) // check if the new window can be grouped into OPENINGON.
- && !g_pXWaylandManager->shouldBeFloated(pWindow) // don't group child windows. Fix for floated groups. Tiled groups don't need this because we check if !FLOATEDINTOTILED.
- && !FLOATEDINTOTILED) { // don't group a new floated window into a tiled group (for convenience).
-
- pWindow->m_isFloating = OPENINGON->m_isFloating; // match the floating state. Needed to autogroup a new tiled window into a floated group.
-
- static auto USECURRPOS = CConfigValue<Hyprlang::INT>("group:insert_after_current");
- (*USECURRPOS ? OPENINGON : OPENINGON->getGroupTail())->insertWindowToGroup(pWindow);
-
- OPENINGON->setGroupCurrent(pWindow);
- pWindow->applyGroupRules();
- pWindow->updateWindowDecos();
- recalculateWindow(pWindow);
-
- return true;
- }
-
- return false;
-}
-
-void IHyprLayout::onBeginDragWindow() {
- const auto DRAGGINGWINDOW = g_pInputManager->m_currentlyDraggedWindow.lock();
- static auto PDRAGTHRESHOLD = CConfigValue<Hyprlang::INT>("binds:drag_threshold");
-
- m_mouseMoveEventCount = 1;
- m_beginDragSizeXY = Vector2D();
-
- // Window will be floating. Let's check if it's valid. It should be, but I don't like crashing.
- if (!validMapped(DRAGGINGWINDOW)) {
- Log::logger->log(Log::ERR, "Dragging attempted on an invalid window!");
- CKeybindManager::changeMouseBindMode(MBIND_INVALID);
- return;
- }
-
- // Try to pick up dragged window now if drag_threshold is disabled
- // or at least update dragging related variables for the cursors
- g_pInputManager->m_dragThresholdReached = *PDRAGTHRESHOLD <= 0;
- if (updateDragWindow())
- return;
-
- // get the grab corner
- static auto RESIZECORNER = CConfigValue<Hyprlang::INT>("general:resize_corner");
- if (*RESIZECORNER != 0 && *RESIZECORNER <= 4 && DRAGGINGWINDOW->m_isFloating) {
- switch (*RESIZECORNER) {
- case 1:
- m_grabbedCorner = CORNER_TOPLEFT;
- Cursor::overrideController->setOverride("nw-resize", Cursor::CURSOR_OVERRIDE_SPECIAL_ACTION);
- break;
- case 2:
- m_grabbedCorner = CORNER_TOPRIGHT;
- Cursor::overrideController->setOverride("ne-resize", Cursor::CURSOR_OVERRIDE_SPECIAL_ACTION);
- break;
- case 3:
- m_grabbedCorner = CORNER_BOTTOMRIGHT;
- Cursor::overrideController->setOverride("se-resize", Cursor::CURSOR_OVERRIDE_SPECIAL_ACTION);
- break;
- case 4:
- m_grabbedCorner = CORNER_BOTTOMLEFT;
- Cursor::overrideController->setOverride("sw-resize", Cursor::CURSOR_OVERRIDE_SPECIAL_ACTION);
- break;
- }
- } else if (m_beginDragXY.x < m_beginDragPositionXY.x + m_beginDragSizeXY.x / 2.0) {
- if (m_beginDragXY.y < m_beginDragPositionXY.y + m_beginDragSizeXY.y / 2.0) {
- m_grabbedCorner = CORNER_TOPLEFT;
- Cursor::overrideController->setOverride("nw-resize", Cursor::CURSOR_OVERRIDE_SPECIAL_ACTION);
- } else {
- m_grabbedCorner = CORNER_BOTTOMLEFT;
- Cursor::overrideController->setOverride("sw-resize", Cursor::CURSOR_OVERRIDE_SPECIAL_ACTION);
- }
- } else {
- if (m_beginDragXY.y < m_beginDragPositionXY.y + m_beginDragSizeXY.y / 2.0) {
- m_grabbedCorner = CORNER_TOPRIGHT;
- Cursor::overrideController->setOverride("ne-resize", Cursor::CURSOR_OVERRIDE_SPECIAL_ACTION);
- } else {
- m_grabbedCorner = CORNER_BOTTOMRIGHT;
- Cursor::overrideController->setOverride("se-resize", Cursor::CURSOR_OVERRIDE_SPECIAL_ACTION);
- }
- }
-
- if (g_pInputManager->m_dragMode != MBIND_RESIZE && g_pInputManager->m_dragMode != MBIND_RESIZE_FORCE_RATIO && g_pInputManager->m_dragMode != MBIND_RESIZE_BLOCK_RATIO)
- Cursor::overrideController->setOverride("grabbing", Cursor::CURSOR_OVERRIDE_SPECIAL_ACTION);
-
- g_pHyprRenderer->damageWindow(DRAGGINGWINDOW);
-
- g_pKeybindManager->shadowKeybinds();
-
- Desktop::focusState()->rawWindowFocus(DRAGGINGWINDOW);
- g_pCompositor->changeWindowZOrder(DRAGGINGWINDOW, true);
-}
-
-void IHyprLayout::onEndDragWindow() {
- const auto DRAGGINGWINDOW = g_pInputManager->m_currentlyDraggedWindow.lock();
-
- m_mouseMoveEventCount = 1;
-
- if (!validMapped(DRAGGINGWINDOW)) {
- if (DRAGGINGWINDOW) {
- Cursor::overrideController->unsetOverride(Cursor::CURSOR_OVERRIDE_SPECIAL_ACTION);
- g_pInputManager->m_currentlyDraggedWindow.reset();
- }
- return;
- }
-
- Cursor::overrideController->unsetOverride(Cursor::CURSOR_OVERRIDE_SPECIAL_ACTION);
- g_pInputManager->m_currentlyDraggedWindow.reset();
- g_pInputManager->m_wasDraggingWindow = true;
-
- if (g_pInputManager->m_dragMode == MBIND_MOVE) {
- g_pHyprRenderer->damageWindow(DRAGGINGWINDOW);
- const auto MOUSECOORDS = g_pInputManager->getMouseCoordsInternal();
- PHLWINDOW pWindow =
- g_pCompositor->vectorToWindowUnified(MOUSECOORDS, Desktop::View::RESERVED_EXTENTS | Desktop::View::INPUT_EXTENTS | Desktop::View::ALLOW_FLOATING, DRAGGINGWINDOW);
-
- if (pWindow) {
- if (pWindow->checkInputOnDecos(INPUT_TYPE_DRAG_END, MOUSECOORDS, DRAGGINGWINDOW))
- return;
-
- const bool FLOATEDINTOTILED = !pWindow->m_isFloating && !DRAGGINGWINDOW->m_draggingTiled;
- static auto PDRAGINTOGROUP = CConfigValue<Hyprlang::INT>("group:drag_into_group");
-
- if (pWindow->m_groupData.pNextWindow.lock() && DRAGGINGWINDOW->canBeGroupedInto(pWindow) && *PDRAGINTOGROUP == 1 && !FLOATEDINTOTILED) {
-
- if (DRAGGINGWINDOW->m_groupData.pNextWindow) {
- PHLWINDOW next = DRAGGINGWINDOW->m_groupData.pNextWindow.lock();
- while (next != DRAGGINGWINDOW) {
- next->m_isFloating = pWindow->m_isFloating; // match the floating state of group members
- *next->m_realSize = pWindow->m_realSize->goal(); // match the size of group members
- *next->m_realPosition = pWindow->m_realPosition->goal(); // match the position of group members
- next = next->m_groupData.pNextWindow.lock();
- }
- }
-
- DRAGGINGWINDOW->m_isFloating = pWindow->m_isFloating; // match the floating state of the window
- DRAGGINGWINDOW->m_lastFloatingSize = m_draggingWindowOriginalFloatSize;
- DRAGGINGWINDOW->m_draggingTiled = false;
-
- static auto USECURRPOS = CConfigValue<Hyprlang::INT>("group:insert_after_current");
- (*USECURRPOS ? pWindow : pWindow->getGroupTail())->insertWindowToGroup(DRAGGINGWINDOW);
- pWindow->setGroupCurrent(DRAGGINGWINDOW);
- DRAGGINGWINDOW->applyGroupRules();
- DRAGGINGWINDOW->updateWindowDecos();
- }
- }
- }
-
- if (DRAGGINGWINDOW->m_draggingTiled) {
- static auto PPRECISEMOUSE = CConfigValue<Hyprlang::INT>("dwindle:precise_mouse_move");
- DRAGGINGWINDOW->m_isFloating = false;
- g_pInputManager->refocus();
-
- if (*PPRECISEMOUSE) {
- eDirection direction = DIRECTION_DEFAULT;
-
- const auto MOUSECOORDS = g_pInputManager->getMouseCoordsInternal();
- const PHLWINDOW pReferenceWindow =
- g_pCompositor->vectorToWindowUnified(MOUSECOORDS, Desktop::View::RESERVED_EXTENTS | Desktop::View::INPUT_EXTENTS | Desktop::View::ALLOW_FLOATING, DRAGGINGWINDOW);
-
- if (pReferenceWindow && pReferenceWindow != DRAGGINGWINDOW) {
- const Vector2D draggedCenter = DRAGGINGWINDOW->m_realPosition->goal() + DRAGGINGWINDOW->m_realSize->goal() / 2.f;
- const Vector2D referenceCenter = pReferenceWindow->m_realPosition->goal() + pReferenceWindow->m_realSize->goal() / 2.f;
- const float xDiff = draggedCenter.x - referenceCenter.x;
- const float yDiff = draggedCenter.y - referenceCenter.y;
-
- if (fabs(xDiff) > fabs(yDiff))
- direction = xDiff < 0 ? DIRECTION_LEFT : DIRECTION_RIGHT;
- else
- direction = yDiff < 0 ? DIRECTION_UP : DIRECTION_DOWN;
- }
-
- onWindowRemovedTiling(DRAGGINGWINDOW);
- onWindowCreatedTiling(DRAGGINGWINDOW, direction);
- } else
- changeWindowFloatingMode(DRAGGINGWINDOW);
-
- DRAGGINGWINDOW->m_lastFloatingSize = m_draggingWindowOriginalFloatSize;
- }
-
- g_pHyprRenderer->damageWindow(DRAGGINGWINDOW);
- Desktop::focusState()->fullWindowFocus(DRAGGINGWINDOW);
-
- g_pInputManager->m_wasDraggingWindow = false;
-}
-
-static inline bool canSnap(const double SIDEA, const double SIDEB, const double GAP) {
- return std::abs(SIDEA - SIDEB) < GAP;
-}
-
-static void snapMove(double& start, double& end, const double P) {
- end = P + (end - start);
- start = P;
-}
-
-static void snapResize(double& start, double& end, const double P) {
- start = P;
-}
-
-using SnapFn = std::function<void(double&, double&, const double)>;
-
-void IHyprLayout::performSnap(Vector2D& sourcePos, Vector2D& sourceSize, PHLWINDOW DRAGGINGWINDOW, const eMouseBindMode MODE, const int CORNER, const Vector2D& BEGINSIZE) {
- static auto SNAPWINDOWGAP = CConfigValue<Hyprlang::INT>("general:snap:window_gap");
- static auto SNAPMONITORGAP = CConfigValue<Hyprlang::INT>("general:snap:monitor_gap");
- static auto SNAPBORDEROVERLAP = CConfigValue<Hyprlang::INT>("general:snap:border_overlap");
- static auto SNAPRESPECTGAPS = CConfigValue<Hyprlang::INT>("general:snap:respect_gaps");
-
- static auto PGAPSIN = CConfigValue<Hyprlang::CUSTOMTYPE>("general:gaps_in");
- static auto PGAPSOUT = CConfigValue<Hyprlang::CUSTOMTYPE>("general:gaps_out");
- const auto GAPSNONE = CCssGapData{0, 0, 0, 0};
-
- const SnapFn SNAP = (MODE == MBIND_MOVE) ? snapMove : snapResize;
- int snaps = 0;
-
- struct SRange {
- double start = 0;
- double end = 0;
- };
- const auto EXTENTS = DRAGGINGWINDOW->getWindowExtentsUnified(Desktop::View::RESERVED_EXTENTS | Desktop::View::INPUT_EXTENTS);
- SRange sourceX = {sourcePos.x - EXTENTS.topLeft.x, sourcePos.x + sourceSize.x + EXTENTS.bottomRight.x};
- SRange sourceY = {sourcePos.y - EXTENTS.topLeft.y, sourcePos.y + sourceSize.y + EXTENTS.bottomRight.y};
-
- if (*SNAPWINDOWGAP) {
- const double GAPSIZE = *SNAPWINDOWGAP;
- const auto WSID = DRAGGINGWINDOW->workspaceID();
- const bool HASFULLSCREEN = DRAGGINGWINDOW->m_workspace && DRAGGINGWINDOW->m_workspace->m_hasFullscreenWindow;
-
- const auto* GAPSIN = *SNAPRESPECTGAPS ? sc<CCssGapData*>(PGAPSIN.ptr()->getData()) : &GAPSNONE;
- const double GAPSX = GAPSIN->m_left + GAPSIN->m_right;
- const double GAPSY = GAPSIN->m_top + GAPSIN->m_bottom;
-
- for (auto& other : g_pCompositor->m_windows) {
- if ((HASFULLSCREEN && !other->m_createdOverFullscreen) || other == DRAGGINGWINDOW || other->workspaceID() != WSID || !other->m_isMapped || other->m_fadingOut ||
- other->isX11OverrideRedirect())
- continue;
-
- const CBox SURF = other->getWindowBoxUnified(Desktop::View::RESERVED_EXTENTS);
- const SRange SURFBX = {SURF.x - GAPSX, SURF.x + SURF.w + GAPSX};
- const SRange SURFBY = {SURF.y - GAPSY, SURF.y + SURF.h + GAPSY};
-
- // only snap windows if their ranges overlap in the opposite axis
- if (sourceY.start <= SURFBY.end && SURFBY.start <= sourceY.end) {
- if (CORNER & (CORNER_TOPLEFT | CORNER_BOTTOMLEFT) && canSnap(sourceX.start, SURFBX.end, GAPSIZE)) {
- SNAP(sourceX.start, sourceX.end, SURFBX.end);
- snaps |= SNAP_LEFT;
- } else if (CORNER & (CORNER_TOPRIGHT | CORNER_BOTTOMRIGHT) && canSnap(sourceX.end, SURFBX.start, GAPSIZE)) {
- SNAP(sourceX.end, sourceX.start, SURFBX.start);
- snaps |= SNAP_RIGHT;
- }
- }
- if (sourceX.start <= SURFBX.end && SURFBX.start <= sourceX.end) {
- if (CORNER & (CORNER_TOPLEFT | CORNER_TOPRIGHT) && canSnap(sourceY.start, SURFBY.end, GAPSIZE)) {
- SNAP(sourceY.start, sourceY.end, SURFBY.end);
- snaps |= SNAP_UP;
- } else if (CORNER & (CORNER_BOTTOMLEFT | CORNER_BOTTOMRIGHT) && canSnap(sourceY.end, SURFBY.start, GAPSIZE)) {
- SNAP(sourceY.end, sourceY.start, SURFBY.start);
- snaps |= SNAP_DOWN;
- }
- }
-
- // corner snapping
- if (sourceX.start == SURFBX.end || SURFBX.start == sourceX.end) {
- const SRange SURFY = {SURFBY.start + GAPSY, SURFBY.end - GAPSY};
- if (CORNER & (CORNER_TOPLEFT | CORNER_TOPRIGHT) && !(snaps & SNAP_UP) && canSnap(sourceY.start, SURFY.start, GAPSIZE)) {
- SNAP(sourceY.start, sourceY.end, SURFY.start);
- snaps |= SNAP_UP;
- } else if (CORNER & (CORNER_BOTTOMLEFT | CORNER_BOTTOMRIGHT) && !(snaps & SNAP_DOWN) && canSnap(sourceY.end, SURFY.end, GAPSIZE)) {
- SNAP(sourceY.end, sourceY.start, SURFY.end);
- snaps |= SNAP_DOWN;
- }
- }
- if (sourceY.start == SURFBY.end || SURFBY.start == sourceY.end) {
- const SRange SURFX = {SURFBX.start + GAPSX, SURFBX.end - GAPSX};
- if (CORNER & (CORNER_TOPLEFT | CORNER_BOTTOMLEFT) && !(snaps & SNAP_LEFT) && canSnap(sourceX.start, SURFX.start, GAPSIZE)) {
- SNAP(sourceX.start, sourceX.end, SURFX.start);
- snaps |= SNAP_LEFT;
- } else if (CORNER & (CORNER_TOPRIGHT | CORNER_BOTTOMRIGHT) && !(snaps & SNAP_RIGHT) && canSnap(sourceX.end, SURFX.end, GAPSIZE)) {
- SNAP(sourceX.end, sourceX.start, SURFX.end);
- snaps |= SNAP_RIGHT;
- }
- }
- }
- }
-
- if (*SNAPMONITORGAP) {
- const double GAPSIZE = *SNAPMONITORGAP;
- const auto EXTENTNONE = SBoxExtents{{0, 0}, {0, 0}};
- const auto* EXTENTDIFF = *SNAPBORDEROVERLAP ? &EXTENTS : &EXTENTNONE;
- const auto MON = DRAGGINGWINDOW->m_monitor.lock();
-
- const auto* GAPSOUT = *SNAPRESPECTGAPS ? sc<CCssGapData*>(PGAPSOUT.ptr()->getData()) : &GAPSNONE;
- const auto WORK_AREA = Desktop::CReservedArea{GAPSOUT->m_top, GAPSOUT->m_right, GAPSOUT->m_bottom, GAPSOUT->m_left}.apply(MON->logicalBoxMinusReserved());
-
- SRange monX = {WORK_AREA.x, WORK_AREA.x + WORK_AREA.w};
- SRange monY = {WORK_AREA.y, WORK_AREA.y + WORK_AREA.h};
-
- const bool HAS_LEFT = MON->m_reservedArea.left() > 0;
- const bool HAS_TOP = MON->m_reservedArea.top() > 0;
- const bool HAS_BOTTOM = MON->m_reservedArea.bottom() > 0;
- const bool HAS_RIGHT = MON->m_reservedArea.right() > 0;
-
- if (CORNER & (CORNER_TOPLEFT | CORNER_BOTTOMLEFT) &&
- ((HAS_LEFT && canSnap(sourceX.start, monX.start, GAPSIZE)) || canSnap(sourceX.start, (monX.start -= MON->m_reservedArea.left() + EXTENTDIFF->topLeft.x), GAPSIZE))) {
- SNAP(sourceX.start, sourceX.end, monX.start);
- snaps |= SNAP_LEFT;
- }
- if (CORNER & (CORNER_TOPRIGHT | CORNER_BOTTOMRIGHT) &&
- ((HAS_RIGHT && canSnap(sourceX.end, monX.end, GAPSIZE)) || canSnap(sourceX.end, (monX.end += MON->m_reservedArea.right() + EXTENTDIFF->bottomRight.x), GAPSIZE))) {
- SNAP(sourceX.end, sourceX.start, monX.end);
- snaps |= SNAP_RIGHT;
- }
- if (CORNER & (CORNER_TOPLEFT | CORNER_TOPRIGHT) &&
- ((HAS_TOP && canSnap(sourceY.start, monY.start, GAPSIZE)) || canSnap(sourceY.start, (monY.start -= MON->m_reservedArea.top() + EXTENTDIFF->topLeft.y), GAPSIZE))) {
- SNAP(sourceY.start, sourceY.end, monY.start);
- snaps |= SNAP_UP;
- }
- if (CORNER & (CORNER_BOTTOMLEFT | CORNER_BOTTOMRIGHT) &&
- ((HAS_BOTTOM && canSnap(sourceY.end, monY.end, GAPSIZE)) || canSnap(sourceY.end, (monY.end += MON->m_reservedArea.bottom() + EXTENTDIFF->bottomRight.y), GAPSIZE))) {
- SNAP(sourceY.end, sourceY.start, monY.end);
- snaps |= SNAP_DOWN;
- }
- }
-
- // remove extents from main surface
- sourceX = {sourceX.start + EXTENTS.topLeft.x, sourceX.end - EXTENTS.bottomRight.x};
- sourceY = {sourceY.start + EXTENTS.topLeft.y, sourceY.end - EXTENTS.bottomRight.y};
-
- if (MODE == MBIND_RESIZE_FORCE_RATIO) {
- if ((CORNER & (CORNER_TOPLEFT | CORNER_BOTTOMLEFT) && snaps & SNAP_LEFT) || (CORNER & (CORNER_TOPRIGHT | CORNER_BOTTOMRIGHT) && snaps & SNAP_RIGHT)) {
- const double SIZEY = (sourceX.end - sourceX.start) * (BEGINSIZE.y / BEGINSIZE.x);
- if (CORNER & (CORNER_TOPLEFT | CORNER_TOPRIGHT))
- sourceY.start = sourceY.end - SIZEY;
- else
- sourceY.end = sourceY.start + SIZEY;
- } else if ((CORNER & (CORNER_TOPLEFT | CORNER_TOPRIGHT) && snaps & SNAP_UP) || (CORNER & (CORNER_BOTTOMLEFT | CORNER_BOTTOMRIGHT) && snaps & SNAP_DOWN)) {
- const double SIZEX = (sourceY.end - sourceY.start) * (BEGINSIZE.x / BEGINSIZE.y);
- if (CORNER & (CORNER_TOPLEFT | CORNER_BOTTOMLEFT))
- sourceX.start = sourceX.end - SIZEX;
- else
- sourceX.end = sourceX.start + SIZEX;
- }
- }
-
- sourcePos = {sourceX.start, sourceY.start};
- sourceSize = {sourceX.end - sourceX.start, sourceY.end - sourceY.start};
-}
-
-void IHyprLayout::onMouseMove(const Vector2D& mousePos) {
- if (g_pInputManager->m_currentlyDraggedWindow.expired())
- return;
-
- const auto DRAGGINGWINDOW = g_pInputManager->m_currentlyDraggedWindow.lock();
- static auto PDRAGTHRESHOLD = CConfigValue<Hyprlang::INT>("binds:drag_threshold");
-
- // Window invalid or drag begin size 0,0 meaning we rejected it.
- if ((!validMapped(DRAGGINGWINDOW) || m_beginDragSizeXY == Vector2D())) {
- g_pKeybindManager->changeMouseBindMode(MBIND_INVALID);
- return;
- }
-
- // Yoink dragged window here instead if using drag_threshold and it has been reached
- if (*PDRAGTHRESHOLD > 0 && !g_pInputManager->m_dragThresholdReached) {
- if ((m_beginDragXY.distanceSq(mousePos) <= std::pow(*PDRAGTHRESHOLD, 2) && m_beginDragXY == m_lastDragXY))
- return;
- g_pInputManager->m_dragThresholdReached = true;
- if (updateDragWindow())
- return;
- }
-
- static auto TIMER = std::chrono::high_resolution_clock::now(), MSTIMER = TIMER;
-
- const auto SPECIAL = DRAGGINGWINDOW->onSpecialWorkspace();
-
- const auto DELTA = Vector2D(mousePos.x - m_beginDragXY.x, mousePos.y - m_beginDragXY.y);
- const auto TICKDELTA = Vector2D(mousePos.x - m_lastDragXY.x, mousePos.y - m_lastDragXY.y);
-
- static auto PANIMATEMOUSE = CConfigValue<Hyprlang::INT>("misc:animate_mouse_windowdragging");
- static auto PANIMATE = CConfigValue<Hyprlang::INT>("misc:animate_manual_resizes");
-
- static auto SNAPENABLED = CConfigValue<Hyprlang::INT>("general:snap:enabled");
-
- const auto TIMERDELTA = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - TIMER).count();
- const auto MSDELTA = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - MSTIMER).count();
- const auto MSMONITOR = 1000.0 / g_pHyprRenderer->m_mostHzMonitor->m_refreshRate;
- static int totalMs = 0;
- bool canSkipUpdate = true;
-
- MSTIMER = std::chrono::high_resolution_clock::now();
-
- if (m_mouseMoveEventCount == 1)
- totalMs = 0;
-
- if (MSMONITOR > 16.0) {
- totalMs += MSDELTA < MSMONITOR ? MSDELTA : std::round(totalMs * 1.0 / m_mouseMoveEventCount);
- m_mouseMoveEventCount += 1;
-
- // check if time-window is enough to skip update on 60hz monitor
- canSkipUpdate = std::clamp(MSMONITOR - TIMERDELTA, 0.0, MSMONITOR) > totalMs * 1.0 / m_mouseMoveEventCount;
- }
-
- if ((abs(TICKDELTA.x) < 1.f && abs(TICKDELTA.y) < 1.f) || (TIMERDELTA < MSMONITOR && canSkipUpdate && (g_pInputManager->m_dragMode != MBIND_MOVE || *PANIMATEMOUSE)))
- return;
-
- TIMER = std::chrono::high_resolution_clock::now();
-
- m_lastDragXY = mousePos;
-
- g_pHyprRenderer->damageWindow(DRAGGINGWINDOW);
-
- if (g_pInputManager->m_dragMode == MBIND_MOVE) {
-
- Vector2D newPos = m_beginDragPositionXY + DELTA;
- Vector2D newSize = DRAGGINGWINDOW->m_realSize->goal();
-
- if (*SNAPENABLED && !DRAGGINGWINDOW->m_draggingTiled)
- performSnap(newPos, newSize, DRAGGINGWINDOW, MBIND_MOVE, -1, m_beginDragSizeXY);
-
- newPos = newPos.round();
-
- if (*PANIMATEMOUSE)
- *DRAGGINGWINDOW->m_realPosition = newPos;
- else {
- DRAGGINGWINDOW->m_realPosition->setValueAndWarp(newPos);
- DRAGGINGWINDOW->sendWindowSize();
- }
-
- DRAGGINGWINDOW->m_position = newPos;
-
- } else if (g_pInputManager->m_dragMode == MBIND_RESIZE || g_pInputManager->m_dragMode == MBIND_RESIZE_FORCE_RATIO || g_pInputManager->m_dragMode == MBIND_RESIZE_BLOCK_RATIO) {
- if (DRAGGINGWINDOW->m_isFloating) {
-
- Vector2D MINSIZE = DRAGGINGWINDOW->minSize().value_or(Vector2D{MIN_WINDOW_SIZE, MIN_WINDOW_SIZE});
- Vector2D MAXSIZE = DRAGGINGWINDOW->maxSize().value_or(Math::VECTOR2D_MAX);
-
- Vector2D newSize = m_beginDragSizeXY;
- Vector2D newPos = m_beginDragPositionXY;
-
- if (m_grabbedCorner == CORNER_BOTTOMRIGHT)
- newSize = newSize + DELTA;
- else if (m_grabbedCorner == CORNER_TOPLEFT)
- newSize = newSize - DELTA;
- else if (m_grabbedCorner == CORNER_TOPRIGHT)
- newSize = newSize + Vector2D(DELTA.x, -DELTA.y);
- else if (m_grabbedCorner == CORNER_BOTTOMLEFT)
- newSize = newSize + Vector2D(-DELTA.x, DELTA.y);
-
- eMouseBindMode mode = g_pInputManager->m_dragMode;
- if (DRAGGINGWINDOW->m_ruleApplicator->keepAspectRatio().valueOrDefault() && mode != MBIND_RESIZE_BLOCK_RATIO)
- mode = MBIND_RESIZE_FORCE_RATIO;
-
- if (m_beginDragSizeXY.x >= 1 && m_beginDragSizeXY.y >= 1 && mode == MBIND_RESIZE_FORCE_RATIO) {
-
- const float RATIO = m_beginDragSizeXY.y / m_beginDragSizeXY.x;
-
- if (MINSIZE.x * RATIO > MINSIZE.y)
- MINSIZE = Vector2D(MINSIZE.x, MINSIZE.x * RATIO);
- else
- MINSIZE = Vector2D(MINSIZE.y / RATIO, MINSIZE.y);
-
- if (MAXSIZE.x * RATIO < MAXSIZE.y)
- MAXSIZE = Vector2D(MAXSIZE.x, MAXSIZE.x * RATIO);
- else
- MAXSIZE = Vector2D(MAXSIZE.y / RATIO, MAXSIZE.y);
-
- if (newSize.x * RATIO > newSize.y)
- newSize = Vector2D(newSize.x, newSize.x * RATIO);
- else
- newSize = Vector2D(newSize.y / RATIO, newSize.y);
- }
-
- newSize = newSize.clamp(MINSIZE, MAXSIZE);
-
- if (m_grabbedCorner == CORNER_TOPLEFT)
- newPos = newPos - newSize + m_beginDragSizeXY;
- else if (m_grabbedCorner == CORNER_TOPRIGHT)
- newPos = newPos + Vector2D(0.0, (m_beginDragSizeXY - newSize).y);
- else if (m_grabbedCorner == CORNER_BOTTOMLEFT)
- newPos = newPos + Vector2D((m_beginDragSizeXY - newSize).x, 0.0);
-
- if (*SNAPENABLED) {
- performSnap(newPos, newSize, DRAGGINGWINDOW, mode, m_grabbedCorner, m_beginDragSizeXY);
- newSize = newSize.clamp(MINSIZE, MAXSIZE);
- }
-
- CBox wb = {newPos, newSize};
- wb.round();
-
- if (*PANIMATE) {
- *DRAGGINGWINDOW->m_realSize = wb.size();
- *DRAGGINGWINDOW->m_realPosition = wb.pos();
- } else {
- DRAGGINGWINDOW->m_realSize->setValueAndWarp(wb.size());
- DRAGGINGWINDOW->m_realPosition->setValueAndWarp(wb.pos());
- DRAGGINGWINDOW->sendWindowSize();
- }
-
- DRAGGINGWINDOW->m_position = wb.pos();
- DRAGGINGWINDOW->m_size = wb.size();
- } else {
- resizeActiveWindow(TICKDELTA, m_grabbedCorner, DRAGGINGWINDOW);
- }
- }
-
- // get middle point
- Vector2D middle = DRAGGINGWINDOW->m_realPosition->value() + DRAGGINGWINDOW->m_realSize->value() / 2.f;
-
- // and check its monitor
- const auto PMONITOR = g_pCompositor->getMonitorFromVector(middle);
-
- if (PMONITOR && !SPECIAL) {
- DRAGGINGWINDOW->m_monitor = PMONITOR;
- DRAGGINGWINDOW->moveToWorkspace(PMONITOR->m_activeWorkspace);
- DRAGGINGWINDOW->updateGroupOutputs();
-
- DRAGGINGWINDOW->updateToplevel();
- }
-
- DRAGGINGWINDOW->updateWindowDecos();
-
- g_pHyprRenderer->damageWindow(DRAGGINGWINDOW);
-}
-
-void IHyprLayout::changeWindowFloatingMode(PHLWINDOW pWindow) {
-
- if (pWindow->isFullscreen()) {
- Log::logger->log(Log::DEBUG, "changeWindowFloatingMode: fullscreen");
- g_pCompositor->setWindowFullscreenInternal(pWindow, FSMODE_NONE);
- }
-
- pWindow->m_pinned = false;
-
- g_pHyprRenderer->damageWindow(pWindow, true);
-
- const auto TILED = isWindowTiled(pWindow);
-
- // event
- g_pEventManager->postEvent(SHyprIPCEvent{"changefloatingmode", std::format("{:x},{}", rc<uintptr_t>(pWindow.get()), sc<int>(TILED))});
- EMIT_HOOK_EVENT("changeFloatingMode", pWindow);
-
- if (!TILED) {
- const auto PNEWMON = g_pCompositor->getMonitorFromVector(pWindow->m_realPosition->value() + pWindow->m_realSize->value() / 2.f);
- pWindow->m_monitor = PNEWMON;
- pWindow->moveToWorkspace(PNEWMON->m_activeSpecialWorkspace ? PNEWMON->m_activeSpecialWorkspace : PNEWMON->m_activeWorkspace);
- pWindow->updateGroupOutputs();
-
- const auto PWORKSPACE = PNEWMON->m_activeSpecialWorkspace ? PNEWMON->m_activeSpecialWorkspace : PNEWMON->m_activeWorkspace;
-
- if (PWORKSPACE->m_hasFullscreenWindow)
- g_pCompositor->setWindowFullscreenInternal(PWORKSPACE->getFullscreenWindow(), FSMODE_NONE);
-
- // save real pos cuz the func applies the default 5,5 mid
- const auto PSAVEDPOS = pWindow->m_realPosition->goal();
- const auto PSAVEDSIZE = pWindow->m_realSize->goal();
-
- // if the window is pseudo, update its size
- if (!pWindow->m_draggingTiled)
- pWindow->m_pseudoSize = pWindow->m_realSize->goal();
-
- pWindow->m_lastFloatingSize = PSAVEDSIZE;
-
- // move to narnia because we don't wanna find our own node. onWindowCreatedTiling should apply the coords back.
- pWindow->m_position = Vector2D(-999999, -999999);
-
- onWindowCreatedTiling(pWindow);
-
- pWindow->m_realPosition->setValue(PSAVEDPOS);
- pWindow->m_realSize->setValue(PSAVEDSIZE);
-
- // fix pseudo leaving artifacts
- g_pHyprRenderer->damageMonitor(pWindow->m_monitor.lock());
-
- if (pWindow == Desktop::focusState()->window())
- m_lastTiledWindow = pWindow;
- } else {
- onWindowRemovedTiling(pWindow);
-
- g_pCompositor->changeWindowZOrder(pWindow, true);
-
- CBox wb = {pWindow->m_realPosition->goal() + (pWindow->m_realSize->goal() - pWindow->m_lastFloatingSize) / 2.f, pWindow->m_lastFloatingSize};
- wb.round();
-
- if (!(pWindow->m_isFloating && pWindow->m_isPseudotiled) && DELTALESSTHAN(pWindow->m_realSize->goal().x, pWindow->m_lastFloatingSize.x, 10) &&
- DELTALESSTHAN(pWindow->m_realSize->goal().y, pWindow->m_lastFloatingSize.y, 10)) {
- wb = {wb.pos() + Vector2D{10, 10}, wb.size() - Vector2D{20, 20}};
- }
-
- pWindow->m_size = wb.size();
- pWindow->m_position = wb.pos();
-
- fitFloatingWindowOnMonitor(pWindow, wb);
-
- g_pHyprRenderer->damageMonitor(pWindow->m_monitor.lock());
-
- pWindow->m_ruleApplicator->resetProps(Desktop::Rule::RULE_PROP_ALL, Desktop::Types::PRIORITY_LAYOUT);
- pWindow->updateWindowData();
-
- if (pWindow == m_lastTiledWindow)
- m_lastTiledWindow.reset();
- }
-
- pWindow->m_ruleApplicator->propertiesChanged(Desktop::Rule::RULE_PROP_ON_WORKSPACE | Desktop::Rule::RULE_PROP_FLOATING);
- pWindow->updateDecorationValues();
- pWindow->updateToplevel();
- g_pHyprRenderer->damageWindow(pWindow);
-}
-
-void IHyprLayout::fitFloatingWindowOnMonitor(PHLWINDOW w, std::optional<CBox> tb) {
- if (!w->m_isFloating)
- return;
-
- const auto PMONITOR = w->m_monitor.lock();
-
- if (!PMONITOR)
- return;
-
- const auto EXTENTS = w->getWindowExtentsUnified(Desktop::View::RESERVED_EXTENTS | Desktop::View::INPUT_EXTENTS);
- CBox targetBoxMonLocal = tb.value_or(w->getWindowMainSurfaceBox()).translate(-PMONITOR->m_position).addExtents(EXTENTS);
- const auto MONITOR_LOCAL_BOX = PMONITOR->logicalBoxMinusReserved().translate(-PMONITOR->m_position);
-
- if (targetBoxMonLocal.w < MONITOR_LOCAL_BOX.w) {
- if (targetBoxMonLocal.x < MONITOR_LOCAL_BOX.x)
- targetBoxMonLocal.x = MONITOR_LOCAL_BOX.x;
- else if (targetBoxMonLocal.x + targetBoxMonLocal.w > MONITOR_LOCAL_BOX.w)
- targetBoxMonLocal.x = MONITOR_LOCAL_BOX.w - targetBoxMonLocal.w;
- }
-
- if (targetBoxMonLocal.h < MONITOR_LOCAL_BOX.h) {
- if (targetBoxMonLocal.y < MONITOR_LOCAL_BOX.y)
- targetBoxMonLocal.y = MONITOR_LOCAL_BOX.y;
- else if (targetBoxMonLocal.y + targetBoxMonLocal.h > MONITOR_LOCAL_BOX.h)
- targetBoxMonLocal.y = MONITOR_LOCAL_BOX.h - targetBoxMonLocal.h;
- }
-
- *w->m_realPosition = (targetBoxMonLocal.pos() + PMONITOR->m_position + EXTENTS.topLeft).round();
- *w->m_realSize = (targetBoxMonLocal.size() - EXTENTS.topLeft - EXTENTS.bottomRight).round();
-}
-
-void IHyprLayout::moveActiveWindow(const Vector2D& delta, PHLWINDOW pWindow) {
- const auto PWINDOW = pWindow ? pWindow : Desktop::focusState()->window();
-
- if (!validMapped(PWINDOW))
- return;
-
- if (!PWINDOW->m_isFloating) {
- Log::logger->log(Log::DEBUG, "Dwindle cannot move a tiled window in moveActiveWindow!");
- return;
- }
-
- PWINDOW->setAnimationsToMove();
-
- PWINDOW->m_position += delta;
- *PWINDOW->m_realPosition = PWINDOW->m_realPosition->goal() + delta;
-
- g_pHyprRenderer->damageWindow(PWINDOW);
-}
-
-void IHyprLayout::onWindowFocusChange(PHLWINDOW pNewFocus) {
- m_lastTiledWindow = pNewFocus && !pNewFocus->m_isFloating ? pNewFocus : m_lastTiledWindow;
-}
-
-PHLWINDOW IHyprLayout::getNextWindowCandidate(PHLWINDOW pWindow) {
- // although we don't expect nullptrs here, let's verify jic
- if (!pWindow)
- return nullptr;
-
- const auto PWORKSPACE = pWindow->m_workspace;
-
- // first of all, if this is a fullscreen workspace,
- if (PWORKSPACE->m_hasFullscreenWindow)
- return PWORKSPACE->getFullscreenWindow();
-
- if (pWindow->m_isFloating) {
-
- // find whether there is a floating window below this one
- for (auto const& w : g_pCompositor->m_windows) {
- if (w->m_isMapped && !w->isHidden() && w->m_isFloating && !w->isX11OverrideRedirect() && w->m_workspace == pWindow->m_workspace && !w->m_X11ShouldntFocus &&
- !w->m_ruleApplicator->noFocus().valueOrDefault() && w != pWindow) {
- if (VECINRECT((pWindow->m_size / 2.f + pWindow->m_position), w->m_position.x, w->m_position.y, w->m_position.x + w->m_size.x, w->m_position.y + w->m_size.y)) {
- return w;
- }
- }
- }
-
- // let's try the last tiled window.
- if (m_lastTiledWindow.lock() && m_lastTiledWindow->m_workspace == pWindow->m_workspace)
- return m_lastTiledWindow.lock();
-
- // if we don't, let's try to find any window that is in the middle
- if (const auto PWINDOWCANDIDATE =
- g_pCompositor->vectorToWindowUnified(pWindow->middle(), Desktop::View::RESERVED_EXTENTS | Desktop::View::INPUT_EXTENTS | Desktop::View::ALLOW_FLOATING);
- PWINDOWCANDIDATE && PWINDOWCANDIDATE != pWindow)
- return PWINDOWCANDIDATE;
-
- // if not, floating window
- for (auto const& w : g_pCompositor->m_windows) {
- if (w->m_isMapped && !w->isHidden() && w->m_isFloating && !w->isX11OverrideRedirect() && w->m_workspace == pWindow->m_workspace && !w->m_X11ShouldntFocus &&
- !w->m_ruleApplicator->noFocus().valueOrDefault() && w != pWindow)
- return w;
- }
-
- // if there is no candidate, too bad
- return nullptr;
- }
-
- // if it was a tiled window, we first try to find the window that will replace it.
- auto pWindowCandidate = g_pCompositor->vectorToWindowUnified(pWindow->middle(), Desktop::View::RESERVED_EXTENTS | Desktop::View::INPUT_EXTENTS | Desktop::View::ALLOW_FLOATING);
-
- if (!pWindowCandidate)
- pWindowCandidate = PWORKSPACE->getTopLeftWindow();
-
- if (!pWindowCandidate)
- pWindowCandidate = PWORKSPACE->getFirstWindow();
-
- if (!pWindowCandidate || pWindow == pWindowCandidate || !pWindowCandidate->m_isMapped || pWindowCandidate->isHidden() || pWindowCandidate->m_X11ShouldntFocus ||
- pWindowCandidate->isX11OverrideRedirect() || pWindowCandidate->m_monitor != Desktop::focusState()->monitor())
- return nullptr;
-
- return pWindowCandidate;
-}
-
-bool IHyprLayout::isWindowReachable(PHLWINDOW pWindow) {
- return pWindow && (!pWindow->isHidden() || pWindow->m_groupData.pNextWindow);
-}
-
-void IHyprLayout::bringWindowToTop(PHLWINDOW pWindow) {
- if (pWindow == nullptr)
- return;
-
- if (pWindow->isHidden() && pWindow->m_groupData.pNextWindow) {
- // grouped, change the current to this window
- pWindow->setGroupCurrent(pWindow);
- }
-}
-
-void IHyprLayout::requestFocusForWindow(PHLWINDOW pWindow) {
- bringWindowToTop(pWindow);
- Desktop::focusState()->fullWindowFocus(pWindow);
- g_pCompositor->warpCursorTo(pWindow->middle());
-}
-
-Vector2D IHyprLayout::predictSizeForNewWindowFloating(PHLWINDOW pWindow) { // get all rules, see if we have any size overrides.
- Vector2D sizeOverride = {};
- if (Desktop::focusState()->monitor()) {
-
- // If `persistentsize` is set, use the stored size if available.
- const bool HASPERSISTENTSIZE = pWindow->m_ruleApplicator->persistentSize().valueOrDefault();
-
- const auto STOREDSIZE = HASPERSISTENTSIZE ? g_pConfigManager->getStoredFloatingSize(pWindow) : std::nullopt;
-
- if (STOREDSIZE.has_value()) {
- Log::logger->log(Log::DEBUG, "using stored size {}x{} for new floating window {}::{}", STOREDSIZE->x, STOREDSIZE->y, pWindow->m_class, pWindow->m_title);
- return STOREDSIZE.value();
- }
-
- if (!pWindow->m_ruleApplicator->static_.size.empty()) {
- const auto SIZE = pWindow->calculateExpression(pWindow->m_ruleApplicator->static_.size);
- if (SIZE)
- return SIZE.value();
- }
- }
-
- return sizeOverride;
-}
-
-Vector2D IHyprLayout::predictSizeForNewWindow(PHLWINDOW pWindow) {
- bool shouldBeFloated = g_pXWaylandManager->shouldBeFloated(pWindow, true) || pWindow->m_ruleApplicator->static_.floating.value_or(false);
-
- Vector2D sizePredicted = {};
-
- if (!shouldBeFloated)
- sizePredicted = predictSizeForNewWindowTiled();
- else
- sizePredicted = predictSizeForNewWindowFloating(pWindow);
-
- Vector2D maxSize = pWindow->m_xdgSurface->m_toplevel->m_pending.maxSize;
-
- if ((maxSize.x > 0 && maxSize.x < sizePredicted.x) || (maxSize.y > 0 && maxSize.y < sizePredicted.y))
- sizePredicted = {};
-
- return sizePredicted;
-}
-
-bool IHyprLayout::updateDragWindow() {
- const auto DRAGGINGWINDOW = g_pInputManager->m_currentlyDraggedWindow.lock();
- const bool WAS_FULLSCREEN = DRAGGINGWINDOW->isFullscreen();
-
- if (g_pInputManager->m_dragThresholdReached) {
- if (WAS_FULLSCREEN) {
- Log::logger->log(Log::DEBUG, "Dragging a fullscreen window");
- g_pCompositor->setWindowFullscreenInternal(DRAGGINGWINDOW, FSMODE_NONE);
- }
-
- const auto PWORKSPACE = DRAGGINGWINDOW->m_workspace;
-
- if (PWORKSPACE->m_hasFullscreenWindow && (!DRAGGINGWINDOW->m_isFloating || (!DRAGGINGWINDOW->m_createdOverFullscreen && !DRAGGINGWINDOW->m_pinned))) {
- Log::logger->log(Log::DEBUG, "Rejecting drag on a fullscreen workspace. (window under fullscreen)");
- g_pKeybindManager->changeMouseBindMode(MBIND_INVALID);
- return true;
- }
- }
-
- DRAGGINGWINDOW->m_draggingTiled = false;
- m_draggingWindowOriginalFloatSize = DRAGGINGWINDOW->m_lastFloatingSize;
-
- if (WAS_FULLSCREEN && DRAGGINGWINDOW->m_isFloating) {
- const auto MOUSECOORDS = g_pInputManager->getMouseCoordsInternal();
- *DRAGGINGWINDOW->m_realPosition = MOUSECOORDS - DRAGGINGWINDOW->m_realSize->goal() / 2.f;
- } else if (!DRAGGINGWINDOW->m_isFloating && g_pInputManager->m_dragMode == MBIND_MOVE) {
- Vector2D MINSIZE = DRAGGINGWINDOW->minSize().value_or(Vector2D{MIN_WINDOW_SIZE, MIN_WINDOW_SIZE});
- DRAGGINGWINDOW->m_lastFloatingSize = (DRAGGINGWINDOW->m_realSize->goal() * 0.8489).clamp(MINSIZE, Vector2D{}).floor();
- *DRAGGINGWINDOW->m_realPosition = g_pInputManager->getMouseCoordsInternal() - DRAGGINGWINDOW->m_realSize->goal() / 2.f;
- if (g_pInputManager->m_dragThresholdReached) {
- changeWindowFloatingMode(DRAGGINGWINDOW);
- DRAGGINGWINDOW->m_isFloating = true;
- DRAGGINGWINDOW->m_draggingTiled = true;
- }
- }
-
- m_beginDragXY = g_pInputManager->getMouseCoordsInternal();
- m_beginDragPositionXY = DRAGGINGWINDOW->m_realPosition->goal();
- m_beginDragSizeXY = DRAGGINGWINDOW->m_realSize->goal();
- m_lastDragXY = m_beginDragXY;
-
- return false;
-}
-
-CBox IHyprLayout::workAreaOnWorkspace(const PHLWORKSPACE& pWorkspace) {
- if (!pWorkspace || !pWorkspace->m_monitor)
- return {};
-
- const auto WORKSPACERULE = g_pConfigManager->getWorkspaceRuleFor(pWorkspace);
-
- auto workArea = pWorkspace->m_monitor->logicalBoxMinusReserved();
-
- static auto PGAPSOUTDATA = CConfigValue<Hyprlang::CUSTOMTYPE>("general:gaps_out");
- auto* const PGAPSOUT = sc<CCssGapData*>((PGAPSOUTDATA.ptr())->getData());
- auto gapsOut = WORKSPACERULE.gapsOut.value_or(*PGAPSOUT);
-
- Desktop::CReservedArea reservedGaps{gapsOut.m_top, gapsOut.m_right, gapsOut.m_bottom, gapsOut.m_left};
-
- reservedGaps.applyip(workArea);
-
- return workArea;
-}