-
-
Notifications
You must be signed in to change notification settings - Fork 344
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix Window Positioning with Multiple Montiors #2756
Fix Window Positioning with Multiple Montiors #2756
Conversation
… dpi has changed, the position will be rescaled proportionally
Flow.Launcher/MainWindow.xaml.cs
Outdated
private double _previousScreenWidth; | ||
private double _previousScreenHeight; | ||
private double _previousDpiX; | ||
private double _previousDpiY; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Store previously used resolution and dpi values.
Top = 10; | ||
Top = VerticalTop(screen); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because this value is a fixed value (not related screen number), there is a problem with vertical alignment monitor situation. This code will try to locate the window and set the position with screen
Flow.Launcher/MainWindow.xaml.cs
Outdated
if (!( | ||
_previousScreenWidth == currentScreenWidth && | ||
_previousScreenHeight == currentScreenHeight && | ||
_previousDpiX == currentDpi.X && | ||
_previousDpiY == currentDpi.Y | ||
)) | ||
{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This line means, “If anything is different from the previous information”
Flow.Launcher/MainWindow.xaml.cs
Outdated
_previousDpiY == currentDpi.Y | ||
)) | ||
{ | ||
if (_previousScreenWidth != 0 && _previousScreenHeight != 0 && _previousDpiX != 0 && _previousDpiY != 0) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure why it's there...unless they're all non-zero. chatgpt wrote.
Flow.Launcher/MainWindow.xaml.cs
Outdated
double widthRatio = currentScreenWidth / _previousScreenWidth; | ||
double heightRatio = currentScreenHeight / _previousScreenHeight; | ||
double dpiXRatio = currentDpi.X / _previousDpiX; | ||
double dpiYRatio = currentDpi.Y / _previousDpiY; | ||
|
||
_settings.WindowLeft *= widthRatio * dpiXRatio; | ||
_settings.WindowTop *= heightRatio * dpiYRatio; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rescales previously stored values to a ratio.
This function is intended to be applied when the resolution is changed even when the program is turned off. It didn't work well, so I stopped. I'll think about the logic a little more. |
Flow.Launcher/MainWindow.xaml.cs
Outdated
_settings.PreviousDpiY = GetDpiY(); | ||
|
||
// If previous screen width, height, DPI X, or DPI Y are not zero | ||
if (previousScreenWidth != 0 && previousScreenHeight != 0 && |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what does it mean to be 0?
…sounds/Flow.Launcher into 240605-Fix-RightTop-Position
Be a legend 🏆 by adding a before and after screenshot of the changes you made, especially if they are around UI/UX. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 7
Outside diff range and nitpick comments (2)
Flow.Launcher/SettingWindow.xaml.cs (2)
153-153
: Validate the calculation for window left position.Ensure that the calculation for the window's left position correctly handles different screen resolutions and DPI settings. It's crucial that this calculation is accurate to prevent the window from appearing off-screen in multi-monitor setups.
162-162
: Validate the calculation for window top position.Similar to the left position, validate that the top position calculation is robust against various screen sizes and configurations, particularly in vertical multi-monitor setups where the Y-coordinate can significantly vary.
SetWindowPosition(WindowTop(), WindowLeft()); | ||
} | ||
else | ||
{ | ||
Top = _settings.SettingWindowTop.Value; | ||
Left = _settings.SettingWindowLeft.Value; | ||
double left = _settings.SettingWindowLeft.Value; | ||
double top = _settings.SettingWindowTop.Value; | ||
AdjustWindowPosition(ref top, ref left); | ||
SetWindowPosition(top, left); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ensure proper handling of null values for window position settings.
Given that _settings.SettingWindowTop
and _settings.SettingWindowLeft
can potentially be null
, it's crucial to ensure they are handled properly before using their Value
property directly in lines 119 and 120. This could potentially throw a InvalidOperationException
if they are null
when accessed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe the condition in above line 113 needs to be 'and' not ''or'? Because one of them could be a null and still passes through the condition check.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jjw24 You're absolutely right that changing the condition to 'and' would ensure that we don't attempt to use a null value inadvertently, which would enhance the robustness of the code. However, we should also consider scenarios where only one of the two settings (_settings.SettingWindowTop
or _settings.SettingWindowLeft
) is null. In such cases, we might still want to adjust the position based on the non-null value. Here's a modified approach that could handle both scenarios:
public void InitializePosition()
{
double? top = _settings.SettingWindowTop;
double? left = _settings.SettingWindowLeft;
if (top == null || left == null)
{
// If either is null, calculate both to ensure the window is positioned safely
top = WindowTop();
left = WindowLeft();
}
// Now we can safely assume both top and left are not null
AdjustWindowPosition(ref top.Value, ref left.Value);
SetWindowPosition(top.Value, left.Value);
}
This approach ensures that if either top
or left
is null, both values are recalculated, thus keeping the window within safe screen boundaries. What do you think of this implementation?
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); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Optimize the adjustment of window position to ensure it remains within screen boundaries.
Similar to the previous comment, this logic is duplicated and should be handled by a single helper method to ensure consistency and reduce errors.
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; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Refactor window boundary checks to a helper method to avoid code duplication.
The code for ensuring the window does not exceed screen boundaries is duplicated in both SetWindowPosition
and AdjustWindowPosition
. Consider refactoring this into a helper method to reduce redundancy and improve maintainability.
- 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);
+ EnsureWithinScreenBounds(ref top, ref left);
Committable suggestion was skipped due to low confidence.
public double PreviousScreenWidth { get; set; } | ||
public double PreviousScreenHeight { get; set; } | ||
public double PreviousDpiX { get; set; } | ||
public double PreviousDpiY { get; set; } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Properly initialize new settings properties to default values.
The newly added properties PreviousScreenWidth
, PreviousScreenHeight
, PreviousDpiX
, and PreviousDpiY
should be initialized to sensible defaults to prevent issues when they are first accessed before being explicitly set.
+ public double PreviousScreenWidth { get; set; } = 0;
+ public double PreviousScreenHeight { get; set; } = 0;
+ public double PreviousDpiX { get; set; } = 96; // Assuming default DPI
+ public double PreviousDpiY { get; set; } = 96; // Assuming default DPI
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.
public double PreviousScreenWidth { get; set; } | |
public double PreviousScreenHeight { get; set; } | |
public double PreviousDpiX { get; set; } | |
public double PreviousDpiY { get; set; } | |
public double PreviousScreenWidth { get; set; } = 0; | |
public double PreviousScreenHeight { get; set; } = 0; | |
public double PreviousDpiX { get; set; } = 96; // Assuming default DPI | |
public double PreviousDpiY { get; set; } = 96; // Assuming default DPI |
Flow.Launcher/MainWindow.xaml.cs
Outdated
double previousScreenWidth = _settings.PreviousScreenWidth; | ||
double previousScreenHeight = _settings.PreviousScreenHeight; | ||
double previousDpiX, previousDpiY; | ||
GetDpi(out previousDpiX, out previousDpiY); | ||
|
||
_settings.PreviousScreenWidth = SystemParameters.VirtualScreenWidth; | ||
_settings.PreviousScreenHeight = SystemParameters.VirtualScreenHeight; | ||
double currentDpiX, currentDpiY; | ||
GetDpi(out currentDpiX, out 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; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ensure DPI and screen size changes are handled accurately.
The logic to handle resolution and DPI changes appears complex and could benefit from additional error handling and validation to ensure it behaves correctly across all scenarios, especially with unusual DPI settings or rapid changes in configuration.
Flow.Launcher/MainWindow.xaml.cs
Outdated
private void AdjustPositionForResolutionChange() | ||
{ | ||
double screenWidth = SystemParameters.VirtualScreenWidth; | ||
double screenHeight = SystemParameters.VirtualScreenHeight; | ||
double currentDpiX, currentDpiY; | ||
GetDpi(out currentDpiX, out currentDpiY); | ||
|
||
double previousLeft = _settings.WindowLeft; | ||
double previousTop = _settings.WindowTop; | ||
double previousDpiX, previousDpiY; | ||
GetDpi(out previousDpiX, out previousDpiY); | ||
|
||
double widthRatio = screenWidth / _settings.PreviousScreenWidth; | ||
double heightRatio = screenHeight / _settings.PreviousScreenHeight; | ||
double dpiXRatio = currentDpiX / previousDpiX; | ||
double dpiYRatio = currentDpiY / previousDpiY; | ||
|
||
double newLeft = previousLeft * widthRatio * dpiXRatio; | ||
double newTop = previousTop * heightRatio * dpiYRatio; | ||
|
||
double screenLeft = SystemParameters.VirtualScreenLeft; | ||
double screenTop = SystemParameters.VirtualScreenTop; | ||
|
||
double maxX = screenLeft + screenWidth - ActualWidth; | ||
double maxY = screenTop + screenHeight - ActualHeight; | ||
|
||
Left = Math.Max(screenLeft, Math.Min(newLeft, maxX)); | ||
Top = Math.Max(screenTop, Math.Min(newTop, maxY)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Refactor resolution change adjustment logic to enhance clarity and reduce complexity.
The method AdjustPositionForResolutionChange
contains complex calculations that could be simplified or broken down into smaller, more manageable methods. This would improve readability and maintainability.
- double widthRatio = screenWidth / _settings.PreviousScreenWidth;
- double heightRatio = screenHeight / _settings.PreviousScreenHeight;
- double dpiXRatio = currentDpiX / previousDpiX;
- double dpiYRatio = currentDpiY / previousDpiY;
+ CalculateRatios(screenWidth, screenHeight, currentDpiX, currentDpiY);
Committable suggestion was skipped due to low confidence.
Flow.Launcher/MainWindow.xaml.cs
Outdated
public double VerticalTop(Screen screen) | ||
{ | ||
var dip1 = WindowsInteropHelper.TransformPixelsToDIP(this, 0, screen.WorkingArea.Y); | ||
var top = dip1.Y +10; | ||
return top; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ensure vertical positioning takes into account taskbar and window decorations.
The method VerticalTop
calculates the top position but does not account for potential obstructions like the taskbar or window decorations that might obscure the window. Consider adjusting the calculation to ensure the window is fully visible.
- var top = dip1.Y +10;
+ var top = Math.Max(dip1.Y + 10, SystemParameters.WorkArea.Top);
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.
public double VerticalTop(Screen screen) | |
{ | |
var dip1 = WindowsInteropHelper.TransformPixelsToDIP(this, 0, screen.WorkingArea.Y); | |
var top = dip1.Y +10; | |
return top; | |
} | |
public double VerticalTop(Screen screen) | |
{ | |
var dip1 = WindowsInteropHelper.TransformPixelsToDIP(this, 0, screen.WorkingArea.Y); | |
var top = Math.Max(dip1.Y + 10, SystemParameters.WorkArea.Top); | |
return top; | |
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe you want Math.Min
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@taooceros, you're right to consider Math.Min
in the context of taskbar positioning, especially if the taskbar is at the top of the screen. Using Math.Min
would ensure that the window does not overlap with a top-positioned taskbar by limiting the window's top boundary to be no lower than the top of the work area.
Here's the adjusted method with Math.Min
:
public double VerticalTop(Screen screen)
{
var dip1 = WindowsInteropHelper.TransformPixelsToDIP(this, 0, screen.WorkingArea.Y);
var top = Math.Min(dip1.Y + 10, SystemParameters.WorkArea.Top);
return top;
}
This change will make sure that the window respects the upper boundary of the work area, which is particularly useful if the taskbar is placed at the top of the screen. If this modification suits the typical setup for your users, it would indeed be a beneficial change.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry I am wrong.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@taooceros, no worries at all! It's great that we're on the same page now regarding the positioning. Using Math.Max
ensures that the window does not overlap with a top-positioned taskbar, maintaining visibility and accessibility. If there's anything else you'd like to discuss or adjust, feel free to let me know! 😊
|
This comment has been minimized.
This comment has been minimized.
The problem I found exists in |
… into fork/240605-Fix-RightTop-Position
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
🥷 Code experts: Yusyuriv, VictoriousRaptor onesounds, Yusyuriv have 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: To learn more about /:\ gitStream - Visit our Docs |
This PR is 74.04580152671755% new code. |
This comment has been minimized.
This comment has been minimized.
|
||
var currentDpi = GetDpi(); | ||
|
||
if (previousScreen == default || |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should reset the position if no previous record is found.
This comment has been minimized.
This comment has been minimized.
@onesounds I made some change to group Left and Top operation mainly without change of logic except some very obvious one. You can take a look and merge as you wish. |
@check-spelling-bot Report🔴 Please reviewSee the 📂 files view, the 📜action log, or 📝 job summary for details.
See ❌ Event descriptions for more information. If the flagged items are 🤯 false positivesIf items relate to a ...
|
Review Guide
What's the PR
Test Cases
After the program ends, change the horizontal resolution to be narrower, and then the window position does not deviate from the screen when the program is executed.
Remember last position should operate as before
Other settings other than the last position setting must operate normally.
When you select Top-Left/Center-Top/Right as the custom monitor position in a vertical dual-monitor alignment, both monitors should display in their normal positions.
Both the setup window and the main window must work.
ETC
Summary by CodeRabbit
New Features
Bug Fixes