[PATCH] user32: Improve EnumDisplayDevices

Andrew Eikum aeikum at codeweavers.com
Wed Feb 7 13:18:49 CST 2018


Signed-off-by: Andrew Eikum <aeikum at codeweavers.com>
---
On my 2-monitor setup this results in:

    for device 0, got name: \\.\DISPLAY1, string: X11 Windowing System, flags: 0x15
    for device 0 sub 0, got name: \\.\DISPLAY1\Monitor0, string: Generic PnP Monitor, flags: 0x3

    for device 1, got name: \\.\DISPLAY1, string: X11 Windowing System, flags: 0x11
    for device 1 sub 0, got name: \\.\DISPLAY1\Monitor0, string: Generic PnP Monitor, flags: 0x3

Which nearly matches Windows 10 on the same hardware.  The differences
are the 2nd device should be DISPLAY2, not DISPLAY1; and the primary
adapter comes 2nd on Windows.

However, DISPLAY1 is hard-coded at least in gdi32, winex11, and
winemac, so I hard-coded it here as well. This results in both
monitors and adapters having the same name, which is clumsy. But it is
sufficient to fix Unity games displaying on the non-primary monitor by
default.

 dlls/user32/misc.c | 94 ++++++++++++++++++++++++++++++++++++++++++++----------
 include/wingdi.h   |  6 +++-
 2 files changed, 82 insertions(+), 18 deletions(-)

diff --git a/dlls/user32/misc.c b/dlls/user32/misc.c
index 895ccce312..96d5212725 100644
--- a/dlls/user32/misc.c
+++ b/dlls/user32/misc.c
@@ -243,11 +243,13 @@ DWORD WINAPI SetLogonNotifyWindow(HWINSTA hwinsta,HWND hwnd)
     return 1;
 }
 
