[PATCH 3/6] winex11.drv: Support virtual desktop display mode enumeration using the new display settings handler interface.

Zhiyi Zhang zzhang at codeweavers.com
Wed Jul 22 02:24:41 CDT 2020


Signed-off-by: Zhiyi Zhang <zzhang at codeweavers.com>
---
 dlls/winex11.drv/desktop.c  | 68 +++++++++++++++++++++++++++++++++++++
 dlls/winex11.drv/settings.c | 25 +++++++++++++-
 dlls/winex11.drv/x11drv.h   | 17 ++++++++++
 3 files changed, 109 insertions(+), 1 deletion(-)

diff --git a/dlls/winex11.drv/desktop.c b/dlls/winex11.drv/desktop.c
index d3dcf90fb9d..72a315e35be 100644
--- a/dlls/winex11.drv/desktop.c
+++ b/dlls/winex11.drv/desktop.c
@@ -168,6 +168,72 @@ static BOOL X11DRV_desktop_get_id( const WCHAR *device_name, ULONG_PTR *id )
     return TRUE;
 }
 
+static void add_desktop_mode( DEVMODEW *mode, DWORD depth, DWORD width, DWORD height )
+{
+    mode->dmSize = sizeof(*mode);
+    mode->dmFields = DM_DISPLAYORIENTATION | DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT |
+                     DM_DISPLAYFLAGS | DM_DISPLAYFREQUENCY;
+    mode->u1.s2.dmDisplayOrientation = DMDO_DEFAULT;
+    mode->dmBitsPerPel = depth;
+    mode->dmPelsWidth = width;
+    mode->dmPelsHeight = height;
+    mode->u2.dmDisplayFlags = 0;
+    mode->dmDisplayFrequency = 60;
+}
+
+static BOOL X11DRV_desktop_get_modes( ULONG_PTR id, DWORD flags, DEVMODEW **new_modes, UINT *mode_count )
+{
+    UINT depth_idx, size_idx, mode_idx = 0;
+    UINT screen_width, screen_height;
+    RECT primary_rect;
+    DEVMODEW *modes;
+
+    primary_rect = get_primary_monitor_rect();
+    screen_width = primary_rect.right - primary_rect.left;
+    screen_height = primary_rect.bottom - primary_rect.top;
+
+    /* Allocate memory for modes in different color depths */
+    if (!(modes = heap_calloc( (ARRAY_SIZE(screen_sizes) + 2) * DEPTH_COUNT, sizeof(*modes))) )
+    {
+        SetLastError( ERROR_NOT_ENOUGH_MEMORY );
+        return FALSE;
+    }
+
+    for (depth_idx = 0; depth_idx < DEPTH_COUNT; ++depth_idx)
+    {
+        for (size_idx = 0; size_idx < ARRAY_SIZE(screen_sizes); ++size_idx)
+        {
+            if (screen_sizes[size_idx].width > max_width ||
+                screen_sizes[size_idx].height > max_height)
+                continue;
+
+            if (screen_sizes[size_idx].width == max_width &&
+                screen_sizes[size_idx].height == max_height)
+                continue;
+
+            if (screen_sizes[size_idx].width == screen_width &&
+                screen_sizes[size_idx].height == screen_height)
+                continue;
+
+            add_desktop_mode( &modes[mode_idx++], depths[depth_idx], screen_sizes[size_idx].width,
+                              screen_sizes[size_idx].height );
+        }
+
+        add_desktop_mode( &modes[mode_idx++], depths[depth_idx], screen_width, screen_height );
+        if (max_width != screen_width || max_height != screen_height)
+            add_desktop_mode( &modes[mode_idx++], depths[depth_idx], max_width, max_height );
+    }
+
+    *new_modes = modes;
+    *mode_count = mode_idx;
+    return TRUE;
+}
+
+static void X11DRV_desktop_free_modes( DEVMODEW *modes )
+{
+    heap_free( modes );
+}
+
 static BOOL X11DRV_desktop_get_current_mode( ULONG_PTR id, DEVMODEW *mode )
 {
     RECT primary_rect = get_primary_monitor_rect();
@@ -309,6 +375,8 @@ void X11DRV_init_desktop( Window win, unsigned int width, unsigned int height )
     settings_handler.name = "Virtual Desktop";
     settings_handler.priority = 1000;
     settings_handler.get_id = X11DRV_desktop_get_id;
+    settings_handler.get_modes = X11DRV_desktop_get_modes;
+    settings_handler.free_modes = X11DRV_desktop_free_modes;
     settings_handler.get_current_mode = X11DRV_desktop_get_current_mode;
     X11DRV_Settings_SetHandler( &settings_handler );
 }
