fix(windows): scale and frame the Actions Ring correctly - #1186
Open
zrides wants to merge 2 commits into
Open
Conversation
added 2 commits
August 31, 2026 02:34
Windows had no native display lookup, so `ring_window_options` fell through to the GPUI display list and compared the hook's physical cursor position against logical display bounds. Above 100% scaling the physical point matches no display, the lookup falls back to the primary display, and the ring opens at that display's centre instead of at the cursor. Resolve the cursor's monitor with `MonitorFromPoint` and convert the cursor and the monitor bounds using that monitor's own effective DPI, which is exactly the conversion GPUI's Windows backend applies when it builds its display bounds, so the two describe the same coordinate space. The conversion is kept free of Win32 so the scaling and negative-origin cases are covered on every host. `platform.rs` becomes a per-OS module tree: a second platform turns the interleaved cfg arms into the shape the workspace rules already reject. macOS keeps its display-relative CoreGraphics lookup unchanged. One macOS behaviour does change. When the native lookup fails, macOS no longer reuses the raw global cursor point against GPUI's display list: that point is not in GPUI's coordinate space, so placing a window from it was only ever accidental. The ring now centres on the primary display instead. Refs AprilNEA#1027
The ring window is transparent apart from the ring itself, but DWM still drew its default frame around it: a drop shadow, a border colour and rounded corners, so the ring rendered inside a visible rectangle. Disable non-client rendering, clear the border colour and opt out of corner rounding on the GPUI HWND. Each attribute is set independently and a rejection is logged rather than propagated: these are presentation hints, and a Windows build that does not recognise one should still get a working ring.
Greptile SummaryThe PR adds native Windows monitor lookup and effective-DPI conversion so the Actions Ring uses the same logical coordinate space as GPUI, while also removing native framing from the transparent window.
Confidence Score: 5/5The PR appears safe to merge based on the reviewed changes, with the explicitly acknowledged mixed-DPI window-creation behavior remaining an unverified hardware scenario rather than an established defect. The Windows coordinate conversion matches the intended cursor-monitor geometry model, platform fallbacks remain defined, and no concrete changed-code failure was established from the available repository evidence.
|
| Filename | Overview |
|---|---|
| crates/openlogi-overlay/src/platform/windows.rs | Adds Windows monitor resolution, effective-DPI conversion, HWND extraction, and best-effort DWM frame configuration; no publishable defect was established. |
| crates/openlogi-overlay/src/platform.rs | Introduces the shared placement model, platform dispatch, geometry validation, and portable conversion tests. |
| crates/openlogi-overlay/src/ring.rs | Uses native placement when available and safely falls back according to each platform’s coordinate-space guarantees. |
| crates/openlogi-overlay/src/main.rs | Applies native window policy directly to each newly created GPUI window. |
| crates/openlogi-overlay/src/platform/macos.rs | Preserves native display-relative placement and existing application, window, and click-away policies in the new module structure. |
| crates/openlogi-overlay/Cargo.toml | Adds narrowly gated Windows dependencies and required Win32 feature sets. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart LR
A[Native cursor position] --> B{Platform lookup succeeds?}
B -->|Windows| C[Resolve HMONITOR and effective DPI]
B -->|macOS| D[Resolve CoreGraphics display]
B -->|Linux fallback| E[Match GPUI display bounds]
C --> F[Convert physical global geometry to logical geometry]
D --> G[Convert cursor to display-relative geometry]
F --> H[Clamp ring within cursor display]
G --> H
E --> H
B -->|Windows or macOS failure| I[Center on primary display]
I --> H
H --> J[Create transparent Actions Ring window]
J --> K[Apply native window-frame policy]
Reviews (1): Last reviewed commit: "fix(windows): suppress action ring windo..." | Re-trigger Greptile
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
On Windows the Actions Ring opened at the centre of the primary display instead
of at the cursor whenever display scaling was above 100% (#1027).
The overlay had no native display lookup on Windows, so
ring_window_optionsfell through to the GPUI display list and compared the hook's physical
cursor position against logical display bounds. Above 100% scaling the
physical point matches no display, the lookup falls back to the primary display,
and the ring is placed at that display's centre — the "opens at a fixed
position" symptom in the issue.
The fix resolves the cursor's monitor with
MonitorFromPointand converts thecursor and the monitor bounds with that monitor's own effective DPI. That is
exactly the conversion GPUI's Windows backend applies when it builds its display
bounds (
logical_point(rcMonitor.left, top, scale)withscale = GetDpiForMonitor(MDT_EFFECTIVE_DPI) / 96), so the overlay and GPUI nowdescribe one coordinate space instead of two.
A second commit removes the DWM frame that Windows drew around the transparent
ring window.
Changes
crates/openlogi-overlayplatform.rsbecomes a per-OS module tree (macos.rs,windows.rs,other.rs) behind a facade owning the sharedCursorPlacementtype. A secondplatform turns the interleaved
cfgarms into the shape the workspace rulesalready reject.
MonitorFromPoint+GetMonitorInfoW+GetDpiForMonitor(MDT_EFFECTIVE_DPI). It returnsNone— and so falls backto the primary display — for a point no monitor covers, a failed query, or
anisotropic DPI, rather than guessing.
scaled_cursor_placementis kept free of Win32, so the 100/125/150% andnegative-origin monitor cases are unit-tested on every host.
configure_windows()becomesconfigure_window(&Window), applying DWMNCRENDERING_POLICY,BORDER_COLORandWINDOW_CORNER_PREFERENCEto theGPUI HWND so the transparent ring no longer sits inside a shadowed, rounded
rectangle. Each attribute is set independently and a rejection is logged, not
propagated: they are presentation hints, and a Windows build that does not
recognise one should still get a working ring.
raw-window-handle, andwindows-syswith theWin32_Foundation,Win32_Graphics_Dwm,Win32_Graphics_GdiandWin32_UI_HiDpifeatures.One macOS behaviour change
When the native display lookup fails, macOS no longer falls back to matching the
raw global cursor point against GPUI's display list. That point is not in GPUI's
coordinate space, so any placement derived from it was accidental; the ring now
centres on the primary display, matching the new Windows path. Flagging it
because it is a macOS change inside a Windows fix.
Testing
Full local gate on Windows 11 (x86_64-pc-windows-msvc),
RUSTFLAGS=-D warnings:cargo fmt --all -- --check— greencargo clippy --workspace --all-targets -- -D warnings— greencargo test --workspace— one pre-existing failure, unrelated to this branchRUSTDOCFLAGS=-D warnings cargo doc --workspace --no-deps --document-private-items --exclude openlogi-ui --exclude openlogi-desktop --exclude openlogi-overlay --exclude openlogi-agent— pre-existing failure, unrelated to this branchcargo test -p openlogi-overlaycovers the new conversion directly: identity at100%, 125% and 150% scaling, negative monitor origins preserved, and an invalid
scale factor falling through to the primary-display path.
The two failures above reproduce on master from a Windows checkout and are
untouched by this branch. Neither is visible in CI:
xtask'sci_yml_runs_what_this_runner_runsjoinsci.ymllinecontinuations by stripping a backslash followed by a bare LF, so a checkout
with CRLF endings (the Git for Windows default, and there is no
.gitattributeshere) fails to match every multi-linerun:.openlogi-permissionslinks toPermissionStatus::Unknownin its crate-leveldocs, but that type is gated to macOS and Linux, so the link resolves nowhere
under a Windows rustdoc run. The CI rustdoc job runs on Linux.
Both were verified green with local one-line fixes applied, confirming they are
the only two failures and that this branch adds none.
Not run locally: the macOS and Linux CI lanes, MSRV, cargo-deny, typos, shell
lint, and wasm — this host cannot reproduce them.
cargo xtask cicannotcomplete on Windows either: the
publish closurejob shells out tocargo xtask release check-publish, which cannot relink the xtask binary undertarget/debugwhile that binary is the running process.Hardware verification
Verified on Windows 11 at 125% display scaling: the Actions Ring opens centred
on the cursor, and the shadow, border and rounded corner previously drawn around
the transparent ring window are gone.
Not exercised: a multi-monitor setup where the ring's target display has a
different scale factor from the display a new window default-places on. GPUI
converts the requested window bounds with
GetDpiForWindowsampled while thewindow is still at
CW_USEDEFAULTrather than with the target display's scalefactor, so that mixed-DPI case is worth a look from anyone who has the setup.
Fixes #1027