From e63941275e539fd5dd2044c9e9bb93915dda0392 Mon Sep 17 00:00:00 2001
From: Jack251970 <1160210343@qq.com>
Date: Wed, 23 Jul 2025 13:27:36 +0800
Subject: [PATCH] Upgrade MonitorInfo class
---
Flow.Launcher.Infrastructure/MonitorInfo.cs | 91 ++++++++++++++++---
.../NativeMethods.txt | 4 +-
Flow.Launcher.Infrastructure/Win32Helper.cs | 4 +-
3 files changed, 81 insertions(+), 18 deletions(-)
diff --git a/Flow.Launcher.Infrastructure/MonitorInfo.cs b/Flow.Launcher.Infrastructure/MonitorInfo.cs
index 3221708c1..53617f7e9 100644
--- a/Flow.Launcher.Infrastructure/MonitorInfo.cs
+++ b/Flow.Launcher.Infrastructure/MonitorInfo.cs
@@ -1,5 +1,5 @@
-using System.Collections.Generic;
-using System;
+using System;
+using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Windows;
using Windows.Win32;
@@ -11,9 +11,12 @@ namespace Flow.Launcher.Infrastructure;
///
/// Contains full information about a display monitor.
-/// Codes are edited from: .
+/// Inspired from: https://github.com/Jack251970/DesktopWidgets3.
///
-internal class MonitorInfo
+///
+/// Use this class to replace the System.Windows.Forms.Screen class which can cause possible System.PlatformNotSupportedException.
+///
+public class MonitorInfo
{
///
/// Gets the display monitors (including invisible pseudo-monitors associated with the mirroring drivers).
@@ -23,14 +26,14 @@ internal class MonitorInfo
{
var monitorCount = PInvoke.GetSystemMetrics(SYSTEM_METRICS_INDEX.SM_CMONITORS);
var list = new List(monitorCount);
- var callback = new MONITORENUMPROC((HMONITOR monitor, HDC deviceContext, RECT* rect, LPARAM data) =>
+ var callback = new MONITORENUMPROC((monitor, deviceContext, rect, data) =>
{
list.Add(new MonitorInfo(monitor, rect));
return true;
});
var dwData = new LPARAM();
var hdc = new HDC();
- bool ok = PInvoke.EnumDisplayMonitors(hdc, (RECT?)null, callback, dwData);
+ bool ok = PInvoke.EnumDisplayMonitors(hdc, null, callback, dwData);
if (!ok)
{
Marshal.ThrowExceptionForHR(Marshal.GetLastWin32Error());
@@ -43,11 +46,11 @@ internal class MonitorInfo
///
/// Window handle
/// The display monitor that is nearest to a given window, or null if no monitor is found.
- public static unsafe MonitorInfo GetNearestDisplayMonitor(HWND hwnd)
+ public static unsafe MonitorInfo GetNearestDisplayMonitor(nint hwnd)
{
- var nearestMonitor = PInvoke.MonitorFromWindow(hwnd, MONITOR_FROM_FLAGS.MONITOR_DEFAULTTONEAREST);
+ var nearestMonitor = PInvoke.MonitorFromWindow(new(hwnd), MONITOR_FROM_FLAGS.MONITOR_DEFAULTTONEAREST);
MonitorInfo nearestMonitorInfo = null;
- var callback = new MONITORENUMPROC((HMONITOR monitor, HDC deviceContext, RECT* rect, LPARAM data) =>
+ var callback = new MONITORENUMPROC((monitor, deviceContext, rect, data) =>
{
if (monitor == nearestMonitor)
{
@@ -58,7 +61,7 @@ internal class MonitorInfo
});
var dwData = new LPARAM();
var hdc = new HDC();
- bool ok = PInvoke.EnumDisplayMonitors(hdc, (RECT?)null, callback, dwData);
+ bool ok = PInvoke.EnumDisplayMonitors(hdc, null, callback, dwData);
if (!ok)
{
Marshal.ThrowExceptionForHR(Marshal.GetLastWin32Error());
@@ -66,17 +69,75 @@ internal class MonitorInfo
return nearestMonitorInfo;
}
+ ///
+ /// Gets the primary display monitor (the one that contains the taskbar).
+ ///
+ /// The primary display monitor, or null if no monitor is found.
+ public static unsafe MonitorInfo GetPrimaryDisplayMonitor()
+ {
+ var primaryMonitor = PInvoke.MonitorFromWindow(new HWND(IntPtr.Zero), MONITOR_FROM_FLAGS.MONITOR_DEFAULTTOPRIMARY);
+ MonitorInfo primaryMonitorInfo = null;
+ var callback = new MONITORENUMPROC((monitor, deviceContext, rect, data) =>
+ {
+ if (monitor == primaryMonitor)
+ {
+ primaryMonitorInfo = new MonitorInfo(monitor, rect);
+ return false;
+ }
+ return true;
+ });
+ var dwData = new LPARAM();
+ var hdc = new HDC();
+ bool ok = PInvoke.EnumDisplayMonitors(hdc, null, callback, dwData);
+ if (!ok)
+ {
+ Marshal.ThrowExceptionForHR(Marshal.GetLastWin32Error());
+ }
+ return primaryMonitorInfo;
+ }
+
+ ///
+ /// Gets the display monitor that contains the cursor.
+ ///
+ /// The display monitor that contains the cursor, or null if no monitor is found.
+ public static unsafe MonitorInfo GetCursorDisplayMonitor()
+ {
+ if (!PInvoke.GetCursorPos(out var pt))
+ {
+ Marshal.ThrowExceptionForHR(Marshal.GetLastWin32Error());
+ }
+ var cursorMonitor = PInvoke.MonitorFromPoint(pt, MONITOR_FROM_FLAGS.MONITOR_DEFAULTTONEAREST);
+ MonitorInfo cursorMonitorInfo = null;
+ var callback = new MONITORENUMPROC((monitor, deviceContext, rect, data) =>
+ {
+ if (monitor == cursorMonitor)
+ {
+ cursorMonitorInfo = new MonitorInfo(monitor, rect);
+ return false;
+ }
+ return true;
+ });
+ var dwData = new LPARAM();
+ var hdc = new HDC();
+ bool ok = PInvoke.EnumDisplayMonitors(hdc, null, callback, dwData);
+ if (!ok)
+ {
+ Marshal.ThrowExceptionForHR(Marshal.GetLastWin32Error());
+ }
+ return cursorMonitorInfo;
+ }
+
private readonly HMONITOR _monitor;
internal unsafe MonitorInfo(HMONITOR monitor, RECT* rect)
{
- RectMonitor =
+ Bounds =
new Rect(new Point(rect->left, rect->top),
new Point(rect->right, rect->bottom));
_monitor = monitor;
var info = new MONITORINFOEXW() { monitorInfo = new MONITORINFO() { cbSize = (uint)sizeof(MONITORINFOEXW) } };
GetMonitorInfo(monitor, ref info);
- RectWork =
+ WorkingArea =
new Rect(new Point(info.monitorInfo.rcWork.left, info.monitorInfo.rcWork.top),
new Point(info.monitorInfo.rcWork.right, info.monitorInfo.rcWork.bottom));
Name = new string(info.szDevice.AsSpan()).Replace("\0", "").Trim();
@@ -93,7 +154,7 @@ internal class MonitorInfo
///
/// If the monitor is not the primary display monitor, some of the rectangle's coordinates may be negative values.
///
- public Rect RectMonitor { get; }
+ public Rect Bounds { get; }
///
/// Gets the work area rectangle of the display monitor, expressed in virtual-screen coordinates.
@@ -101,7 +162,7 @@ internal class MonitorInfo
///
/// If the monitor is not the primary display monitor, some of the rectangle's coordinates may be negative values.
///
- public Rect RectWork { get; }
+ public Rect WorkingArea { get; }
///
/// Gets if the monitor is the the primary display monitor.
@@ -109,7 +170,7 @@ internal class MonitorInfo
public bool IsPrimary => _monitor == PInvoke.MonitorFromWindow(new(IntPtr.Zero), MONITOR_FROM_FLAGS.MONITOR_DEFAULTTOPRIMARY);
///
- public override string ToString() => $"{Name} {RectMonitor.Width}x{RectMonitor.Height}";
+ public override string ToString() => $"{Name} {Bounds.Width}x{Bounds.Height}";
private static unsafe bool GetMonitorInfo(HMONITOR hMonitor, ref MONITORINFOEXW lpmi)
{
diff --git a/Flow.Launcher.Infrastructure/NativeMethods.txt b/Flow.Launcher.Infrastructure/NativeMethods.txt
index 965ab6caa..2054bc2c0 100644
--- a/Flow.Launcher.Infrastructure/NativeMethods.txt
+++ b/Flow.Launcher.Infrastructure/NativeMethods.txt
@@ -39,6 +39,8 @@ EnumDisplayMonitors
MonitorFromWindow
GetMonitorInfo
MONITORINFOEXW
+GetCursorPos
+MonitorFromPoint
WM_ENTERSIZEMOVE
WM_EXITSIZEMOVE
@@ -89,4 +91,4 @@ WM_GETTEXT
OpenProcess
QueryFullProcessImageName
EVENT_OBJECT_HIDE
-EVENT_SYSTEM_DIALOGEND
+EVENT_SYSTEM_DIALOGEND
\ No newline at end of file
diff --git a/Flow.Launcher.Infrastructure/Win32Helper.cs b/Flow.Launcher.Infrastructure/Win32Helper.cs
index 5770bbf12..84880d68c 100644
--- a/Flow.Launcher.Infrastructure/Win32Helper.cs
+++ b/Flow.Launcher.Infrastructure/Win32Helper.cs
@@ -293,8 +293,8 @@ namespace Flow.Launcher.Infrastructure
}
var monitorInfo = MonitorInfo.GetNearestDisplayMonitor(hWnd);
- return (appBounds.bottom - appBounds.top) == monitorInfo.RectMonitor.Height &&
- (appBounds.right - appBounds.left) == monitorInfo.RectMonitor.Width;
+ return (appBounds.bottom - appBounds.top) == monitorInfo.Bounds.Height &&
+ (appBounds.right - appBounds.left) == monitorInfo.Bounds.Width;
}
#endregion