hyprland: dwindle resize only moves the dragged edge
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
81b8cd173d
commit
fa0a654f5f
2 changed files with 99 additions and 1 deletions
91
patches/hyprland-dwindle-pin-far-sides.patch
Normal file
91
patches/hyprland-dwindle-pin-far-sides.patch
Normal file
|
|
@ -0,0 +1,91 @@
|
||||||
|
--- a/src/layout/algorithm/tiled/dwindle/DwindleAlgorithm.cpp
|
||||||
|
+++ b/src/layout/algorithm/tiled/dwindle/DwindleAlgorithm.cpp
|
||||||
|
@@ -297,6 +297,56 @@
|
||||||
|
recalculate();
|
||||||
|
}
|
||||||
|
|
||||||
|
+// Moving a split only changes that node's ratio, so every split nested on
|
||||||
|
+// either side of it gets rescaled and edges that weren't dragged slide along.
|
||||||
|
+// Record the size of each region that doesn't touch the moved edge, so it can
|
||||||
|
+// be pinned afterwards and only the windows along the edge absorb the resize.
|
||||||
|
+struct SFarSide {
|
||||||
|
+ SP<SDwindleNodeData> node;
|
||||||
|
+ bool farIsSecond = false;
|
||||||
|
+ float size = 0;
|
||||||
|
+};
|
||||||
|
+using FarSides = std::vector<SFarSide>;
|
||||||
|
+
|
||||||
|
+static void collectFarSides(const SP<SDwindleNodeData>& node, bool vertical, bool edgeAtStart, FarSides& out) {
|
||||||
|
+ if (!node || !node->children[0] || !node->children[1])
|
||||||
|
+ return;
|
||||||
|
+
|
||||||
|
+ const auto C0 = node->children[0].lock();
|
||||||
|
+ const auto C1 = node->children[1].lock();
|
||||||
|
+
|
||||||
|
+ if (node->splitTop == vertical) {
|
||||||
|
+ // split along the resize axis: pin the far child, follow the near one
|
||||||
|
+ const auto FARCHILD = edgeAtStart ? C1 : C0;
|
||||||
|
+ out.push_back({node, edgeAtStart, (float)(vertical ? FARCHILD->box.h : FARCHILD->box.w)});
|
||||||
|
+ collectFarSides(edgeAtStart ? C0 : C1, vertical, edgeAtStart, out);
|
||||||
|
+ } else {
|
||||||
|
+ // perpendicular split: both children touch the edge
|
||||||
|
+ collectFarSides(C0, vertical, edgeAtStart, out);
|
||||||
|
+ collectFarSides(C1, vertical, edgeAtStart, out);
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static FarSides collectFarSides(const SP<SDwindleNodeData>& split, bool vertical) {
|
||||||
|
+ FarSides out;
|
||||||
|
+ collectFarSides(split->children[0].lock(), vertical, false, out);
|
||||||
|
+ collectFarSides(split->children[1].lock(), vertical, true, out);
|
||||||
|
+ return out;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+// parents come before their children in `far`, so each node's box is already
|
||||||
|
+// final by the time its own ratio is recomputed
|
||||||
|
+static void restoreFarSides(const FarSides& far, bool vertical, bool force) {
|
||||||
|
+ for (const auto& [node, farIsSecond, size] : far) {
|
||||||
|
+ const float TOTAL = vertical ? node->box.h : node->box.w;
|
||||||
|
+ if (TOTAL <= 0)
|
||||||
|
+ continue;
|
||||||
|
+
|
||||||
|
+ node->splitRatio = std::clamp(farIsSecond ? 2.f - size / TOTAL * 2.f : size / TOTAL * 2.f, 0.1F, 1.9F);
|
||||||
|
+ node->recalcSizePosRecursive(force);
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
void CDwindleAlgorithm::resizeTarget(const Vector2D& Δ, SP<ITarget> target, eRectCorner corner) {
|
||||||
|
if (!validMapped(target->window()))
|
||||||
|
return;
|
||||||
|
@@ -356,6 +406,8 @@
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PHOUTER) {
|
||||||
|
+ const auto HFAR = collectFarSides(PHOUTER->pParent.lock(), false);
|
||||||
|
+
|
||||||
|
PHOUTER->pParent->splitRatio = std::clamp(PHOUTER->pParent->splitRatio + allowedMovement.x * 2.f / PHOUTER->pParent->box.w, 0.1, 1.9);
|
||||||
|
|
||||||
|
if (PHINNER) {
|
||||||
|
@@ -368,9 +420,13 @@
|
||||||
|
PHINNER->pParent->recalcSizePosRecursive(*PANIMATE == 0);
|
||||||
|
} else
|
||||||
|
PHOUTER->pParent->recalcSizePosRecursive(*PANIMATE == 0);
|
||||||
|
+
|
||||||
|
+ restoreFarSides(HFAR, false, *PANIMATE == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PVOUTER) {
|
||||||
|
+ const auto VFAR = collectFarSides(PVOUTER->pParent.lock(), true);
|
||||||
|
+
|
||||||
|
PVOUTER->pParent->splitRatio = std::clamp(PVOUTER->pParent->splitRatio + allowedMovement.y * 2.f / PVOUTER->pParent->box.h, 0.1, 1.9);
|
||||||
|
|
||||||
|
if (PVINNER) {
|
||||||
|
@@ -383,6 +439,8 @@
|
||||||
|
PVINNER->pParent->recalcSizePosRecursive(*PANIMATE == 0);
|
||||||
|
} else
|
||||||
|
PVOUTER->pParent->recalcSizePosRecursive(*PANIMATE == 0);
|
||||||
|
+
|
||||||
|
+ restoreFarSides(VFAR, true, *PANIMATE == 0);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// get the correct containers to apply splitratio to
|
||||||
|
|
@ -11,6 +11,11 @@ in
|
||||||
programs.hyprland = {
|
programs.hyprland = {
|
||||||
enable = true;
|
enable = true;
|
||||||
xwayland.enable = true;
|
xwayland.enable = true;
|
||||||
|
# Dragging a tiled edge only resizes the windows touching it; stock
|
||||||
|
# dwindle rescales the whole subtree beyond it, so untouched edges slid.
|
||||||
|
package = pkgs.hyprland.overrideAttrs (old: {
|
||||||
|
patches = (old.patches or [ ]) ++ [ ../patches/hyprland-dwindle-pin-far-sides.patch ];
|
||||||
|
});
|
||||||
# Closing a window that's being shared ends the share (Discord stops the
|
# Closing a window that's being shared ends the share (Discord stops the
|
||||||
# stream) instead of streaming its last frame forever.
|
# stream) instead of streaming its last frame forever.
|
||||||
portalPackage = pkgs.xdg-desktop-portal-hyprland.overrideAttrs (old: {
|
portalPackage = pkgs.xdg-desktop-portal-hyprland.overrideAttrs (old: {
|
||||||
|
|
@ -72,7 +77,7 @@ in
|
||||||
libcanberra-gtk3
|
libcanberra-gtk3
|
||||||
];
|
];
|
||||||
|
|
||||||
home-manager.users.fred = { config, lib, pkgs, inputs, ... }:
|
home-manager.users.fred = { config, osConfig, lib, pkgs, inputs, ... }:
|
||||||
let
|
let
|
||||||
c = config.lib.stylix.colors;
|
c = config.lib.stylix.colors;
|
||||||
rgb = hex: "rgb(${hex})";
|
rgb = hex: "rgb(${hex})";
|
||||||
|
|
@ -218,6 +223,8 @@ in
|
||||||
wayland.windowManager.hyprland = {
|
wayland.windowManager.hyprland = {
|
||||||
enable = true;
|
enable = true;
|
||||||
configType = "lua";
|
configType = "lua";
|
||||||
|
# same patched build as programs.hyprland, not a second stock copy
|
||||||
|
package = osConfig.programs.hyprland.package;
|
||||||
systemd.variables = [ "--all" ];
|
systemd.variables = [ "--all" ];
|
||||||
|
|
||||||
settings = {
|
settings = {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue