Skip to content

Grab and Move: tight warning-gold overlay border + Always On Top 4px default#48474

Open
crutkas wants to merge 4 commits into
mainfrom
user/crutkas/grabmove-aot-border
Open

Grab and Move: tight warning-gold overlay border + Always On Top 4px default#48474
crutkas wants to merge 4 commits into
mainfrom
user/crutkas/grabmove-aot-border

Conversation

@crutkas

@crutkas crutkas commented Jun 11, 2026

Copy link
Copy Markdown
Member

Summary

Refines the Grab and Move drag/resize overlay so it matches the polish of Always on Top (AoT), and lowers the AoT default border thickness. Created at the request of @crutkas.

Two related border-refinement changes, kept in one PR because the Grab and Move "double layer" is designed around AoT's border.

Recording.2026-06-11.130417.mp4

1. Always on Top - default border thickness 15 -> 4

The default highlight border was 15px, which is visually heavy. Dropped to 4px for a tighter, Fluent-style frame.

  • src/modules/alwaysontop/AlwaysOnTop/Settings.h (C++ default)
  • src/settings-ui/Settings.UI.Library/AlwaysOnTopProperties.cs (DefaultFrameThickness)
  • Existing users keep their configured value; only fresh installs / "reset" pick up 4. Slider range (1-30) is unchanged.

2. Grab and Move - tight, warning-gold overlay (fill + border)

Previously the overlay was a full translucent white wash sized to GetWindowRect, which includes the invisible resize-border / shadow margins (~7px) - so it sat off the visible window. It now hugs the visible frame, mirroring AoT:

  • Keeps the translucent white wash over the visible window (the familiar "grabbed" feedback) and adds a tight warning-gold border on top. Both hug the visible frame and are rounded to match the window corners.
  • Tight geometry: anchored to DWMWA_EXTENDED_FRAME_BOUNDS (inset by the invisible-border margins) instead of GetWindowRect.
  • Corner detection: matches the window's corner radius via DWMWA_WINDOW_CORNER_PREFERENCE (same mapping AoT uses); border thickness and radius scale with the target window DPI.
  • Distinct accent: Fluent warning gold #FFB900 - the literal equivalent of WinUI SystemFillColorCaution (used as a ThemeResource for warnings across the Settings UI; a Win32 layered window can't resolve a ThemeResource, so a literal is required). Keeps Grab and Move visually distinct from AoT's accent-blue.
  • Double layer, for free: the Grab and Move border is drawn just inside the visible edge, while AoT draws its border just outside the visible edge. The two naturally stack into a clean double layer, so Grab and Move stays a constant 4px with no AoT detection / window enumeration.

Rendering keeps the existing GDI + UpdateLayeredWindow per-pixel-alpha path and adds GDI+ (a Windows system library - no new third-party dependency) for the antialiased, rounded fill and border. Frame metrics are computed once per drag/resize (never in the mouse-move hot path). The optional geometry label is unchanged.

Before / After

Before After
Grab and Move overlay Full white wash, offset from the window edge Same wash, now tight to the visible frame + gold border, corner-matched
AoT default border 15px 4px
AoT + Grab and Move together white wash over AoT border GM gold inside the edge + AoT accent outside it = double layer

Validation

  • Builds clean (exit 0, 0 warnings/errors) for x64 Debug: GrabAndMove, AlwaysOnTop, and Settings.UI.Library (Code Analysis / C26451 clean).
  • Smoke-tested live by running the standalone module exes: tight gold border + wash on Alt-drag / Alt-right-drag, AoT 4px border, and the inside/outside double layer on a pinned window.
  • WARNING: still draft pending broader visual validation (border tightness across DPIs, the exact gold, rounded vs square corners, AoT z-order during fast drags - AoT renders from a separate process and follows on a ~100ms timer). Screenshots to be added.

Follow-up (not in this PR)

