1 /* DirectDraw driver for User-based primary surfaces
2 * with XF86VidMode mode switching in full-screen mode.
4 * Copyright 2000 TransGaming Technologies Inc.
11 #include "debugtools.h"
13 #include "ts_xf86vmode.h"
20 #include "ddraw_private.h"
21 #include "ddraw/main.h"
22 #include "ddraw/user.h"
23 #include "ddraw/xvidmode.h"
24 #include "dclipper/main.h"
25 #include "dpalette/main.h"
26 #include "dsurface/main.h"
27 #include "dsurface/dib.h"
28 #include "dsurface/user.h"
33 DEFAULT_DEBUG_CHANNEL(ddraw);
35 static ICOM_VTABLE(IDirectDraw7) XVidMode_DirectDraw_VTable;
37 static const DDDEVICEIDENTIFIER2 xvidmode_device =
41 { { 0x00010001, 0x00010001 } },
43 /* 40c1b248-9d7d-4a29-b7d7-4cd8109f3d5d */
44 {0x40c1b248,0x9d7d,0x4a29,{0xd7,0xb7,0x4c,0xd8,0x10,0x9f,0x3d,0x5d}},
48 HRESULT XVidMode_DirectDraw_Create(const GUID* pGUID, LPDIRECTDRAW7* pIface,
49 IUnknown* pUnkOuter, BOOL ex);
50 HRESULT XVidMode_DirectDraw_Initialize(IDirectDrawImpl*, const GUID*);
52 static const ddraw_driver xvidmode_driver =
56 XVidMode_DirectDraw_Create,
57 XVidMode_DirectDraw_Initialize
60 static XF86VidModeModeInfo** modes;
61 static DWORD num_modes;
63 /* Called from DllInit, which is synchronised so there are no threading
65 static BOOL initialize(void)
70 if (X11DRV_GetXRootWindow() != DefaultRootWindow(display)) return FALSE;
72 if (!TSXF86VidModeQueryVersion(display, &major, &minor)) return FALSE;
74 if (!TSXF86VidModeGetAllModeLines(display, DefaultScreen(display), &nmodes,
80 TRACE("enabling XVidMode\n");
85 static void cleanup(void)
90 static HRESULT set_display_mode(XF86VidModeModeInfo* mode)
92 int screen = DefaultScreen(display);
94 TRACE("%d %d\n", mode->hdisplay, mode->vdisplay);
96 /* This is questionable. Programs should leave switching unlocked when
97 * they exit. So the only reason the display should be locked is if
98 * another really doesn't want switches to happen. Maybe it would be better
99 * to detect an XF86VideModeZoomLocked error. */
100 TSXF86VidModeLockModeSwitch(display, screen, False);
102 TSXSync(display, False);
104 TSXF86VidModeSwitchToMode(display, screen, mode);
106 TSXSync(display, False);
108 #if 0 /* doesn't work for me */
109 TSXF86VidModeSetViewPort(display, screen, 0, 0);
111 TSXWarpPointer(display, None, RootWindow(display, screen), 0, 0, 0, 0, 0,
120 static XF86VidModeModeInfo* choose_mode(DWORD dwWidth, DWORD dwHeight,
121 DWORD dwRefreshRate, DWORD dwFlags)
123 XF86VidModeModeInfo* best = NULL;
126 /* Choose the smallest mode that is large enough. */
127 for (i=0; i < num_modes; i++)
129 if (modes[i]->hdisplay >= dwWidth && modes[i]->vdisplay >= dwHeight)
131 if (best == NULL) best = modes[i];
134 if (modes[i]->hdisplay < best->hdisplay
135 || modes[i]->vdisplay < best->vdisplay)
141 /* all modes were too small, use the largest */
144 TRACE("all modes too small\n");
146 for (i=1; i < num_modes; i++)
148 if (best == NULL) best = modes[i];
151 if (modes[i]->hdisplay > best->hdisplay
152 || modes[i]->vdisplay > best->vdisplay)
158 TRACE("using %d %d for %lu %lu\n", best->hdisplay, best->vdisplay,
164 static XF86VidModeModeInfo* get_current_mode(void)
166 XF86VidModeModeLine line;
170 TSXF86VidModeGetModeLine(display, DefaultScreen(display), &dotclock,
173 for (i=0; i < num_modes; i++)
175 if (modes[i]->dotclock == dotclock
176 && modes[i]->hdisplay == line.hdisplay
177 && modes[i]->hsyncstart == line.hsyncstart
178 && modes[i]->hsyncend == line.hsyncend
179 && modes[i]->htotal == line.htotal
180 /* && modes[i]->hskew == line.hskew */
181 && modes[i]->vdisplay == line.vdisplay
182 && modes[i]->vsyncstart == line.vsyncstart
183 && modes[i]->vsyncend == line.vsyncend
184 && modes[i]->vtotal == line.vtotal
185 && modes[i]->flags == line.flags)
189 WARN("this can't happen\n");
190 return modes[0]; /* should be the mode that X started in */
193 BOOL DDRAW_XVidMode_Init(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpv)
195 if (fdwReason == DLL_PROCESS_ATTACH)
198 DDRAW_register_driver(&xvidmode_driver);
200 else if (fdwReason == DLL_PROCESS_DETACH)
208 /* Not called from the vtable. */
209 HRESULT XVidMode_DirectDraw_Construct(IDirectDrawImpl *This, BOOL ex)
211 XVIDMODE_DDRAW_PRIV_VAR(priv,This);
216 hr = User_DirectDraw_Construct(This, ex);
217 if (FAILED(hr)) return hr;
219 This->final_release = XVidMode_DirectDraw_final_release;
221 priv->xvidmode.original_mode = get_current_mode();
222 priv->xvidmode.current_mode = priv->xvidmode.original_mode;
224 ICOM_INIT_INTERFACE(This, IDirectDraw7, XVidMode_DirectDraw_VTable);
229 /* This function is called from DirectDrawCreate(Ex) on the most-derived
230 * class to start construction.
231 * Not called from the vtable. */
232 HRESULT XVidMode_DirectDraw_Create(const GUID* pGUID, LPDIRECTDRAW7* pIface,
233 IUnknown* pUnkOuter, BOOL ex)
236 IDirectDrawImpl* This;
240 assert(pUnkOuter == NULL);
242 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
243 sizeof(IDirectDrawImpl)
244 + sizeof(XVidMode_DirectDrawImpl));
245 if (This == NULL) return E_OUTOFMEMORY;
247 /* Note that this relation does *not* hold true if the DD object was
248 * CoCreateInstanced then Initialized. */
249 This->private = (XVidMode_DirectDrawImpl *)(This+1);
251 hr = XVidMode_DirectDraw_Construct(This, ex);
253 HeapFree(GetProcessHeap(), 0, This);
255 *pIface = ICOM_INTERFACE(This, IDirectDraw7);
260 /* This function is called from Uninit_DirectDraw_Initialize on the
261 * most-derived-class to start initialization.
262 * Not called from the vtable. */
263 HRESULT XVidMode_DirectDraw_Initialize(IDirectDrawImpl *This, const GUID* guid)
269 This->private = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
270 sizeof(XVidMode_DirectDrawImpl));
271 if (This->private == NULL) return E_OUTOFMEMORY;
273 hr = XVidMode_DirectDraw_Construct(This, TRUE); /* XXX ex? */
276 HeapFree(GetProcessHeap(), 0, This->private);
283 /* Called from an internal function pointer. */
284 void XVidMode_DirectDraw_final_release(IDirectDrawImpl *This)
286 XVIDMODE_DDRAW_PRIV_VAR(priv, This);
288 if (priv->xvidmode.current_mode != priv->xvidmode.original_mode)
289 set_display_mode(priv->xvidmode.original_mode);
291 User_DirectDraw_final_release(This);
295 XVidMode_DirectDraw_GetDeviceIdentifier(LPDIRECTDRAW7 iface,
296 LPDDDEVICEIDENTIFIER2 pDDDI,
299 *pDDDI = xvidmode_device;
304 XVidMode_DirectDraw_RestoreDisplayMode(LPDIRECTDRAW7 iface)
306 ICOM_THIS(IDirectDrawImpl, iface);
311 hr = Main_DirectDraw_RestoreDisplayMode(iface);
314 XVIDMODE_DDRAW_PRIV_VAR(priv, This);
316 if (priv->xvidmode.current_mode != priv->xvidmode.original_mode)
318 set_display_mode(priv->xvidmode.original_mode);
319 priv->xvidmode.current_mode = priv->xvidmode.original_mode;
327 XVidMode_DirectDraw_SetDisplayMode(LPDIRECTDRAW7 iface, DWORD dwWidth,
328 DWORD dwHeight, DWORD dwBPP,
329 DWORD dwRefreshRate, DWORD dwFlags)
331 ICOM_THIS(IDirectDrawImpl, iface);
335 TRACE("(%p)->(%ldx%ldx%ld,%ld Hz,%08lx)\n",This,dwWidth,dwHeight,dwBPP,dwRefreshRate,dwFlags);
336 hr = User_DirectDraw_SetDisplayMode(iface, dwWidth, dwHeight, dwBPP,
337 dwRefreshRate, dwFlags);
341 XVIDMODE_DDRAW_PRIV_VAR(priv, This);
342 XF86VidModeModeInfo* new_mode;
343 WND *tmpWnd = WIN_FindWndPtr(This->window);
344 Window x11Wnd = X11DRV_WND_GetXWindow(tmpWnd);
345 WIN_ReleaseWndPtr(tmpWnd);
347 new_mode = choose_mode(dwWidth, dwHeight, dwRefreshRate, dwFlags);
349 if (new_mode != NULL && new_mode != priv->xvidmode.current_mode)
351 priv->xvidmode.current_mode = new_mode;
352 set_display_mode(priv->xvidmode.current_mode);
354 if (PROFILE_GetWineIniBool( "x11drv", "DXGrab", 0)) {
355 /* Confine cursor movement (risky, but the user asked for it) */
356 TSXGrabPointer(display, x11Wnd, True, 0, GrabModeAsync, GrabModeAsync, x11Wnd, None, CurrentTime);
363 static ICOM_VTABLE(IDirectDraw7) XVidMode_DirectDraw_VTable =
365 Main_DirectDraw_QueryInterface,
366 Main_DirectDraw_AddRef,
367 Main_DirectDraw_Release,
368 Main_DirectDraw_Compact,
369 Main_DirectDraw_CreateClipper,
370 Main_DirectDraw_CreatePalette,
371 Main_DirectDraw_CreateSurface,
372 Main_DirectDraw_DuplicateSurface,
373 User_DirectDraw_EnumDisplayModes,
374 Main_DirectDraw_EnumSurfaces,
375 Main_DirectDraw_FlipToGDISurface,
376 User_DirectDraw_GetCaps,
377 Main_DirectDraw_GetDisplayMode,
378 Main_DirectDraw_GetFourCCCodes,
379 Main_DirectDraw_GetGDISurface,
380 Main_DirectDraw_GetMonitorFrequency,
381 Main_DirectDraw_GetScanLine,
382 Main_DirectDraw_GetVerticalBlankStatus,
383 Main_DirectDraw_Initialize,
384 XVidMode_DirectDraw_RestoreDisplayMode,
385 Main_DirectDraw_SetCooperativeLevel,
386 XVidMode_DirectDraw_SetDisplayMode,
387 Main_DirectDraw_WaitForVerticalBlank,
388 Main_DirectDraw_GetAvailableVidMem,
389 Main_DirectDraw_GetSurfaceFromDC,
390 Main_DirectDraw_RestoreAllSurfaces,
391 Main_DirectDraw_TestCooperativeLevel,
392 XVidMode_DirectDraw_GetDeviceIdentifier,
393 Main_DirectDraw_StartModeTest,
394 Main_DirectDraw_EvaluateMode
397 #endif /* HAVE_LIBXXF86VM */