[PATCH v2 4/6] winemac.drv: Add monitor initialization functions.

Zhiyi Zhang zzhang at codeweavers.com
Wed Aug 28 08:30:35 CDT 2019


Signed-off-by: Zhiyi Zhang <zzhang at codeweavers.com>
---
 dlls/winemac.drv/cocoa_display.m | 108 +++++++++++++++++++++++++++++++++++++++
 dlls/winemac.drv/display.c       | 103 +++++++++++++++++++++++++++++++++++--
 dlls/winemac.drv/macdrv_cocoa.h  |  14 +++++
 dlls/winemac.drv/macdrv_main.c   |   2 +
 4 files changed, 222 insertions(+), 5 deletions(-)

diff --git a/dlls/winemac.drv/cocoa_display.m b/dlls/winemac.drv/cocoa_display.m
index 92d233df89..f068a8aa3f 100644
--- a/dlls/winemac.drv/cocoa_display.m
+++ b/dlls/winemac.drv/cocoa_display.m
@@ -577,3 +577,111 @@ void macdrv_free_adapters(struct macdrv_adapter* adapters)
     if (adapters)
         free(adapters);
 }
+
+/***********************************************************************
+ *              macdrv_get_monitors
+ *
+ * Get a list of monitors under adapter_id. The first monitor is primary if adapter is primary.
+ * Call macdrv_free_monitors() when you are done using the data.
+ *
+ * Returns non-zero value on failure with parameters unchanged and zero on success.
+ */
+int macdrv_get_monitors(uint32_t adapter_id, struct macdrv_monitor** new_monitors, int* count)
+{
+    struct macdrv_monitor* monitors = NULL;
+    struct macdrv_monitor* realloc_monitors;
+    struct macdrv_display* displays = NULL;
+    CGDirectDisplayID display_ids[16];
+    uint32_t display_id_count;
+    int primary_index = 0;
+    int monitor_count = 0;
+    int display_count;
+    int capacity;
+    int ret = -1;
+    int i, j;
+
+    /* 2 should be enough for most cases */
+    capacity = 2;
+    monitors = calloc(capacity, sizeof(*monitors));
+    if (!monitors)
+        return -1;
+
+    /* Report an inactive monitor */
+    if (!CGDisplayIsActive(adapter_id) && !CGDisplayIsInMirrorSet(adapter_id))
+    {
+        strcpy(monitors[monitor_count].name, "Generic Non-PnP Monitor");
+        monitors[monitor_count].state_flags = DISPLAY_DEVICE_ATTACHED;
+        monitor_count++;
+    }
+    /* Report active and mirrored monitors in the same mirroring set */
+    else
+    {
+        if (CGGetOnlineDisplayList(sizeof(display_ids) / sizeof(display_ids[0]), display_ids, &display_id_count)
+            != kCGErrorSuccess)
+            goto done;
+
+        if (macdrv_get_displays(&displays, &display_count))
+            goto done;
+
+        for (i = 0; i < display_id_count; i++)
+        {
+            if (display_ids[i] != adapter_id && CGDisplayMirrorsDisplay(display_ids[i]) != adapter_id)
+                continue;
+
+            /* Find and fill in monitor info */
+            for (j = 0; j < display_count; j++)
+            {
+                if (displays[i].displayID == display_ids[j]
+                    || CGDisplayMirrorsDisplay(display_ids[i]) == displays[j].displayID)
+                {
+                    /* Allocate more space if needed */
+                    if (monitor_count >= capacity)
+                    {
+                        capacity *= 2;
+                        realloc_monitors = realloc(monitors, sizeof(*monitors) * capacity);
+                        if (!realloc_monitors)
+                            goto done;
+                        monitors = realloc_monitors;
+                    }
+
+                    if (CGDisplayIsMain(display_ids[j]))
+                        primary_index = monitor_count;
+
+                    strcpy(monitors[monitor_count].name, "Generic Non-PnP Monitor");
+                    monitors[monitor_count].state_flags = DISPLAY_DEVICE_ATTACHED | DISPLAY_DEVICE_ACTIVE;
+                    monitor_count++;
+                }
+            }
+        }
+
+        /* Make sure the first monitor on primary adapter is primary */
+        if (primary_index)
+        {
+            struct macdrv_monitor tmp;
+            tmp = monitors[0];
+            monitors[0] = monitors[primary_index];
+            monitors[primary_index] = tmp;
+        }
+    }
+
+    *new_monitors = monitors;
+    *count = monitor_count;
+    ret = 0;
+done:
+    if (displays)
+        macdrv_free_displays(displays);
+    if (ret)
+        macdrv_free_monitors(monitors);
+    return ret;
+}
+
+/***********************************************************************
+ *              macdrv_free_monitors
+ *
+ * Frees an monitor list allocated from macdrv_get_monitors()
+ */
+void macdrv_free_monitors(struct macdrv_monitor* monitors)
+{
+    if (monitors)
+        free(monitors);
+}
diff --git a/dlls/winemac.drv/display.c b/dlls/winemac.drv/display.c
index 97ebca22e5..a953e0c574 100644
--- a/dlls/winemac.drv/display.c
+++ b/dlls/winemac.drv/display.c
@@ -51,15 +51,19 @@ struct display_mode_descriptor
 
 BOOL CDECL macdrv_EnumDisplaySettingsEx(LPCWSTR devname, DWORD mode, LPDEVMODEW devmode, DWORD flags);
 