AoT and Grab and Move remain separate overlay systems (AoT: persistent per-window Direct2D border; Grab and Move: transient GDI/UpdateLayeredWindow overlay). They can't share one runtime window, but the frame-geometry + corner-detection + DPI helpers are worth extracting into src/common (seeded by AoT's WindowCornersUtil/ScalingUtils). Tracked separately to keep this PR atomic (src/common is an ABI-careful area).

Notes

  • No IPC/JSON schema changes; no new settings.
  • No new third-party dependencies (GDI+ is a system library).

The default highlight border was 15px, which is visually heavy. Drop the default to 4px for a tighter, more refined frame. Existing users keep their configured value; only fresh installs / reset pick up the new default. Slider range (1-30) is unchanged. Kept in sync across the C++ (Settings.h) and C# (AlwaysOnTopProperties.cs) defaults.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Comment thread src/modules/GrabAndMove/GrabAndMove/main.cpp Fixed
@github-actions

This comment has been minimized.

@crutkas crutkas force-pushed the user/crutkas/grabmove-aot-border branch from 85ca4e6 to 036d493 Compare June 11, 2026 19:29
@github-actions

This comment has been minimized.

Refine the drag/resize overlay so it hugs the visible window frame instead of the
old full-window white wash that was offset by the invisible resize border:

- Keep the prior translucent white wash over the visible window and add a tight
  warning-gold border on top. Both hug the visible frame and are rounded to match
  the window corners. The accent is Fluent warning gold (#FFB900, the literal
  equivalent of WinUI SystemFillColorCaution, used as a ThemeResource for warnings
  across the Settings UI; a Win32 layered window can't resolve a ThemeResource).
- Anchor to DWMWA_EXTENDED_FRAME_BOUNDS (inset by the invisible-border margins)
  instead of GetWindowRect, and match the corner radius via
  DWMWA_WINDOW_CORNER_PREFERENCE; thickness and radius scale with the window DPI.
- The border is drawn just inside the visible edge while Always On Top draws its
  border just outside it, so the two naturally stack into a clean double layer
  with no special-casing (constant 4px).

Rendering keeps the GDI + UpdateLayeredWindow per-pixel-alpha path and adds GDI+
(a system library) for the antialiased, rounded fill and border. Window-frame
metrics are computed once per drag/resize, never in the mouse-move hot path.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@crutkas crutkas force-pushed the user/crutkas/grabmove-aot-border branch from 036d493 to 688d975 Compare June 11, 2026 20:05
@crutkas crutkas marked this pull request as ready for review June 11, 2026 20:06
@crutkas crutkas added Area-User Interface things that regard UX for PowerToys Product-Always On Top Refers to the idea of a Always on Top Powertoy Product-Grab And Move labels Jun 11, 2026
@crutkas

crutkas commented Jun 11, 2026

Copy link
Copy Markdown
Member Author

after this, i think the two UX subsystems should be unified from same code .

@DHowett DHowett left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pending notes. i would reduce the burden of comments by at least half, and also make the description of the PR like... i dunno, two lines? two lines would be fine.

Comment thread .github/actions/spell-check/allow/code.txt Outdated
Comment thread src/modules/GrabAndMove/GrabAndMove/main.cpp Outdated
Comment thread src/modules/GrabAndMove/GrabAndMove/main.cpp Outdated
Comment thread src/modules/GrabAndMove/GrabAndMove/main.cpp
Comment thread src/modules/GrabAndMove/GrabAndMove/main.cpp Outdated
Comment thread src/modules/GrabAndMove/GrabAndMove/main.cpp Outdated
Comment thread src/modules/GrabAndMove/GrabAndMove/main.cpp Outdated
@crutkas

crutkas commented Jun 12, 2026

Copy link
Copy Markdown
Member Author

comments addressed per dustin

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area-User Interface things that regard UX for PowerToys Product-Always On Top Refers to the idea of a Always on Top Powertoy Product-Grab And Move

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants