| 
 | 1 | +using System.Collections.Generic;  | 
 | 2 | +using System;  | 
 | 3 | +using System.Runtime.InteropServices;  | 
 | 4 | +using System.Windows;  | 
 | 5 | +using Windows.Win32;  | 
 | 6 | +using Windows.Win32.Foundation;  | 
 | 7 | +using Windows.Win32.Graphics.Gdi;  | 
 | 8 | +using Windows.Win32.UI.WindowsAndMessaging;  | 
 | 9 | + | 
 | 10 | +namespace Flow.Launcher.Infrastructure;  | 
 | 11 | + | 
 | 12 | +/// <summary>  | 
 | 13 | +/// Contains full information about a display monitor.  | 
 | 14 | +/// Codes are edited from: <see href="https://github.com/Jack251970/DesktopWidgets3">.  | 
 | 15 | +/// </summary>  | 
 | 16 | +internal class MonitorInfo  | 
 | 17 | +{  | 
 | 18 | +    /// <summary>  | 
 | 19 | +    /// Gets the display monitors (including invisible pseudo-monitors associated with the mirroring drivers).  | 
 | 20 | +    /// </summary>  | 
 | 21 | +    /// <returns>A list of display monitors</returns>  | 
 | 22 | +    public static unsafe IList<MonitorInfo> GetDisplayMonitors()  | 
 | 23 | +    {  | 
 | 24 | +        var monitorCount = PInvoke.GetSystemMetrics(SYSTEM_METRICS_INDEX.SM_CMONITORS);  | 
 | 25 | +        var list = new List<MonitorInfo>(monitorCount);  | 
 | 26 | +        var callback = new MONITORENUMPROC((HMONITOR monitor, HDC deviceContext, RECT* rect, LPARAM data) =>  | 
 | 27 | +        {  | 
 | 28 | +            list.Add(new MonitorInfo(monitor, rect));  | 
 | 29 | +            return true;  | 
 | 30 | +        });  | 
 | 31 | +        var dwData = new LPARAM();  | 
 | 32 | +        var hdc = new HDC();  | 
 | 33 | +        bool ok = PInvoke.EnumDisplayMonitors(hdc, (RECT?)null, callback, dwData);  | 
 | 34 | +        if (!ok)  | 
 | 35 | +        {  | 
 | 36 | +            Marshal.ThrowExceptionForHR(Marshal.GetLastWin32Error());  | 
 | 37 | +        }  | 
 | 38 | +        return list;  | 
 | 39 | +    }  | 
 | 40 | + | 
 | 41 | +    /// <summary>  | 
 | 42 | +    /// Gets the display monitor that is nearest to a given window.  | 
 | 43 | +    /// </summary>  | 
 | 44 | +    /// <param name="hwnd">Window handle</param>  | 
 | 45 | +    /// <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)  | 
 | 47 | +    {  | 
 | 48 | +        var nearestMonitor = PInvoke.MonitorFromWindow(hwnd, MONITOR_FROM_FLAGS.MONITOR_DEFAULTTONEAREST);  | 
 | 49 | +        MonitorInfo nearestMonitorInfo = null;  | 
 | 50 | +        var callback = new MONITORENUMPROC((HMONITOR monitor, HDC deviceContext, RECT* rect, LPARAM data) =>  | 
 | 51 | +        {  | 
 | 52 | +            if (monitor == nearestMonitor)  | 
 | 53 | +            {  | 
 | 54 | +                nearestMonitorInfo = new MonitorInfo(monitor, rect);  | 
 | 55 | +                return false;  | 
 | 56 | +            }  | 
 | 57 | +            return true;  | 
 | 58 | +        });  | 
 | 59 | +        var dwData = new LPARAM();  | 
 | 60 | +        var hdc = new HDC();  | 
 | 61 | +        bool ok = PInvoke.EnumDisplayMonitors(hdc, (RECT?)null, callback, dwData);  | 
 | 62 | +        if (!ok)  | 
 | 63 | +        {  | 
 | 64 | +            Marshal.ThrowExceptionForHR(Marshal.GetLastWin32Error());  | 
 | 65 | +        }  | 
 | 66 | +        return nearestMonitorInfo;  | 
 | 67 | +    }  | 
 | 68 | + | 
 | 69 | +    private readonly HMONITOR _monitor;  | 
 | 70 | + | 
 | 71 | +    internal unsafe MonitorInfo(HMONITOR monitor, RECT* rect)  | 
 | 72 | +    {  | 
 | 73 | +        RectMonitor =  | 
 | 74 | +            new Rect(new Point(rect->left, rect->top),  | 
 | 75 | +            new Point(rect->right, rect->bottom));  | 
 | 76 | +        _monitor = monitor;  | 
 | 77 | +        var info = new MONITORINFOEXW() { monitorInfo = new MONITORINFO() { cbSize = (uint)sizeof(MONITORINFOEXW) } };  | 
 | 78 | +        GetMonitorInfo(monitor, ref info);  | 
 | 79 | +        RectWork =  | 
 | 80 | +            new Rect(new Point(info.monitorInfo.rcWork.left, info.monitorInfo.rcWork.top),  | 
 | 81 | +            new Point(info.monitorInfo.rcWork.right, info.monitorInfo.rcWork.bottom));  | 
 | 82 | +        Name = new string(info.szDevice.AsSpan()).Replace("\0", "").Trim();  | 
 | 83 | +    }  | 
 | 84 | + | 
 | 85 | +    /// <summary>  | 
 | 86 | +    /// Gets the name of the display.  | 
 | 87 | +    /// </summary>  | 
 | 88 | +    public string Name { get; }  | 
 | 89 | + | 
 | 90 | +    /// <summary>  | 
 | 91 | +    /// Gets the display monitor rectangle, expressed in virtual-screen coordinates.  | 
 | 92 | +    /// </summary>  | 
 | 93 | +    /// <remarks>  | 
 | 94 | +    /// <note>If the monitor is not the primary display monitor, some of the rectangle's coordinates may be negative values.</note>  | 
 | 95 | +    /// </remarks>  | 
 | 96 | +    public Rect RectMonitor { get; }  | 
 | 97 | + | 
 | 98 | +    /// <summary>  | 
 | 99 | +    /// Gets the work area rectangle of the display monitor, expressed in virtual-screen coordinates.  | 
 | 100 | +    /// </summary>  | 
 | 101 | +    /// <remarks>  | 
 | 102 | +    /// <note>If the monitor is not the primary display monitor, some of the rectangle's coordinates may be negative values.</note>  | 
 | 103 | +    /// </remarks>  | 
 | 104 | +    public Rect RectWork { get; }  | 
 | 105 | + | 
 | 106 | +    /// <summary>  | 
 | 107 | +    /// Gets if the monitor is the the primary display monitor.  | 
 | 108 | +    /// </summary>  | 
 | 109 | +    public bool IsPrimary => _monitor == PInvoke.MonitorFromWindow(new(IntPtr.Zero), MONITOR_FROM_FLAGS.MONITOR_DEFAULTTOPRIMARY);  | 
 | 110 | + | 
 | 111 | +    /// <inheritdoc />  | 
 | 112 | +    public override string ToString() => $"{Name} {RectMonitor.Width}x{RectMonitor.Height}";  | 
 | 113 | + | 
 | 114 | +    private static unsafe bool GetMonitorInfo(HMONITOR hMonitor, ref MONITORINFOEXW lpmi)  | 
 | 115 | +    {  | 
 | 116 | +        fixed (MONITORINFOEXW* lpmiLocal = &lpmi)  | 
 | 117 | +        {  | 
 | 118 | +            var lpmiBase = (MONITORINFO*)lpmiLocal;  | 
 | 119 | +            var __result = PInvoke.GetMonitorInfo(hMonitor, lpmiBase);  | 
 | 120 | +            return __result;  | 
 | 121 | +        }  | 
 | 122 | +    }  | 
 | 123 | +}  | 
0 commit comments