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:
Yu Leng
2025-12-17 10:26:54 +08:00
parent 6d032713aa
commit 734ef8816b
2 changed files with 21 additions and 57 deletions

View File

@@ -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);
}
}

View File

@@ -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