diff --git a/src/Window.cpp b/src/Window.cpp index f1acc791..f48d27f1 100644 --- a/src/Window.cpp +++ b/src/Window.cpp @@ -532,6 +532,8 @@ void CWindow::applyDynamicRule(const SWindowRule& r) { } catch (std::exception& e) { Debug::log(ERR, "BorderColor rule \"%s\" failed with: %s", r.szRule.c_str(), e.what()); } } else if (r.szRule == "dimaround") { m_sAdditionalConfigData.dimAround = true; + } else if (r.szRule == "keepaspectratio") { + m_sAdditionalConfigData.keepAspectRatio = true; } } @@ -546,12 +548,13 @@ void CWindow::updateDynamicRules() { m_sAdditionalConfigData.forceNoDim = false; if (!m_sAdditionalConfigData.forceOpaqueOverridden) m_sAdditionalConfigData.forceOpaque = false; - m_sAdditionalConfigData.forceNoAnims = false; - m_sAdditionalConfigData.animationStyle = std::string(""); - m_sAdditionalConfigData.rounding = -1; - m_sAdditionalConfigData.dimAround = false; - m_sAdditionalConfigData.forceRGBX = false; - m_sAdditionalConfigData.borderSize = -1; + m_sAdditionalConfigData.forceNoAnims = false; + m_sAdditionalConfigData.animationStyle = std::string(""); + m_sAdditionalConfigData.rounding = -1; + m_sAdditionalConfigData.dimAround = false; + m_sAdditionalConfigData.forceRGBX = false; + m_sAdditionalConfigData.borderSize = -1; + m_sAdditionalConfigData.keepAspectRatio = false; const auto WINDOWRULES = g_pConfigManager->getMatchingRules(this); for (auto& r : WINDOWRULES) { diff --git a/src/Window.hpp b/src/Window.hpp index bdd079de..d3c34a63 100644 --- a/src/Window.hpp +++ b/src/Window.hpp @@ -10,8 +10,7 @@ #include "helpers/Vector2D.hpp" #include "helpers/WLSurface.hpp" -enum eIdleInhibitMode -{ +enum eIdleInhibitMode { IDLEINHIBIT_NONE = 0, IDLEINHIBIT_ALWAYS, IDLEINHIBIT_FULLSCREEN, @@ -122,6 +121,7 @@ struct SWindowAdditionalConfigData { CWindowOverridableVar noMaxSize = false; CWindowOverridableVar dimAround = false; CWindowOverridableVar forceRGBX = false; + CWindowOverridableVar keepAspectRatio = false; CWindowOverridableVar borderSize = -1; // -1 means unset, takes precedence over the renderdata one }; diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 5182942d..461956a2 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -887,8 +887,9 @@ bool windowRuleValid(const std::string& RULE) { RULE.find("maxsize") != 0 && RULE.find("pseudo") != 0 && RULE.find("monitor") != 0 && RULE.find("idleinhibit") != 0 && RULE != "nofocus" && RULE != "noblur" && RULE != "noshadow" && RULE != "nodim" && RULE != "noborder" && RULE != "center" && RULE != "opaque" && RULE != "forceinput" && RULE != "fullscreen" && RULE != "nofullscreenrequest" && RULE != "nomaximizerequest" && RULE != "fakefullscreen" && RULE != "nomaxsize" && RULE != "pin" && RULE != "noanim" && - RULE != "dimaround" && RULE != "windowdance" && RULE != "maximize" && RULE.find("animation") != 0 && RULE.find("rounding") != 0 && RULE.find("workspace") != 0 && - RULE.find("bordercolor") != 0 && RULE != "forcergbx" && RULE != "noinitialfocus" && RULE != "stayfocused" && RULE.find("bordersize") != 0); + RULE != "dimaround" && RULE != "windowdance" && RULE != "maximize" && RULE != "keepaspectratio" && RULE.find("animation") != 0 && RULE.find("rounding") != 0 && + RULE.find("workspace") != 0 && RULE.find("bordercolor") != 0 && RULE != "forcergbx" && RULE != "noinitialfocus" && RULE != "stayfocused" && + RULE.find("bordersize") != 0); } bool layerRuleValid(const std::string& RULE) { diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index 6ad13ce4..2713dee2 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -1002,6 +1002,8 @@ std::string dispatchSetProp(std::string request) { PWINDOW->m_sAdditionalConfigData.forceRGBX.forceSetIgnoreLocked(configStringToInt(VAL), lock); } else if (PROP == "bordersize") { PWINDOW->m_sSpecialRenderData.borderSize.forceSetIgnoreLocked(configStringToInt(VAL), lock); + } else if (PROP == "keepaspectratio") { + PWINDOW->m_sAdditionalConfigData.keepAspectRatio.forceSetIgnoreLocked(configStringToInt(VAL), lock); } else { return "prop not found"; } diff --git a/src/layout/IHyprLayout.cpp b/src/layout/IHyprLayout.cpp index baae6616..f39b190a 100644 --- a/src/layout/IHyprLayout.cpp +++ b/src/layout/IHyprLayout.cpp @@ -235,7 +235,7 @@ void IHyprLayout::onBeginDragWindow() { } } - if (g_pInputManager->dragMode != MBIND_RESIZE) + if (g_pInputManager->dragMode != MBIND_RESIZE && g_pInputManager->dragMode != MBIND_RESIZE_FORCE_RATIO && g_pInputManager->dragMode != MBIND_RESIZE_BLOCK_RATIO) g_pInputManager->setCursorImageUntilUnset("grab"); g_pHyprRenderer->damageWindow(DRAGGINGWINDOW); @@ -314,29 +314,55 @@ void IHyprLayout::onMouseMove(const Vector2D& mousePos) { } g_pXWaylandManager->setWindowSize(DRAGGINGWINDOW, DRAGGINGWINDOW->m_vRealSize.goalv()); - } else if (g_pInputManager->dragMode == MBIND_RESIZE) { + } else if (g_pInputManager->dragMode == MBIND_RESIZE || g_pInputManager->dragMode == MBIND_RESIZE_FORCE_RATIO || g_pInputManager->dragMode == MBIND_RESIZE_BLOCK_RATIO) { if (DRAGGINGWINDOW->m_bIsFloating) { - const auto MAXSIZE = g_pXWaylandManager->getMaxSizeForWindow(DRAGGINGWINDOW); - - // calc the new size and pos + Vector2D MINSIZE = Vector2D(20, 20); + Vector2D MAXSIZE = g_pXWaylandManager->getMaxSizeForWindow(DRAGGINGWINDOW); Vector2D newSize = m_vBeginDragSizeXY; Vector2D newPos = m_vBeginDragPositionXY; - if (m_eGrabbedCorner == CORNER_BOTTOMRIGHT) { - newSize = (newSize + DELTA).clamp(Vector2D(20, 20), MAXSIZE); - } else if (m_eGrabbedCorner == CORNER_TOPLEFT) { - newSize = (newSize - DELTA).clamp(Vector2D(20, 20), MAXSIZE); - newPos = newPos - newSize + m_vBeginDragSizeXY; - } else if (m_eGrabbedCorner == CORNER_TOPRIGHT) { - newSize = (newSize + Vector2D(DELTA.x, -DELTA.y)).clamp(Vector2D(20, 20), MAXSIZE); - newPos = newPos + Vector2D(0, (m_vBeginDragSizeXY - newSize).y); - } else if (m_eGrabbedCorner == CORNER_BOTTOMLEFT) { - newSize = (newSize + Vector2D(-DELTA.x, DELTA.y)).clamp(Vector2D(20, 20), MAXSIZE); - newPos = newPos + Vector2D((m_vBeginDragSizeXY - newSize).x, 0); + 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); + + if ((m_vBeginDragSizeXY.x >= 1 && m_vBeginDragSizeXY.y >= 1) && + (g_pInputManager->dragMode == MBIND_RESIZE_FORCE_RATIO || + (!(g_pInputManager->dragMode == MBIND_RESIZE_BLOCK_RATIO) && DRAGGINGWINDOW->m_sAdditionalConfigData.keepAspectRatio))) { + + const float RATIO = m_vBeginDragSizeXY.y / m_vBeginDragSizeXY.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_eGrabbedCorner == CORNER_TOPLEFT) + newPos = newPos - newSize + m_vBeginDragSizeXY; + else if (m_eGrabbedCorner == CORNER_TOPRIGHT) + newPos = newPos + Vector2D(0, (m_vBeginDragSizeXY - newSize).y); + else if (m_eGrabbedCorner == CORNER_BOTTOMLEFT) + newPos = newPos + Vector2D((m_vBeginDragSizeXY - newSize).x, 0); + if (*PANIMATE) { DRAGGINGWINDOW->m_vRealSize = newSize; DRAGGINGWINDOW->m_vRealPosition = newPos; diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 8c0cfab4..9cdf05d0 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -1942,10 +1942,10 @@ void CKeybindManager::pinActive(std::string args) { } void CKeybindManager::mouse(std::string args) { - const auto TRUEARG = args.substr(1); + const auto ARGS = CVarList(args.substr(1), 2, ' '); const auto PRESSED = args[0] == '1'; - if (TRUEARG == "movewindow") { + if (ARGS[0] == "movewindow") { if (PRESSED) { g_pKeybindManager->m_bIsMouseBindActive = true; @@ -1962,13 +1962,19 @@ void CKeybindManager::mouse(std::string args) { g_pInputManager->dragMode = MBIND_INVALID; } } - } else if (TRUEARG == "resizewindow") { + } else if (ARGS[0] == "resizewindow") { if (PRESSED) { g_pKeybindManager->m_bIsMouseBindActive = true; g_pInputManager->currentlyDraggedWindow = g_pCompositor->vectorToWindowIdeal(g_pInputManager->getMouseCoordsInternal()); - g_pInputManager->dragMode = MBIND_RESIZE; + try { + switch (std::stoi(ARGS[1])) { + case 1: g_pInputManager->dragMode = MBIND_RESIZE_FORCE_RATIO; break; + case 2: g_pInputManager->dragMode = MBIND_RESIZE_BLOCK_RATIO; break; + default: g_pInputManager->dragMode = MBIND_RESIZE; + } + } catch (std::exception& e) { g_pInputManager->dragMode = MBIND_RESIZE; } g_pLayoutManager->getCurrentLayout()->onBeginDragWindow(); } else { g_pKeybindManager->m_bIsMouseBindActive = false; diff --git a/src/managers/input/InputManager.hpp b/src/managers/input/InputManager.hpp index 862dc886..1a3eac0c 100644 --- a/src/managers/input/InputManager.hpp +++ b/src/managers/input/InputManager.hpp @@ -7,21 +7,20 @@ #include "../../helpers/Timer.hpp" #include "InputMethodRelay.hpp" -enum eClickBehaviorMode -{ +enum eClickBehaviorMode { CLICKMODE_DEFAULT = 0, CLICKMODE_KILL }; -enum eMouseBindMode -{ - MBIND_INVALID = -1, - MBIND_MOVE = 0, - MBIND_RESIZE +enum eMouseBindMode { + MBIND_INVALID = -1, + MBIND_MOVE = 0, + MBIND_RESIZE = 1, + MBIND_RESIZE_BLOCK_RATIO = 2, + MBIND_RESIZE_FORCE_RATIO = 3 }; -enum eBorderIconDirection -{ +enum eBorderIconDirection { BORDERICON_NONE, BORDERICON_UP, BORDERICON_DOWN,