From b96a69a5b636c91ff00b681adad785446b98f5c4 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Mon, 12 May 2025 22:03:00 +0800 Subject: [PATCH] Fix Window Positioning with Multiple Montiors Co-authored-by: onesounds --- .../UserSettings/Settings.cs | 4 + Flow.Launcher/MainWindow.xaml.cs | 87 +++++++++++++++++-- Flow.Launcher/SettingWindow.xaml.cs | 30 ++++++- 3 files changed, 109 insertions(+), 12 deletions(-) diff --git a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs index 34bf4f90e5c..ce1269a2995 100644 --- a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs +++ b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs @@ -293,6 +293,10 @@ public SearchPrecisionScore QuerySearchPrecision public double WindowLeft { get; set; } public double WindowTop { get; set; } + public double PreviousScreenWidth { get; set; } + public double PreviousScreenHeight { get; set; } + public double PreviousDpiX { get; set; } + public double PreviousDpiY { get; set; } /// /// Custom left position on selected monitor diff --git a/Flow.Launcher/MainWindow.xaml.cs b/Flow.Launcher/MainWindow.xaml.cs index 46eeb2adc6e..230472d8804 100644 --- a/Flow.Launcher/MainWindow.xaml.cs +++ b/Flow.Launcher/MainWindow.xaml.cs @@ -711,8 +711,26 @@ void InitializePositionInner() { if (_settings.SearchWindowScreen == SearchWindowScreens.RememberLastLaunchLocation) { - Top = _settings.WindowTop; + var previousScreenWidth = _settings.PreviousScreenWidth; + var previousScreenHeight = _settings.PreviousScreenHeight; + GetDpi(out var previousDpiX, out var previousDpiY); + + _settings.PreviousScreenWidth = SystemParameters.VirtualScreenWidth; + _settings.PreviousScreenHeight = SystemParameters.VirtualScreenHeight; + GetDpi(out var currentDpiX, out var currentDpiY); + + if (previousScreenWidth != 0 && previousScreenHeight != 0 && + previousDpiX != 0 && previousDpiY != 0 && + (previousScreenWidth != SystemParameters.VirtualScreenWidth || + previousScreenHeight != SystemParameters.VirtualScreenHeight || + previousDpiX != currentDpiX || previousDpiY != currentDpiY)) + { + AdjustPositionForResolutionChange(); + return; + } + Left = _settings.WindowLeft; + Top = _settings.WindowTop; } else { @@ -725,27 +743,73 @@ void InitializePositionInner() break; case SearchWindowAligns.CenterTop: Left = HorizonCenter(screen); - Top = 10; + Top = VerticalTop(screen); break; case SearchWindowAligns.LeftTop: Left = HorizonLeft(screen); - Top = 10; + Top = VerticalTop(screen); break; case SearchWindowAligns.RightTop: Left = HorizonRight(screen); - Top = 10; + Top = VerticalTop(screen); break; case SearchWindowAligns.Custom: - Left = Win32Helper.TransformPixelsToDIP(this, - screen.WorkingArea.X + _settings.CustomWindowLeft, 0).X; - Top = Win32Helper.TransformPixelsToDIP(this, 0, - screen.WorkingArea.Y + _settings.CustomWindowTop).Y; + var customLeft = Win32Helper.TransformPixelsToDIP(this, + screen.WorkingArea.X + _settings.CustomWindowLeft, 0); + var customTop = Win32Helper.TransformPixelsToDIP(this, 0, + screen.WorkingArea.Y + _settings.CustomWindowTop); + Left = customLeft.X; + Top = customTop.Y; break; } } } } + private void AdjustPositionForResolutionChange() + { + var screenWidth = SystemParameters.VirtualScreenWidth; + var screenHeight = SystemParameters.VirtualScreenHeight; + GetDpi(out var currentDpiX, out var currentDpiY); + + var previousLeft = _settings.WindowLeft; + var previousTop = _settings.WindowTop; + GetDpi(out var previousDpiX, out var previousDpiY); + + var widthRatio = screenWidth / _settings.PreviousScreenWidth; + var heightRatio = screenHeight / _settings.PreviousScreenHeight; + var dpiXRatio = currentDpiX / previousDpiX; + var dpiYRatio = currentDpiY / previousDpiY; + + var newLeft = previousLeft * widthRatio * dpiXRatio; + var newTop = previousTop * heightRatio * dpiYRatio; + + var screenLeft = SystemParameters.VirtualScreenLeft; + var screenTop = SystemParameters.VirtualScreenTop; + + var maxX = screenLeft + screenWidth - ActualWidth; + var maxY = screenTop + screenHeight - ActualHeight; + + Left = Math.Max(screenLeft, Math.Min(newLeft, maxX)); + Top = Math.Max(screenTop, Math.Min(newTop, maxY)); + } + + private void GetDpi(out double dpiX, out double dpiY) + { + var source = PresentationSource.FromVisual(this); + if (source != null && source.CompositionTarget != null) + { + var matrix = source.CompositionTarget.TransformToDevice; + dpiX = 96 * matrix.M11; + dpiY = 96 * matrix.M22; + } + else + { + dpiX = 96; + dpiY = 96; + } + } + private Screen SelectedScreen() { Screen screen; @@ -806,6 +870,13 @@ private double HorizonLeft(Screen screen) return left; } + public double VerticalTop(Screen screen) + { + var dip1 = Win32Helper.TransformPixelsToDIP(this, 0, screen.WorkingArea.Y); + var top = dip1.Y + 10; + return top; + } + #endregion #region Window Animation diff --git a/Flow.Launcher/SettingWindow.xaml.cs b/Flow.Launcher/SettingWindow.xaml.cs index 79bd171edfe..cf84317acb0 100644 --- a/Flow.Launcher/SettingWindow.xaml.cs +++ b/Flow.Launcher/SettingWindow.xaml.cs @@ -137,18 +137,40 @@ public void UpdatePositionAndState() if (previousTop == null || previousLeft == null || !IsPositionValid(previousTop.Value, previousLeft.Value)) { - Top = WindowTop(); - Left = WindowLeft(); + SetWindowPosition(WindowTop(), WindowLeft()); } else { - Top = previousTop.Value; - Left = previousLeft.Value; + var left = _settings.SettingWindowLeft.Value; + var top = _settings.SettingWindowTop.Value; + AdjustWindowPosition(ref top, ref left); + SetWindowPosition(top, left); } WindowState = _settings.SettingWindowState; } + private void SetWindowPosition(double top, double left) + { + // Ensure window does not exceed screen boundaries + top = Math.Max(top, SystemParameters.VirtualScreenTop); + left = Math.Max(left, SystemParameters.VirtualScreenLeft); + top = Math.Min(top, SystemParameters.VirtualScreenHeight - ActualHeight); + left = Math.Min(left, SystemParameters.VirtualScreenWidth - ActualWidth); + + Top = top; + Left = left; + } + + private void AdjustWindowPosition(ref double top, ref double left) + { + // Adjust window position if it exceeds screen boundaries + top = Math.Max(top, SystemParameters.VirtualScreenTop); + left = Math.Max(left, SystemParameters.VirtualScreenLeft); + top = Math.Min(top, SystemParameters.VirtualScreenHeight - ActualHeight); + left = Math.Min(left, SystemParameters.VirtualScreenWidth - ActualWidth); + } + private static bool IsPositionValid(double top, double left) { foreach (var screen in Screen.AllScreens)