Zhiyi Zhang : winex11.drv: Support setting virtual desktop display mode using the new display settings handler interface.

Alexandre Julliard julliard at winehq.org
Thu Jul 23 16:36:58 CDT 2020


Module: wine
Branch: master
Commit: 6f305dd881e16f77f9eb183684d04b0b8746b769
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=6f305dd881e16f77f9eb183684d04b0b8746b769

Author: Zhiyi Zhang <zzhang at codeweavers.com>
Date:   Wed Jul 22 15:25:08 2020 +0800

winex11.drv: Support setting virtual desktop display mode using the new display settings handler interface.

Signed-off-by: Zhiyi Zhang <zzhang at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/winex11.drv/desktop.c  |  11 ++++
 dlls/winex11.drv/settings.c | 123 +++++++++++++++++++++++++++++++++++++++++++-
 dlls/winex11.drv/x11drv.h   |   6 +++
 3 files changed, 139 insertions(+), 1 deletion(-)

diff --git a/dlls/winex11.drv/desktop.c b/dlls/winex11.drv/desktop.c
index 72a315e35b..ea269d8f2c 100644
--- a/dlls/winex11.drv/desktop.c
+++ b/dlls/winex11.drv/desktop.c
@@ -251,6 +251,16 @@ static BOOL X11DRV_desktop_get_current_mode( ULONG_PTR id, DEVMODEW *mode )
     return TRUE;
 }
 
+static LONG X11DRV_desktop_set_current_mode( ULONG_PTR id, DEVMODEW *mode )
+{
+    if (mode->dmFields & DM_BITSPERPEL && mode->dmBitsPerPel != screen_bpp)
+        WARN("Cannot change screen color depth from %dbits to %dbits!\n", screen_bpp, mode->dmBitsPerPel);
+
+    desktop_width = mode->dmPelsWidth;
+    desktop_height = mode->dmPelsHeight;
+    return DISP_CHANGE_SUCCESSFUL;
+}
+
 static void query_desktop_work_area( RECT *rc_work )
 {
     static const WCHAR trayW[] = {'S','h','e','l','l','_','T','r','a','y','W','n','d',0};
@@ -378,6 +388,7 @@ void X11DRV_init_desktop( Window win, unsigned int width, unsigned int height )
     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;
+    settings_handler.set_current_mode = X11DRV_desktop_set_current_mode;
     X11DRV_Settings_SetHandler( &settings_handler );
 }
 
diff --git a/dlls/winex11.drv/settings.c b/dlls/winex11.drv/settings.c
index 8fc8cbd44d..28c405ae0e 100644
--- a/dlls/winex11.drv/settings.c
+++ b/dlls/winex11.drv/settings.c
@@ -30,6 +30,7 @@
 #include "winreg.h"
 #include "wingdi.h"
 #include "wine/debug.h"
+#include "wine/heap.h"
 #include "wine/unicode.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(x11settings);
@@ -466,6 +467,53 @@ BOOL is_detached_mode(const DEVMODEW *mode)
            mode->dmPelsHeight == 0;
 }
 
