From 0b0ac41981006514616abdd4c4b6922cf66be7b6 Mon Sep 17 00:00:00 2001 From: Zhiyi Zhang Date: Wed, 22 Jul 2020 15:24:41 +0800 Subject: [PATCH] winex11.drv: Support virtual desktop display mode enumeration using the new display settings handler interface. Signed-off-by: Zhiyi Zhang Signed-off-by: Alexandre Julliard --- 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: