From ea25612af0b4c456b130f6247805fd66ed55bf00 Mon Sep 17 00:00:00 2001 From: Yocraft-2000 <304616174+Yocraft-2000@users.noreply.github.com> Date: Mon, 24 Aug 2026 12:27:54 +0200 Subject: [PATCH 1/2] fix: use same logic as scrolling for floatin resize edges --- src/input/cursor.cpp | 28 ++++++++++++---------------- tests/unit/presentation.cpp | 8 ++++---- 2 files changed, 16 insertions(+), 20 deletions(-) diff --git a/src/input/cursor.cpp b/src/input/cursor.cpp index a3f7abe..52e3732 100644 --- a/src/input/cursor.cpp +++ b/src/input/cursor.cpp @@ -22,6 +22,7 @@ #include #include "wlr.h" // clang-format on +#include "wlr/util/edges.h" #include "workspace/scratchpad.h" #include "workspace/workspace.h" @@ -1689,24 +1690,19 @@ namespace umbriel { const int y = view->sceneTree()->node.y + geo.y; const double cx = m_cursor->x; const double cy = m_cursor->y; - const double distLeft = std::abs(cx - x); - const double distRight = std::abs(cx - (x + geo.width)); - const double distTop = std::abs(cy - y); - const double distBottom = std::abs(cy - (y + geo.height)); - const double nearestH = std::min(distLeft, distRight); - const double nearestV = std::min(distTop, distBottom); + const double px = cx - x; + const double py = cy - y; uint32_t edges = 0; - if (nearestH <= nearestV) { - edges |= distLeft <= distRight ? WLR_EDGE_LEFT : WLR_EDGE_RIGHT; - } else { - edges |= distTop <= distBottom ? WLR_EDGE_TOP : WLR_EDGE_BOTTOM; - } - // Prefer a corner when the cursor is near both axes. - constexpr double kCornerSlop = 32.0; - if (nearestH < kCornerSlop && nearestV < kCornerSlop) { - edges = (distLeft <= distRight ? WLR_EDGE_LEFT : WLR_EDGE_RIGHT) - | (distTop <= distBottom ? WLR_EDGE_TOP : WLR_EDGE_BOTTOM); + if (px < geo.width / 3.0) { + edges |= WLR_EDGE_LEFT; + } else if (px > 2.0 * geo.width / 3.0) { + edges |= WLR_EDGE_RIGHT; + } + if (py < geo.height / 3.0) { + edges |= WLR_EDGE_TOP; + } else if (py > 2.0 * geo.height / 3.0) { + edges |= WLR_EDGE_BOTTOM; } return edges; } diff --git a/tests/unit/presentation.cpp b/tests/unit/presentation.cpp index c30d060..848203e 100644 --- a/tests/unit/presentation.cpp +++ b/tests/unit/presentation.cpp @@ -6,10 +6,10 @@ #include "wlr.h" // clang-format on -// A fullscreen client whose buffer does not match the output is centered rather than scaled, and that centering lives in -// the scene node's position. The wlroots xdg scene helper rewrites that position to (-geometry.x, -geometry.y) on every -// commit, so the offset has to be re-applied afterwards or an oversized fullscreen buffer drifts to the top left on the -// next frame the client draws. +// A fullscreen client whose buffer does not match the output is centered rather than scaled, and that centering lives +// in the scene node's position. The wlroots xdg scene helper rewrites that position to (-geometry.x, -geometry.y) on +// every commit, so the offset has to be re-applied afterwards or an oversized fullscreen buffer drifts to the top left +// on the next frame the client draws. UMBRIEL_TEST(fullscreenCenteringSurvivesSceneReconfiguration) { wlr_scene* scene = wlr_scene_create(); CHECK(scene != nullptr); From ab4110ff4e9211712f65e685ab5bd0588fafd675 Mon Sep 17 00:00:00 2001 From: Lemmy Date: Tue, 25 Aug 2026 22:56:33 -0400 Subject: [PATCH 2/2] fix(input): ignore empty interactive resize edges --- docs/user/configuration.md | 11 +-- src/input/cursor.cpp | 16 +++- tests/harness/checks/515_resize_center.sh | 90 +++++++++++++++++++++++ 3 files changed, 108 insertions(+), 9 deletions(-) create mode 100755 tests/harness/checks/515_resize_center.sh diff --git a/docs/user/configuration.md b/docs/user/configuration.md index 68a4154..b8b5fe6 100644 --- a/docs/user/configuration.md +++ b/docs/user/configuration.md @@ -349,11 +349,12 @@ The three-finger vertical swipe continues to switch workspaces. The three-finger horizontal strip gesture is inert on vertical workspaces, so use keyboard or wheel bindings to scroll the strip. -In the scrolling layout, Mod+Right-drag selects horizontal and vertical resize -edges from the outer thirds of a window. Dragging from a corner region resizes -both axes. Mod+Right-click in the center region starts no resize and instead -scrolls the focused window into view. When a tiled resize ends, the focused -scrolling column animates back into view. +Mod+Right-drag selects horizontal and vertical resize edges from the outer +thirds of both tiled and floating windows. Dragging from a corner region resizes +both axes. Mod+Right-click in the center region starts no resize and preserves +the window's maximize state. For tiled windows, a center click also scrolls the +focused window into view. When a tiled resize ends, the focused scrolling column +animates back into view. When focus moves to a partially or fully hidden column, Umbriel scrolls by the shortest distance needed to reveal it completely. A column entering from the diff --git a/src/input/cursor.cpp b/src/input/cursor.cpp index 52e3732..8c13e50 100644 --- a/src/input/cursor.cpp +++ b/src/input/cursor.cpp @@ -467,10 +467,6 @@ namespace umbriel { tiled = false; } - setActiveConstraint(nullptr); - if (view->maximizedToEdges()) { - view->setMaximizedToEdges(false); - } if (tiled) { Workspace* workspace = view->workspace(); if (workspace == nullptr || workspace->group() == nullptr || workspace->group()->output() == nullptr) { @@ -487,6 +483,10 @@ namespace umbriel { refreshInteractiveCursor(); return; } + setActiveConstraint(nullptr); + if (view->maximizedToEdges()) { + view->setMaximizedToEdges(false); + } const wlr_box usable = workspace->group()->output()->usableArea(); std::unique_ptr session = layout.beginResize(view, resolvedEdges, usable); if (session == nullptr) { @@ -507,6 +507,14 @@ namespace umbriel { updateInteractiveCursor(view); return; } + if (edges == 0) { + refreshInteractiveCursor(); + return; + } + setActiveConstraint(nullptr); + if (view->maximizedToEdges()) { + view->setMaximizedToEdges(false); + } const wlr_box& geometry = view->toplevel()->base->geometry; const double borderX = diff --git a/tests/harness/checks/515_resize_center.sh b/tests/harness/checks/515_resize_center.sh new file mode 100755 index 0000000..493374e --- /dev/null +++ b/tests/harness/checks/515_resize_center.sh @@ -0,0 +1,90 @@ +#!/usr/bin/env bash +# A center-region Mod+Right click proposes no resize edge. It must not begin an empty resize grab or clear maximize state. +set -euo pipefail + +readonly BTN_RIGHT=273 # evdev BTN_RIGHT +readonly OUTPUT_W=1280 +readonly OUTPUT_H=720 +readonly POINTER="${UMBRIEL_POINTER_CLIENT:-./build-debug/pointer-client}" + +spawn_client() { + foot sh -c 'sleep 120' > /dev/null 2>&1 & +} + +pointer() { + "$POINTER" "$OUTPUT_W" "$OUTPUT_H" "$@" +} + +wait_for_window() { + for _ in $(seq 60); do + [[ $("$UMBRIEL" windows --json | jq 'length') -eq 1 ]] && return 0 + sleep 0.25 + done + echo "timed out waiting for one window" + return 1 +} + +wait_for_floating() { + local want=$1 + for _ in $(seq 40); do + [[ $("$UMBRIEL" windows --json | jq -r '.[0].floating') == "$want" ]] && return 0 + sleep 0.1 + done + echo "timed out waiting for floating=$want: $("$UMBRIEL" windows --json)" + return 1 +} + +wait_for_maximized_size() { + for _ in $(seq 40); do + local windows width height + windows=$("$UMBRIEL" windows --json) + width=$(jq -r '.[0].w' <<< "$windows") + height=$(jq -r '.[0].h' <<< "$windows") + (( width >= 1200 && height >= 700 )) && return 0 + sleep 0.1 + done + echo "timed out waiting for maximized geometry: $("$UMBRIEL" windows --json)" + return 1 +} + +center_resize_click() { + local windows x y + windows=$("$UMBRIEL" windows --json) + x=$(jq -r '.[0].x + (.[0].w / 2 | floor)' <<< "$windows") + y=$(jq -r '.[0].y + (.[0].h / 2 | floor)' <<< "$windows") + pointer move "$x" "$y" mod logo click "$BTN_RIGHT" mod none + sleep 0.8 +} + +check_maximized_size_unchanged() { + local kind=$1 before after before_size after_size + before=$("$UMBRIEL" windows --json) + before_size=$(jq -r '.[0] | "\(.w)x\(.h)"' <<< "$before") + center_resize_click + after=$("$UMBRIEL" windows --json) + after_size=$(jq -r '.[0] | "\(.w)x\(.h)"' <<< "$after") + if [[ $after_size != "$before_size" ]]; then + echo "$kind center resize click changed maximized geometry: $before_size to $after_size" + return 1 + fi +} + +spawn_client +wait_for_window + +"$UMBRIEL" msg window-toggle-maximize-to-edges > /dev/null +wait_for_maximized_size +failed=0 +check_maximized_size_unchanged tiled || failed=1 + +"$UMBRIEL" msg window-toggle-floating > /dev/null +wait_for_floating true +"$UMBRIEL" msg window-toggle-maximize-to-edges > /dev/null +wait_for_maximized_size +check_maximized_size_unchanged floating || failed=1 + +if (( failed != 0 )); then + exit 1 +fi + +echo "center resize clicks preserve tiled and floating maximize state"