From ce906736217952e2da2bb254db2e59af63079c89 Mon Sep 17 00:00:00 2001 From: Agent_00Ming Date: Tue, 11 Jun 2024 21:06:38 -0400 Subject: [PATCH] Customizable directional window resize logic --- src/Compositor.cpp | 4 +- src/config/ConfigManager.cpp | 2 + src/layout/DwindleLayout.cpp | 74 +++++--- src/layout/DwindleLayout.hpp | 4 +- src/layout/IHyprLayout.cpp | 315 +++++++++++++++++++++++++++++++---- src/layout/IHyprLayout.hpp | 18 +- src/layout/MasterLayout.cpp | 4 +- 7 files changed, 360 insertions(+), 61 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 2ed1a951..d6a62400 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -701,7 +701,7 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper if (properties & ALLOW_FLOATING) { for (auto& w : m_vWindows | std::views::reverse) { const auto BB = w->getWindowBoxUnified(properties); - CBox box = BB.copy().expand(w->m_iX11Type == 2 ? BORDER_GRAB_AREA : 0); + CBox box = BB.copy().expand(w->m_iX11Type != 2 ? BORDER_GRAB_AREA : 0); if (w->m_bIsFloating && w->m_bIsMapped && !w->isHidden() && !w->m_bX11ShouldntFocus && w->m_bPinned && !w->m_sAdditionalConfigData.noFocus && w != pIgnoreWindow) { if (box.containsPoint(g_pPointerManager->position())) return w; @@ -730,7 +730,7 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper BB.x + BB.width <= PWINDOWMONITOR->vecPosition.x + PWINDOWMONITOR->vecSize.x && BB.y + BB.height <= PWINDOWMONITOR->vecPosition.y + PWINDOWMONITOR->vecSize.y) continue; - CBox box = BB.copy().expand(w->m_iX11Type == 2 ? BORDER_GRAB_AREA : 0); + CBox box = BB.copy().expand(w->m_iX11Type != 2 ? BORDER_GRAB_AREA : 0); if (w->m_bIsFloating && w->m_bIsMapped && isWorkspaceVisible(w->m_pWorkspace) && !w->isHidden() && !w->m_bPinned && !w->m_sAdditionalConfigData.noFocus && w != pIgnoreWindow && (!aboveFullscreen || w->m_bCreatedOverFullscreen)) { // OR windows should add focus to parent diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index a4a80944..38fb7f9a 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -324,6 +324,8 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("general:layout", {"dwindle"}); m_pConfig->addConfigValue("general:allow_tearing", Hyprlang::INT{0}); m_pConfig->addConfigValue("general:resize_corner", Hyprlang::INT{0}); + m_pConfig->addConfigValue("general:edge_depth", {0.0f}); + m_pConfig->addConfigValue("general:resize_mouse_bind_pattern", Hyprlang::INT{0}); m_pConfig->addConfigValue("misc:disable_hyprland_logo", Hyprlang::INT{0}); m_pConfig->addConfigValue("misc:disable_splash_rendering", Hyprlang::INT{0}); diff --git a/src/layout/DwindleLayout.cpp b/src/layout/DwindleLayout.cpp index cbeaa420..01b51d4c 100644 --- a/src/layout/DwindleLayout.cpp +++ b/src/layout/DwindleLayout.cpp @@ -2,6 +2,7 @@ #include "../render/decorations/CHyprGroupBarDecoration.hpp" #include "../Compositor.hpp" #include "../config/ConfigValue.hpp" +#include "debug/Log.hpp" void SDwindleNodeData::recalcSizePosRecursive(bool force, bool horizontalOverride, bool verticalOverride) { if (children[0]) { @@ -624,29 +625,60 @@ void CHyprDwindleLayout::resizeActiveWindow(const Vector2D& pixResize, eRectCorn if (!m_PseudoDragFlags.started) { m_PseudoDragFlags.started = true; - const auto pseudoSize = PWINDOW->m_vRealSize.goal(); - const auto mouseOffset = g_pInputManager->getMouseCoordsInternal() - (PNODE->box.pos() + ((PNODE->box.size() / 2) - (pseudoSize / 2))); + // I know this appears like 4 times... + static auto b = CConfigValue("general:border_size"); + static auto r = CConfigValue("general:resize_on_border"); + static auto e = CConfigValue("general:extend_border_grab_area"); + const CBox h = {-(*b + *e * (*r != 0)), -(*b + *e * (*r != 0)), 2 * (*b + *e * (*r != 0)) + 1, 2 * (*b + *e * (*r != 0)) + 1}; // why weird vs IHyprlayout:432 ? + const CBox p = {PWINDOW->m_vRealPosition.goal() + h.pos(), PWINDOW->m_vRealSize.goal() + h.size()}; - if (mouseOffset.x > 0 && mouseOffset.x < pseudoSize.x && mouseOffset.y > 0 && mouseOffset.y < pseudoSize.y) { - m_PseudoDragFlags.pseudo = true; - m_PseudoDragFlags.xExtent = mouseOffset.x > pseudoSize.x / 2; - m_PseudoDragFlags.yExtent = mouseOffset.y > pseudoSize.y / 2; + if (p.containsPoint(g_pInputManager->getMouseCoordsInternal())) { + m_PseudoDragFlags.pseudo = true; - PWINDOW->m_vPseudoSize = pseudoSize; - } else { + switch (corner) { + case CORNER_TOPLEFT: + m_PseudoDragFlags.xExtent = -1; + m_PseudoDragFlags.yExtent = -1; + break; + case CORNER_TOPRIGHT: + m_PseudoDragFlags.xExtent = 1; + m_PseudoDragFlags.yExtent = -1; + break; + case CORNER_BOTTOMRIGHT: + m_PseudoDragFlags.xExtent = 1; + m_PseudoDragFlags.yExtent = 1; + break; + case CORNER_BOTTOMLEFT: + m_PseudoDragFlags.xExtent = -1; + m_PseudoDragFlags.yExtent = 1; + break; + case EDGE_TOP: + m_PseudoDragFlags.xExtent = 0; + m_PseudoDragFlags.yExtent = -1; + break; + case EDGE_RIGHT: + m_PseudoDragFlags.xExtent = 1; + m_PseudoDragFlags.yExtent = 0; + break; + case EDGE_BOTTOM: + m_PseudoDragFlags.xExtent = 0; + m_PseudoDragFlags.yExtent = 1; + break; + case EDGE_LEFT: + m_PseudoDragFlags.xExtent = -1; + m_PseudoDragFlags.yExtent = 0; + break; + default: break; // idk future problem + } + + PWINDOW->m_vPseudoSize = pWindow->m_vRealSize.goal(); + } else m_PseudoDragFlags.pseudo = false; - } } if (m_PseudoDragFlags.pseudo) { - if (m_PseudoDragFlags.xExtent) - PWINDOW->m_vPseudoSize.x += pixResize.x * 2; - else - PWINDOW->m_vPseudoSize.x -= pixResize.x * 2; - if (m_PseudoDragFlags.yExtent) - PWINDOW->m_vPseudoSize.y += pixResize.y * 2; - else - PWINDOW->m_vPseudoSize.y -= pixResize.y * 2; + PWINDOW->m_vPseudoSize.x += 2 * pixResize.x * m_PseudoDragFlags.xExtent; + PWINDOW->m_vPseudoSize.y += 2 * pixResize.y * m_PseudoDragFlags.yExtent; CBox wbox = PNODE->box; wbox.round(); @@ -675,10 +707,10 @@ void CHyprDwindleLayout::resizeActiveWindow(const Vector2D& pixResize, eRectCorn SDwindleNodeData* PHOUTER = nullptr; SDwindleNodeData* PHINNER = nullptr; - const auto LEFT = corner == CORNER_TOPLEFT || corner == CORNER_BOTTOMLEFT || DISPLAYRIGHT; - const auto TOP = corner == CORNER_TOPLEFT || corner == CORNER_TOPRIGHT || DISPLAYBOTTOM; - const auto RIGHT = corner == CORNER_TOPRIGHT || corner == CORNER_BOTTOMRIGHT || DISPLAYLEFT; - const auto BOTTOM = corner == CORNER_BOTTOMLEFT || corner == CORNER_BOTTOMRIGHT || DISPLAYTOP; + const auto LEFT = corner == EDGE_LEFT || corner == CORNER_TOPLEFT || corner == CORNER_BOTTOMLEFT /*|| DISPLAYRIGHT*/; + const auto TOP = corner == EDGE_TOP || corner == CORNER_TOPLEFT || corner == CORNER_TOPRIGHT /*|| DISPLAYBOTTOM*/; + const auto RIGHT = corner == EDGE_RIGHT || corner == CORNER_TOPRIGHT || corner == CORNER_BOTTOMRIGHT /*|| DISPLAYLEFT*/; + const auto BOTTOM = corner == EDGE_BOTTOM || corner == CORNER_BOTTOMLEFT || corner == CORNER_BOTTOMRIGHT /*|| DISPLAYTOP*/; const auto NONE = corner == CORNER_NONE; for (auto PCURRENT = PNODE; PCURRENT && PCURRENT->pParent; PCURRENT = PCURRENT->pParent) { diff --git a/src/layout/DwindleLayout.hpp b/src/layout/DwindleLayout.hpp index 13834bc7..2b5d981c 100644 --- a/src/layout/DwindleLayout.hpp +++ b/src/layout/DwindleLayout.hpp @@ -71,8 +71,8 @@ class CHyprDwindleLayout : public IHyprLayout { struct { bool started = false; bool pseudo = false; - bool xExtent = false; - bool yExtent = false; + int xExtent = 0; + int yExtent = 0; } m_PseudoDragFlags; std::optional m_vOverrideFocalPoint; // for onWindowCreatedTiling. diff --git a/src/layout/IHyprLayout.cpp b/src/layout/IHyprLayout.cpp index c6a7a66c..fda3adf5 100644 --- a/src/layout/IHyprLayout.cpp +++ b/src/layout/IHyprLayout.cpp @@ -7,6 +7,15 @@ #include "../protocols/XDGShell.hpp" #include "../protocols/core/Compositor.hpp" #include "../xwayland/XSurface.hpp" +#include "debug/Log.hpp" +#include "managers/input/InputManager.hpp" +#include +#include +#include +#include +#include +#include +#include void IHyprLayout::onWindowCreated(PHLWINDOW pWindow, eDirection direction) { if (pWindow->m_bIsFloating) { @@ -176,6 +185,159 @@ void IHyprLayout::onWindowCreatedFloating(PHLWINDOW pWindow) { pWindow->m_vPendingReportedSize = pWindow->m_vRealSize.goal(); pWindow->m_vReportedSize = pWindow->m_vPendingReportedSize; } + + // additional hitbox area to be added to floating windows + static auto b = CConfigValue("general:border_size"); + static auto r = CConfigValue("general:resize_on_border"); + static auto e = CConfigValue("general:extend_border_grab_area"); + const CBox h = {-(*b + *e * (*r != 0)), -(*b + *e * (*r != 0)), 2 * (*b + *e * (*r != 0)), 2 * (*b + *e * (*r != 0))}; + + pWindow->m_vPosition = pWindow->m_vRealPosition.goal() + h.pos(); + pWindow->m_vSize = pWindow->m_vRealSize.goal() + h.size(); +} + +int IHyprLayout::getWindowRegion(Vector2D cursor, CBox window, CBox edge, bool raw) { + + // explode if point isn't in rectangle + if (!window.containsPoint(cursor)) + return 255; + + // middle rectangle of the window with the edges cut off + const CBox middle = {window.x + edge.x, window.y + edge.y, window.w - (edge.x + edge.w), window.h - (edge.y + edge.h)}; + + std::string b1 = std::to_string(window.x - middle.x); + std::string b2 = std::to_string(window.y - middle.y); + std::string b3 = std::to_string(window.w - middle.w); + std::string b4 = std::to_string(window.h - middle.h); + + // Debug::log(WARN, "DIFF: {} {} -- {} {}", b1, b2, b3, b4); + + std::string s1 = std::to_string(window.x); + std::string s2 = std::to_string(window.y); + std::string s3 = std::to_string(window.w); + std::string s4 = std::to_string(window.h); + std::string s5 = std::to_string(middle.x); + std::string s6 = std::to_string(middle.y); + std::string s7 = std::to_string(middle.w); + std::string s8 = std::to_string(middle.h); + std::string s9 = std::to_string(cursor.x); + std::string s0 = std::to_string(cursor.y); + + // Debug::log(WARN, "Window: {} {} -- {} {}", s1,s2,s3,s4); + // Debug::log(WARN, "Edge: {} {} -- {} {}", edge.x, edge.y, edge.w, edge.h); + // Debug::log(WARN, "Middle: {} {} -- {} {}", s5,s6,s7,s8); + // Debug::log(WARN, "Mouse: {} {}", s9,s0); + + // Bit meanings from left to right: + // 10000000 is in bottom half + // 01000000 is in right half + // 00110000 is in left/right edge (exclusive) + // 00001100 is in top/bottom edge (exclusive) + // 00000010 is in bottom left half ([\] diagonal split) + // 00000001 is in bottom right half ([/] diagonal split) + uint8_t BITTALLY = 0; + + // cardinals + if (cursor.x > window.x + window.w / 2.0) + BITTALLY |= 1 << 7; + if (cursor.y > window.y + window.h / 2.0) + BITTALLY |= 1 << 6; + + if (edge != 0) { + // left edge + if (cursor.x < middle.x) + BITTALLY |= 1 << 5; + // right edge + if (cursor.x > middle.x + middle.w) + BITTALLY |= 1 << 4; + // top edge + if (cursor.y < middle.y) + BITTALLY |= 1 << 3; + // bottom edge + if (cursor.y > middle.y + middle.h) + BITTALLY |= 1 << 2; + } + + // look at bits 2 through 5 for edges to check the diagonal(s) where necessary + // divide by zero :trollface: + switch (BITTALLY & 0b00111100) { + case 0b00101000: // top left corner -> check [\] diagonal + if ((cursor.y - middle.y) / (cursor.x - middle.x) < (edge.y / edge.x)) + BITTALLY |= 1 << 1; + break; + case 0b00001000: // top edge only -> none + break; + case 0b00011000: // top right corner -> check diagonal + if ((cursor.y - middle.y) / (cursor.x - (middle.x + middle.w)) > (-edge.y / edge.w)) + BITTALLY |= 1 << 0; + break; + case 0b00010000: // right edge only == [/] diagonal + BITTALLY |= 1 << 0; + break; + case 0b00010100: // bottom right corner -> [/] diagonal + check [\] diagonal + if ((cursor.y - (middle.y + middle.h)) / (cursor.x - (middle.x + middle.w)) > (edge.h / edge.w)) + BITTALLY |= 0b00000011; + else + BITTALLY |= 0b00000001; + break; + case 0b00000100: // bottom edge only == [/] + [\] diagonals + BITTALLY |= 0b00000011; + break; + case 0b00100100: // bottom left corner -> [\] diagonal + check [/] diagonal + if ((cursor.y - (middle.y + middle.h)) / (cursor.x - middle.x) < (edge.h / -edge.x)) + BITTALLY |= 0b00000011; + else + BITTALLY |= 0b00000010; + break; + case 0b00100000: // left edge only == [\] diagonal + BITTALLY |= 1 << 1; + break; + default: // catch-all for central rectangle and edge == 0 + if ((cursor.y - middle.y) / (cursor.x - middle.x) > middle.h / middle.w) + BITTALLY |= 1 << 1; + if ((cursor.y - (middle.y + middle.h)) / (cursor.x - middle.x) > -1 * middle.h / middle.w) + BITTALLY |= 1 << 0; + break; + } + + std::bitset<8> funny = BITTALLY; + Debug::log(WARN, "{}", funny.to_string()); + + if (!raw) + switch (BITTALLY) { + // ordered clockwise starting and ending at top left quadrant + // center 8 'tiles' (no edges) + case 0b00000000: return 0; + case 0b10000000: return 1; + case 0b10000001: return 2; + case 0b11000001: return 3; + case 0b11000011: return 4; + case 0b01000011: return 5; + case 0b01000010: return 6; + case 0b00000010: return 7; + // edge 8 'tiles' (1 edge) + case 0b00001000: return 8; + case 0b10001000: return 9; + case 0b10010001: return 10; + case 0b11010001: return 11; + case 0b11000111: return 12; + case 0b01000111: return 13; + case 0b01100010: return 14; + case 0b00100010: return 15; + // corner 8 'tiles' (2 edges) + case 0b00101000: return 16; + case 0b10011000: return 17; + case 0b10011001: return 18; + case 0b11010101: return 19; + case 0b11010111: return 20; + case 0b01100111: return 21; + case 0b01100110: return 22; + case 0b00101010: return 23; + // oopsie + default: Debug::log(WARN, "No window region matching table."); return 0; + } + + return BITTALLY; } void IHyprLayout::onBeginDragWindow() { @@ -222,10 +384,26 @@ void IHyprLayout::onBeginDragWindow() { m_vBeginDragXY = g_pInputManager->getMouseCoordsInternal(); m_vBeginDragPositionXY = DRAGGINGWINDOW->m_vRealPosition.goal(); m_vBeginDragSizeXY = DRAGGINGWINDOW->m_vRealSize.goal(); + m_vBeginDragFullPosXY = DRAGGINGWINDOW->m_vPosition; + m_vBeginDragFullSizeXY = DRAGGINGWINDOW->m_vSize; m_vLastDragXY = m_vBeginDragXY; - // get the grab corner - static auto RESIZECORNER = CConfigValue("general:resize_corner"); + std::string s1 = std::to_string(m_vBeginDragPositionXY.x); + std::string s2 = std::to_string(m_vBeginDragPositionXY.y); + std::string s3 = std::to_string(m_vBeginDragSizeXY.x); + std::string s4 = std::to_string(m_vBeginDragSizeXY.y); + std::string s5 = std::to_string(m_vBeginDragFullPosXY.x); + std::string s6 = std::to_string(m_vBeginDragFullPosXY.y); + std::string s7 = std::to_string(m_vBeginDragFullSizeXY.x); + std::string s8 = std::to_string(m_vBeginDragFullSizeXY.y); + + Debug::log(WARN, "Real: {}, {} -- {}, {}", s1, s2, s3, s4); + Debug::log(WARN, "Full: {}, {} -- {}, {}", s5, s6, s7, s8); + + static auto RESIZECORNER = CConfigValue("general:resize_corner"); + static auto EDGEDEPTH = CConfigValue("general:edge_depth"); + static auto RESIZEPATTERN = CConfigValue("general:resize_mouse_bind_pattern"); + if (*RESIZECORNER != 0 && *RESIZECORNER <= 4 && DRAGGINGWINDOW->m_bIsFloating) { switch (*RESIZECORNER) { case 1: @@ -245,22 +423,72 @@ void IHyprLayout::onBeginDragWindow() { g_pInputManager->setCursorImageUntilUnset("sw-resize"); break; } - } else if (m_vBeginDragXY.x < m_vBeginDragPositionXY.x + m_vBeginDragSizeXY.x / 2.0) { - if (m_vBeginDragXY.y < m_vBeginDragPositionXY.y + m_vBeginDragSizeXY.y / 2.0) { - m_eGrabbedCorner = CORNER_TOPLEFT; - g_pInputManager->setCursorImageUntilUnset("nw-resize"); - } else { - m_eGrabbedCorner = CORNER_BOTTOMLEFT; - g_pInputManager->setCursorImageUntilUnset("sw-resize"); - } } else { - if (m_vBeginDragXY.y < m_vBeginDragPositionXY.y + m_vBeginDragSizeXY.y / 2.0) { - m_eGrabbedCorner = CORNER_TOPRIGHT; - g_pInputManager->setCursorImageUntilUnset("ne-resize"); - } else { - m_eGrabbedCorner = CORNER_BOTTOMRIGHT; - g_pInputManager->setCursorImageUntilUnset("se-resize"); + + CBox window = {m_vBeginDragFullPosXY, m_vBeginDragFullSizeXY}; + CBox edge; + + if (DRAGGINGWINDOW->m_bIsPseudotiled) { + static auto b = CConfigValue("general:border_size"); + static auto r = CConfigValue("general:resize_on_border"); + static auto e = CConfigValue("general:extend_border_grab_area"); + const CBox h = {-(*b + *e * (*r != 0)), -(*b + *e * (*r != 0)), 2 * (*b + *e * (*r != 0)), 2 * (*b + *e * (*r != 0))}; + const CBox p = {m_vBeginDragPositionXY + h.pos(), m_vBeginDragSizeXY + h.size()}; + if (p.containsPoint(m_vBeginDragXY)) + window = p; } + + if (*EDGEDEPTH <= 0) + edge = 0; + else if (*EDGEDEPTH < 1) + edge = window.h > window.w ? window.w / 2 * *EDGEDEPTH : window.h / 2 * *EDGEDEPTH; + else + edge = std::clamp((int)*EDGEDEPTH, 1, window.h > window.w ? (int)window.w / 2 : (int)window.h / 2); + + // get grabbed corner/edge + const uint8_t region = getWindowRegion(m_vBeginDragXY, window, edge); + const std::string direction[] = {"move", "nw-resize", "ne-resize", "se-resize", "sw-resize", "n-resize", "e-resize", "s-resize", "w-resize"}; + // clang-format off + + // pattern definitions + // a pattern can contain values 0 through 8 to match the valid values of eRectCorner + // for ease of reading, the patterns are broken up into groups of 8 values (center, edge, corner) + std::vector pattern = {1, 2, 2, 3, 3, 4, 4, 1, + 1, 2, 2, 3, 3, 4, 4, 1, + 1, 2, 2, 3, 3, 4, 4, 1}; + + switch ((int)*RESIZEPATTERN) { + case 1: // window pattern: edges & corners = cardinal, center = diagonal + pattern = {1, 2, 2, 3, 3, 4, 4, 1, + 5, 5, 6, 6, 7, 7, 8, 8, + 5, 5, 6, 6, 7, 7, 8, 8}; + break; + case 2: // chess pattern: edges = cardinal, corners & center = diagonal + pattern = {1, 2, 2, 3, 3, 4, 4, 1, + 5, 5, 6, 6, 7, 7, 8, 8, + 1, 2, 2, 3, 3, 4, 4, 1}; + break; + case 3: // cross pattern: center & edges = cardinal, corners = diagonal + pattern = {5, 5, 6, 6, 7, 7, 8, 8, + 5, 5, 6, 6, 7, 7, 8, 8, + 1, 2, 2, 3, 3, 4, 4, 1}; + break; + case 4: // cardinal only + pattern = {5, 5, 6, 6, 7, 7, 8, 8, + 5, 5, 6, 6, 7, 7, 8, 8, + 5, 5, 6, 6, 7, 7, 8, 8}; + break; + case 420: // having a trip + for (std::size_t i = 0; i != pattern.size(); ++i) + pattern[i] = std::rand() % 8; + break; + default: break; + } + // clang-format on + + // we translate the value into the desired direction through table lookup + m_eGrabbedCorner = static_cast(pattern[region]); + g_pInputManager->setCursorImageUntilUnset(direction[pattern[region]]); } if (g_pInputManager->dragMode != MBIND_RESIZE && g_pInputManager->dragMode != MBIND_RESIZE_FORCE_RATIO && g_pInputManager->dragMode != MBIND_RESIZE_BLOCK_RATIO) @@ -381,6 +609,8 @@ void IHyprLayout::onMouseMove(const Vector2D& mousePos) { DRAGGINGWINDOW->m_vRealPosition = wb.pos(); else DRAGGINGWINDOW->m_vRealPosition.setValueAndWarp(wb.pos()); + // update window pos alongside realpos + DRAGGINGWINDOW->m_vPosition = m_vBeginDragFullPosXY + DELTA; g_pXWaylandManager->setWindowSize(DRAGGINGWINDOW, DRAGGINGWINDOW->m_vRealSize.goal()); } else if (g_pInputManager->dragMode == MBIND_RESIZE || g_pInputManager->dragMode == MBIND_RESIZE_FORCE_RATIO || g_pInputManager->dragMode == MBIND_RESIZE_BLOCK_RATIO) { @@ -392,14 +622,17 @@ void IHyprLayout::onMouseMove(const Vector2D& mousePos) { Vector2D newSize = m_vBeginDragSizeXY; Vector2D newPos = m_vBeginDragPositionXY; - if (m_eGrabbedCorner == CORNER_BOTTOMRIGHT) - newSize = newSize + DELTA; - else if (m_eGrabbedCorner == CORNER_TOPLEFT) - newSize = newSize - DELTA; - else if (m_eGrabbedCorner == CORNER_TOPRIGHT) - newSize = newSize + Vector2D(DELTA.x, -DELTA.y); - else if (m_eGrabbedCorner == CORNER_BOTTOMLEFT) - newSize = newSize + Vector2D(-DELTA.x, DELTA.y); + switch (m_eGrabbedCorner) { + case CORNER_NONE: break; + case CORNER_TOPLEFT: newSize = newSize - DELTA; break; + case CORNER_TOPRIGHT: newSize = newSize + Vector2D(DELTA.x, -DELTA.y); break; + case CORNER_BOTTOMRIGHT: newSize = newSize + DELTA; break; + case CORNER_BOTTOMLEFT: newSize = newSize + Vector2D(-DELTA.x, DELTA.y); break; + case EDGE_TOP: newSize = newSize + Vector2D(0.0, -DELTA.y); break; + case EDGE_RIGHT: newSize = newSize + Vector2D(DELTA.x, 0.0); break; + case EDGE_BOTTOM: newSize = newSize + Vector2D(0.0, DELTA.y); break; + case EDGE_LEFT: newSize = newSize + Vector2D(-DELTA.x, 0.0); break; + } if ((m_vBeginDragSizeXY.x >= 1 && m_vBeginDragSizeXY.y >= 1) && (g_pInputManager->dragMode == MBIND_RESIZE_FORCE_RATIO || @@ -425,15 +658,18 @@ void IHyprLayout::onMouseMove(const Vector2D& mousePos) { newSize = newSize.clamp(MINSIZE, MAXSIZE); - if (m_eGrabbedCorner == CORNER_TOPLEFT) - newPos = newPos - newSize + m_vBeginDragSizeXY; - else if (m_eGrabbedCorner == CORNER_TOPRIGHT) - newPos = newPos + Vector2D(0.0, (m_vBeginDragSizeXY - newSize).y); - else if (m_eGrabbedCorner == CORNER_BOTTOMLEFT) - newPos = newPos + Vector2D((m_vBeginDragSizeXY - newSize).x, 0.0); + switch (m_eGrabbedCorner) { + case CORNER_TOPLEFT: newPos = newPos - newSize + m_vBeginDragSizeXY; break; + case CORNER_TOPRIGHT: newPos = newPos + Vector2D(0.0, (m_vBeginDragSizeXY - newSize).y); break; + case CORNER_BOTTOMLEFT: newPos = newPos + Vector2D((m_vBeginDragSizeXY - newSize).x, 0.0); break; + case EDGE_TOP: newPos = newPos + Vector2D(0.0, (m_vBeginDragSizeXY - newSize).y); break; + case EDGE_LEFT: newPos = newPos + Vector2D((m_vBeginDragSizeXY - newSize).x, 0.0); break; + default: break; + } CBox wb = {newPos, newSize}; wb.round(); + CBox transform = {wb.pos() - m_vBeginDragPositionXY, wb.size() - m_vBeginDragSizeXY}; if (*PANIMATE) { DRAGGINGWINDOW->m_vRealSize = wb.size(); @@ -443,6 +679,12 @@ void IHyprLayout::onMouseMove(const Vector2D& mousePos) { DRAGGINGWINDOW->m_vRealPosition.setValueAndWarp(wb.pos()); } + // update window size and pos alongisde realsize and realpos + // not always correct if the user messes with the config values + // but it's corrected on float/unfloat so whatever :P + DRAGGINGWINDOW->m_vSize = m_vBeginDragFullSizeXY + transform.size(); + DRAGGINGWINDOW->m_vPosition = m_vBeginDragFullPosXY + transform.pos(); + g_pXWaylandManager->setWindowSize(DRAGGINGWINDOW, DRAGGINGWINDOW->m_vRealSize.goal()); } else { resizeActiveWindow(TICKDELTA, m_eGrabbedCorner, DRAGGINGWINDOW); @@ -522,7 +764,13 @@ void IHyprLayout::changeWindowFloatingMode(PHLWINDOW pWindow) { g_pCompositor->changeWindowZOrder(pWindow, true); - CBox wb = {pWindow->m_vRealPosition.goal() + (pWindow->m_vRealSize.goal() - pWindow->m_vLastFloatingSize) / 2.f, pWindow->m_vLastFloatingSize}; + // additional hitbox area to be added to floating windows + static auto b = CConfigValue("general:border_size"); + static auto r = CConfigValue("general:resize_on_border"); + static auto e = CConfigValue("general:extend_border_grab_area"); + const CBox h = {-(*b + *e * (*r != 0)), -(*b + *e * (*r != 0)), 2 * (*b + *e * (*r != 0)), 2 * (*b + *e * (*r != 0))}; + + CBox wb = {pWindow->m_vRealPosition.goal() + (pWindow->m_vRealSize.goal() - pWindow->m_vLastFloatingSize) / 2.f, pWindow->m_vLastFloatingSize}; wb.round(); if (!(pWindow->m_bIsFloating && pWindow->m_bIsPseudotiled) && DELTALESSTHAN(pWindow->m_vRealSize.value().x, pWindow->m_vLastFloatingSize.x, 10) && @@ -533,8 +781,8 @@ void IHyprLayout::changeWindowFloatingMode(PHLWINDOW pWindow) { pWindow->m_vRealPosition = wb.pos(); pWindow->m_vRealSize = wb.size(); - pWindow->m_vSize = wb.pos(); - pWindow->m_vPosition = wb.size(); + pWindow->m_vPosition = wb.pos() + h.pos(); + pWindow->m_vSize = wb.size() + h.size(); g_pHyprRenderer->damageMonitor(g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID)); @@ -563,6 +811,7 @@ void IHyprLayout::moveActiveWindow(const Vector2D& delta, PHLWINDOW pWindow) { PWINDOW->setAnimationsToMove(); PWINDOW->m_vRealPosition = PWINDOW->m_vRealPosition.goal() + delta; + PWINDOW->m_vPosition = PWINDOW->m_vPosition + delta; g_pHyprRenderer->damageWindow(PWINDOW); } diff --git a/src/layout/IHyprLayout.hpp b/src/layout/IHyprLayout.hpp index 74a00d19..c330e191 100644 --- a/src/layout/IHyprLayout.hpp +++ b/src/layout/IHyprLayout.hpp @@ -1,7 +1,10 @@ #pragma once #include "../defines.hpp" +#include "hyprutils/math/Box.hpp" +#include "hyprutils/math/Vector2D.hpp" #include +#include class CWindow; class CGradientValueData; @@ -22,7 +25,11 @@ enum eRectCorner { CORNER_TOPLEFT, CORNER_TOPRIGHT, CORNER_BOTTOMRIGHT, - CORNER_BOTTOMLEFT + CORNER_BOTTOMLEFT, + EDGE_TOP, + EDGE_RIGHT, + EDGE_BOTTOM, + EDGE_LEFT }; enum eDirection { @@ -75,6 +82,13 @@ class IHyprLayout { Called when a window is requested to be floated */ virtual void changeWindowFloatingMode(PHLWINDOW); + + /* + Called when cursor position on a window is requested. Returns a value between from 0 to 23 + depending on the parameters given or the raw uint8_t to be interpreted by its bit composition. + */ + virtual int getWindowRegion(Vector2D cursor, CBox window, CBox edge = 0, bool raw = false); + /* Called when a window is clicked on, beginning a drag this might be a resize, move, whatever the layout defines it @@ -201,6 +215,8 @@ class IHyprLayout { Vector2D m_vLastDragXY; Vector2D m_vBeginDragPositionXY; Vector2D m_vBeginDragSizeXY; + Vector2D m_vBeginDragFullPosXY; + Vector2D m_vBeginDragFullSizeXY; Vector2D m_vDraggingWindowOriginalFloatSize; eRectCorner m_eGrabbedCorner = CORNER_TOPLEFT; diff --git a/src/layout/MasterLayout.cpp b/src/layout/MasterLayout.cpp index 965c0ed7..0574c57f 100644 --- a/src/layout/MasterLayout.cpp +++ b/src/layout/MasterLayout.cpp @@ -763,8 +763,8 @@ void CHyprMasterLayout::resizeActiveWindow(const Vector2D& pixResize, eRectCorne const bool DISPLAYTOP = STICKS(PWINDOW->m_vPosition.y, PMONITOR->vecPosition.y + PMONITOR->vecReservedTopLeft.y); const bool DISPLAYLEFT = STICKS(PWINDOW->m_vPosition.x, PMONITOR->vecPosition.x + PMONITOR->vecReservedTopLeft.x); - const bool LEFT = corner == CORNER_TOPLEFT || corner == CORNER_BOTTOMLEFT; - const bool TOP = corner == CORNER_TOPLEFT || corner == CORNER_TOPRIGHT; + const bool LEFT = corner == EDGE_LEFT || corner == CORNER_TOPLEFT || corner == CORNER_BOTTOMLEFT; + const bool TOP = corner == EDGE_TOP || corner == CORNER_TOPLEFT || corner == CORNER_TOPRIGHT; const bool NONE = corner == CORNER_NONE; const auto MASTERS = getMastersOnWorkspace(PNODE->workspaceID);