Fix Settings window off-screen after disconnecting high-DPI monitor#4342
Fix Settings window off-screen after disconnecting high-DPI monitor#4342
Conversation
- Fix IsPositionValid to use SystemParameters.VirtualScreen* (DIP units) instead of MonitorInfo.WorkingArea (physical pixels) to avoid DPI coordinate mismatch on high-DPI and mixed-DPI multi-monitor setups. - Fix AdjustWindowPosition and SetWindowPosition to correctly calculate the max boundary as VirtualScreenTop + VirtualScreenHeight - ActualHeight (was VirtualScreenHeight - ActualHeight), which incorrectly allowed windows to extend beyond the bottom/right edge when VirtualScreenTop or VirtualScreenLeft were non-zero (e.g., monitors above/left of primary). Co-authored-by: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com>
31c47e6 to
a8e755e
Compare
|
🥷 Code experts: Jack251970 Jack251970 has most 👩💻 activity in the files. See details
Activity based on git-commit:
Knowledge based on git-blame:
Activity based on git-commit:
Knowledge based on git-blame:
Activity based on git-commit:
Knowledge based on git-blame:
Activity based on git-commit:
Knowledge based on git-blame:
Activity based on git-commit:
Knowledge based on git-blame: ✨ Comment |
|
Be a legend 🏆 by adding a before and after screenshot of the changes you made, especially if they are around UI/UX. |
|
Please reopen PR under your name when ready to go. |
There was a problem hiding this comment.
2 issues found across 5 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="Flow.Launcher.Plugin/SharedModels/MonitorInfo.cs">
<violation number="1" location="Flow.Launcher.Plugin/SharedModels/MonitorInfo.cs:197">
P1: DPI scale uses integer division, truncating non-100%/200% scaling and producing incorrect DIP coordinates.</violation>
</file>
<file name="Flow.Launcher/SettingWindow.xaml.cs">
<violation number="1" location="Flow.Launcher/SettingWindow.xaml.cs:203">
P2: `IsPositionValid` now validates against the virtual-screen bounding box, which can mark coordinates in non-visible gaps between monitors as valid. That can still restore Settings off-screen on irregular multi-monitor layouts.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
| { | ||
| if (GetDpiForMonitor(_monitor, MonitorDpiType.EffectiveDpi, out var dpiX, out var dpiY) == 0 && dpiX != 0 && dpiY != 0) | ||
| { | ||
| return (dpiX / 96, dpiY / 96); |
There was a problem hiding this comment.
P1: DPI scale uses integer division, truncating non-100%/200% scaling and producing incorrect DIP coordinates.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At Flow.Launcher.Plugin/SharedModels/MonitorInfo.cs, line 197:
<comment>DPI scale uses integer division, truncating non-100%/200% scaling and producing incorrect DIP coordinates.</comment>
<file context>
@@ -171,6 +190,24 @@ internal unsafe MonitorInfo(HMONITOR monitor, RECT* rect)
+ {
+ if (GetDpiForMonitor(_monitor, MonitorDpiType.EffectiveDpi, out var dpiX, out var dpiY) == 0 && dpiX != 0 && dpiY != 0)
+ {
+ return (dpiX / 96, dpiY / 96);
+ }
+
</file context>
| return (dpiX / 96, dpiY / 96); | |
| return (dpiX / 96d, dpiY / 96d); |
| return left >= SystemParameters.VirtualScreenLeft && | ||
| left < SystemParameters.VirtualScreenLeft + SystemParameters.VirtualScreenWidth && | ||
| top >= SystemParameters.VirtualScreenTop && | ||
| top < SystemParameters.VirtualScreenTop + SystemParameters.VirtualScreenHeight; |
There was a problem hiding this comment.
P2: IsPositionValid now validates against the virtual-screen bounding box, which can mark coordinates in non-visible gaps between monitors as valid. That can still restore Settings off-screen on irregular multi-monitor layouts.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At Flow.Launcher/SettingWindow.xaml.cs, line 203:
<comment>`IsPositionValid` now validates against the virtual-screen bounding box, which can mark coordinates in non-visible gaps between monitors as valid. That can still restore Settings off-screen on irregular multi-monitor layouts.</comment>
<file context>
@@ -191,39 +191,35 @@ private void AdjustWindowPosition(ref double top, ref double left)
+ // Use SystemParameters (DIP units) to match the coordinate system of Window.Top/Left.
+ // MonitorInfo.WorkingArea uses physical pixels which can differ from DIP units when DPI
+ // scaling is active, leading to incorrect results on high-DPI or mixed-DPI setups.
+ return left >= SystemParameters.VirtualScreenLeft &&
+ left < SystemParameters.VirtualScreenLeft + SystemParameters.VirtualScreenWidth &&
+ top >= SystemParameters.VirtualScreenTop &&
</file context>
| return left >= SystemParameters.VirtualScreenLeft && | |
| left < SystemParameters.VirtualScreenLeft + SystemParameters.VirtualScreenWidth && | |
| top >= SystemParameters.VirtualScreenTop && | |
| top < SystemParameters.VirtualScreenTop + SystemParameters.VirtualScreenHeight; | |
| foreach (var screen in MonitorInfo.GetDisplayMonitors()) | |
| { | |
| var origin = screen.TransformPixelsToDIP(screen.WorkingArea.X, screen.WorkingArea.Y); | |
| var size = screen.TransformPixelsToDIP(screen.WorkingArea.Width, screen.WorkingArea.Height); | |
| if (left >= origin.X && left < origin.X + size.X && | |
| top >= origin.Y && top < origin.Y + size.Y) | |
| { | |
| return true; | |
| } | |
| } | |
| return false; |
it's more about testing what copilot can do and found a lot of issues in this pr. and i don't have a dual screen setup for testing. closing this pr for now |
|
Ok no worries. |
IsPositionValidto use DIP-basedSystemParameters.VirtualScreen*instead of physical pixelMonitorInfo.WorkingArea(DPI mismatch)AdjustWindowPositionmax boundary:VirtualScreenTop + VirtualScreenHeight - ActualHeight(not justVirtualScreenHeight - ActualHeight)SetWindowPositionmax boundary the same wayOriginal prompt
💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.
Summary by cubic
Prevents the Settings window from opening off-screen after disconnecting a high‑DPI monitor. Normalizes window math to DIP, clamps within the full virtual screen (including negative origins), and saves display metrics to recover safely after DPI/resolution changes.
SystemParameters.VirtualScreen*(DIP) for position validation and clamping in Settings window; fix max bounds toVirtualScreenTop/Left + VirtualScreenHeight/Width - ActualHeight/Widthto handle non‑zero virtual origins.Win32Helper.TransformPixelsToDIPcall sites with per‑monitorMonitorInfo.TransformPixelsToDIPin Main/Settings windows;Win32Helper.TransformPixelsToDIPnow returns doubles (no rounding).PreviousScreenWidth/Heightand newPreviousDpiX/Y; adjust position on startup when screen size or DPI changed;AdjustPositionForResolutionChangenow scales by virtual screen ratios only (removed DPI factor).MonitorInfo.TransformPixelsToDIP(point/rect) usingGetDpiForMonitor(Effective DPI) and helpersSaveWindowPositionAndDisplayMetrics/SaveCurrentDisplayMetrics.IsPositionValid; integer rounding in pixel→DIP conversion; DPI ratio scaling in resolution adjustment.Written for commit 386f2b4. Summary will update on new commits.