-static const WCHAR primary_device_name[] = {'\\','\\','.','\\','D','I','S','P','L','A','Y','1',0};
-static const WCHAR primary_device_string[] = {'X','1','1',' ','W','i','n','d','o','w','i','n','g',' ',
+static const WCHAR device_name[] = {'\\','\\','.','\\','D','I','S','P','L','A','Y','1',0};
+static const WCHAR device_string[] = {'X','1','1',' ','W','i','n','d','o','w','i','n','g',' ',
                                               'S','y','s','t','e','m',0};
-static const WCHAR primary_device_deviceid[] = {'P','C','I','\\','V','E','N','_','0','0','0','0','&',
+static const WCHAR monitor_string[] = {'G','e','n','e','r','i','c',' ','P','n','P',' ','M','o','n','i','t','o','r',0};
+static const WCHAR device_deviceid[] = {'P','C','I','\\','V','E','N','_','0','0','0','0','&',
                                                 'D','E','V','_','0','0','0','0',0};
+static const WCHAR monitor0W[] = {'\\','M','o','n','i','t','o','r','0',0};
 
 /***********************************************************************
  *		EnumDisplayDevicesA (USER32.@)
@@ -282,29 +284,87 @@ BOOL WINAPI EnumDisplayDevicesA( LPCSTR lpDevice, DWORD i, LPDISPLAY_DEVICEA lpD
     return TRUE;
 }
 
+struct edd_enum_info
+{
+    UINT idx;
+    UINT desired;
+    HMONITOR hmon;
+};
+
+static BOOL CALLBACK edd_enum( HMONITOR monitor, HDC hdc, LPRECT rect, LPARAM lp )
+{
+    struct edd_enum_info *info = (struct edd_enum_info *)lp;
+    if (info->idx == info->desired)
+    {
+        info->hmon = monitor;
+        return FALSE;
+    }
+    info->idx++;
+    return TRUE;
+}
+
 /***********************************************************************
  *		EnumDisplayDevicesW (USER32.@)
  */
 BOOL WINAPI EnumDisplayDevicesW( LPCWSTR lpDevice, DWORD i, LPDISPLAY_DEVICEW lpDisplayDevice,
                                  DWORD dwFlags )
 {
-    FIXME("(%s,%d,%p,0x%08x), stub!\n",debugstr_w(lpDevice),i,lpDisplayDevice,dwFlags);
+    TRACE("(%s, %d, %p, 0x%08x)\n", debugstr_w(lpDevice), i, lpDisplayDevice, dwFlags);
 
-    if (i)
+    if (!lpDisplayDevice)
         return FALSE;
 
-    memcpy(lpDisplayDevice->DeviceName, primary_device_name, sizeof(primary_device_name));
-    memcpy(lpDisplayDevice->DeviceString, primary_device_string, sizeof(primary_device_string));
-  
-    lpDisplayDevice->StateFlags =
-        DISPLAY_DEVICE_ATTACHED_TO_DESKTOP |
-        DISPLAY_DEVICE_PRIMARY_DEVICE |
-        DISPLAY_DEVICE_VGA_COMPATIBLE;
-
-    if(lpDisplayDevice->cb >= offsetof(DISPLAY_DEVICEW, DeviceID) + sizeof(lpDisplayDevice->DeviceID))
-        memcpy(lpDisplayDevice->DeviceID, primary_device_deviceid, sizeof(primary_device_deviceid));
-    if(lpDisplayDevice->cb >= offsetof(DISPLAY_DEVICEW, DeviceKey) + sizeof(lpDisplayDevice->DeviceKey))
-        lpDisplayDevice->DeviceKey[0] = 0;
+    if (!lpDevice)
+    {
+        struct edd_enum_info info = {0};
+        MONITORINFO monitor = {0};
+
+        /* one adapter per monitor */
+        info.desired = i;
+        EnumDisplayMonitors(0, NULL, edd_enum, (LPARAM)&info);
+
+        if (info.hmon == NULL)
+            return FALSE;
+
+        monitor.cbSize = sizeof(monitor);
+        if (!GetMonitorInfoW(info.hmon, &monitor))
+            return FALSE;
+
+        memcpy(lpDisplayDevice->DeviceName, device_name, sizeof(device_name));
+        memcpy(lpDisplayDevice->DeviceString, device_string, sizeof(device_string));
+
+        lpDisplayDevice->StateFlags = DISPLAY_DEVICE_ATTACHED_TO_DESKTOP |
+            DISPLAY_DEVICE_VGA_COMPATIBLE;
+
+        if (monitor.dwFlags & MONITORINFOF_PRIMARY)
+            lpDisplayDevice->StateFlags |= DISPLAY_DEVICE_PRIMARY_DEVICE;
+
+        if (lpDisplayDevice->cb >= offsetof(DISPLAY_DEVICEW, DeviceID) + sizeof(lpDisplayDevice->DeviceID))
+            memcpy(lpDisplayDevice->DeviceID, device_deviceid, sizeof(device_deviceid));
+        if (lpDisplayDevice->cb >= offsetof(DISPLAY_DEVICEW, DeviceKey) + sizeof(lpDisplayDevice->DeviceKey))
+            lpDisplayDevice->DeviceKey[0] = 0;
+    }
+    else
+    {
+        if (i != 0)
+            /* one monitor per adapter */
+            return FALSE;
+
+        if (strcmpW(lpDevice, device_name) != 0)
+            return FALSE;
+
+        strcpyW(lpDisplayDevice->DeviceName, lpDevice);
+        strcatW(lpDisplayDevice->DeviceName, monitor0W);
+
+        memcpy(lpDisplayDevice->DeviceString, monitor_string, sizeof(monitor_string));
+
+        lpDisplayDevice->StateFlags = DISPLAY_DEVICE_ACTIVE | DISPLAY_DEVICE_ATTACHED;
+
+        if (lpDisplayDevice->cb >= offsetof(DISPLAY_DEVICEW, DeviceID) + sizeof(lpDisplayDevice->DeviceID))
+            memcpy(lpDisplayDevice->DeviceID, device_deviceid, sizeof(device_deviceid));
+        if (lpDisplayDevice->cb >= offsetof(DISPLAY_DEVICEW, DeviceKey) + sizeof(lpDisplayDevice->DeviceKey))
+            lpDisplayDevice->DeviceKey[0] = 0;
+    }
 
     return TRUE;
 }
diff --git a/include/wingdi.h b/include/wingdi.h
index 1851654194..03b7ed2ce4 100644
--- a/include/wingdi.h
+++ b/include/wingdi.h
@@ -3318,13 +3318,17 @@ DECL_WINELIB_TYPE_AW(DISPLAY_DEVICE)
 DECL_WINELIB_TYPE_AW(PDISPLAY_DEVICE)
 DECL_WINELIB_TYPE_AW(LPDISPLAY_DEVICE)
 
-/* DISPLAY_DEVICE.StateFlags (?)*/
+/* DISPLAY_DEVICE.StateFlags, adapter flags */
 #define	DISPLAY_DEVICE_ATTACHED_TO_DESKTOP	0x00000001
 #define	DISPLAY_DEVICE_MULTI_DRIVER		0x00000002
 #define	DISPLAY_DEVICE_PRIMARY_DEVICE		0x00000004
 #define	DISPLAY_DEVICE_MIRRORING_DRIVER		0x00000008
 #define	DISPLAY_DEVICE_VGA_COMPATIBLE		0x00000010
 
+/* DISPLAY_DEVICE.StateFlags, monitor flags */
+#define DISPLAY_DEVICE_ACTIVE 0x00000001
+#define DISPLAY_DEVICE_ATTACHED 0x00000002
+
 typedef struct DISPLAYCONFIG_DESKTOP_IMAGE_INFO
 {
     POINTL PathSourceSize;
-- 
2.16.1




More information about the wine-devel mailing list