Const-ify a mask.
[wine] / dlls / ddraw / ddraw_user.c
1 /*      DirectDraw driver for User-based primary surfaces
2  *
3  * Copyright 2000-2001 TransGaming Technologies Inc.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  */
19
20 #include "config.h"
21
22 #include <assert.h>
23 #include <stdarg.h>
24 #include <string.h>
25
26 #define NONAMELESSUNION
27 #define NONAMELESSSTRUCT
28
29 #define CONST_VTABLE
30
31 #include "windef.h"
32 #include "winbase.h"
33 #include "wingdi.h"
34 #include "winuser.h"
35 #include "ddraw.h"
36 #include "ddraw_private.h"
37 #include "wine/debug.h"
38
39 WINE_DEFAULT_DEBUG_CHANNEL(ddraw);
40
41 static const IDirectDraw7Vtbl User_DirectDraw_VTable;
42
43 static const DDDEVICEIDENTIFIER2 user_device =
44 {
45     "display",
46     "User (and GDI)",
47     { { 0x00010001, 0x00010001 } },
48     0, 0, 0, 0,
49     /* fe38440c-8969-4283-bc73-749e7bc3c2eb */
50     {0xfe38440c,0x8969,0x428e, {0x73,0xbc,0x74,0x9e,0x7b,0xc3,0xc2,0xeb}},
51     0
52 };
53
54 static const DDPIXELFORMAT pixelformats[] =
55 {
56     /* 8bpp paletted */
57     { sizeof(DDPIXELFORMAT), DDPF_RGB|DDPF_PALETTEINDEXED8, 0, { 8 } },
58     /* 15bpp 5/5/5 */
59     { sizeof(DDPIXELFORMAT), DDPF_RGB, 0, { 16 }, { 0x7C00 }, { 0x3E0 },
60       { 0x1F } },
61     /* 16bpp 5/6/5 */
62     { sizeof(DDPIXELFORMAT), DDPF_RGB, 0, { 16 }, { 0xF800 }, { 0x7E0 },
63       { 0x1F } },
64     /* 24bpp 8/8/8 */
65     { sizeof(DDPIXELFORMAT), DDPF_RGB, 0, { 24 }, { 0xFF0000 },
66       { 0x00FF00 }, { 0x0000FF } },
67     /* 32bpp 8/8/8 */
68     { sizeof(DDPIXELFORMAT), DDPF_RGB, 0, { 32 }, { 0xFF0000 },
69       { 0x00FF00 }, { 0x0000FF } }
70 };
71
72 HRESULT User_DirectDraw_Create(const GUID* pGUID, LPDIRECTDRAW7* pIface,
73                                      IUnknown* pUnkOuter, BOOL ex);
74 HRESULT User_DirectDraw_Initialize(IDirectDrawImpl*, const GUID*);
75
76 static const ddraw_driver user_driver =
77 {
78     &user_device,
79     10,
80     User_DirectDraw_Create,
81     User_DirectDraw_Initialize
82 };
83
84 BOOL DDRAW_User_Init(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpv)
85 {
86     if (fdwReason == DLL_PROCESS_ATTACH)
87         DDRAW_register_driver(&user_driver);
88
89     return TRUE;
90 }
91
92 static const DDPIXELFORMAT* pixelformat_for_depth(DWORD depth)
93 {
94     switch (depth)
95     {
96     case  8: return pixelformats + 0;
97     case 15: return pixelformats + 1;
98     case 16: return pixelformats + 2;
99     case 24: return pixelformats + 3;
100     case 32: return pixelformats + 4;
101     default: return NULL;
102     }
103 }
104
105 /* Not called from the vtable. */
106 HRESULT User_DirectDraw_Construct(IDirectDrawImpl *This, BOOL ex)
107 {
108     HRESULT hr;
109     DWORD depth;
110     HDC hDC;
111
112     TRACE("(%p,%d)\n",This,ex);
113
114     hr = Main_DirectDraw_Construct(This, ex);
115     if (FAILED(hr)) return hr;
116
117     This->final_release = User_DirectDraw_final_release;
118
119     This->create_primary    = User_DirectDraw_create_primary;
120     This->create_backbuffer = User_DirectDraw_create_backbuffer;
121
122     hDC = CreateDCA("DISPLAY", NULL, NULL, NULL);
123     depth = GetDeviceCaps(hDC, BITSPIXEL) * GetDeviceCaps(hDC, PLANES);
124     DeleteDC(hDC);
125
126     This->width       = GetSystemMetrics(SM_CXSCREEN);
127     This->height      = GetSystemMetrics(SM_CYSCREEN);
128     This->pitch       = DDRAW_width_bpp_to_pitch(This->width, depth);
129     This->pixelformat = *pixelformat_for_depth(depth);
130
131     This->orig_width       = This->width;
132     This->orig_height      = This->height;
133     This->orig_pitch       = This->pitch;
134     This->orig_pixelformat = This->pixelformat;
135
136     ICOM_INIT_INTERFACE(This, IDirectDraw7, User_DirectDraw_VTable);
137
138     /* capabilities */
139 #define BLIT_CAPS (DDCAPS_BLT | DDCAPS_BLTCOLORFILL | DDCAPS_BLTDEPTHFILL \
140           | DDCAPS_BLTSTRETCH | DDCAPS_CANBLTSYSMEM | DDCAPS_CANCLIP      \
141           | DDCAPS_CANCLIPSTRETCHED | DDCAPS_COLORKEY                     \
142           | DDCAPS_COLORKEYHWASSIST | DDCAPS_OVERLAY | DDCAPS_OVERLAYSTRETCH)
143 #define CKEY_CAPS (DDCKEYCAPS_DESTBLT | DDCKEYCAPS_SRCBLT)
144 #define FX_CAPS (DDFXCAPS_BLTALPHA | DDFXCAPS_BLTMIRRORLEFTRIGHT        \
145                 | DDFXCAPS_BLTMIRRORUPDOWN | DDFXCAPS_BLTROTATION90     \
146                 | DDFXCAPS_BLTSHRINKX | DDFXCAPS_BLTSHRINKXN            \
147                 | DDFXCAPS_BLTSHRINKY | DDFXCAPS_BLTSHRINKXN            \
148                 | DDFXCAPS_BLTSTRETCHX | DDFXCAPS_BLTSTRETCHXN          \
149                 | DDFXCAPS_BLTSTRETCHY | DDFXCAPS_BLTSTRETCHYN)
150     This->caps.dwCaps |= DDCAPS_GDI | DDCAPS_PALETTE | BLIT_CAPS;
151     if( opengl_initialized )
152     {
153         /* Hack for D3D code */
154         This->caps.dwCaps |= DDCAPS_3D;
155     }
156     This->caps.dwCaps2 |= DDCAPS2_CERTIFIED | DDCAPS2_NOPAGELOCKREQUIRED |
157                           DDCAPS2_PRIMARYGAMMA | DDCAPS2_WIDESURFACES;
158     This->caps.dwCKeyCaps |= CKEY_CAPS;
159     This->caps.dwFXCaps |= FX_CAPS;
160     This->caps.dwPalCaps |= DDPCAPS_8BIT | DDPCAPS_PRIMARYSURFACE;
161     This->caps.dwVidMemTotal = 16*1024*1024;
162     This->caps.dwVidMemFree = 16*1024*1024;
163     This->caps.dwSVBCaps |= BLIT_CAPS;
164     This->caps.dwSVBCKeyCaps |= CKEY_CAPS;
165     This->caps.dwSVBFXCaps |= FX_CAPS;
166     This->caps.dwVSBCaps |= BLIT_CAPS;
167     This->caps.dwVSBCKeyCaps |= CKEY_CAPS;
168     This->caps.dwVSBFXCaps |= FX_CAPS;
169     This->caps.dwSSBCaps |= BLIT_CAPS;
170     This->caps.dwSSBCKeyCaps |= CKEY_CAPS;
171     This->caps.dwSSBFXCaps |= FX_CAPS;
172     This->caps.ddsCaps.dwCaps |= DDSCAPS_ALPHA | DDSCAPS_BACKBUFFER |
173                                  DDSCAPS_FLIP | DDSCAPS_FRONTBUFFER |
174                                  DDSCAPS_OFFSCREENPLAIN | DDSCAPS_PALETTE |
175                                  DDSCAPS_PRIMARYSURFACE | DDSCAPS_SYSTEMMEMORY |
176                                  DDSCAPS_VIDEOMEMORY | DDSCAPS_VISIBLE;
177     if( opengl_initialized )
178     {
179         /* Hacks for D3D code */
180         This->caps.ddsCaps.dwCaps |= DDSCAPS_3DDEVICE | DDSCAPS_MIPMAP | DDSCAPS_TEXTURE | DDSCAPS_ZBUFFER;
181     }
182     
183     This->caps.ddsOldCaps.dwCaps = This->caps.ddsCaps.dwCaps;
184 #undef BLIT_CAPS
185 #undef CKEY_CAPS
186 #undef FX_CAPS
187
188     return S_OK;
189 }
190
191 /* This function is called from DirectDrawCreate(Ex) on the most-derived
192  * class to start construction.
193  * Not called from the vtable. */
194 HRESULT User_DirectDraw_Create(const GUID* pGUID, LPDIRECTDRAW7* pIface,
195                                IUnknown* pUnkOuter, BOOL ex)
196 {
197     HRESULT hr;
198     IDirectDrawImpl* This;
199
200     assert(pUnkOuter == NULL);
201
202     This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
203                      sizeof(IDirectDrawImpl) + sizeof(User_DirectDrawImpl));
204     if (This == NULL) return E_OUTOFMEMORY;
205
206     /* Note that this relation does *not* hold true if the DD object was
207      * CoCreateInstanced then Initialized. */
208     This->private = (User_DirectDrawImpl *)(This+1);
209
210     /* Initialize the DDCAPS structure */
211     This->caps.dwSize = sizeof(This->caps);
212
213     hr = User_DirectDraw_Construct(This, ex);
214     if (FAILED(hr))
215         HeapFree(GetProcessHeap(), 0, This);
216     else
217         *pIface = ICOM_INTERFACE(This, IDirectDraw7);
218
219     return hr;
220 }
221
222 /* This function is called from Uninit_DirectDraw_Initialize on the
223  * most-derived-class to start initialization.
224  * Not called from the vtable. */
225 HRESULT User_DirectDraw_Initialize(IDirectDrawImpl *This, const GUID* guid)
226 {
227     HRESULT hr;
228     This->private = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
229                               sizeof(User_DirectDrawImpl));
230     if (This->private == NULL) return E_OUTOFMEMORY;
231
232     /* Initialize the DDCAPS structure */
233     This->caps.dwSize = sizeof(This->caps);
234
235     hr = User_DirectDraw_Construct(This, TRUE); /* XXX ex? */
236     if (FAILED(hr))
237     {
238         HeapFree(GetProcessHeap(), 0, This->private);
239         return hr;
240     }
241
242     return DD_OK;
243 }
244
245 /* Called from an internal function pointer. */
246 void User_DirectDraw_final_release(IDirectDrawImpl *This)
247 {
248     Main_DirectDraw_final_release(This);
249 }
250
251 /* Compact: generic */
252 /* CreateClipper: generic */
253 /* CreatePalette: generic (with callback) */
254 /* CreateSurface: generic (with callbacks) */
255
256 HRESULT
257 User_DirectDraw_create_primary(IDirectDrawImpl* This,
258                                const DDSURFACEDESC2* pDDSD,
259                                LPDIRECTDRAWSURFACE7* ppSurf,
260                                IUnknown* pUnkOuter)
261 {
262     return User_DirectDrawSurface_Create(This, pDDSD, ppSurf, pUnkOuter);
263 }
264
265 HRESULT
266 User_DirectDraw_create_backbuffer(IDirectDrawImpl* This,
267                                   const DDSURFACEDESC2* pDDSD,
268                                   LPDIRECTDRAWSURFACE7* ppSurf,
269                                   IUnknown* pUnkOuter,
270                                   IDirectDrawSurfaceImpl* primary)
271 {
272     return User_DirectDrawSurface_Create(This, pDDSD, ppSurf, pUnkOuter);
273 }
274
275 /* DuplicateSurface: generic */
276
277 /* Originally derived from Xlib_IDirectDraw2Impl_EnumDisplayModes.
278  *
279  * The depths are whatever DIBsections support on the client side.
280  * Should they be limited by screen depth?
281  */
282 HRESULT WINAPI
283 User_DirectDraw_EnumDisplayModes(LPDIRECTDRAW7 iface, DWORD dwFlags,
284                                  LPDDSURFACEDESC2 pDDSD, LPVOID context,
285                                  LPDDENUMMODESCALLBACK2 callback)
286 {
287     DDSURFACEDESC2 callback_sd;
288     DEVMODEW DevModeW;
289     const DDPIXELFORMAT* pixelformat;
290
291     int i;
292
293     TRACE("(%p)->(0x%08lx,%p,%p,%p)\n",iface,dwFlags,pDDSD,context,callback);
294
295     ZeroMemory(&callback_sd, sizeof(callback_sd));
296     callback_sd.dwSize = sizeof(callback_sd);
297
298     callback_sd.dwFlags = DDSD_HEIGHT|DDSD_WIDTH|DDSD_PIXELFORMAT|DDSD_CAPS
299         | DDSD_PITCH;
300
301     if (dwFlags & DDEDM_REFRESHRATES)
302         callback_sd.dwFlags |= DDSD_REFRESHRATE;
303
304     callback_sd.u2.dwRefreshRate = 60.0;
305
306     i = 0;
307     while (EnumDisplaySettingsExW(NULL, i, &DevModeW, 0))
308     {
309         callback_sd.dwHeight = DevModeW.dmPelsHeight;
310         callback_sd.dwWidth = DevModeW.dmPelsWidth;
311         if (DevModeW.dmFields&DM_DISPLAYFREQUENCY)
312         {
313             callback_sd.u2.dwRefreshRate = DevModeW.dmDisplayFrequency;
314         }
315
316         TRACE("- mode: %ldx%ld\n", callback_sd.dwWidth, callback_sd.dwHeight);
317         
318         pixelformat = pixelformat_for_depth(DevModeW.dmBitsPerPel);
319         callback_sd.u1.lPitch
320             = DDRAW_width_bpp_to_pitch(DevModeW.dmPelsWidth,
321                                        pixelformat->u1.dwRGBBitCount);
322
323         callback_sd.u4.ddpfPixelFormat = *pixelformat;
324
325         callback_sd.ddsCaps.dwCaps = 0;
326         if (pixelformat->dwFlags & DDPF_PALETTEINDEXED8) /* ick */
327             callback_sd.ddsCaps.dwCaps |= DDSCAPS_PALETTE;
328
329         TRACE(" - %2ld bpp, R=%08lx G=%08lx B=%08lx\n",
330             callback_sd.u4.ddpfPixelFormat.u1.dwRGBBitCount,
331             callback_sd.u4.ddpfPixelFormat.u2.dwRBitMask,
332             callback_sd.u4.ddpfPixelFormat.u3.dwGBitMask,
333             callback_sd.u4.ddpfPixelFormat.u4.dwBBitMask);
334         if (callback(&callback_sd, context) == DDENUMRET_CANCEL)
335             return DD_OK;
336         i++;
337     }
338
339     return DD_OK;
340 }
341
342 /* EnumSurfaces: generic */
343 /* FlipToGDISurface: ??? */
344
345 #if 0
346 HRESULT WINAPI
347 User_DirectDraw_GetCaps(LPDIRECTDRAW7 iface, LPDDCAPS pDriverCaps,
348                         LPDDCAPS pHELCaps)
349 {
350 /* Based on my guesses for what is appropriate with some clues from the
351  * NVidia driver. Not everything is actually implemented yet.
352  * NV has but we don't: Overlays, Video Ports, DDCAPS_READSCANLINE,
353  * DDCAPS2_CERTIFIED (heh), DDSCAPS2_NONLOCALVIDMEM, DDSCAPS2_COPYFOURCC.
354  * It actually has no FX alpha caps.
355  * Oddly, it doesn't list DDPCAPS_PRIMARYSURFACE.
356  * And the HEL caps make little sense.
357  */
358 #define BLIT_CAPS (DDCAPS_BLT | DDCAPS_BLTCOLORFILL | DDCAPS_BLTDEPTHFILL \
359           | DDCAPS_BLTSTRETCH | DDCAPS_CANBLTSYSMEM | DDCAPS_CANCLIP      \
360           | DDCAPS_CANCLIPSTRETCHED | DDCAPS_COLORKEY                     \
361           | DDCAPS_COLORKEYHWASSIST | DDCAPS_OVERLAY | DDCAPS_OVERLAYSTRETCH)
362
363 #define CKEY_CAPS (DDCKEYCAPS_DESTBLT | DDCKEYCAPS_SRCBLT)
364
365 #define FX_CAPS (DDFXCAPS_BLTALPHA | DDFXCAPS_BLTMIRRORLEFTRIGHT        \
366                 | DDFXCAPS_BLTMIRRORUPDOWN | DDFXCAPS_BLTROTATION90     \
367                 | DDFXCAPS_BLTSHRINKX | DDFXCAPS_BLTSHRINKXN            \
368                 | DDFXCAPS_BLTSHRINKY | DDFXCAPS_BLTSHRINKXN            \
369                 | DDFXCAPS_BLTSTRETCHX | DDFXCAPS_BLTSTRETCHXN          \
370                 | DDFXCAPS_BLTSTRETCHY | DDFXCAPS_BLTSTRETCHYN)
371
372 #if 0
373 #define ROPS { SRCCOPY, SRCPAINT, SRCAND, SRCINVERT, SRCERASE, NOTSRCCOPY, \
374         NOTSRCERASE, MERGEPAINT, BLACKNESS, WHITENESS, }
375 #else
376 #define ROPS { 0, }
377 #endif
378
379     static const DDCAPS caps =
380     { sizeof(DDCAPS),
381       DDCAPS_3D | DDCAPS_GDI | DDCAPS_PALETTE | BLIT_CAPS,
382       DDCAPS2_CANMANAGETEXTURE | DDCAPS2_CANRENDERWINDOWED | DDCAPS2_CERTIFIED
383       | DDCAPS2_NOPAGELOCKREQUIRED | DDCAPS2_PRIMARYGAMMA
384       | DDCAPS2_WIDESURFACES,
385       CKEY_CAPS,
386       FX_CAPS,
387       0, /* dwFXAlphaCaps */
388       DDPCAPS_8BIT | DDPCAPS_PRIMARYSURFACE,
389       0, /* dwSVCaps */
390       0, /* ? dwAlphaBitConstBitDepths */
391       0, /* ? dwAlphaBitPixelPitDepths */
392       0, /* ? dwAlphaBltSurfaceBitDepths */
393       0, /* ? dwAlphaOverlayConstBitDepths */
394       0, /* ? dwAlphaOverlayPixelBitDepths */
395       0, /* ? dwAlphaOverlaySurfaceBitDepths */
396       DDBD_16, /* ? dwZBufferBitDepths */
397       16*1024*1024, /* dwVidMemTotal */
398       16*1024*1024, /* dwVidMemFree */
399       0, /* dwMaxVisibleOverlays */
400       0, /* dwCurrVisibleOverlays */
401       0, /* dwNumFourCCCodes */
402       0, /* dwAlignBoundarySrc */
403       0, /* dwAlignSizeSrc */
404       0, /* dwAlignBoundaryDest */
405       0, /* dwAlignSizeDest */
406       0, /* dwAlignStrideAlign */
407       ROPS, /* XXX dwRops[DD_ROP_SPACE] */
408       { 0, }, /* XXX ddsOldCaps */
409       1000, /* dwMinOverlayStretch */
410       1000, /* dwMaxOverlayStretch */
411       1000, /* dwMinLiveVideoStretch */
412       1000, /* dwMaxLiveVideoStretch */
413       1000, /* dwMinHwCodecStretch */
414       1000, /* dwMaxHwCodecStretch */
415       0, 0, 0, /* dwReserved1, 2, 3 */
416       BLIT_CAPS, /* dwSVBCaps */
417       CKEY_CAPS, /* dwSVBCKeyCaps */
418       FX_CAPS, /* dwSVBFXCaps */
419       ROPS, /* dwSVBRops */
420       BLIT_CAPS, /* dwVSBCaps */
421       CKEY_CAPS, /* dwVSBCKeyCaps */
422       FX_CAPS, /* dwVSBFXCaps */
423       ROPS, /* dwVSBRops */
424       BLIT_CAPS, /* dwSSBCaps */
425       CKEY_CAPS, /* dwSSBCKeyCaps */
426       FX_CAPS, /* dwSSBFXCaps */
427       ROPS, /* dwSSBRops */
428       0, /* dwMaxVideoPorts */
429       0, /* dwCurrVideoPorts */
430       0, /* ? dwSVBCaps2 */
431       BLIT_CAPS, /* ? dwNLVBCaps */
432       0, /* ? dwNLVBCaps2 */
433       CKEY_CAPS, /* dwNLVBCKeyCaps */
434       FX_CAPS, /* dwNLVBFXCaps */
435       ROPS, /* dwNLVBRops */
436       { /* ddsCaps */
437           DDSCAPS_3DDEVICE | DDSCAPS_ALPHA | DDSCAPS_BACKBUFFER | DDSCAPS_FLIP
438           | DDSCAPS_FRONTBUFFER | DDSCAPS_MIPMAP | DDSCAPS_OFFSCREENPLAIN
439           | DDSCAPS_PALETTE | DDSCAPS_PRIMARYSURFACE | DDSCAPS_SYSTEMMEMORY
440           | DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY | DDSCAPS_VISIBLE
441           | DDSCAPS_ZBUFFER,
442           DDSCAPS2_CUBEMAP,
443           0,
444           0
445       }
446     };
447
448 #undef BLIT_CAPS
449 #undef CKEY_CAPS
450 #undef FX_CAPS
451 #undef ROPS
452
453     IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
454
455     TRACE("(%p)->(%p,%p)\n",This,pDriverCaps,pHELCaps);
456
457     if (pDriverCaps != NULL)
458         DD_STRUCT_COPY_BYSIZE(pDriverCaps,&caps);
459
460     if (pHELCaps != NULL)
461         DD_STRUCT_COPY_BYSIZE(pHELCaps,&caps);
462
463     return DD_OK;
464 }
465 #endif
466
467 HRESULT WINAPI
468 User_DirectDraw_GetDeviceIdentifier(LPDIRECTDRAW7 iface,
469                                     LPDDDEVICEIDENTIFIER2 pDDDI,
470                                     DWORD dwFlags)
471 {
472     TRACE("(%p)->(%p,%08lx)\n",iface,pDDDI,dwFlags);
473     *pDDDI = user_device;
474     return DD_OK;
475 }
476
477 /* GetDisplayMode: generic */
478 /* GetFourCCCodes: generic */
479 /* GetGDISurface: ??? */
480 /* GetMonitorFrequency: generic */
481 /* GetScanLine: generic */
482 /* GetSurfaceFromDC: generic */
483 /* GetVerticalBlankStatus: generic */
484 /* Initialize: generic */
485 /* RestoreAllSurfaces: generic */
486 /* RestoreDisplayMode: generic */
487 /* SetCooperativeLevel: ??? */
488
489 HRESULT WINAPI
490 User_DirectDraw_SetDisplayMode(LPDIRECTDRAW7 iface, DWORD dwWidth,
491                                DWORD dwHeight, DWORD dwBPP,
492                                DWORD dwRefreshRate, DWORD dwFlags)
493 {
494     IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
495
496     const DDPIXELFORMAT* pixelformat;
497     DEVMODEW devmode;
498     LONG pitch;
499
500     TRACE("(%p)->(%ldx%ldx%ld,%ld Hz,%08lx)\n",This,dwWidth,dwHeight,dwBPP,dwRefreshRate,dwFlags);
501     devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
502     devmode.dmBitsPerPel = dwBPP;
503     devmode.dmPelsWidth  = dwWidth;
504     devmode.dmPelsHeight = dwHeight;
505     /* '0' means default frequency */
506     if (dwRefreshRate != 0) 
507     {
508         devmode.dmFields |= DM_DISPLAYFREQUENCY;
509         devmode.dmDisplayFrequency = dwRefreshRate;
510     }
511     if (ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL)
512         return DDERR_INVALIDMODE;
513
514     pixelformat = pixelformat_for_depth(dwBPP);
515     if (pixelformat == NULL)
516     {
517         assert(0);
518         return DDERR_GENERIC;
519     }
520
521     pitch = DDRAW_width_bpp_to_pitch(dwWidth, dwBPP);
522     return Main_DirectDraw_SetDisplayMode(iface, dwWidth, dwHeight, pitch,
523                                           dwRefreshRate, dwFlags, pixelformat);
524 }
525
526 /* StartModeTest: ??? */
527 /* TestCooperativeLevel: generic? */
528 /* WaitForVerticalBlank: ??? */
529
530 static const IDirectDraw7Vtbl User_DirectDraw_VTable =
531 {
532     Main_DirectDraw_QueryInterface,
533     Main_DirectDraw_AddRef,
534     Main_DirectDraw_Release,
535     Main_DirectDraw_Compact,
536     Main_DirectDraw_CreateClipper,
537     Main_DirectDraw_CreatePalette,
538     Main_DirectDraw_CreateSurface,
539     Main_DirectDraw_DuplicateSurface,
540     User_DirectDraw_EnumDisplayModes,
541     Main_DirectDraw_EnumSurfaces,
542     Main_DirectDraw_FlipToGDISurface,
543     Main_DirectDraw_GetCaps,
544     Main_DirectDraw_GetDisplayMode,
545     Main_DirectDraw_GetFourCCCodes,
546     Main_DirectDraw_GetGDISurface,
547     Main_DirectDraw_GetMonitorFrequency,
548     Main_DirectDraw_GetScanLine,
549     Main_DirectDraw_GetVerticalBlankStatus,
550     Main_DirectDraw_Initialize,
551     Main_DirectDraw_RestoreDisplayMode,
552     Main_DirectDraw_SetCooperativeLevel,
553     User_DirectDraw_SetDisplayMode,
554     Main_DirectDraw_WaitForVerticalBlank,
555     Main_DirectDraw_GetAvailableVidMem,
556     Main_DirectDraw_GetSurfaceFromDC,
557     Main_DirectDraw_RestoreAllSurfaces,
558     Main_DirectDraw_TestCooperativeLevel,
559     User_DirectDraw_GetDeviceIdentifier,
560     Main_DirectDraw_StartModeTest,
561     Main_DirectDraw_EvaluateMode
562 };