diff --git a/hyprtester/src/tests/main/snap.cpp b/hyprtester/src/tests/main/snap.cpp index c7c2b256c..5c0e624dc 100644 --- a/hyprtester/src/tests/main/snap.cpp +++ b/hyprtester/src/tests/main/snap.cpp @@ -45,69 +45,68 @@ static void expectSnapMove(const Vector2D FROM, const Vector2D* TO) { EXPECT_CONTAINS(getFromSocket("/activewindow"), std::format("at: {},{}", B.x, B.y)); } -static void testSnap(const bool OVERLAP, const bool RESPECT) { +static void testWindowSnap(const bool RESPECTGAPS) { const double BORDERSIZE = 2; const double WINDOWSIZE = 100; - // test window snapping - { - const double OTHER = 500; - const double WINDOWGAP = 8; - const double GAPSIN = 5; - const double GAP = (RESPECT ? GAPSIN : 0) + BORDERSIZE + (OVERLAP ? 0 : BORDERSIZE); - const double END = GAP + WINDOWSIZE; + const double OTHER = 500; + const double WINDOWGAP = 8; + const double GAPSIN = 5; + const double GAP = (RESPECTGAPS ? 2 * GAPSIN : 0) + (2 * BORDERSIZE); + const double END = GAP + WINDOWSIZE; - double x; - Vector2D predict; + double x; + Vector2D predict; - x = WINDOWGAP + END; - expectSnapMove({OTHER + x, OTHER}, nullptr); - expectSnapMove({OTHER - x, OTHER}, nullptr); - expectSnapMove({OTHER, OTHER + x}, nullptr); - expectSnapMove({OTHER, OTHER - x}, nullptr); - x -= 1; - expectSnapMove({OTHER + x, OTHER}, &(predict = {OTHER + END, OTHER})); - expectSnapMove({OTHER - x, OTHER}, &(predict = {OTHER - END, OTHER})); - expectSnapMove({OTHER, OTHER + x}, &(predict = {OTHER, OTHER + END})); - expectSnapMove({OTHER, OTHER - x}, &(predict = {OTHER, OTHER - END})); - } + x = WINDOWGAP + END; + expectSnapMove({OTHER + x, OTHER}, nullptr); + expectSnapMove({OTHER - x, OTHER}, nullptr); + expectSnapMove({OTHER, OTHER + x}, nullptr); + expectSnapMove({OTHER, OTHER - x}, nullptr); + x -= 1; + expectSnapMove({OTHER + x, OTHER}, &(predict = {OTHER + END, OTHER})); + expectSnapMove({OTHER - x, OTHER}, &(predict = {OTHER - END, OTHER})); + expectSnapMove({OTHER, OTHER + x}, &(predict = {OTHER, OTHER + END})); + expectSnapMove({OTHER, OTHER - x}, &(predict = {OTHER, OTHER - END})); +} - // test monitor snapping - { - const double MONITORGAP = 10; - const double GAPSOUT = 20; - const double RESP = (RESPECT ? GAPSOUT : 0); - const double GAP = RESP + (OVERLAP ? 0 : BORDERSIZE); - const double END = GAP + WINDOWSIZE; +static void testMonitorSnap(const bool RESPECTGAPS, const bool OVERLAP) { + const double BORDERSIZE = 2; + const double WINDOWSIZE = 100; - double x; - Vector2D predict; + const double MONITORGAP = 10; + const double GAPSOUT = 20; + const double RESP = (RESPECTGAPS ? GAPSOUT : 0); + const double GAP = RESP + (OVERLAP ? 0 : BORDERSIZE); + const double END = GAP + WINDOWSIZE; - x = MONITORGAP + GAP; - expectSnapMove({x, x}, nullptr); - x -= 1; - expectSnapMove({x, x}, &(predict = {GAP, GAP})); + double x; + Vector2D predict; - x = MONITORGAP + END; - expectSnapMove({1920 - x, 1080 - x}, nullptr); - x -= 1; - expectSnapMove({1920 - x, 1080 - x}, &(predict = {1920 - END, 1080 - END})); + x = MONITORGAP + GAP; + expectSnapMove({x, x}, nullptr); + x -= 1; + expectSnapMove({x, x}, &(predict = {GAP, GAP})); - // test reserved area - const double RESERVED = 200; - const double RGAP = RESERVED + RESP + BORDERSIZE; - const double REND = RGAP + WINDOWSIZE; + x = MONITORGAP + END; + expectSnapMove({1920 - x, 1080 - x}, nullptr); + x -= 1; + expectSnapMove({1920 - x, 1080 - x}, &(predict = {1920 - END, 1080 - END})); - x = MONITORGAP + RGAP; - expectSnapMove({x, x}, nullptr); - x -= 1; - expectSnapMove({x, x}, &(predict = {RGAP, RGAP})); + // test reserved area + const double RESERVED = 200; + const double RGAP = RESERVED + RESP + BORDERSIZE; + const double REND = RGAP + WINDOWSIZE; - x = MONITORGAP + REND; - expectSnapMove({1920 - x, 1080 - x}, nullptr); - x -= 1; - expectSnapMove({1920 - x, 1080 - x}, &(predict = {1920 - REND, 1080 - REND})); - } + x = MONITORGAP + RGAP; + expectSnapMove({x, x}, nullptr); + x -= 1; + expectSnapMove({x, x}, &(predict = {RGAP, RGAP})); + + x = MONITORGAP + REND; + expectSnapMove({1920 - x, 1080 - x}, nullptr); + x -= 1; + expectSnapMove({1920 - x, 1080 - x}, &(predict = {1920 - REND, 1080 - REND})); } static bool test() { @@ -143,20 +142,22 @@ static bool test() { EXPECT(Tests::windowCount(), 2); NLog::log(""); - testSnap(false, false); - - NLog::log("\n{}Turning on border_overlap", Colors::YELLOW); - OK(getFromSocket("/keyword general:snap:border_overlap true")); - testSnap(true, false); + testWindowSnap(false); + testMonitorSnap(false, false); NLog::log("\n{}Turning on respect_gaps", Colors::YELLOW); - OK(getFromSocket("/keyword general:snap:border_overlap false")); OK(getFromSocket("/keyword general:snap:respect_gaps true")); - testSnap(false, true); + testWindowSnap(true); + testMonitorSnap(true, false); + + NLog::log("\n{}Turning on border_overlap", Colors::YELLOW); + OK(getFromSocket("/keyword general:snap:respect_gaps false")); + OK(getFromSocket("/keyword general:snap:border_overlap true")); + testMonitorSnap(false, true); NLog::log("\n{}Turning on both border_overlap and respect_gaps", Colors::YELLOW); - OK(getFromSocket("/keyword general:snap:border_overlap true")); - testSnap(true, true); + OK(getFromSocket("/keyword general:snap:respect_gaps true")); + testMonitorSnap(true, true); // kill all NLog::log("\n{}Killing all windows", Colors::YELLOW); diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index 8cdb5cebe..ceb21d09c 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -236,6 +236,18 @@ CBox CWindow::getWindowIdealBoundingBoxIgnoreReserved() { return CBox{(int)POS.x, (int)POS.y, (int)SIZE.x, (int)SIZE.y}; } +SBoxExtents CWindow::getWindowExtentsUnified(uint64_t properties) { + SBoxExtents extents = {.topLeft = {0, 0}, .bottomRight = {0, 0}}; + if (properties & RESERVED_EXTENTS) + extents.addExtents(g_pDecorationPositioner->getWindowDecorationReserved(m_self.lock())); + if (properties & INPUT_EXTENTS) + extents.addExtents(g_pDecorationPositioner->getWindowDecorationExtents(m_self.lock(), true)); + if (properties & FULL_EXTENTS) + extents.addExtents(g_pDecorationPositioner->getWindowDecorationExtents(m_self.lock(), false)); + + return extents; +} + CBox CWindow::getWindowBoxUnified(uint64_t properties) { if (m_windowData.dimAround.valueOrDefault()) { const auto PMONITOR = m_monitor.lock(); @@ -243,16 +255,8 @@ CBox CWindow::getWindowBoxUnified(uint64_t properties) { return {PMONITOR->m_position.x, PMONITOR->m_position.y, PMONITOR->m_size.x, PMONITOR->m_size.y}; } - SBoxExtents EXTENTS = {.topLeft = {0, 0}, .bottomRight = {0, 0}}; - if (properties & RESERVED_EXTENTS) - EXTENTS.addExtents(g_pDecorationPositioner->getWindowDecorationReserved(m_self.lock())); - if (properties & INPUT_EXTENTS) - EXTENTS.addExtents(g_pDecorationPositioner->getWindowDecorationExtents(m_self.lock(), true)); - if (properties & FULL_EXTENTS) - EXTENTS.addExtents(g_pDecorationPositioner->getWindowDecorationExtents(m_self.lock(), false)); - CBox box = {m_realPosition->value().x, m_realPosition->value().y, m_realSize->value().x, m_realSize->value().y}; - box.addExtents(EXTENTS); + box.addExtents(getWindowExtentsUnified(properties)); return box; } diff --git a/src/desktop/Window.hpp b/src/desktop/Window.hpp index 1c4d3c67f..8f4216725 100644 --- a/src/desktop/Window.hpp +++ b/src/desktop/Window.hpp @@ -324,6 +324,7 @@ class CWindow { CBox getFullWindowBoundingBox(); SBoxExtents getFullWindowExtents(); CBox getWindowBoxUnified(uint64_t props); + SBoxExtents getWindowExtentsUnified(uint64_t props); CBox getWindowIdealBoundingBoxIgnoreReserved(); void addWindowDeco(UP deco); void updateWindowDecos(); diff --git a/src/layout/IHyprLayout.cpp b/src/layout/IHyprLayout.cpp index 629fb3fb8..d97f87961 100644 --- a/src/layout/IHyprLayout.cpp +++ b/src/layout/IHyprLayout.cpp @@ -420,42 +420,38 @@ void IHyprLayout::performSnap(Vector2D& sourcePos, Vector2D& sourceSize, PHLWIND static auto SNAPBORDEROVERLAP = CConfigValue("general:snap:border_overlap"); static auto SNAPRESPECTGAPS = CConfigValue("general:snap:respect_gaps"); + static auto PGAPSIN = CConfigValue("general:gaps_in"); + static auto PGAPSOUT = CConfigValue("general:gaps_out"); + const auto GAPSNONE = CCssGapData{0, 0, 0, 0}; + const SnapFn SNAP = (MODE == MBIND_MOVE) ? snapMove : snapResize; int snaps = 0; - const bool OVERLAP = *SNAPBORDEROVERLAP; - const int DRAGGINGBORDERSIZE = DRAGGINGWINDOW->getRealBorderSize(); - struct SRange { double start = 0; double end = 0; }; - SRange sourceX = {sourcePos.x, sourcePos.x + sourceSize.x}; - SRange sourceY = {sourcePos.y, sourcePos.y + sourceSize.y}; + const auto EXTENTS = DRAGGINGWINDOW->getWindowExtentsUnified(RESERVED_EXTENTS | 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; - double gapOffset = 0; - if (*SNAPRESPECTGAPS) { - static auto PGAPSINDATA = CConfigValue("general:gaps_in"); - auto* PGAPSINPTR = (CCssGapData*)(PGAPSINDATA.ptr())->getData(); - gapOffset = std::max({PGAPSINPTR->m_left, PGAPSINPTR->m_right, PGAPSINPTR->m_top, PGAPSINPTR->m_bottom}); - } + const auto* GAPSIN = *SNAPRESPECTGAPS ? (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 int OTHERBORDERSIZE = other->getRealBorderSize(); - const double BORDERSIZE = OVERLAP ? std::max(DRAGGINGBORDERSIZE, OTHERBORDERSIZE) : (DRAGGINGBORDERSIZE + OTHERBORDERSIZE); - - const CBox SURF = other->getWindowMainSurfaceBox(); - const SRange SURFBX = {SURF.x - BORDERSIZE - gapOffset, SURF.x + SURF.w + BORDERSIZE + gapOffset}; - const SRange SURFBY = {SURF.y - BORDERSIZE - gapOffset, SURF.y + SURF.h + BORDERSIZE + gapOffset}; + const CBox SURF = other->getWindowBoxUnified(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) { @@ -478,9 +474,8 @@ void IHyprLayout::performSnap(Vector2D& sourcePos, Vector2D& sourceSize, PHLWIND } // corner snapping - const double BORDERDIFF = OTHERBORDERSIZE - DRAGGINGBORDERSIZE; if (sourceX.start == SURFBX.end || SURFBX.start == sourceX.end) { - const SRange SURFY = {SURF.y - BORDERDIFF, SURF.y + SURF.h + BORDERDIFF}; + 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; @@ -490,7 +485,7 @@ void IHyprLayout::performSnap(Vector2D& sourcePos, Vector2D& sourceSize, PHLWIND } } if (sourceY.start == SURFBY.end || SURFBY.start == sourceY.end) { - const SRange SURFX = {SURF.x - BORDERDIFF, SURF.x + SURF.w + BORDERDIFF}; + 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; @@ -504,46 +499,44 @@ void IHyprLayout::performSnap(Vector2D& sourcePos, Vector2D& sourceSize, PHLWIND if (*SNAPMONITORGAP) { const double GAPSIZE = *SNAPMONITORGAP; - const double BORDERDIFF = OVERLAP ? DRAGGINGBORDERSIZE : 0; + const auto EXTENTNONE = SBoxExtents{{0, 0}, {0, 0}}; + const auto* EXTENTDIFF = *SNAPBORDEROVERLAP ? &EXTENTS : &EXTENTNONE; const auto MON = DRAGGINGWINDOW->m_monitor.lock(); - double gapOffset = 0; - if (*SNAPRESPECTGAPS) { - static auto PGAPSOUTDATA = CConfigValue("general:gaps_out"); - auto* PGAPSOUTPTR = (CCssGapData*)(PGAPSOUTDATA.ptr())->getData(); - gapOffset = std::max({PGAPSOUTPTR->m_left, PGAPSOUTPTR->m_right, PGAPSOUTPTR->m_top, PGAPSOUTPTR->m_bottom}); - } + const auto* GAPSOUT = *SNAPRESPECTGAPS ? (CCssGapData*)PGAPSOUT.ptr()->getData() : &GAPSNONE; - SRange monX = {MON->m_position.x + MON->m_reservedTopLeft.x + DRAGGINGBORDERSIZE + gapOffset, - MON->m_position.x + MON->m_size.x - MON->m_reservedBottomRight.x - DRAGGINGBORDERSIZE - gapOffset}; - SRange monY = {MON->m_position.y + MON->m_reservedTopLeft.y + DRAGGINGBORDERSIZE + gapOffset, - MON->m_position.y + MON->m_size.y - MON->m_reservedBottomRight.y - DRAGGINGBORDERSIZE - gapOffset}; + SRange monX = {MON->m_position.x + MON->m_reservedTopLeft.x + GAPSOUT->m_left, MON->m_position.x + MON->m_size.x - MON->m_reservedBottomRight.x - GAPSOUT->m_right}; + SRange monY = {MON->m_position.y + MON->m_reservedTopLeft.y + GAPSOUT->m_top, MON->m_position.y + MON->m_size.y - MON->m_reservedBottomRight.y - GAPSOUT->m_bottom}; if (CORNER & (CORNER_TOPLEFT | CORNER_BOTTOMLEFT) && ((MON->m_reservedTopLeft.x > 0 && canSnap(sourceX.start, monX.start, GAPSIZE)) || - canSnap(sourceX.start, (monX.start -= MON->m_reservedTopLeft.x + BORDERDIFF), GAPSIZE))) { + canSnap(sourceX.start, (monX.start -= MON->m_reservedTopLeft.x + EXTENTDIFF->topLeft.x), GAPSIZE))) { SNAP(sourceX.start, sourceX.end, monX.start); snaps |= SNAP_LEFT; } if (CORNER & (CORNER_TOPRIGHT | CORNER_BOTTOMRIGHT) && ((MON->m_reservedBottomRight.x > 0 && canSnap(sourceX.end, monX.end, GAPSIZE)) || - canSnap(sourceX.end, (monX.end += MON->m_reservedBottomRight.x + BORDERDIFF), GAPSIZE))) { + canSnap(sourceX.end, (monX.end += MON->m_reservedBottomRight.x + EXTENTDIFF->bottomRight.x), GAPSIZE))) { SNAP(sourceX.end, sourceX.start, monX.end); snaps |= SNAP_RIGHT; } if (CORNER & (CORNER_TOPLEFT | CORNER_TOPRIGHT) && ((MON->m_reservedTopLeft.y > 0 && canSnap(sourceY.start, monY.start, GAPSIZE)) || - canSnap(sourceY.start, (monY.start -= MON->m_reservedTopLeft.y + BORDERDIFF), GAPSIZE))) { + canSnap(sourceY.start, (monY.start -= MON->m_reservedTopLeft.y + EXTENTDIFF->topLeft.y), GAPSIZE))) { SNAP(sourceY.start, sourceY.end, monY.start); snaps |= SNAP_UP; } if (CORNER & (CORNER_BOTTOMLEFT | CORNER_BOTTOMRIGHT) && ((MON->m_reservedBottomRight.y > 0 && canSnap(sourceY.end, monY.end, GAPSIZE)) || - canSnap(sourceY.end, (monY.end += MON->m_reservedBottomRight.y + BORDERDIFF), GAPSIZE))) { + canSnap(sourceY.end, (monY.end += MON->m_reservedBottomRight.y + 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);