[PATCH 4/6] winex11.drv: Migrate XVidMode display settings handler to a new interface.
Zhiyi Zhang
zzhang at codeweavers.com
Mon Jul 27 03:01:38 CDT 2020
Signed-off-by: Zhiyi Zhang <zzhang at codeweavers.com>
---
dlls/winex11.drv/xvidmode.c | 267 +++++++++++++++++++++++-------------
1 file changed, 173 insertions(+), 94 deletions(-)
diff --git a/dlls/winex11.drv/xvidmode.c b/dlls/winex11.drv/xvidmode.c
index a5884543163..c449157f6b3 100644
--- a/dlls/winex11.drv/xvidmode.c
+++ b/dlls/winex11.drv/xvidmode.c
@@ -2,6 +2,7 @@
* DirectDraw XVidMode interface
*
* Copyright 2001 TransGaming Technologies, Inc.
+ * Copyright 2020 Zhiyi Zhang for CodeWeavers
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -21,10 +22,14 @@
#include "config.h"
#include "wine/port.h"
+#include <assert.h>
#include <string.h>
#include <stdio.h>
#include <math.h>
+#define NONAMELESSSTRUCT
+#define NONAMELESSUNION
+
#include "x11drv.h"
#ifdef HAVE_X11_EXTENSIONS_XF86VMODE_H
@@ -38,6 +43,7 @@
#include "wingdi.h"
#include "wine/debug.h"
#include "wine/heap.h"
+#include "wine/unicode.h"
WINE_DEFAULT_DEBUG_CHANNEL(xvidmode);
@@ -52,11 +58,6 @@ static int xf86vm_gammaramp_size;
static BOOL xf86vm_use_gammaramp;
#endif /* X_XF86VidModeSetGammaRamp */
-static struct x11drv_mode_info *dd_modes;
-static unsigned int dd_mode_count;
-static XF86VidModeModeInfo** real_xf86vm_modes;
-static unsigned int real_xf86vm_mode_count;
-
#define MAKE_FUNCPTR(f) static typeof(f) * p##f;
MAKE_FUNCPTR(XF86VidModeGetAllModeLines)
MAKE_FUNCPTR(XF86VidModeGetModeLine)
@@ -76,86 +77,182 @@ MAKE_FUNCPTR(XF86VidModeSetGammaRamp)
#endif
#undef MAKE_FUNCPTR
-
-static void convert_modeinfo( const XF86VidModeModeInfo *mode)
-{
- int rate;
- if (mode->htotal!=0 && mode->vtotal!=0)
- rate = mode->dotclock * 1000 / (mode->htotal * mode->vtotal);
- else
- rate = 0;
- X11DRV_Settings_AddOneMode(mode->hdisplay, mode->vdisplay, 0, rate);
-}
-
-static void convert_modeline(int dotclock, const XF86VidModeModeLine *mode,
- struct x11drv_mode_info *info, unsigned int bpp)
-{
- info->width = mode->hdisplay;
- info->height = mode->vdisplay;
- if (mode->htotal!=0 && mode->vtotal!=0)
- info->refresh_rate = dotclock * 1000 / (mode->htotal * mode->vtotal);
- else
- info->refresh_rate = 0;
- TRACE(" width=%d, height=%d, refresh=%d\n",
- info->width, info->height, info->refresh_rate);
- info->bpp = bpp;
-}
-
static int XVidModeErrorHandler(Display *dpy, XErrorEvent *event, void *arg)
{
return 1;
}
-static int X11DRV_XF86VM_GetCurrentMode(void)
+/* XF86VidMode display settings handler */
+static BOOL xf86vm_get_id(const WCHAR *device_name, ULONG_PTR *id)
{
- XF86VidModeModeLine line;
- int dotclock;
- unsigned int i;
- struct x11drv_mode_info cmode;
- DWORD dwBpp = screen_bpp;
+ WCHAR primary_adapter[CCHDEVICENAME];
- TRACE("Querying XVidMode current mode\n");
- pXF86VidModeGetModeLine(gdi_display, DefaultScreen(gdi_display), &dotclock, &line);
- convert_modeline(dotclock, &line, &cmode, dwBpp);
- for (i=0; i<dd_mode_count; i++)
- if (memcmp(&dd_modes[i], &cmode, sizeof(cmode)) == 0) {
- TRACE("mode=%d\n", i);
- return i;
+ if (!get_primary_adapter( primary_adapter ))
+ return FALSE;
+
+ /* XVidMode only supports changing the primary adapter settings.
+ * For non-primary adapters, an id is still provided but getting
+ * and changing non-primary adapters' settings will be ignored. */
+ *id = !lstrcmpiW( device_name, primary_adapter ) ? 1 : 0;
+ return TRUE;
+}
+
+static void add_xf86vm_mode(DEVMODEW *mode, DWORD depth, const XF86VidModeModeInfo *mode_info)
+{
+ mode->dmSize = sizeof(*mode);
+ mode->dmDriverExtra = sizeof(mode_info);
+ mode->dmFields = DM_DISPLAYORIENTATION | DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFLAGS;
+ if (mode_info->htotal && mode_info->vtotal)
+ {
+ mode->dmFields |= DM_DISPLAYFREQUENCY;
+ mode->dmDisplayFrequency = mode_info->dotclock * 1000 / (mode_info->htotal * mode_info->vtotal);
}
- ERR("In unknown mode, returning default\n");
- return 0;
+ mode->u1.s2.dmDisplayOrientation = DMDO_DEFAULT;
+ mode->dmBitsPerPel = depth;
+ mode->dmPelsWidth = mode_info->hdisplay;
+ mode->dmPelsHeight = mode_info->vdisplay;
+ mode->u2.dmDisplayFlags = 0;
+ memcpy((BYTE *)mode + sizeof(*mode), &mode_info, sizeof(mode_info));
}
-static LONG X11DRV_XF86VM_SetCurrentMode(int mode)
+static BOOL xf86vm_get_modes(ULONG_PTR id, DWORD flags, DEVMODEW **new_modes, UINT *mode_count)
{
- DWORD dwBpp = screen_bpp;
- /* only set modes from the original color depth */
- if (dwBpp != dd_modes[mode].bpp)
- {
- FIXME("Cannot change screen BPP from %d to %d\n", dwBpp, dd_modes[mode].bpp);
- }
- mode = mode % real_xf86vm_mode_count;
+ INT xf86vm_mode_idx, xf86vm_mode_count;
+ XF86VidModeModeInfo **xf86vm_modes;
+ UINT depth_idx, mode_idx = 0;
+ DEVMODEW *modes, *mode;
+ SIZE_T size;
+ BYTE *ptr;
+ Bool ret;
- TRACE("Resizing X display to %dx%d\n",
- real_xf86vm_modes[mode]->hdisplay, real_xf86vm_modes[mode]->vdisplay);
- pXF86VidModeSwitchToMode(gdi_display, DefaultScreen(gdi_display), real_xf86vm_modes[mode]);
-#if 0 /* it is said that SetViewPort causes problems with some X servers */
- pXF86VidModeSetViewPort(gdi_display, DefaultScreen(gdi_display), 0, 0);
-#else
- XWarpPointer(gdi_display, None, DefaultRootWindow(gdi_display), 0, 0, 0, 0, 0, 0);
-#endif
- XSync(gdi_display, False);
- X11DRV_DisplayDevices_Update( TRUE );
- return DISP_CHANGE_SUCCESSFUL;
+ X11DRV_expect_error(gdi_display, XVidModeErrorHandler, NULL);
+ ret = pXF86VidModeGetAllModeLines(gdi_display, DefaultScreen(gdi_display), &xf86vm_mode_count, &xf86vm_modes);
+ if (X11DRV_check_error() || !ret || !xf86vm_mode_count)
+ return FALSE;
+
+ /* Put a XF86VidModeModeInfo ** at the start to store the XF86VidMode modes pointer */
+ size = sizeof(XF86VidModeModeInfo **);
+ /* Display modes in different color depth, with a XF86VidModeModeInfo * at the end of each
+ * DEVMODEW as driver private data */
+ size += (xf86vm_mode_count * DEPTH_COUNT) * (sizeof(DEVMODEW) + sizeof(XF86VidModeModeInfo *));
+ ptr = heap_alloc_zero(size);
+ if (!ptr)
+ {
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ return FALSE;
+ }
+
+ memcpy(ptr, &xf86vm_modes, sizeof(xf86vm_modes));
+ modes = (DEVMODEW *)(ptr + sizeof(xf86vm_modes));
+
+ for (depth_idx = 0; depth_idx < DEPTH_COUNT; ++depth_idx)
+ {
+ for (xf86vm_mode_idx = 0; xf86vm_mode_idx < xf86vm_mode_count; ++xf86vm_mode_idx)
+ {
+ mode = (DEVMODEW *)((BYTE *)modes + (sizeof(DEVMODEW) + sizeof(XF86VidModeModeInfo *)) * mode_idx++);
+ add_xf86vm_mode(mode, depths[depth_idx], xf86vm_modes[xf86vm_mode_idx]);
+ }
+ }
+
+ *new_modes = modes;
+ *mode_count = mode_idx;
+ return TRUE;
}
+static void xf86vm_free_modes(DEVMODEW *modes)
+{
+ XF86VidModeModeInfo **xf86vm_modes;
+
+ if (modes)
+ {
+ assert(modes[0].dmDriverExtra == sizeof(XF86VidModeModeInfo *));
+ memcpy(&xf86vm_modes, (BYTE *)modes - sizeof(xf86vm_modes), sizeof(xf86vm_modes));
+ XFree(xf86vm_modes);
+ }
+ heap_free(modes);
+}
+
+static BOOL xf86vm_get_current_mode(ULONG_PTR id, DEVMODEW *mode)
+{
+ XF86VidModeModeLine xf86vm_mode;
+ INT dotclock;
+ Bool ret;
+
+ mode->dmFields = DM_DISPLAYORIENTATION | DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT |
+ DM_DISPLAYFLAGS | DM_DISPLAYFREQUENCY | DM_POSITION;
+ mode->u1.s2.dmDisplayOrientation = DMDO_DEFAULT;
+ mode->u2.dmDisplayFlags = 0;
+ mode->u1.s2.dmPosition.x = 0;
+ mode->u1.s2.dmPosition.y = 0;
+
+ if (id != 1)
+ {
+ FIXME("Non-primary adapters are unsupported.\n");
+ mode->dmBitsPerPel = 0;
+ mode->dmPelsWidth = 0;
+ mode->dmPelsHeight = 0;
+ mode->dmDisplayFrequency = 0;
+ return TRUE;
+ }
+
+ X11DRV_expect_error(gdi_display, XVidModeErrorHandler, NULL);
+ ret = pXF86VidModeGetModeLine(gdi_display, DefaultScreen(gdi_display), &dotclock, &xf86vm_mode);
+ if (X11DRV_check_error() || !ret)
+ return FALSE;
+
+ mode->dmBitsPerPel = screen_bpp;
+ mode->dmPelsWidth = xf86vm_mode.hdisplay;
+ mode->dmPelsHeight = xf86vm_mode.vdisplay;
+ if (xf86vm_mode.htotal && xf86vm_mode.vtotal)
+ mode->dmDisplayFrequency = dotclock * 1000 / (xf86vm_mode.htotal * xf86vm_mode.vtotal);
+ else
+ mode->dmDisplayFrequency = 0;
+
+ if (xf86vm_mode.privsize)
+ XFree(xf86vm_mode.private);
+ return TRUE;
+}
+
+static LONG xf86vm_set_current_mode(ULONG_PTR id, DEVMODEW *mode)
+{
+ XF86VidModeModeInfo *xf86vm_mode;
+ Bool ret;
+
+ if (id != 1)
+ {
+ FIXME("Non-primary adapters are unsupported.\n");
+ return DISP_CHANGE_SUCCESSFUL;
+ }
+
+ if (is_detached_mode(mode))
+ {
+ FIXME("Detaching adapters is unsupported.\n");
+ return DISP_CHANGE_SUCCESSFUL;
+ }
+
+ if (mode->dmFields & DM_BITSPERPEL && mode->dmBitsPerPel != screen_bpp)
+ WARN("Cannot change screen bit depth from %dbits to %dbits!\n", screen_bpp, mode->dmBitsPerPel);
+
+ assert(mode->dmDriverExtra == sizeof(XF86VidModeModeInfo *));
+ memcpy(&xf86vm_mode, (BYTE *)mode + sizeof(*mode), sizeof(xf86vm_mode));
+ X11DRV_expect_error(gdi_display, XVidModeErrorHandler, NULL);
+ ret = pXF86VidModeSwitchToMode(gdi_display, DefaultScreen(gdi_display), xf86vm_mode);
+ if (X11DRV_check_error() || !ret)
+ return DISP_CHANGE_FAILED;
+#if 0 /* it is said that SetViewPort causes problems with some X servers */
+ pXF86VidModeSetViewPort(gdi_display, DefaultScreen(gdi_display), 0, 0);
+#else
+ XWarpPointer(gdi_display, None, DefaultRootWindow(gdi_display), 0, 0, 0, 0, 0, 0);
+#endif
+ XFlush(gdi_display);
+ return DISP_CHANGE_SUCCESSFUL;
+}
void X11DRV_XF86VM_Init(void)
{
+ struct x11drv_settings_handler xf86vm_handler;
void *xvidmode_handle;
Bool ok;
- int nmodes;
- unsigned int i;
if (xf86vm_major) return; /* already initialized? */
@@ -207,35 +304,17 @@ void X11DRV_XF86VM_Init(void)
}
#endif /* X_XF86VidModeSetGammaRamp */
- /* retrieve modes */
- if (usexvidmode && !is_virtual_desktop())
- {
- X11DRV_expect_error(gdi_display, XVidModeErrorHandler, NULL);
- ok = pXF86VidModeGetAllModeLines(gdi_display, DefaultScreen(gdi_display), &nmodes, &real_xf86vm_modes);
- if (X11DRV_check_error() || !ok) return;
- }
- else return; /* In desktop mode, do not switch resolution... But still use the Gamma ramp stuff */
+ if (!usexvidmode)
+ return;
- TRACE("XVidMode modes: count=%d\n", nmodes);
-
- real_xf86vm_mode_count = nmodes;
-
- dd_modes = X11DRV_Settings_SetHandlers("XF86VidMode",
- X11DRV_XF86VM_GetCurrentMode,
- X11DRV_XF86VM_SetCurrentMode,
- nmodes, 1);
-
- /* convert modes to x11drv_mode_info format */
- for (i=0; i<real_xf86vm_mode_count; i++)
- {
- convert_modeinfo(real_xf86vm_modes[i]);
- }
- /* add modes for different color depths */
- X11DRV_Settings_AddDepthModes();
- dd_mode_count = X11DRV_Settings_GetModeCount();
-
- TRACE("Available DD modes: count=%d\n", dd_mode_count);
- TRACE("Enabling XVidMode\n");
+ xf86vm_handler.name = "XF86VidMode";
+ xf86vm_handler.priority = 100;
+ xf86vm_handler.get_id = xf86vm_get_id;
+ xf86vm_handler.get_modes = xf86vm_get_modes;
+ xf86vm_handler.free_modes = xf86vm_free_modes;
+ xf86vm_handler.get_current_mode = xf86vm_get_current_mode;
+ xf86vm_handler.set_current_mode = xf86vm_set_current_mode;
+ X11DRV_Settings_SetHandler(&xf86vm_handler);
return;
sym_not_found:
--
2.25.1
More information about the wine-devel
mailing list