diff --git a/dlls/winex11.drv/settings.c b/dlls/winex11.drv/settings.c
index e0dee951543..097710fc1cc 100644
--- a/dlls/winex11.drv/settings.c
+++ b/dlls/winex11.drv/settings.c
@@ -42,6 +42,7 @@ static unsigned int dd_max_modes = 0;
  */
 static const unsigned int depths_24[]  = {8, 16, 24};
 static const unsigned int depths_32[]  = {8, 16, 32};
+const unsigned int *depths;
 
 /* pointers to functions that actually do the hard stuff */
 static int (*pGetCurrentMode)(void);
@@ -158,6 +159,9 @@ static LONG X11DRV_nores_SetCurrentMode(int mode)
 void X11DRV_Settings_Init(void)
 {
     RECT primary = get_host_primary_monitor_rect();
+
+    depths = screen_bpp == 32 ? depths_32 : depths_24;
+
     X11DRV_Settings_SetHandlers("NoRes", 
                                 X11DRV_nores_GetCurrentMode, 
                                 X11DRV_nores_SetCurrentMode, 
@@ -321,10 +325,12 @@ BOOL CDECL X11DRV_EnumDisplaySettingsEx( LPCWSTR name, DWORD n, LPDEVMODEW devmo
 {
     static const WCHAR dev_name[CCHDEVICENAME] =
         { 'W','i','n','e',' ','X','1','1',' ','d','r','i','v','e','r',0 };
+    DEVMODEW *modes;
+    UINT mode_count;
     ULONG_PTR id;
 
     /* Use the new interface if it is available */
-    if (!handler.name || (n != ENUM_REGISTRY_SETTINGS && n != ENUM_CURRENT_SETTINGS))
+    if (!handler.name)
         goto old_interface;
 
     if (n == ENUM_REGISTRY_SETTINGS)
@@ -347,6 +353,23 @@ BOOL CDECL X11DRV_EnumDisplaySettingsEx( LPCWSTR name, DWORD n, LPDEVMODEW devmo
         goto done;
     }
 
+    if (!handler.get_id(name, &id) || !handler.get_modes(id, flags, &modes, &mode_count))
+    {
+        ERR("Failed to get %s supported display modes.\n", wine_dbgstr_w(name));
+        return FALSE;
+    }
+
+    if (n >= mode_count)
+    {
+        WARN("handler:%s device:%s mode index:%#x not found.\n", handler.name, wine_dbgstr_w(name), n);
+        handler.free_modes(modes);
+        SetLastError(ERROR_NO_MORE_FILES);
+        return FALSE;
+    }
+
+    memcpy(devmode, (BYTE *)modes + (sizeof(*modes) + modes[0].dmDriverExtra) * n, sizeof(*devmode));
+    handler.free_modes(modes);
+
 done:
     /* Set generic fields */
     devmode->dmSize = FIELD_OFFSET(DEVMODEW, dmICMMethod);
diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h
index 49059e09b70..b19e0e3e80a 100644
--- a/dlls/winex11.drv/x11drv.h
+++ b/dlls/winex11.drv/x11drv.h
@@ -657,6 +657,9 @@ struct x11drv_mode_info
     unsigned int refresh_rate;
 };
 
+#define DEPTH_COUNT 3
+extern const unsigned int *depths DECLSPEC_HIDDEN;
+
 /* Required functions for changing and enumerating display settings */
 struct x11drv_settings_handler
 {
@@ -672,6 +675,20 @@ struct x11drv_settings_handler
      * Return FALSE if the device can not be found and TRUE on success */
     BOOL (*get_id)(const WCHAR *device_name, ULONG_PTR *id);
 
+    /* get_modes() will be called to get a list of supported modes of the device of id in modes
+     * with respect to flags, which could be 0, EDS_RAWMODE or EDS_ROTATEDMODE. If the implementation
+     * uses dmDriverExtra then every DEVMODEW in the list must have the same dmDriverExtra value
+     *
+     * Following fields in DEVMODE must be valid:
+     * dmSize, dmDriverExtra, dmFields, dmDisplayOrientation, dmBitsPerPel, dmPelsWidth, dmPelsHeight,
+     * dmDisplayFlags and dmDisplayFrequency
+     *
+     * Return FALSE on failure with parameters unchanged and error code set. Return TRUE on success */
+    BOOL (*get_modes)(ULONG_PTR id, DWORD flags, DEVMODEW **modes, UINT *mode_count);
+
+    /* free_modes() will be called to free the mode list returned from get_modes() */
+    void (*free_modes)(DEVMODEW *modes);
+
     /* get_current_mode() will be called to get the current display mode of the device of id
      *
      * Following fields in DEVMODE must be valid:
-- 
2.25.1




More information about the wine-devel mailing list