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