Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Flow.Launcher.Infrastructure/UserSettings/Settings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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; }

/// <summary>
/// Custom left position on selected monitor
Expand Down
87 changes: 79 additions & 8 deletions Flow.Launcher/MainWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Comment on lines +714 to +721
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Previous DPI/screen data are never read from settings and therefore always equal current values

previousDpiX/Y are obtained via GetDpi, which returns current DPI, not the saved values.
As a result the “resolution/DPI change” branch is never taken and scaling never occurs.

-var previousScreenWidth  = _settings.PreviousScreenWidth;
-var previousScreenHeight = _settings.PreviousScreenHeight;
-GetDpi(out var previousDpiX, out var previousDpiY);
+var previousScreenWidth  = _settings.PreviousScreenWidth;
+var previousScreenHeight = _settings.PreviousScreenHeight;
+var previousDpiX         = _settings.PreviousDpiX;
+var previousDpiY         = _settings.PreviousDpiY;

Remember to store the current values after the position logic runs:

_settings.PreviousScreenWidth  = SystemParameters.VirtualScreenWidth;
_settings.PreviousScreenHeight = SystemParameters.VirtualScreenHeight;
_settings.PreviousDpiX         = currentDpiX;
_settings.PreviousDpiY         = currentDpiY;

Without this, the new properties added to Settings are never populated.

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
{
Expand All @@ -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;

Comment on lines +779 to +786
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Scaling uses freshly-overwritten values ⇒ ratios are always 1

Inside AdjustPositionForResolutionChange you divide by _settings.PreviousScreenWidth/Height, but these fields were just overwritten with the current size a few lines earlier, so widthRatio and heightRatio are always 1.

Either pass the captured previousScreenWidth/Height/Dpi into the method, or compute the ratios before writing the new values.

-var widthRatio  = screenWidth  / _settings.PreviousScreenWidth;
-var heightRatio = screenHeight / _settings.PreviousScreenHeight;
-var dpiXRatio   = currentDpiX  / previousDpiX;
-var dpiYRatio   = currentDpiY  / previousDpiY;
+var widthRatio  = screenWidth  / previousScreenWidth;
+var heightRatio = screenHeight / previousScreenHeight;
+var dpiXRatio   = currentDpiX  / previousDpiX;
+var dpiYRatio   = currentDpiY  / previousDpiY;

Fixing this will finally position the window correctly after display configuration changes.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
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;
// compute ratios using the captured "previous" values, not the overwritten settings
var widthRatio = screenWidth / previousScreenWidth;
var heightRatio = screenHeight / 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;
Expand Down Expand Up @@ -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
Expand Down
30 changes: 26 additions & 4 deletions Flow.Launcher/SettingWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Comment on lines +153 to +172
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Clamp calculations use width/height instead of absolute screen bounds – may push window off-screen

SystemParameters.VirtualScreenHeight/Width return the size of the virtual desktop, not the bottom/right coordinates.
To keep the window fully on screen you must add the origin (VirtualScreenTop/Left) when computing the maximum allowed Top/Left.

Current logic allows the window to slip below / to the right of the virtual desktop when monitors start at a negative coordinate (very common with mixed-resolution or vertical layouts).

-top  = Math.Min(top, SystemParameters.VirtualScreenHeight - ActualHeight);
-left = Math.Min(left, SystemParameters.VirtualScreenWidth  - ActualWidth);
+var maxTop  = SystemParameters.VirtualScreenTop  + SystemParameters.VirtualScreenHeight - ActualHeight;
+var maxLeft = SystemParameters.VirtualScreenLeft + SystemParameters.VirtualScreenWidth  - ActualWidth;
+
+top  = Math.Min(top,  maxTop);
+left = Math.Min(left, maxLeft);

Apply the same fix in AdjustWindowPosition.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
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 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);
var maxTop = SystemParameters.VirtualScreenTop + SystemParameters.VirtualScreenHeight - ActualHeight;
var maxLeft = SystemParameters.VirtualScreenLeft + SystemParameters.VirtualScreenWidth - ActualWidth;
top = Math.Min(top, maxTop);
left = Math.Min(left, maxLeft);
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);
var maxTop = SystemParameters.VirtualScreenTop + SystemParameters.VirtualScreenHeight - ActualHeight;
var maxLeft = SystemParameters.VirtualScreenLeft + SystemParameters.VirtualScreenWidth - ActualWidth;
top = Math.Min(top, maxTop);
left = Math.Min(left, maxLeft);
}


private static bool IsPositionValid(double top, double left)
{
foreach (var screen in Screen.AllScreens)
Expand Down
Loading