Skip to content

Commit e639412

Browse files
committed
Upgrade MonitorInfo class
1 parent 55589f8 commit e639412

File tree

3 files changed

+81
-18
lines changed

3 files changed

+81
-18
lines changed

Flow.Launcher.Infrastructure/MonitorInfo.cs

Lines changed: 76 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
using System.Collections.Generic;
2-
using System;
1+
using System;
2+
using System.Collections.Generic;
33
using System.Runtime.InteropServices;
44
using System.Windows;
55
using Windows.Win32;
@@ -11,9 +11,12 @@ namespace Flow.Launcher.Infrastructure;
1111

1212
/// <summary>
1313
/// Contains full information about a display monitor.
14-
/// Codes are edited from: <see href="https://github.com/Jack251970/DesktopWidgets3">.
14+
/// Inspired from: https://github.com/Jack251970/DesktopWidgets3.
1515
/// </summary>
16-
internal class MonitorInfo
16+
/// <remarks>
17+
/// Use this class to replace the System.Windows.Forms.Screen class which can cause possible System.PlatformNotSupportedException.
18+
/// </remarks>
19+
public class MonitorInfo
1720
{
1821
/// <summary>
1922
/// Gets the display monitors (including invisible pseudo-monitors associated with the mirroring drivers).
@@ -23,14 +26,14 @@ public static unsafe IList<MonitorInfo> GetDisplayMonitors()
2326
{
2427
var monitorCount = PInvoke.GetSystemMetrics(SYSTEM_METRICS_INDEX.SM_CMONITORS);
2528
var list = new List<MonitorInfo>(monitorCount);
26-
var callback = new MONITORENUMPROC((HMONITOR monitor, HDC deviceContext, RECT* rect, LPARAM data) =>
29+
var callback = new MONITORENUMPROC((monitor, deviceContext, rect, data) =>
2730
{
2831
list.Add(new MonitorInfo(monitor, rect));
2932
return true;
3033
});
3134
var dwData = new LPARAM();
3235
var hdc = new HDC();
33-
bool ok = PInvoke.EnumDisplayMonitors(hdc, (RECT?)null, callback, dwData);
36+
bool ok = PInvoke.EnumDisplayMonitors(hdc, null, callback, dwData);
3437
if (!ok)
3538
{
3639
Marshal.ThrowExceptionForHR(Marshal.GetLastWin32Error());
@@ -43,11 +46,11 @@ public static unsafe IList<MonitorInfo> GetDisplayMonitors()
4346
/// </summary>
4447
/// <param name="hwnd">Window handle</param>
4548
/// <returns>The display monitor that is nearest to a given window, or null if no monitor is found.</returns>
46-
public static unsafe MonitorInfo GetNearestDisplayMonitor(HWND hwnd)
49+
public static unsafe MonitorInfo GetNearestDisplayMonitor(nint hwnd)
4750
{
48-
var nearestMonitor = PInvoke.MonitorFromWindow(hwnd, MONITOR_FROM_FLAGS.MONITOR_DEFAULTTONEAREST);
51+
var nearestMonitor = PInvoke.MonitorFromWindow(new(hwnd), MONITOR_FROM_FLAGS.MONITOR_DEFAULTTONEAREST);
4952
MonitorInfo nearestMonitorInfo = null;
50-
var callback = new MONITORENUMPROC((HMONITOR monitor, HDC deviceContext, RECT* rect, LPARAM data) =>
53+
var callback = new MONITORENUMPROC((monitor, deviceContext, rect, data) =>
5154
{
5255
if (monitor == nearestMonitor)
5356
{
@@ -58,25 +61,83 @@ public static unsafe MonitorInfo GetNearestDisplayMonitor(HWND hwnd)
5861
});
5962
var dwData = new LPARAM();
6063
var hdc = new HDC();
61-
bool ok = PInvoke.EnumDisplayMonitors(hdc, (RECT?)null, callback, dwData);
64+
bool ok = PInvoke.EnumDisplayMonitors(hdc, null, callback, dwData);
6265
if (!ok)
6366
{
6467
Marshal.ThrowExceptionForHR(Marshal.GetLastWin32Error());
6568
}
6669
return nearestMonitorInfo;
6770
}
6871

72+
/// <summary>
73+
/// Gets the primary display monitor (the one that contains the taskbar).
74+
/// </summary>
75+
/// <returns>The primary display monitor, or null if no monitor is found.</returns>
76+
public static unsafe MonitorInfo GetPrimaryDisplayMonitor()
77+
{
78+
var primaryMonitor = PInvoke.MonitorFromWindow(new HWND(IntPtr.Zero), MONITOR_FROM_FLAGS.MONITOR_DEFAULTTOPRIMARY);
79+
MonitorInfo primaryMonitorInfo = null;
80+
var callback = new MONITORENUMPROC((monitor, deviceContext, rect, data) =>
81+
{
82+
if (monitor == primaryMonitor)
83+
{
84+
primaryMonitorInfo = new MonitorInfo(monitor, rect);
85+
return false;
86+
}
87+
return true;
88+
});
89+
var dwData = new LPARAM();
90+
var hdc = new HDC();
91+
bool ok = PInvoke.EnumDisplayMonitors(hdc, null, callback, dwData);
92+
if (!ok)
93+
{
94+
Marshal.ThrowExceptionForHR(Marshal.GetLastWin32Error());
95+
}
96+
return primaryMonitorInfo;
97+
}
98+
99+
/// <summary>
100+
/// Gets the display monitor that contains the cursor.
101+
/// </summary>
102+
/// <returns>The display monitor that contains the cursor, or null if no monitor is found.</returns>
103+
public static unsafe MonitorInfo GetCursorDisplayMonitor()
104+
{
105+
if (!PInvoke.GetCursorPos(out var pt))
106+
{
107+
Marshal.ThrowExceptionForHR(Marshal.GetLastWin32Error());
108+
}
109+
var cursorMonitor = PInvoke.MonitorFromPoint(pt, MONITOR_FROM_FLAGS.MONITOR_DEFAULTTONEAREST);
110+
MonitorInfo cursorMonitorInfo = null;
111+
var callback = new MONITORENUMPROC((monitor, deviceContext, rect, data) =>
112+
{
113+
if (monitor == cursorMonitor)
114+
{
115+
cursorMonitorInfo = new MonitorInfo(monitor, rect);
116+
return false;
117+
}
118+
return true;
119+
});
120+
var dwData = new LPARAM();
121+
var hdc = new HDC();
122+
bool ok = PInvoke.EnumDisplayMonitors(hdc, null, callback, dwData);
123+
if (!ok)
124+
{
125+
Marshal.ThrowExceptionForHR(Marshal.GetLastWin32Error());
126+
}
127+
return cursorMonitorInfo;
128+
}
129+
69130
private readonly HMONITOR _monitor;
70131

71132
internal unsafe MonitorInfo(HMONITOR monitor, RECT* rect)
72133
{
73-
RectMonitor =
134+
Bounds =
74135
new Rect(new Point(rect->left, rect->top),
75136
new Point(rect->right, rect->bottom));
76137
_monitor = monitor;
77138
var info = new MONITORINFOEXW() { monitorInfo = new MONITORINFO() { cbSize = (uint)sizeof(MONITORINFOEXW) } };
78139
GetMonitorInfo(monitor, ref info);
79-
RectWork =
140+
WorkingArea =
80141
new Rect(new Point(info.monitorInfo.rcWork.left, info.monitorInfo.rcWork.top),
81142
new Point(info.monitorInfo.rcWork.right, info.monitorInfo.rcWork.bottom));
82143
Name = new string(info.szDevice.AsSpan()).Replace("\0", "").Trim();
@@ -93,23 +154,23 @@ internal unsafe MonitorInfo(HMONITOR monitor, RECT* rect)
93154
/// <remarks>
94155
/// <note>If the monitor is not the primary display monitor, some of the rectangle's coordinates may be negative values.</note>
95156
/// </remarks>
96-
public Rect RectMonitor { get; }
157+
public Rect Bounds { get; }
97158

98159
/// <summary>
99160
/// Gets the work area rectangle of the display monitor, expressed in virtual-screen coordinates.
100161
/// </summary>
101162
/// <remarks>
102163
/// <note>If the monitor is not the primary display monitor, some of the rectangle's coordinates may be negative values.</note>
103164
/// </remarks>
104-
public Rect RectWork { get; }
165+
public Rect WorkingArea { get; }
105166

106167
/// <summary>
107168
/// Gets if the monitor is the the primary display monitor.
108169
/// </summary>
109170
public bool IsPrimary => _monitor == PInvoke.MonitorFromWindow(new(IntPtr.Zero), MONITOR_FROM_FLAGS.MONITOR_DEFAULTTOPRIMARY);
110171

111172
/// <inheritdoc />
112-
public override string ToString() => $"{Name} {RectMonitor.Width}x{RectMonitor.Height}";
173+
public override string ToString() => $"{Name} {Bounds.Width}x{Bounds.Height}";
113174

114175
private static unsafe bool GetMonitorInfo(HMONITOR hMonitor, ref MONITORINFOEXW lpmi)
115176
{

Flow.Launcher.Infrastructure/NativeMethods.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ EnumDisplayMonitors
3939
MonitorFromWindow
4040
GetMonitorInfo
4141
MONITORINFOEXW
42+
GetCursorPos
43+
MonitorFromPoint
4244

4345
WM_ENTERSIZEMOVE
4446
WM_EXITSIZEMOVE
@@ -89,4 +91,4 @@ WM_GETTEXT
8991
OpenProcess
9092
QueryFullProcessImageName
9193
EVENT_OBJECT_HIDE
92-
EVENT_SYSTEM_DIALOGEND
94+
EVENT_SYSTEM_DIALOGEND

Flow.Launcher.Infrastructure/Win32Helper.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -293,8 +293,8 @@ public static unsafe bool IsForegroundWindowFullscreen()
293293
}
294294

295295
var monitorInfo = MonitorInfo.GetNearestDisplayMonitor(hWnd);
296-
return (appBounds.bottom - appBounds.top) == monitorInfo.RectMonitor.Height &&
297-
(appBounds.right - appBounds.left) == monitorInfo.RectMonitor.Width;
296+
return (appBounds.bottom - appBounds.top) == monitorInfo.Bounds.Height &&
297+
(appBounds.right - appBounds.left) == monitorInfo.Bounds.Width;
298298
}
299299

300300
#endregion

0 commit comments

Comments
 (0)