+/* Wine specific monitor properties */
+DEFINE_DEVPROPKEY(WINE_DEVPROPKEY_MONITOR_STATEFLAGS, 0x233a9ef3, 0xafc4, 0x4abd, 0xb5, 0x64, 0xc3, 0x2f, 0x21, 0xf1, 0x53, 0x5b, 2);
 
 static const char initial_mode_key[] = "Initial Display Mode";
 static const WCHAR pixelencodingW[] = {'P','i','x','e','l','E','n','c','o','d','i','n','g',0};
 static const WCHAR driver_date_dataW[] = {'D','r','i','v','e','r','D','a','t','e','D','a','t','a',0};
 static const WCHAR driver_descW[] = {'D','r','i','v','e','r','D','e','s','c',0};
+static const WCHAR displayW[] = {'D','I','S','P','L','A','Y',0};
 static const WCHAR pciW[] = {'P','C','I',0};
 static const WCHAR video_idW[] = {'V','i','d','e','o','I','D',0};
 static const WCHAR symbolic_link_valueW[]= {'S','y','m','b','o','l','i','c','L','i','n','k','V','a','l','u','e',0};
 static const WCHAR gpu_idW[] = {'G','P','U','I','D',0};
+static const WCHAR mointor_id_fmtW[] = {'M','o','n','i','t','o','r','I','D','%','d',0};
 static const WCHAR state_flagsW[] = {'S','t','a','t','e','F','l','a','g','s',0};
 static const WCHAR guid_fmtW[] = {
     '{','%','0','8','x','-','%','0','4','x','-','%','0','4','x','-','%','0','2','x','%','0','2','x','-',
@@ -101,6 +105,13 @@ static const WCHAR nt_classW[] = {
     'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
     'C','o','n','t','r','o','l','\\',
     'C','l','a','s','s','\\',0};
+static const WCHAR monitor_instance_fmtW[] = {
+    'D','I','S','P','L','A','Y','\\',
+    'D','e','f','a','u','l','t','_','M','o','n','i','t','o','r','\\',
+    '%','0','4','X','&','%','0','4','X',0};
+static const WCHAR monitor_hardware_idW[] = {
+    'M','O','N','I','T','O','R','\\',
+    'D','e','f','a','u','l','t','_','M','o','n','i','t','o','r',0,0};
 
 
 static CFArrayRef modes;
@@ -1544,7 +1555,7 @@ done:
  *
  * Return FALSE on failure and TRUE on success.
  */
-static BOOL macdrv_init_adapter(HKEY video_hkey, int video_index, int gpu_index, int adapter_index,
+static BOOL macdrv_init_adapter(HKEY video_hkey, int video_index, int gpu_index, int adapter_index, int monitor_count,
                                 const struct macdrv_gpu *gpu, const WCHAR *guid_string, const WCHAR *gpu_driver,
                                 const struct macdrv_adapter *adapter)
 {
@@ -1554,6 +1565,7 @@ static BOOL macdrv_init_adapter(HKEY video_hkey, int video_index, int gpu_index,
     HKEY hkey = NULL;
     BOOL ret = FALSE;
     LSTATUS ls;
+    INT i;
 
     sprintfW(key_nameW, device_video_fmtW, video_index);
     lstrcpyW(bufferW, machine_prefixW);
@@ -1588,6 +1600,15 @@ static BOOL macdrv_init_adapter(HKEY video_hkey, int video_index, int gpu_index,
     if (RegSetValueExW(hkey, gpu_idW, 0, REG_SZ, (const BYTE *)bufferW, (lstrlenW(bufferW) + 1) * sizeof(WCHAR)))
         goto done;
 
+    /* Write all monitor instances paths under this adapter */
+    for (i = 0; i < monitor_count; i++)
+    {
+        sprintfW(key_nameW, mointor_id_fmtW, i);
+        sprintfW(bufferW, monitor_instance_fmtW, video_index, i);
+        if (RegSetValueExW(hkey, key_nameW, 0, REG_SZ, (const BYTE *)bufferW, (lstrlenW(bufferW) + 1) * sizeof(WCHAR)))
+            goto done;
+    }
+
     /* Write StateFlags */
     if (RegSetValueExW(hkey, state_flagsW, 0, REG_DWORD, (const BYTE *)&adapter->state_flags,
                        sizeof(adapter->state_flags)))
@@ -1601,6 +1622,52 @@ done:
     return ret;
 }
 
+/***********************************************************************
+ *              macdrv_init_monitor
+ *
+ * Initialize an monitor.
+ *
+ * Return FALSE on failure and TRUE on success.
+ */
+static BOOL macdrv_init_monitor(HDEVINFO devinfo, const struct macdrv_monitor *monitor, int monitor_index,
+                                 int video_index)
+{
+    SP_DEVINFO_DATA device_data = {sizeof(SP_DEVINFO_DATA)};
+    WCHAR nameW[MAX_PATH];
+    WCHAR bufferW[MAX_PATH];
+    HKEY hkey;
+    BOOL ret = FALSE;
+
+    /* Create GUID_DEVCLASS_MONITOR instance */
+    sprintfW(bufferW, monitor_instance_fmtW, video_index, monitor_index);
+    MultiByteToWideChar(CP_UTF8, 0, monitor->name, -1, nameW, ARRAY_SIZE(nameW));
+    SetupDiCreateDeviceInfoW(devinfo, bufferW, &GUID_DEVCLASS_MONITOR, nameW, NULL, 0, &device_data);
+    if (!SetupDiRegisterDeviceInfo(devinfo, &device_data, 0, NULL, NULL, NULL))
+        goto done;
+
+    /* Write HardwareID registry property */
+    if (!SetupDiSetDeviceRegistryPropertyW(devinfo, &device_data, SPDRP_HARDWAREID,
+                                           (const BYTE *)monitor_hardware_idW, sizeof(monitor_hardware_idW)))
+        goto done;
+
+    /* Create driver key */
+    hkey = SetupDiCreateDevRegKeyW(devinfo, &device_data, DICS_FLAG_GLOBAL, 0, DIREG_DRV, NULL, NULL);
+    RegCloseKey(hkey);
+
+    /* FIXME:
+     * Following properties are Wine specific, see comments in macdrv_init_adapter for details */
+    /* StateFlags */
+    if (!SetupDiSetDevicePropertyW(devinfo, &device_data, &WINE_DEVPROPKEY_MONITOR_STATEFLAGS, DEVPROP_TYPE_UINT32,
+                                   (const BYTE *)&monitor->state_flags, sizeof(monitor->state_flags), 0))
+        goto done;
+
+    ret = TRUE;
+done:
+    if (!ret)
+        ERR("Failed to initialize monitor\n");
+    return ret;
+}
+
 static void prepare_devices(HKEY video_hkey)
 {
     static const BOOL not_present = FALSE;
@@ -1608,6 +1675,15 @@ static void prepare_devices(HKEY video_hkey)
     HDEVINFO devinfo;
     DWORD i = 0;
 
+    /* Remove all monitors */
+    devinfo = SetupDiGetClassDevsW(&GUID_DEVCLASS_MONITOR, displayW, NULL, 0);
+    while (SetupDiEnumDeviceInfo(devinfo, i++, &device_data))
+    {
+        if (!SetupDiRemoveDevice(devinfo, &device_data))
+            ERR("Failed to remove monitor\n");
+    }
+    SetupDiDestroyDeviceInfoList(devinfo);
+
     /* Clean up old adapter keys for reinitialization */
     RegDeleteTreeW(video_hkey, NULL);
 
@@ -1616,6 +1692,7 @@ static void prepare_devices(HKEY video_hkey)
      * case application uses SetupDiGetClassDevsW to enumerate devices. Wrong devices could exist in registry as a result
      * of prefix copying or having devices unplugged. But then we couldn't simply delete GPUs because we need to retain
      * the same GUID for the same GPU. */
+    i = 0;
     devinfo = SetupDiGetClassDevsW(&GUID_DEVCLASS_DISPLAY, pciW, NULL, 0);
     while (SetupDiEnumDeviceInfo(devinfo, i++, &device_data))
     {
@@ -1657,9 +1734,10 @@ void macdrv_init_display_devices(void)
     HANDLE mutex;
     struct macdrv_gpu *gpus = NULL;
     struct macdrv_adapter *adapters = NULL;
-    INT gpu_count, adapter_count;
-    INT gpu, adapter;
-    HDEVINFO gpu_devinfo = NULL;
+    struct macdrv_monitor *monitors = NULL;
+    INT gpu_count, adapter_count, monitor_count;
+    INT gpu, adapter, monitor;
+    HDEVINFO gpu_devinfo = NULL, monitor_devinfo = NULL;
     HKEY video_hkey = NULL;
     INT video_index = 0;
     DWORD disposition = 0;
@@ -1685,6 +1763,7 @@ void macdrv_init_display_devices(void)
     prepare_devices(video_hkey);
 
     gpu_devinfo = SetupDiCreateDeviceInfoList(&GUID_DEVCLASS_DISPLAY, NULL);
+    monitor_devinfo = SetupDiCreateDeviceInfoList(&GUID_DEVCLASS_MONITOR, NULL);
 
     /* Initialize GPUs */
     if (macdrv_get_gpus(&gpus, &gpu_count))
@@ -1701,10 +1780,22 @@ void macdrv_init_display_devices(void)
 
         for (adapter = 0; adapter < adapter_count; adapter++)
         {
-            if (!macdrv_init_adapter(video_hkey, video_index, gpu, adapter, &gpus[gpu], guidW, driverW,
+            if (macdrv_get_monitors(adapters[adapter].id, &monitors, &monitor_count))
+                goto done;
+
+            if (!macdrv_init_adapter(video_hkey, video_index, gpu, adapter, monitor_count, &gpus[gpu], guidW, driverW,
                                      &adapters[adapter]))
                 goto done;
 
+            /* Initialize monitors */
+            for (monitor = 0; monitor < monitor_count; monitor++)
+            {
+                if (!macdrv_init_monitor(monitor_devinfo, &monitors[monitor], monitor, video_index))
+                    goto done;
+            }
+
+            macdrv_free_monitors(monitors);
+            monitors = NULL;
             video_index++;
         }
 
@@ -1714,6 +1805,7 @@ void macdrv_init_display_devices(void)
 
 done:
     cleanup_devices();
+    SetupDiDestroyDeviceInfoList(monitor_devinfo);
     SetupDiDestroyDeviceInfoList(gpu_devinfo);
     RegCloseKey(video_hkey);
 
@@ -1722,4 +1814,5 @@ done:
 
     macdrv_free_gpus(gpus);
     macdrv_free_adapters(adapters);
+    macdrv_free_monitors(monitors);
 }
diff --git a/dlls/winemac.drv/macdrv_cocoa.h b/dlls/winemac.drv/macdrv_cocoa.h
index b960e902e3..96ebb97e76 100644
--- a/dlls/winemac.drv/macdrv_cocoa.h
+++ b/dlls/winemac.drv/macdrv_cocoa.h
@@ -261,6 +261,9 @@ static inline CGPoint cgpoint_win_from_mac(CGPoint point)
 /* Used DISPLAY_DEVICE.StateFlags for adapters */
 #define DISPLAY_DEVICE_ATTACHED_TO_DESKTOP      0x00000001
 #define DISPLAY_DEVICE_PRIMARY_DEVICE           0x00000004
+/* Used DISPLAY_DEVICE.StateFlags for monitors */
+#define DISPLAY_DEVICE_ACTIVE                   0x00000001
+#define DISPLAY_DEVICE_ATTACHED                 0x00000002
 
 /* Represent a physical GPU in the PCI slots */
 struct macdrv_gpu
@@ -285,6 +288,15 @@ static inline CGPoint cgpoint_win_from_mac(CGPoint point)
     uint32_t state_flags;
 };
 
+/* Represent a monitor in EnumDisplayDevices context */
+struct macdrv_monitor
+{
+    /* Name, in UTF-8 encoding */
+    char name[128];
+    /* StateFlags in DISPLAY_DEVICE struct */
+    uint32_t state_flags;
+};
+
 extern int macdrv_get_displays(struct macdrv_display** displays, int* count) DECLSPEC_HIDDEN;
 extern void macdrv_free_displays(struct macdrv_display* displays) DECLSPEC_HIDDEN;
 extern int macdrv_set_display_mode(const struct macdrv_display* display,
@@ -293,6 +305,8 @@ extern int macdrv_set_display_mode(const struct macdrv_display* display,
 extern void macdrv_free_gpus(struct macdrv_gpu* gpus) DECLSPEC_HIDDEN;
 extern int macdrv_get_adapters(uint64_t gpu_id, struct macdrv_adapter** adapters, int* count) DECLSPEC_HIDDEN;
 extern void macdrv_free_adapters(struct macdrv_adapter* adapters) DECLSPEC_HIDDEN;
+extern int macdrv_get_monitors(uint32_t adapter_id, struct macdrv_monitor** monitors, int* count) DECLSPEC_HIDDEN;
+extern void macdrv_free_monitors(struct macdrv_monitor* monitors) DECLSPEC_HIDDEN;
 
 
 /* event */
diff --git a/dlls/winemac.drv/macdrv_main.c b/dlls/winemac.drv/macdrv_main.c
index 544d448f9f..038578491f 100644
--- a/dlls/winemac.drv/macdrv_main.c
+++ b/dlls/winemac.drv/macdrv_main.c
@@ -299,6 +299,8 @@ static BOOL process_attach(void)
         return FALSE;
     }
 
+    macdrv_init_display_devices();
+
     return TRUE;
 }
 
-- 
2.15.2 (Apple Git-101.1)





More information about the wine-devel mailing list