This patch enables DirectDraw and ChangeDisplaySettings to resize the Wine desktop. I also cleaned things up in such a way that it might be easier now to try using RandR instead of XVidMode. (Some more organizing would help, but the patch was already getting large as it is, so I decided to wait on that.)
It looks like the main benefit of RandR would be that it prevents you from "scrolling away" from the application on smaller resolutions. It does not seem to support depth changing at present.
-ajp
License: LGPL/X11
ChangeLog: - Allow applications to resize the Wine desktop window - Some cleanup of ChangeDisplaySettings and friends
Index: dlls/x11drv/desktop.c =================================================================== RCS file: /home/wine/wine/dlls/x11drv/desktop.c,v retrieving revision 1.12 diff -u -r1.12 desktop.c --- dlls/x11drv/desktop.c 10 Sep 2003 03:56:47 -0000 1.12 +++ dlls/x11drv/desktop.c 15 Sep 2003 05:51:11 -0000 @@ -25,7 +25,9 @@ #include "wine/winuser16.h" #include "win.h" +#include "ddrawi.h" #include "x11drv.h" +#include "x11ddraw.h" #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(x11drv); @@ -111,6 +113,93 @@ } +/* data for resolution changing */ +static LPDDHALMODEINFO dd_modes; +static int nmodes; + +static unsigned int max_width; +static unsigned int max_height; + +static unsigned int widths[] = {320, 640, 800, 1024, 1280, 1600}; +static unsigned int heights[] = {200, 480, 600, 768, 1024, 1200}; + +/* fill in DD mode info for one mode*/ +static void make_one_mode (LPDDHALMODEINFO info, unsigned int width, unsigned int height) +{ + info->dwWidth = width; + info->dwHeight = height; + info->wRefreshRate = 0; + info->lPitch = 0; + info->dwBPP = 0; + info->wFlags = 0; + info->dwRBitMask = 0; + info->dwGBitMask = 0; + info->dwBBitMask = 0; + info->dwAlphaBitMask = 0; + TRACE("initialized mode %dx%d\n", width, height); +} + +/* create the mode structures */ +static void make_modes(void) +{ + int i; + nmodes = 2; + for (i=0; i<6; i++) + { + if ( (widths[i] <= max_width) && (heights[i] <= max_height) ) nmodes++; + } + dd_modes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DDHALMODEINFO) * nmodes); + /* mode 0 is the original specified desktop size */ + make_one_mode(&dd_modes[0], screen_width, screen_height); + /* mode 1 is the root window size */ + make_one_mode(&dd_modes[1], max_width, max_height); + /* these modes are all the standard modes smaller than the root window */ + for (i=2; i<nmodes; i++) + { + make_one_mode(&dd_modes[i], widths[i-2], heights[i-2]); + } +} + +/*********************************************************************** + * X11DRV_resize_desktop + * + * Reset the desktop window size and WM hints + */ +int X11DRV_resize_desktop( unsigned int width, unsigned int height ) +{ + XSizeHints *size_hints; + Display *display = thread_display(); + Window w = root_window; + /* set up */ + wine_tsx11_lock(); + size_hints = XAllocSizeHints(); + if (!size_hints) + { + ERR("Not enough memory for window manager hints.\n" ); + return 0; + } + size_hints->min_width = size_hints->max_width = width; + size_hints->min_height = size_hints->max_height = height; + size_hints->flags = PMinSize | PMaxSize | PSize; + + /* do the work */ + XSetWMNormalHints( display, w, size_hints ); + XResizeWindow( display, w, width, height ); + screen_width = width; + screen_height = height; +#if 0 /* FIXME */ + SYSMETRICS_Set( SM_CXSCREEN, width ); + SYSMETRICS_Set( SM_CYSCREEN, height ); +#endif + + /* clean up */ + XFree( size_hints ); + XFlush( display ); + wine_tsx11_unlock(); + return 1; +} + + /*********************************************************************** * X11DRV_create_desktop * @@ -131,6 +220,8 @@ wine_tsx11_lock(); flags = XParseGeometry( geometry, &x, &y, &width, &height ); + max_width = screen_width; + max_height = screen_height; screen_width = width; screen_height = height; @@ -180,5 +271,129 @@ XFree( class_hints ); XFlush( display ); wine_tsx11_unlock(); + /* initialize the available resolutions */ + make_modes(); return win; } + +void X11DRV_desktop_SetCurrentMode(int mode) +{ + if (mode < nmodes) + { + X11DRV_resize_desktop(dd_modes[mode].dwWidth, dd_modes[mode].dwHeight); + } +} + +int X11DRV_desktop_GetCurrentMode(void) +{ + int i; + for (i=0; i<nmodes; i++) + { + if ( (screen_width == dd_modes[i].dwWidth) && + (screen_height == dd_modes[i].dwHeight) ) + return i; + } + ERR("In unknown mode, returning default\n"); + return 0; +} + +/* ChangeDisplaySettings and related functions */ + +/* implementation of EnumDisplaySettings for desktop */ +BOOL X11DRV_desktop_EnumDisplaySettingsExW( LPCWSTR name, DWORD n, LPDEVMODEW devmode, DWORD flags) +{ + DWORD dwBpp = screen_depth; + if (dwBpp == 24) dwBpp = 32; + devmode->dmDisplayFlags = 0; + devmode->dmDisplayFrequency = 85; + devmode->dmSize = sizeof(DEVMODEW); + if (n==0 || n == (DWORD)-1 || n == (DWORD)-2) + { + devmode->dmBitsPerPel = dwBpp; + devmode->dmPelsHeight = dd_modes[0].dwHeight; + devmode->dmPelsWidth = dd_modes[0].dwWidth; + devmode->dmFields = (DM_PELSWIDTH|DM_PELSHEIGHT|DM_BITSPERPEL); + TRACE("mode %ld -- returning default %ldx%ldx%ldbpp\n", n, + devmode->dmPelsWidth, devmode->dmPelsHeight, devmode->dmBitsPerPel); + return TRUE; + } + if (n <= nmodes) + { + devmode->dmPelsWidth = dd_modes[n].dwWidth; + devmode->dmPelsHeight = dd_modes[n].dwHeight; + devmode->dmBitsPerPel = dwBpp; + devmode->dmFields = (DM_PELSWIDTH|DM_PELSHEIGHT|DM_BITSPERPEL); + TRACE("mode %ld -- %ldx%ldx%ldbpp\n", n, + devmode->dmPelsWidth, devmode->dmPelsHeight, devmode->dmBitsPerPel); + return TRUE; + } + TRACE("mode %ld -- not present\n", n); + return FALSE; +} + +/* implementation of ChangeDisplaySettings for desktop */ +LONG X11DRV_desktop_ChangeDisplaySettingsExW( LPCWSTR devname, LPDEVMODEW devmode, + HWND hwnd, DWORD flags, LPVOID lpvoid ) +{ + DWORD i; + DWORD dwBpp = screen_depth; + if (dwBpp == 24) dwBpp = 32; + if (devmode==NULL) + { + X11DRV_desktop_SetCurrentMode(0); + return DISP_CHANGE_SUCCESSFUL; + } + + for (i = 0; i < nmodes; i++) + { + if (devmode->dmFields & DM_BITSPERPEL) + { + if (devmode->dmBitsPerPel != dwBpp) + continue; + } + if (devmode->dmFields & DM_PELSWIDTH) + { + if (devmode->dmPelsWidth != dd_modes[i].dwWidth) + continue; + } + if (devmode->dmFields & DM_PELSHEIGHT) + { + if (devmode->dmPelsHeight != dd_modes[i].dwHeight) + continue; + } + /* we have a valid mode */ + TRACE("Matches mode %ld\n", i); + X11DRV_desktop_SetCurrentMode(i); +#if 0 /* FIXME */ + SYSMETRICS_Set( SM_CXSCREEN, devmode->dmPelsWidth ); + SYSMETRICS_Set( SM_CYSCREEN, devmode->dmPelsHeight ); +#endif + return DISP_CHANGE_SUCCESSFUL; + } + + /* no valid modes found */ + ERR("No matching mode found!\n"); + return DISP_CHANGE_BADMODE; +} + +/* DirectDraw HAL stuff */ + +static DWORD PASCAL X11DRV_desktop_SetMode(LPDDHAL_SETMODEDATA data) +{ + X11DRV_desktop_SetCurrentMode(data->dwModeIndex); + X11DRV_DDHAL_SwitchMode(data->dwModeIndex, NULL, NULL); + data->ddRVal = DD_OK; + return DDHAL_DRIVER_HANDLED; +} + +int X11DRV_desktop_CreateDriver(LPDDHALINFO info) +{ + if (!nmodes) return 0; /* no desktop */ + + info->dwNumModes = nmodes; + info->lpModeInfo = dd_modes; + X11DRV_DDHAL_SwitchMode(X11DRV_desktop_GetCurrentMode(), NULL, NULL); + info->lpDDCallbacks->SetMode = X11DRV_desktop_SetMode; + return TRUE; +} + Index: dlls/x11drv/x11ddraw.c =================================================================== RCS file: /home/wine/wine/dlls/x11drv/x11ddraw.c,v retrieving revision 1.19 diff -u -r1.19 x11ddraw.c --- dlls/x11drv/x11ddraw.c 7 Jan 2003 20:36:22 -0000 1.19 +++ dlls/x11drv/x11ddraw.c 15 Sep 2003 05:51:11 -0000 @@ -383,8 +383,11 @@ #endif { #ifdef HAVE_LIBXXF86VM - X11DRV_XF86VM_CreateDriver(&hal_info); + if (!X11DRV_XF86VM_CreateDriver(&hal_info)) #endif + { + X11DRV_desktop_CreateDriver(&hal_info); + } } #ifdef HAVE_OPENGL /*X11DRV_GLX_CreateDriver(&hal_info);*/ Index: dlls/x11drv/x11drv.h =================================================================== RCS file: /home/wine/wine/dlls/x11drv/x11drv.h,v retrieving revision 1.4 diff -u -r1.4 x11drv.h --- dlls/x11drv/x11drv.h 5 Sep 2003 23:08:26 -0000 1.4 +++ dlls/x11drv/x11drv.h 15 Sep 2003 05:51:11 -0000 @@ -43,6 +43,7 @@ #include "gdi.h" #include "user.h" #include "win.h" +#include "ddrawi.h" #include "thread.h" #define MAX_PIXELFORMATS 8 @@ -490,6 +491,10 @@ extern void X11DRV_X_to_window_rect( WND *win, RECT *rect ); extern void X11DRV_create_desktop_thread(void); extern Window X11DRV_create_desktop( XVisualInfo *desktop_vi, const char *geometry ); +extern int X11DRV_desktop_CreateDriver(LPDDHALINFO info); +extern BOOL X11DRV_desktop_EnumDisplaySettingsExW( LPCWSTR name, DWORD n, LPDEVMODEW devmode, DWORD flags); +extern LONG X11DRV_desktop_ChangeDisplaySettingsExW( LPCWSTR devname, LPDEVMODEW devmode, + HWND hwnd, DWORD flags, LPVOID lpvoid ); extern void X11DRV_sync_window_style( Display *display, WND *win ); extern int X11DRV_sync_whole_window_position( Display *display, WND *win, int zorder ); extern int X11DRV_sync_client_window_position( Display *display, WND *win ); Index: dlls/x11drv/xvidmode.c =================================================================== RCS file: /home/wine/wine/dlls/x11drv/xvidmode.c,v retrieving revision 1.21 diff -u -r1.21 xvidmode.c --- dlls/x11drv/xvidmode.c 15 Jul 2003 20:44:24 -0000 1.21 +++ dlls/x11drv/xvidmode.c 15 Sep 2003 05:51:12 -0000 @@ -104,11 +104,13 @@ return 1; } +static Bool in_desktop_mode; + void X11DRV_XF86VM_Init(void) { int nmodes, i; Bool ok; - Bool in_desktop_mode = (root_window != DefaultRootWindow(gdi_display)); + in_desktop_mode = (root_window != DefaultRootWindow(gdi_display)); if (xf86vm_major) return; /* already initialized? */ @@ -417,10 +419,8 @@ #endif } -/*********************************************************************** - * EnumDisplaySettingsExW (X11DRV.@) - */ -BOOL X11DRV_EnumDisplaySettingsExW( LPCWSTR name, DWORD n, LPDEVMODEW devmode, DWORD flags) +/* implementation of EnumDisplaySettings for XF86VM */ +BOOL X11DRV_XF86VM_EnumDisplaySettingsExW( LPCWSTR name, DWORD n, LPDEVMODEW devmode, DWORD flags) { DWORD dwBpp = screen_depth; if (dwBpp == 24) dwBpp = 32; @@ -456,59 +456,22 @@ return FALSE; } - - -#define _X_FIELD(prefix, bits) if ((fields) & prefix##_##bits) {p+=sprintf(p, "%s%s", first ? "" : ",", #bits); first=FALSE;} -static const char * _CDS_flags(DWORD fields) -{ - BOOL first = TRUE; - char buf[128]; - char *p = buf; - _X_FIELD(CDS,UPDATEREGISTRY);_X_FIELD(CDS,TEST);_X_FIELD(CDS,FULLSCREEN); - _X_FIELD(CDS,GLOBAL);_X_FIELD(CDS,SET_PRIMARY);_X_FIELD(CDS,RESET); - _X_FIELD(CDS,SETRECT);_X_FIELD(CDS,NORESET); - *p = 0; - return wine_dbg_sprintf("%s", buf); -} -static const char * _DM_fields(DWORD fields) -{ - BOOL first = TRUE; - char buf[128]; - char *p = buf; - _X_FIELD(DM,BITSPERPEL);_X_FIELD(DM,PELSWIDTH);_X_FIELD(DM,PELSHEIGHT); - _X_FIELD(DM,DISPLAYFLAGS);_X_FIELD(DM,DISPLAYFREQUENCY);_X_FIELD(DM,POSITION); - *p = 0; - return wine_dbg_sprintf("%s", buf); -} -#undef _X_FIELD - -/*********************************************************************** - * ChangeDisplaySettingsExW (X11DRV.@) - */ -LONG X11DRV_ChangeDisplaySettingsExW( LPCWSTR devname, LPDEVMODEW devmode, +/* implementation of ChangeDisplaySettings for desktop */ +LONG X11DRV_XF86VM_ChangeDisplaySettingsExW( LPCWSTR devname, LPDEVMODEW devmode, HWND hwnd, DWORD flags, LPVOID lpvoid ) { DWORD i; DWORD dwBpp = screen_depth; if (dwBpp == 24) dwBpp = 32; - TRACE("(%s,%p,%p,0x%08lx,%p\n",debugstr_w(devname),devmode,hwnd,flags,lpvoid); - TRACE("flags=%s\n",_CDS_flags(flags)); if (devmode==NULL) { - TRACE("Return to original display mode\n"); #ifdef HAVE_LIBXXF86VM X11DRV_XF86VM_SetCurrentMode(xf86vm_initial_mode); #endif return DISP_CHANGE_SUCCESSFUL; } - if (TRACE_ON(x11drv)) - { - TRACE("DM_fields=%s\n",_DM_fields(devmode->dmFields)); - TRACE("width=%ld height=%ld bpp=%ld freq=%ld\n", - devmode->dmPelsWidth,devmode->dmPelsHeight, - devmode->dmBitsPerPel,devmode->dmDisplayFrequency); - } +#if 0 /* FIXME: only works if we update SYSMETRICS */ if ((!(devmode->dmFields & DM_BITSPERPEL) || devmode->dmBitsPerPel == dwBpp) && (!(devmode->dmFields & DM_PELSWIDTH) || devmode->dmPelsWidth == GetSystemMetrics(SM_CXSCREEN)) && (!(devmode->dmFields & DM_PELSHEIGHT) || devmode->dmPelsHeight == GetSystemMetrics(SM_CYSCREEN))) @@ -517,6 +480,7 @@ TRACE("Requested mode matches current mode -- no change!\n"); return DISP_CHANGE_SUCCESSFUL; } +#endif #ifdef HAVE_LIBXXF86VM for (i = 0; i < xf86vm_mode_count; i++) @@ -551,4 +515,140 @@ /* no valid modes found */ ERR("No matching mode found!\n"); return DISP_CHANGE_BADMODE; +} + +/* implementation of EnumDisplaySettings for nores */ +BOOL X11DRV_nores_EnumDisplaySettingsExW( LPCWSTR name, DWORD n, LPDEVMODEW devmode, DWORD flags) +{ + DWORD dwBpp = screen_depth; + if (dwBpp == 24) dwBpp = 32; + devmode->dmDisplayFlags = 0; + devmode->dmDisplayFrequency = 85; + devmode->dmSize = sizeof(DEVMODEW); + if (n==0 || n == (DWORD)-1 || n == (DWORD)-2) + { + devmode->dmBitsPerPel = dwBpp; + devmode->dmPelsHeight = GetSystemMetrics(SM_CYSCREEN); + devmode->dmPelsWidth = GetSystemMetrics(SM_CXSCREEN); + devmode->dmFields = (DM_PELSWIDTH|DM_PELSHEIGHT|DM_BITSPERPEL); + TRACE("mode %ld -- returning default %ldx%ldx%ldbpp\n", n, + devmode->dmPelsWidth, devmode->dmPelsHeight, devmode->dmBitsPerPel); + return TRUE; + } + TRACE("mode %ld -- not present\n", n); + return FALSE; +} + +/* implementation of ChangeDisplaySettings for nores */ +LONG X11DRV_nores_ChangeDisplaySettingsExW( LPCWSTR devname, LPDEVMODEW devmode, + HWND hwnd, DWORD flags, LPVOID lpvoid ) +{ + DWORD dwBpp = screen_depth; + if (dwBpp == 24) dwBpp = 32; + if (devmode==NULL) + { + return DISP_CHANGE_SUCCESSFUL; + } + + if ((!(devmode->dmFields & DM_BITSPERPEL) || devmode->dmBitsPerPel == dwBpp) && + (!(devmode->dmFields & DM_PELSWIDTH) || devmode->dmPelsWidth == GetSystemMetrics(SM_CXSCREEN)) && + (!(devmode->dmFields & DM_PELSHEIGHT) || devmode->dmPelsHeight == GetSystemMetrics(SM_CYSCREEN))) + { + /* we are in the desired mode */ + TRACE("Requested mode matches current mode -- no change!\n"); + return DISP_CHANGE_SUCCESSFUL; + } + + /* no valid modes found */ + ERR("No matching mode found!\n"); + return DISP_CHANGE_BADMODE; +} + +/*********************************************************************** + * EnumDisplaySettingsExW (X11DRV.@) + * + * FIXME: should move to somewhere appropriate + */ +BOOL X11DRV_EnumDisplaySettingsExW( LPCWSTR name, DWORD n, LPDEVMODEW devmode, DWORD flags) +{ + if (xf86vm_modes) + { + /* XVidMode */ + return X11DRV_XF86VM_EnumDisplaySettingsExW(name, n, devmode, flags); + } + else if (in_desktop_mode) + { + /* desktop */ + return X11DRV_desktop_EnumDisplaySettingsExW(name, n, devmode, flags); + } + else + { + /* no resolution changing */ + return X11DRV_nores_EnumDisplaySettingsExW(name, n, devmode, flags); + } +} + +#define _X_FIELD(prefix, bits) if ((fields) & prefix##_##bits) {p+=sprintf(p, "%s%s", first ? "" : ",", #bits); first=FALSE;} +static const char * _CDS_flags(DWORD fields) +{ + BOOL first = TRUE; + char buf[128]; + char *p = buf; + _X_FIELD(CDS,UPDATEREGISTRY);_X_FIELD(CDS,TEST);_X_FIELD(CDS,FULLSCREEN); + _X_FIELD(CDS,GLOBAL);_X_FIELD(CDS,SET_PRIMARY);_X_FIELD(CDS,RESET); + _X_FIELD(CDS,SETRECT);_X_FIELD(CDS,NORESET); + *p = 0; + return wine_dbg_sprintf("%s", buf); +} +static const char * _DM_fields(DWORD fields) +{ + BOOL first = TRUE; + char buf[128]; + char *p = buf; + _X_FIELD(DM,BITSPERPEL);_X_FIELD(DM,PELSWIDTH);_X_FIELD(DM,PELSHEIGHT); + _X_FIELD(DM,DISPLAYFLAGS);_X_FIELD(DM,DISPLAYFREQUENCY);_X_FIELD(DM,POSITION); + *p = 0; + return wine_dbg_sprintf("%s", buf); +} +#undef _X_FIELD + +/*********************************************************************** + * ChangeDisplaySettingsExW (X11DRV.@) + * + * FIXME: should move to somewhere appropriate + */ +LONG X11DRV_ChangeDisplaySettingsExW( LPCWSTR devname, LPDEVMODEW devmode, + HWND hwnd, DWORD flags, LPVOID lpvoid ) +{ + TRACE("(%s,%p,%p,0x%08lx,%p\n",debugstr_w(devname),devmode,hwnd,flags,lpvoid); + TRACE("flags=%s\n",_CDS_flags(flags)); + if (devmode) + { + TRACE("DM_fields=%s\n",_DM_fields(devmode->dmFields)); + TRACE("width=%ld height=%ld bpp=%ld freq=%ld\n", + devmode->dmPelsWidth,devmode->dmPelsHeight, + devmode->dmBitsPerPel,devmode->dmDisplayFrequency); + } + else + { + TRACE("Return to original display mode\n"); + } + if (xf86vm_modes) + { + /* XVidMode */ + return X11DRV_XF86VM_ChangeDisplaySettingsExW( devname, devmode, + hwnd, flags, lpvoid ); + } + else if (in_desktop_mode) + { + /* no XVidMode */ + return X11DRV_desktop_ChangeDisplaySettingsExW( devname, devmode, + hwnd, flags, lpvoid ); + } + else + { + /* no resolution changing */ + return X11DRV_nores_ChangeDisplaySettingsExW( devname, devmode, + hwnd, flags, lpvoid ); + } }