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
Constrain child windows to monitor bounds #8341
Constrain child windows to monitor bounds #8341
Conversation
7e46d12
to
910ff88
Compare
I'm sure there's an API in Windows Forms or Win32 to know whether a window
is within the visible desktop area.
Once I have a 2nd monitor I'll be able to explore this.
|
Incidentally I received my 2nd monitor today :D |
I've spent an evening playing in a multi monitor setup, and here's what I propose.
LinqPad test scriptFor the test setup I have two 4K monitors:
NB: the script doesn't currently take dpi into account void Main()
{
var screens = Screen.AllScreens.Select(screen => screen.WorkingArea).ToArray();
int count = 0;
foreach (Rectangle screen in screens)
{
Console.WriteLine($"Screen {++count}: {screen.ToString()}");
}
Console.WriteLine();
Rectangle[] rects = new System.Drawing.Rectangle[]
{
// top left primary monitor
new Rectangle(0, 0, 500, 500),
// incorrect location
new Rectangle(-100, -100, 500, 500),
// creeps into the 2ndary screen
new Rectangle(0, -730, 3840, 750),
// shown on the 2ndary screen
new Rectangle(-100, -1730, 750, 750),
};
foreach (Rectangle rect in rects)
{
Console.WriteLine($"Testing rectangle: {rect.ToString()}\r\n---------------");
var form = new Form();
form.StartPosition = FormStartPosition.Manual;
form.DesktopLocation = rect.Location;
form.Size = rect.Size;
form.Text = rect.ToString();
form.Show();
foreach (Rectangle screen in screens)
{
bool res = IsDisplayedOn10Percent(screen, rect, form);
if (res)
{
Console.WriteLine($"Screen: {screen.ToString()}");
form.BackColor = Color.Green;
// no point testing other screens
Console.WriteLine();
break;
}
else
{
}
}
if (form.BackColor != Color.Green)
{
form.BackColor = Color.Orange;
form.DesktopLocation = Point.Empty;
}
Console.WriteLine();
}
}
private bool IsDisplayedOn10Percent(Rectangle screen, Rectangle window, Form debugForm)
{
if (screen.IsEmpty || window.IsEmpty) return false;
int requiredHeight = (int)(screen.Height * 0.1);
int requireWidth = (int)(screen.Width * 0.1);
var label = new Label
{
AutoSize = false,
Size = new Size(requireWidth, requiredHeight),
BackColor = Color.Blue
};
Point p;
if (screen.Contains(window.Location))
{
p = new Point(window.Left + requireWidth, window.Top + requiredHeight);
bool leftTop = screen.Contains(p);
if (leftTop)
{
Console.WriteLine($"{screen.ToString()} contains {p} (L, T)");
label.Location = new Point(0, 0);
debugForm.Controls.Add(label);
return true;
}
}
if (screen.Contains(new Point(window.Left + (window.Width / 2), window.Top)))
{
p = new Point(window.Left + (window.Width / 2) - requireWidth, window.Top + requiredHeight);
bool middleTop = screen.Contains(p);
if (middleTop)
{
Console.WriteLine($"{screen.ToString()} contains {p} (W/2-, T)");
label.Location = new Point(p.X, 0);
debugForm.Controls.Add(label);
return true;
}
p = new Point(window.Left + (window.Width / 2) + requireWidth, window.Top + requiredHeight);
middleTop = screen.Contains(p);
if (middleTop)
{
Console.WriteLine($"{screen.ToString()} contains {p} (W/2+, T)");
label.Location = new Point(window.Width / 2, 0);
debugForm.Controls.Add(label);
return true;
}
}
if (screen.Contains(new Point(window.Right, window.Top)))
{
p = new Point(window.Right - requireWidth, window.Top + requiredHeight);
bool rightTop = screen.Contains(p);
if (rightTop)
{
Console.WriteLine($"{screen.ToString()} contains {p} (R, T)");
label.Location = new Point(window.Width - requireWidth, 0);
debugForm.Controls.Add(label);
return true;
}
}
return false;
}
|
👍 Sounds like a very good plan. I agree the title bar is most important, and left/right of the middle but not the exact middle covers the case where a window filled two screens and one of them was disconnected. |
910ff88
to
af5ece4
Compare
af5ece4
to
8cae160
Compare
Codecov Report
@@ Coverage Diff @@
## master #8341 +/- ##
==========================================
+ Coverage 55.96% 55.98% +0.02%
==========================================
Files 905 905
Lines 65273 65303 +30
Branches 11877 11884 +7
==========================================
+ Hits 36530 36563 +33
+ Misses 25805 25797 -8
- Partials 2938 2943 +5
Flags with carried forward coverage won't be shown. Click here to find out more. |
fdd4a74
to
47dfe55
Compare
If a parent window is at a corner of a desktop, and it is smaller than a child window, it is possible to end up in a situation where the child window is positioned outside of visible and reachable area. Coupled with the fact that locations and dimensions of most windows get persisted this may lead to a situation where the window may become permanently inaccessible until the settings are reset.
47dfe55
to
bd40ebe
Compare
If a parent window is at a corner of a desktop, and it is smaller than a child window, it is possible to end up in a situation where the child window is positioned outside of visible and reachable area.
Coupled with the fact that locations and dimensions of most windows get persisted this may lead to a situation where the window may become permanently inaccessible until the settings are reset.
Fixes #8091
Resolves #6427
Proposed changes
Screenshots
Before
Steps to replicate:
Test methodology
❗ NB: I have a single monitor and unable to test multi-monitor setup, where a secondary monitor is placed to the left or to the bottom of the main monitor. It is possible that the code need to be tweaked further to account for these cases.
✒️ I contribute this code under The Developer Certificate of Origin.