mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-02-24 04:00:02 +01:00
Refactor window positioning and sizing logic
Simplify and improve window positioning by using WinUIEx MonitorInfo to handle multi-monitor setups, taskbar positions, and DPI scaling. Remove manual DPI calculations and obsolete methods, making window sizing and placement more robust and concise.
This commit is contained in:
@@ -179,7 +179,11 @@ namespace PowerDisplay.Helpers
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Position a window at the bottom-right corner of its display area
|
||||
/// Position a window at the bottom-right corner of the primary monitor's work area.
|
||||
/// Uses WinUIEx MonitorInfo API which correctly handles all edge cases:
|
||||
/// - Multi-monitor setups
|
||||
/// - Taskbar at any position (top/bottom/left/right)
|
||||
/// - Different DPI settings
|
||||
/// </summary>
|
||||
/// <param name="window">WinUIEx window to position</param>
|
||||
/// <param name="width">Window width in device-independent units (DIU)</param>
|
||||
@@ -191,27 +195,22 @@ namespace PowerDisplay.Helpers
|
||||
int height,
|
||||
int rightMargin = 0)
|
||||
{
|
||||
var hwnd = WinRT.Interop.WindowNative.GetWindowHandle(window);
|
||||
var windowId = Win32Interop.GetWindowIdFromWindow(hwnd);
|
||||
var displayArea = DisplayArea.GetFromWindowId(windowId, DisplayAreaFallback.Nearest);
|
||||
|
||||
if (displayArea == null)
|
||||
// Use WinUIEx MonitorInfo - RectWork already includes correct offsets for taskbar position
|
||||
var monitors = MonitorInfo.GetDisplayMonitors();
|
||||
if (monitors == null || monitors.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Get DPI scale for this display
|
||||
// First monitor is typically the primary one
|
||||
var workArea = monitors[0].RectWork;
|
||||
double dpiScale = GetDpiScale(window);
|
||||
|
||||
// Calculate position in physical pixels
|
||||
// WorkArea dimensions are in physical pixels, so we need to scale our DIU values
|
||||
// IMPORTANT: Must include WorkArea.X and WorkArea.Y offsets to handle:
|
||||
// - Multi-monitor setups where the display may not start at (0,0)
|
||||
// - Taskbar positioned at top/left which shifts the WorkArea origin
|
||||
double x = displayArea.WorkArea.X + displayArea.WorkArea.Width - (dpiScale * (width + rightMargin));
|
||||
double y = displayArea.WorkArea.Y + displayArea.WorkArea.Height - (dpiScale * height);
|
||||
// Calculate bottom-right position
|
||||
// RectWork.Right/Bottom already account for taskbar position
|
||||
double x = workArea.Right - (dpiScale * (width + rightMargin));
|
||||
double y = workArea.Bottom - (dpiScale * height);
|
||||
|
||||
// MoveAndResize expects x,y in physical pixels and width,height in DIU
|
||||
window.MoveAndResize(x, y, width, height);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -477,41 +477,19 @@ namespace PowerDisplay
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_appWindow == null || RootGrid == null)
|
||||
if (RootGrid == null)
|
||||
{
|
||||
Logger.LogWarning("[AdjustSize] _appWindow or RootGrid is null, aborting");
|
||||
return;
|
||||
}
|
||||
|
||||
// Force layout update to ensure proper measurement
|
||||
// Force layout update and measure content height
|
||||
RootGrid.UpdateLayout();
|
||||
MainContainer?.Measure(new Windows.Foundation.Size(AppConstants.UI.WindowWidth, double.PositiveInfinity));
|
||||
var contentHeight = (int)Math.Ceiling(MainContainer?.DesiredSize.Height ?? 0);
|
||||
|
||||
// Get precise content height
|
||||
var availableWidth = (double)AppConstants.UI.WindowWidth;
|
||||
var contentHeight = GetContentHeight(availableWidth);
|
||||
|
||||
// Use unified DPI scaling method (consistent with FlyoutWindow pattern)
|
||||
double dpiScale = WindowHelper.GetDpiScale(this);
|
||||
int scaledHeight = WindowHelper.ScaleToPhysicalPixels((int)Math.Ceiling(contentHeight), dpiScale);
|
||||
|
||||
// Apply maximum height limit (also needs DPI scaling)
|
||||
int maxHeight = WindowHelper.ScaleToPhysicalPixels(AppConstants.UI.MaxWindowHeight, dpiScale);
|
||||
scaledHeight = Math.Min(scaledHeight, maxHeight);
|
||||
|
||||
// Check if resize is needed
|
||||
// Check if resize is needed
|
||||
var currentSize = _appWindow.Size;
|
||||
if (Math.Abs(currentSize.Height - scaledHeight) > 1)
|
||||
{
|
||||
// Convert scaled height back to DIU and reposition using DPI-aware method
|
||||
int heightInDiu = (int)Math.Ceiling(scaledHeight / dpiScale);
|
||||
|
||||
WindowHelper.PositionWindowBottomRight(
|
||||
this,
|
||||
AppConstants.UI.WindowWidth,
|
||||
heightInDiu,
|
||||
AppConstants.UI.WindowRightMargin);
|
||||
}
|
||||
// Apply max height limit and reposition (WindowEx handles DPI automatically)
|
||||
var finalHeight = Math.Min(contentHeight, AppConstants.UI.MaxWindowHeight);
|
||||
WindowHelper.PositionWindowBottomRight(this, AppConstants.UI.WindowWidth, finalHeight, AppConstants.UI.WindowRightMargin);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -519,19 +497,6 @@ namespace PowerDisplay
|
||||
}
|
||||
}
|
||||
|
||||
private double GetContentHeight(double availableWidth)
|
||||
{
|
||||
// Elegant solution: Measure the MainContainer directly.
|
||||
// This lets the XAML layout engine calculate the exact height required by all visible content.
|
||||
if (MainContainer != null)
|
||||
{
|
||||
MainContainer.Measure(new Windows.Foundation.Size(availableWidth, double.PositiveInfinity));
|
||||
return MainContainer.DesiredSize.Height;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private void PositionWindowAtBottomRight(AppWindow appWindow)
|
||||
{
|
||||
try
|
||||
|
||||
Reference in New Issue
Block a user