+/* Get the full display mode with all the necessary fields set.
+ * Return NULL on failure. Caller should free the returned mode. */
+static DEVMODEW *get_full_mode(ULONG_PTR id, const DEVMODEW *dev_mode)
+{
+    DEVMODEW *modes, *full_mode, *found_mode = NULL;
+    UINT mode_count, mode_idx;
+
+    if (!handler.get_modes(id, 0, &modes, &mode_count))
+        return NULL;
+
+    for (mode_idx = 0; mode_idx < mode_count; ++mode_idx)
+    {
+        found_mode = (DEVMODEW *)((BYTE *)modes + (sizeof(*modes) + modes[0].dmDriverExtra) * mode_idx);
+
+        if (dev_mode->dmFields & DM_BITSPERPEL && found_mode->dmBitsPerPel != dev_mode->dmBitsPerPel)
+            continue;
+        if (dev_mode->dmFields & DM_PELSWIDTH && found_mode->dmPelsWidth != dev_mode->dmPelsWidth)
+            continue;
+        if (dev_mode->dmFields & DM_PELSHEIGHT && found_mode->dmPelsHeight != dev_mode->dmPelsHeight)
+            continue;
+        if (dev_mode->dmFields & DM_DISPLAYFREQUENCY &&
+            dev_mode->dmDisplayFrequency &&
+            found_mode->dmDisplayFrequency &&
+            dev_mode->dmDisplayFrequency != 1 &&
+            dev_mode->dmDisplayFrequency != found_mode->dmDisplayFrequency)
+            continue;
+
+        break;
+    }
+
+    if (!found_mode || mode_idx == mode_count)
+    {
+        handler.free_modes(modes);
+        return NULL;
+    }
+
+    if (!(full_mode = heap_alloc(sizeof(*found_mode) + found_mode->dmDriverExtra)))
+    {
+        handler.free_modes(modes);
+        return NULL;
+    }
+
+    memcpy(full_mode, found_mode, sizeof(*found_mode) + found_mode->dmDriverExtra);
+    handler.free_modes(modes);
+    return full_mode;
+}
+
 /***********************************************************************
  *		ChangeDisplaySettingsEx  (X11DRV.@)
  *
@@ -475,9 +523,82 @@ LONG CDECL X11DRV_ChangeDisplaySettingsEx( LPCWSTR devname, LPDEVMODEW devmode,
 {
     WCHAR primary_adapter[CCHDEVICENAME];
     char bpp_buffer[16], freq_buffer[18];
-    DEVMODEW default_mode;
+    DEVMODEW default_mode, *full_mode;
+    ULONG_PTR id;
+    LONG ret;
     DWORD i;
 
+    /* Use the new interface if it is available */
+    if (!handler.name)
+        goto old_interface;
+
+    if (!get_primary_adapter(primary_adapter))
+        return DISP_CHANGE_FAILED;
+
+    if (!devname && !devmode)
+    {
+        default_mode.dmSize = sizeof(default_mode);
+        if (!EnumDisplaySettingsExW(primary_adapter, ENUM_REGISTRY_SETTINGS, &default_mode, 0))
+        {
+            ERR("Default mode not found for %s!\n", wine_dbgstr_w(primary_adapter));
+            return DISP_CHANGE_BADMODE;
+        }
+
+        devname = primary_adapter;
+        devmode = &default_mode;
+    }
+
+    if (!handler.get_id(devname, &id))
+    {
+        ERR("Failed to get %s device id.\n", wine_dbgstr_w(devname));
+        return DISP_CHANGE_BADPARAM;
+    }
+
+    if (is_detached_mode(devmode))
+    {
+        FIXME("Detaching adapters is currently unsupported.\n");
+        return DISP_CHANGE_SUCCESSFUL;
+    }
+
+    if (!(full_mode = get_full_mode(id, devmode)))
+    {
+        ERR("Failed to find a valid mode.\n");
+        return DISP_CHANGE_BADMODE;
+    }
+
+    if (flags & CDS_UPDATEREGISTRY && !write_registry_settings(devname, full_mode))
+    {
+        ERR("Failed to write %s display settings to registry.\n", wine_dbgstr_w(devname));
+        heap_free(full_mode);
+        return DISP_CHANGE_NOTUPDATED;
+    }
+
+    if (lstrcmpiW(primary_adapter, devname))
+    {
+        FIXME("Changing non-primary adapter %s settings is currently unsupported.\n",
+              wine_dbgstr_w(devname));
+        heap_free(full_mode);
+        return DISP_CHANGE_SUCCESSFUL;
+    }
+
+    if (flags & (CDS_TEST | CDS_NORESET))
+    {
+        heap_free(full_mode);
+        return DISP_CHANGE_SUCCESSFUL;
+    }
+
+    TRACE("handler:%s device:%s position:(%d,%d) resolution:%ux%u frequency:%uHz depth:%ubits "
+          "orientation:%#x.\n", handler.name, wine_dbgstr_w(devname), full_mode->u1.s2.dmPosition.x,
+          full_mode->u1.s2.dmPosition.y, full_mode->dmPelsWidth, full_mode->dmPelsHeight,
+          full_mode->dmDisplayFrequency, full_mode->dmBitsPerPel, full_mode->u1.s2.dmDisplayOrientation);
+
+    ret = handler.set_current_mode(id, full_mode);
+    if (ret == DISP_CHANGE_SUCCESSFUL)
+        X11DRV_DisplayDevices_Update(TRUE);
+    heap_free(full_mode);
+    return ret;
+
+old_interface:
     if (!get_primary_adapter(primary_adapter))
         return DISP_CHANGE_FAILED;
 
diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h
index b19e0e3e80..1c6b666227 100644
--- a/dlls/winex11.drv/x11drv.h
+++ b/dlls/winex11.drv/x11drv.h
@@ -697,6 +697,12 @@ struct x11drv_settings_handler
      *
      * Return FALSE on failure with parameters unchanged and error code set. Return TRUE on success */
     BOOL (*get_current_mode)(ULONG_PTR id, DEVMODEW *mode);
+
+    /* set_current_mode() will be called to change the display mode of the display device of id.
+     * mode must be a valid mode from get_modes() with optional fields, such as dmPosition set.
+     *
+     * Return DISP_CHANGE_*, same as ChangeDisplaySettingsExW() return values */
+    LONG (*set_current_mode)(ULONG_PTR id, DEVMODEW *mode);
 };
 
 extern void X11DRV_Settings_SetHandler(const struct x11drv_settings_handler *handler) DECLSPEC_HIDDEN;




More information about the wine-cvs mailing list