nixos/patches/hyprland-dwindle-pin-far-sides.patch

92 lines
3.6 KiB
Diff
Raw Normal View History

--- 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