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