using System.Collections.Generic; using System.Runtime.InteropServices; using System.Windows; using Windows.Win32; using Windows.Win32.Foundation; using Windows.Win32.Graphics.Gdi; using Windows.Win32.UI.WindowsAndMessaging; namespace Flow.Launcher.Plugin.SharedModels; /// /// Contains full information about a display monitor. /// Inspired from: https://github.com/Jack251970/DesktopWidgets3. /// /// /// 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). /// /// A list of display monitors public static unsafe IList GetDisplayMonitors() { var monitorCount = PInvoke.GetSystemMetrics(SYSTEM_METRICS_INDEX.SM_CMONITORS); var list = new List(monitorCount); 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, null, callback, dwData); if (!ok) { Marshal.ThrowExceptionForHR(Marshal.GetLastWin32Error()); } return list; } /// /// Gets the display monitor that is nearest to a given window. /// /// Window handle /// The display monitor that is nearest to a given window, or null if no monitor is found. public static unsafe MonitorInfo GetNearestDisplayMonitor(nint hwnd) { var nearestMonitor = PInvoke.MonitorFromWindow(new(hwnd), MONITOR_FROM_FLAGS.MONITOR_DEFAULTTONEAREST); MonitorInfo nearestMonitorInfo = null; var callback = new MONITORENUMPROC((monitor, deviceContext, rect, data) => { if (monitor == nearestMonitor) { nearestMonitorInfo = 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 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(nint.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) { 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); 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(); } /// /// Gets the name of the display. /// public string Name { get; } /// /// Gets the display monitor rectangle, expressed in virtual-screen coordinates. /// /// /// If the monitor is not the primary display monitor, some of the rectangle's coordinates may be negative values. /// public Rect Bounds { get; } /// /// Gets the work area rectangle of the display monitor, expressed in virtual-screen coordinates. /// /// /// If the monitor is not the primary display monitor, some of the rectangle's coordinates may be negative values. /// public Rect WorkingArea { get; } /// /// Gets if the monitor is the primary display monitor. /// public bool IsPrimary => _monitor == PInvoke.MonitorFromWindow(new(nint.Zero), MONITOR_FROM_FLAGS.MONITOR_DEFAULTTOPRIMARY); /// public override string ToString() => $"{Name} {Bounds.Width}x{Bounds.Height}"; private static unsafe bool GetMonitorInfo(HMONITOR hMonitor, ref MONITORINFOEXW lpmi) { fixed (MONITORINFOEXW* lpmiLocal = &lpmi) { var lpmiBase = (MONITORINFO*)lpmiLocal; var __result = PInvoke.GetMonitorInfo(hMonitor, lpmiBase); return __result; } } }