Signed-off-by: Zhiyi Zhang <zzhang(a)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