Better implementation of GetCalendarInfo{A,W}, not perfect.
[wine] / dlls / ddraw / ddraw / main.c
1 /*              DirectDraw IDirectDraw interface (generic)
2  *
3  * Copyright 1997-2000 Marcus Meissner
4  * Copyright 1998-2000 Lionel Ulmer (most of Direct3D stuff)
5  * Copyright 2000-2001 TransGaming Technologies Inc.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21
22 /*
23  * This file contains all the interface functions that are shared between
24  * all interfaces. Or better, it is a "common stub" library for the
25  * IDirectDraw* objects
26  */
27
28 #include "config.h"
29 #include "wine/port.h"
30
31 #include <assert.h>
32 #include <string.h>
33
34 #include "winerror.h"
35 #include "ddraw.h"
36 #include "d3d.h"
37 #include "wine/debug.h"
38
39 #include "ddraw_private.h"
40 #include "ddraw/main.h"
41 #include "dclipper/main.h"
42 #include "dpalette/main.h"
43 #include "dsurface/main.h"
44 #include "dsurface/dib.h"
45 #include "dsurface/fakezbuffer.h"
46
47 WINE_DEFAULT_DEBUG_CHANNEL(ddraw);
48
49 extern ICOM_VTABLE(IDirectDraw) DDRAW_IDirectDraw_VTable;
50 extern ICOM_VTABLE(IDirectDraw2) DDRAW_IDirectDraw2_VTable;
51 extern ICOM_VTABLE(IDirectDraw4) DDRAW_IDirectDraw4_VTable;
52
53 static void DDRAW_UnsubclassWindow(IDirectDrawImpl* This);
54
55 static void Main_DirectDraw_DeleteSurfaces(IDirectDrawImpl* This);
56 static void Main_DirectDraw_DeleteClippers(IDirectDrawImpl* This);
57 static void Main_DirectDraw_DeletePalettes(IDirectDrawImpl* This);
58 static void LosePrimarySurface(IDirectDrawImpl* This);
59
60 static const char ddProp[] = "WINE_DDRAW_Property";
61
62 /* Not called from the vtable. */
63 HRESULT Main_DirectDraw_Construct(IDirectDrawImpl *This, BOOL ex)
64 {
65     /* NOTE: The creator must use HEAP_ZERO_MEMORY or equivalent. */
66     This->ref = 1;
67     This->ex = ex;
68
69     if (ex) This->local.dwLocalFlags |= DDRAWILCL_DIRECTDRAW7;
70     This->local.dwProcessId = GetCurrentProcessId();
71
72     This->final_release = Main_DirectDraw_final_release;
73
74     This->create_palette = Main_DirectDrawPalette_Create;
75
76     This->create_offscreen = Main_create_offscreen;
77     This->create_texture   = Main_create_texture;
78     This->create_zbuffer   = Main_create_zbuffer;
79     /* There are no generic versions of create_{primary,backbuffer}. */
80
81     ICOM_INIT_INTERFACE(This, IDirectDraw,  DDRAW_IDirectDraw_VTable);
82     ICOM_INIT_INTERFACE(This, IDirectDraw2, DDRAW_IDirectDraw2_VTable);
83     ICOM_INIT_INTERFACE(This, IDirectDraw4, DDRAW_IDirectDraw4_VTable);
84     /* There is no generic implementation of IDD7 */
85
86     return DD_OK;
87 }
88
89 void Main_DirectDraw_final_release(IDirectDrawImpl* This)
90 {
91     if (IsWindow(This->window))
92     {
93         if (GetPropA(This->window, ddProp))
94             DDRAW_UnsubclassWindow(This);
95         else
96             FIXME("this shouldn't happen, right?\n");
97     }
98
99     Main_DirectDraw_DeleteSurfaces(This);
100     Main_DirectDraw_DeleteClippers(This);
101     Main_DirectDraw_DeletePalettes(This);
102     if (This->local.lpGbl && This->local.lpGbl->lpExclusiveOwner == &This->local)
103     {
104         This->local.lpGbl->lpExclusiveOwner = NULL;
105         if (This->set_exclusive_mode)
106             This->set_exclusive_mode(This, FALSE);
107     }
108 }
109
110 /* There is no Main_DirectDraw_Create. */
111
112 ULONG WINAPI Main_DirectDraw_AddRef(LPDIRECTDRAW7 iface) {
113     ICOM_THIS(IDirectDrawImpl,iface);
114     TRACE("(%p)->() incrementing from %lu.\n", This, This->ref );
115
116     return ++This->ref;
117 }
118
119 ULONG WINAPI Main_DirectDraw_Release(LPDIRECTDRAW7 iface) {
120     ULONG ref;
121     ICOM_THIS(IDirectDrawImpl,iface);
122     TRACE("(%p)->() decrementing from %lu.\n", This, This->ref );
123
124     ref = --This->ref;
125
126     if (ref == 0)
127     {
128         if (This->final_release != NULL)
129             This->final_release(This);
130
131         /* We free the private. This is an artifact of the fact that I don't
132          * have the destructors set up correctly. */
133         if (This->private != (This+1))
134             HeapFree(GetProcessHeap(), 0, This->private);
135
136         HeapFree(GetProcessHeap(), 0, This);
137     }
138
139     return ref;
140 }
141
142 /* TODO: need to support IDirect3D. */
143 HRESULT WINAPI Main_DirectDraw_QueryInterface(
144     LPDIRECTDRAW7 iface,REFIID refiid,LPVOID *obj
145 ) {
146     ICOM_THIS(IDirectDrawImpl,iface);
147     TRACE("(%p)->(%s,%p)\n", This, debugstr_guid(refiid), obj);
148
149     if ( IsEqualGUID( &IID_IUnknown, refiid )
150          || IsEqualGUID( &IID_IDirectDraw7, refiid ) )
151     {
152         *obj = ICOM_INTERFACE(This, IDirectDraw7);
153     }
154     else if ( IsEqualGUID( &IID_IDirectDraw, refiid ) )
155     {
156         *obj = ICOM_INTERFACE(This, IDirectDraw);
157     }
158     else if ( IsEqualGUID( &IID_IDirectDraw2, refiid ) )
159     {
160         *obj = ICOM_INTERFACE(This, IDirectDraw2);
161     }
162     else if ( IsEqualGUID( &IID_IDirectDraw4, refiid ) )
163     {
164         *obj = ICOM_INTERFACE(This, IDirectDraw4);
165     }
166 #ifdef HAVE_OPENGL
167     else if ( IsEqualGUID( &IID_IDirect3D3, refiid ) )
168     {
169         return create_direct3d3(obj, This);
170     }
171     else if ( IsEqualGUID( &IID_IDirect3D2, refiid ) )
172     {
173         return create_direct3d2(obj, This);
174     }
175     else if ( IsEqualGUID( &IID_IDirect3D, refiid ) )
176     {
177         return create_direct3d(obj, This);
178     }
179 #endif
180     else
181     {
182         FIXME("(%p)->(%s,%p): no interface\n",This,debugstr_guid(refiid),obj);
183         return E_NOINTERFACE;
184     }
185
186     IDirectDraw7_AddRef(iface);
187     return S_OK;
188 }
189
190 /* MSDN: "not currently implemented". */
191 HRESULT WINAPI Main_DirectDraw_Compact(LPDIRECTDRAW7 iface)
192 {
193     TRACE("(%p)\n", iface);
194
195     return DD_OK;
196 }
197
198 HRESULT WINAPI Main_DirectDraw_CreateClipper(LPDIRECTDRAW7 iface,
199                                              DWORD dwFlags,
200                                              LPDIRECTDRAWCLIPPER *ppClipper,
201                                              IUnknown *pUnkOuter)
202 {
203     ICOM_THIS(IDirectDrawImpl, iface);
204     HRESULT hr;
205
206     TRACE("(%p)->(0x%lx, %p, %p)\n", iface, dwFlags, ppClipper, pUnkOuter);
207
208     hr = DirectDrawCreateClipper(dwFlags, ppClipper, pUnkOuter);
209     if (FAILED(hr)) return hr;
210
211     /* dwFlags is passed twice, apparently an API wart. */
212     hr = IDirectDrawClipper_Initialize(*ppClipper,
213                                        ICOM_INTERFACE(This, IDirectDraw),
214                                        dwFlags);
215     if (FAILED(hr))
216     {
217         IDirectDrawClipper_Release(*ppClipper);
218         return hr;
219     }
220
221     return DD_OK;
222 }
223
224 HRESULT WINAPI
225 Main_DirectDraw_CreatePalette(LPDIRECTDRAW7 iface, DWORD dwFlags,
226                               LPPALETTEENTRY palent,
227                               LPDIRECTDRAWPALETTE* ppPalette,
228                               LPUNKNOWN pUnknown)
229 {
230     ICOM_THIS(IDirectDrawImpl,iface);
231     LPDIRECTDRAWPALETTE pPalette;
232     HRESULT hr;
233
234     TRACE("(%p)->(%08lx,%p,%p,%p)\n",This,dwFlags,palent,ppPalette,pUnknown);
235
236     if (ppPalette == NULL) return E_POINTER; /* unchecked */
237     if (pUnknown != NULL) return CLASS_E_NOAGGREGATION; /* unchecked */
238
239     hr = This->create_palette(This, dwFlags, &pPalette, pUnknown);
240     if (FAILED(hr)) return hr;
241
242     hr = IDirectDrawPalette_SetEntries(pPalette, 0, 0,
243                                        Main_DirectDrawPalette_Size(dwFlags),
244                                        palent);
245     if (FAILED(hr))
246     {
247         IDirectDrawPalette_Release(pPalette);
248         return hr;
249     }
250     else
251     {
252         *ppPalette = pPalette;
253         return DD_OK;
254     }
255 }
256
257 HRESULT
258 Main_create_offscreen(IDirectDrawImpl* This, const DDSURFACEDESC2* pDDSD,
259                       LPDIRECTDRAWSURFACE7* ppSurf, LPUNKNOWN pOuter)
260 {
261     assert(pOuter == NULL);
262
263     return DIB_DirectDrawSurface_Create(This, pDDSD, ppSurf, pOuter);
264 }
265
266 HRESULT
267 Main_create_texture(IDirectDrawImpl* This, const DDSURFACEDESC2* pDDSD,
268                     LPDIRECTDRAWSURFACE7* ppSurf, LPUNKNOWN pOuter,
269                     DWORD dwMipMapLevel)
270 {
271     assert(pOuter == NULL);
272
273     return DIB_DirectDrawSurface_Create(This, pDDSD, ppSurf, pOuter);
274 }
275
276 HRESULT
277 Main_create_zbuffer(IDirectDrawImpl* This, const DDSURFACEDESC2* pDDSD,
278                     LPDIRECTDRAWSURFACE7* ppSurf, LPUNKNOWN pOuter)
279 {
280     assert(pOuter == NULL);
281
282     return FakeZBuffer_DirectDrawSurface_Create(This, pDDSD, ppSurf, pOuter);
283 }
284
285 /* Does the texture surface described in pDDSD have any smaller mipmaps? */
286 static BOOL more_mipmaps(const DDSURFACEDESC2 *pDDSD)
287 {
288     return ((pDDSD->dwFlags & DDSD_MIPMAPCOUNT) && pDDSD->u2.dwMipMapCount > 1
289             && (pDDSD->dwWidth > 1 || pDDSD->dwHeight > 1));
290 }
291
292 /* Create a texture surface along with any of its mipmaps. */
293 static HRESULT
294 create_texture(IDirectDrawImpl* This, const DDSURFACEDESC2 *pDDSD,
295                LPDIRECTDRAWSURFACE7* ppSurf, LPUNKNOWN pUnkOuter)
296 {
297     DDSURFACEDESC2 ddsd;
298     DWORD mipmap_level = 0;
299     HRESULT hr;
300
301     assert(pUnkOuter == NULL);
302
303     /* is this check right? (pixelformat can be copied from primary) */
304     if ((pDDSD->dwFlags&(DDSD_HEIGHT|DDSD_WIDTH)) != (DDSD_HEIGHT|DDSD_WIDTH))
305         return DDERR_INVALIDPARAMS;
306
307     ddsd.dwSize = sizeof(ddsd);
308     DD_STRUCT_COPY_BYSIZE((&ddsd),pDDSD);
309
310     if (!(ddsd.dwFlags & DDSD_PIXELFORMAT))
311     {
312         ddsd.u4.ddpfPixelFormat = This->pixelformat;
313     }
314
315     if (!(ddsd.dwFlags & DDSD_PITCH))
316     {
317         ddsd.u1.lPitch = DDRAW_width_bpp_to_pitch(ddsd.dwWidth,
318                                                   GET_BPP(ddsd)*8);
319     }
320
321     ddsd.dwFlags |= DDSD_PITCH | DDSD_PIXELFORMAT;
322
323     hr = This->create_texture(This, &ddsd, ppSurf, pUnkOuter, mipmap_level);
324     if (FAILED(hr)) return hr;
325
326     /* Create attached mipmaps if required. */
327     if (more_mipmaps(&ddsd))
328     {
329         LPDIRECTDRAWSURFACE7 mipmap;
330         LPDIRECTDRAWSURFACE7 prev_mipmap;
331         DDSURFACEDESC2 mipmap_surface_desc;
332
333         prev_mipmap = *ppSurf;
334         IDirectDrawSurface7_AddRef(prev_mipmap);
335         mipmap_surface_desc = ddsd;
336         mipmap_surface_desc.ddsCaps.dwCaps2 |= DDSCAPS2_MIPMAPSUBLEVEL;
337
338         while (more_mipmaps(&mipmap_surface_desc))
339         {
340             mipmap_level++;
341
342             mipmap_surface_desc.u2.dwMipMapCount--;
343
344             if (mipmap_surface_desc.dwWidth > 1)
345                 mipmap_surface_desc.dwWidth /= 2;
346
347             if (mipmap_surface_desc.dwHeight > 1)
348                 mipmap_surface_desc.dwHeight /= 2;
349
350             mipmap_surface_desc.u1.lPitch
351                 = DDRAW_width_bpp_to_pitch(mipmap_surface_desc.dwWidth,
352                                            GET_BPP(ddsd)*8);
353
354             hr = This->create_texture(This, &mipmap_surface_desc, &mipmap,
355                                       pUnkOuter, mipmap_level);
356             if (FAILED(hr))
357             {
358                 IDirectDrawSurface7_Release(prev_mipmap);
359                 IDirectDrawSurface7_Release(*ppSurf);
360                 return hr;
361             }
362
363             IDirectDrawSurface7_AddAttachedSurface(prev_mipmap, mipmap);
364             IDirectDrawSurface7_Release(prev_mipmap);
365             prev_mipmap = mipmap;
366         }
367
368         IDirectDrawSurface7_Release(prev_mipmap);
369     }
370
371     return DD_OK;
372 }
373
374 /* Creates a primary surface and any indicated backbuffers. */
375 static HRESULT
376 create_primary(IDirectDrawImpl* This, LPDDSURFACEDESC2 pDDSD,
377                LPDIRECTDRAWSURFACE7* ppSurf, LPUNKNOWN pUnkOuter)
378 {
379     DDSURFACEDESC2 ddsd;
380     HRESULT hr;
381
382     assert(pUnkOuter == NULL);
383
384     if (This->primary_surface != NULL)
385         return DDERR_PRIMARYSURFACEALREADYEXISTS;
386
387     /* as documented (what about pitch?) */
388     if (pDDSD->dwFlags & (DDSD_HEIGHT|DDSD_WIDTH|DDSD_PIXELFORMAT))
389         return DDERR_INVALIDPARAMS;
390
391     ddsd.dwSize = sizeof(ddsd);
392     DD_STRUCT_COPY_BYSIZE((&ddsd),pDDSD);
393     ddsd.dwFlags |= DDSD_HEIGHT | DDSD_WIDTH | DDSD_PITCH | DDSD_PIXELFORMAT;
394     ddsd.dwHeight = This->height;
395     ddsd.dwWidth = This->width;
396     ddsd.u1.lPitch = This->pitch;
397     ddsd.u4.ddpfPixelFormat = This->pixelformat;
398     ddsd.ddsCaps.dwCaps |= DDSCAPS_LOCALVIDMEM | DDSCAPS_VIDEOMEMORY
399         | DDSCAPS_VISIBLE | DDSCAPS_FRONTBUFFER;
400
401     if ((ddsd.dwFlags & DDSD_BACKBUFFERCOUNT) && ddsd.dwBackBufferCount > 0)
402         ddsd.ddsCaps.dwCaps |= DDSCAPS_FLIP;
403
404     hr = This->create_primary(This, &ddsd, ppSurf, pUnkOuter);
405     if (FAILED(hr)) return hr;
406
407     if (ddsd.dwFlags & DDSD_BACKBUFFERCOUNT)
408     {
409         IDirectDrawSurfaceImpl* primary;
410         LPDIRECTDRAWSURFACE7 pPrev;
411         DWORD i;
412
413         ddsd.dwFlags &= ~DDSD_BACKBUFFERCOUNT;
414         ddsd.ddsCaps.dwCaps &= ~(DDSCAPS_VISIBLE | DDSCAPS_PRIMARYSURFACE
415                                  | DDSCAPS_BACKBUFFER);
416
417         primary = ICOM_OBJECT(IDirectDrawSurfaceImpl,IDirectDrawSurface7,
418                               *ppSurf);
419         pPrev = *ppSurf;
420         IDirectDrawSurface7_AddRef(pPrev);
421
422         for (i=0; i < ddsd.dwBackBufferCount; i++)
423         {
424             LPDIRECTDRAWSURFACE7 pBack;
425
426             if (i == 0)
427                 ddsd.ddsCaps.dwCaps |= DDSCAPS_BACKBUFFER;
428             else
429                 ddsd.ddsCaps.dwCaps &= ~DDSCAPS_BACKBUFFER;
430
431             hr = This->create_backbuffer(This, &ddsd, &pBack, pUnkOuter,
432                                          primary);
433
434             if (FAILED(hr))
435             {
436                 IDirectDraw7_Release(pPrev);
437                 IDirectDraw7_Release(*ppSurf);
438                 return hr;
439             }
440
441             IDirectDrawSurface7_AddAttachedSurface(pPrev, pBack);
442             IDirectDrawSurface7_Release(pPrev);
443             pPrev = pBack;
444         }
445
446         IDirectDrawSurface7_Release(pPrev);
447     }
448
449     This->primary_surface = (IDirectDrawSurfaceImpl *)*ppSurf;
450
451     return DD_OK;
452 }
453
454 static HRESULT
455 create_offscreen(IDirectDrawImpl* This, LPDDSURFACEDESC2 pDDSD,
456                  LPDIRECTDRAWSURFACE7* ppSurf, LPUNKNOWN pUnkOuter)
457 {
458     DDSURFACEDESC2 ddsd;
459     HRESULT hr;
460
461     /* is this check right? (pixelformat can be copied from primary) */
462     if ((pDDSD->dwFlags&(DDSD_HEIGHT|DDSD_WIDTH)) != (DDSD_HEIGHT|DDSD_WIDTH))
463         return DDERR_INVALIDPARAMS;
464
465     ddsd.dwSize = sizeof(ddsd);
466     DD_STRUCT_COPY_BYSIZE((&ddsd),pDDSD);
467
468     if (!(ddsd.dwFlags & DDSD_PIXELFORMAT))
469     {
470         ddsd.u4.ddpfPixelFormat = This->pixelformat;
471     }
472
473     if (!(ddsd.dwFlags & DDSD_PITCH))
474     {
475         ddsd.u1.lPitch = DDRAW_width_bpp_to_pitch(ddsd.dwWidth,
476                                                   GET_BPP(ddsd)*8);
477     }
478
479     ddsd.dwFlags |= DDSD_PITCH | DDSD_PIXELFORMAT;
480
481     hr = This->create_offscreen(This, &ddsd, ppSurf, pUnkOuter);
482     if (FAILED(hr)) return hr;
483
484     return hr;
485 }
486
487 HRESULT WINAPI
488 Main_DirectDraw_CreateSurface(LPDIRECTDRAW7 iface, LPDDSURFACEDESC2 pDDSD,
489                               LPDIRECTDRAWSURFACE7 *ppSurf,
490                               IUnknown *pUnkOuter)
491 {
492     HRESULT hr;
493     ICOM_THIS(IDirectDrawImpl, iface);
494
495     TRACE("(%p)->(%p,%p,%p)\n",This,pDDSD,ppSurf,pUnkOuter);
496     TRACE("Requested Caps: 0x%lx\n", pDDSD->ddsCaps.dwCaps);
497
498     if (pUnkOuter != NULL) {
499         FIXME("outer != NULL?\n");
500         return CLASS_E_NOAGGREGATION; /* unchecked */
501     }
502
503     if (!(pDDSD->dwFlags & DDSD_CAPS)) {
504         /* DVIDEO.DLL does forget the DDSD_CAPS flag ... *sigh* */
505         pDDSD->dwFlags |= DDSD_CAPS;
506     }
507
508     if (ppSurf == NULL) {
509         FIXME("You want to get back a surface? Don't give NULL ptrs!\n");
510         return E_POINTER; /* unchecked */
511     }
512
513     if (pDDSD->ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE)
514     {
515         /* create primary surface & backbuffers */
516         hr = create_primary(This, pDDSD, ppSurf, pUnkOuter);
517     }
518     else if (pDDSD->ddsCaps.dwCaps & DDSCAPS_BACKBUFFER)
519     {
520        /* create backbuffer surface */
521        hr = This->create_backbuffer(This, pDDSD, ppSurf, pUnkOuter, NULL);
522     }
523     else if (pDDSD->ddsCaps.dwCaps & DDSCAPS_OFFSCREENPLAIN)
524     {
525         /* create offscreenplain surface */
526         hr = create_offscreen(This, pDDSD, ppSurf, pUnkOuter);
527     }
528     else if (pDDSD->ddsCaps.dwCaps & DDSCAPS_ZBUFFER)
529     {
530         /* create z-buffer */
531         hr = This->create_zbuffer(This, pDDSD, ppSurf, pUnkOuter);
532     }
533     else if (pDDSD->ddsCaps.dwCaps & DDSCAPS_TEXTURE)
534     {
535         /* create texture */
536         hr = create_texture(This, pDDSD, ppSurf, pUnkOuter);
537     }
538     else
539     {
540         /* Otherwise, assume offscreenplain surface */
541         FIXME("App didn't request a valid surface type - assuming offscreenplain\n");
542         hr = create_offscreen(This, pDDSD, ppSurf, pUnkOuter);
543     }
544
545     if (FAILED(hr)) {
546         FIXME("failed surface creation with code 0x%08lx\n",hr);
547         return hr;
548     }
549
550     return DD_OK;
551 }
552
553 HRESULT WINAPI
554 Main_DirectDraw_DuplicateSurface(LPDIRECTDRAW7 iface, LPDIRECTDRAWSURFACE7 src,
555                                  LPDIRECTDRAWSURFACE7* dst)
556 {
557     ICOM_THIS(IDirectDrawImpl,iface);
558
559     IDirectDrawSurfaceImpl *pSrc = ICOM_OBJECT(IDirectDrawSurfaceImpl,
560                                                IDirectDrawSurface7, src);
561
562     TRACE("(%p)->(%p,%p)\n",This,src,dst);
563
564     return pSrc->duplicate_surface(pSrc, dst);
565 }
566
567 /* EnumDisplayModes */
568
569 BOOL Main_DirectDraw_DDPIXELFORMAT_Match(const DDPIXELFORMAT *requested,
570                                          const DDPIXELFORMAT *provided)
571 {
572     /* Some flags must be present in both or neither for a match. */
573     static const DWORD must_match = DDPF_PALETTEINDEXED1 | DDPF_PALETTEINDEXED2
574         | DDPF_PALETTEINDEXED4 | DDPF_PALETTEINDEXED8 | DDPF_FOURCC
575         | DDPF_ZBUFFER | DDPF_STENCILBUFFER;
576
577     if ((requested->dwFlags & provided->dwFlags) != requested->dwFlags)
578         return FALSE;
579
580     if ((requested->dwFlags & must_match) != (provided->dwFlags & must_match))
581         return FALSE;
582
583     if (requested->dwFlags & DDPF_FOURCC)
584         if (requested->dwFourCC != provided->dwFourCC)
585             return FALSE;
586
587     if (requested->dwFlags & (DDPF_RGB|DDPF_YUV|DDPF_ZBUFFER|DDPF_ALPHA
588                               |DDPF_LUMINANCE|DDPF_BUMPDUDV))
589         if (requested->u1.dwRGBBitCount != provided->u1.dwRGBBitCount)
590             return FALSE;
591
592     if (requested->dwFlags & (DDPF_RGB|DDPF_YUV|DDPF_STENCILBUFFER
593                               |DDPF_LUMINANCE|DDPF_BUMPDUDV))
594         if (requested->u2.dwRBitMask != provided->u2.dwRBitMask)
595             return FALSE;
596
597     if (requested->dwFlags & (DDPF_RGB|DDPF_YUV|DDPF_ZBUFFER|DDPF_BUMPDUDV))
598         if (requested->u3.dwGBitMask != provided->u3.dwGBitMask)
599             return FALSE;
600
601     /* I could be wrong about the bumpmapping. MSDN docs are vague. */
602     if (requested->dwFlags & (DDPF_RGB|DDPF_YUV|DDPF_STENCILBUFFER
603                               |DDPF_BUMPDUDV))
604         if (requested->u4.dwBBitMask != provided->u4.dwBBitMask)
605             return FALSE;
606
607     if (requested->dwFlags & (DDPF_ALPHAPIXELS|DDPF_ZPIXELS))
608         if (requested->u5.dwRGBAlphaBitMask != provided->u5.dwRGBAlphaBitMask)
609             return FALSE;
610
611     return TRUE;
612 }
613
614 BOOL Main_DirectDraw_DDSD_Match(const DDSURFACEDESC2* requested,
615                                 const DDSURFACEDESC2* provided)
616 {
617     struct compare_info
618     {
619         DWORD flag;
620         ptrdiff_t offset;
621         size_t size;
622     };
623
624 #define CMP(FLAG, FIELD)                                \
625         { DDSD_##FLAG, offsetof(DDSURFACEDESC2, FIELD), \
626           sizeof(((DDSURFACEDESC2 *)(NULL))->FIELD) }
627
628     static const struct compare_info compare[] = {
629         CMP(ALPHABITDEPTH, dwAlphaBitDepth),
630         CMP(BACKBUFFERCOUNT, dwBackBufferCount),
631         CMP(CAPS, ddsCaps),
632         CMP(CKDESTBLT, ddckCKDestBlt),
633         CMP(CKDESTOVERLAY, u3.ddckCKDestOverlay),
634         CMP(CKSRCBLT, ddckCKSrcBlt),
635         CMP(CKSRCOVERLAY, ddckCKSrcOverlay),
636         CMP(HEIGHT, dwHeight),
637         CMP(LINEARSIZE, u1.dwLinearSize),
638         CMP(LPSURFACE, lpSurface),
639         CMP(MIPMAPCOUNT, u2.dwMipMapCount),
640         CMP(PITCH, u1.lPitch),
641         /* PIXELFORMAT: manual */
642         CMP(REFRESHRATE, u2.dwRefreshRate),
643         CMP(TEXTURESTAGE, dwTextureStage),
644         CMP(WIDTH, dwWidth),
645         /* ZBUFFERBITDEPTH: "obsolete" */
646     };
647
648 #undef CMP
649
650     int i;
651
652     if ((requested->dwFlags & provided->dwFlags) != requested->dwFlags)
653         return FALSE;
654
655     for (i=0; i < sizeof(compare)/sizeof(compare[0]); i++)
656     {
657         if (requested->dwFlags & compare[i].flag
658             && memcmp((const char *)provided + compare[i].offset,
659                       (const char *)requested + compare[i].offset,
660                       compare[i].size) != 0)
661             return FALSE;
662     }
663
664     if (requested->dwFlags & DDSD_PIXELFORMAT)
665     {
666         if (!Main_DirectDraw_DDPIXELFORMAT_Match(&requested->u4.ddpfPixelFormat,
667                                                  &provided->u4.ddpfPixelFormat))
668             return FALSE;
669     }
670
671     return TRUE;
672 }
673
674 #define DDENUMSURFACES_SEARCHTYPE (DDENUMSURFACES_CANBECREATED|DDENUMSURFACES_DOESEXIST)
675 #define DDENUMSURFACES_MATCHTYPE (DDENUMSURFACES_ALL|DDENUMSURFACES_MATCH|DDENUMSURFACES_NOMATCH)
676
677 /* This should be extended so that it can be used by
678  * IDirectDrawSurface7::EnumAttachedSurfaces. */
679 HRESULT
680 Main_DirectDraw_EnumExistingSurfaces(IDirectDrawImpl *This, DWORD dwFlags,
681                                      LPDDSURFACEDESC2 lpDDSD2, LPVOID context,
682                                      LPDDENUMSURFACESCALLBACK7 callback)
683 {
684     IDirectDrawSurfaceImpl *surf;
685     BOOL all, nomatch;
686
687     /* A NULL lpDDSD2 is permitted if we are enumerating all surfaces anyway */
688     if (lpDDSD2 == NULL && !(dwFlags & DDENUMSURFACES_ALL))
689         return DDERR_INVALIDPARAMS;
690
691     all = dwFlags & DDENUMSURFACES_ALL;
692     nomatch = dwFlags & DDENUMSURFACES_NOMATCH;
693
694     for (surf = This->surfaces; surf != NULL; surf = surf->next_ddraw)
695     {
696         if (all
697             || (nomatch != Main_DirectDraw_DDSD_Match(lpDDSD2,
698                                                       &surf->surface_desc)))
699         {
700             LPDIRECTDRAWSURFACE7 surface = ICOM_INTERFACE(surf,
701                                                           IDirectDrawSurface7);
702
703             /* BOGUS! Violates COM rules, but MSDN says so. */
704             IDirectDrawSurface7_AddRef(surface);
705
706             if (callback(surface, &surf->surface_desc, context)
707                 == DDENUMRET_CANCEL)
708                 break;
709         }
710     }
711
712     return DD_OK;
713 }
714
715 /* I really don't understand how this is supposed to work.
716  * We only consider dwHeight, dwWidth and ddpfPixelFormat.dwFlags. */
717 HRESULT
718 Main_DirectDraw_EnumCreateableSurfaces(IDirectDrawImpl *This, DWORD dwFlags,
719                                        LPDDSURFACEDESC2 lpDDSD2,
720                                        LPVOID context,
721                                        LPDDENUMSURFACESCALLBACK7 callback)
722 {
723     FIXME("This isn't going to work.\n");
724
725     if ((dwFlags & DDENUMSURFACES_MATCHTYPE) != DDENUMSURFACES_MATCH)
726         return DDERR_INVALIDPARAMS;
727
728     /* TODO: implement this.
729      * Does this work before SCL is called?
730      * Does it only consider off-screen surfaces?
731      */
732
733     return E_FAIL;
734 }
735
736 /* For unsigned x. 0 is not a power of 2. */
737 #define IS_POW_2(x) (((x) & ((x) - 1)) == 0)
738
739 HRESULT WINAPI
740 Main_DirectDraw_EnumSurfaces(LPDIRECTDRAW7 iface, DWORD dwFlags,
741                              LPDDSURFACEDESC2 lpDDSD2, LPVOID context,
742                              LPDDENUMSURFACESCALLBACK7 callback)
743 {
744     ICOM_THIS(IDirectDrawImpl, iface);
745     TRACE("(%p)->(0x%lx, %p, %p, %p)\n", iface, dwFlags, lpDDSD2, context,
746           callback);
747
748     if (callback == NULL)
749         return DDERR_INVALIDPARAMS;
750
751     if (dwFlags & ~(DDENUMSURFACES_SEARCHTYPE|DDENUMSURFACES_MATCHTYPE))
752         return DDERR_INVALIDPARAMS;
753
754     if (!IS_POW_2(dwFlags & DDENUMSURFACES_SEARCHTYPE)
755         || !IS_POW_2(dwFlags & DDENUMSURFACES_MATCHTYPE))
756         return DDERR_INVALIDPARAMS;
757
758     if (dwFlags & DDENUMSURFACES_DOESEXIST)
759     {
760         return Main_DirectDraw_EnumExistingSurfaces(This, dwFlags, lpDDSD2,
761                                                     context, callback);
762     }
763     else
764     {
765         return Main_DirectDraw_EnumCreateableSurfaces(This, dwFlags, lpDDSD2,
766                                                       context, callback);
767     }
768 }
769
770 HRESULT WINAPI
771 Main_DirectDraw_EvaluateMode(LPDIRECTDRAW7 iface,DWORD a,DWORD* b)
772 {
773     ICOM_THIS(IDirectDrawImpl,iface);
774     FIXME("(%p)->() stub\n", This);
775
776     return DD_OK;
777 }
778
779 HRESULT WINAPI
780 Main_DirectDraw_FlipToGDISurface(LPDIRECTDRAW7 iface)
781 {
782     ICOM_THIS(IDirectDrawImpl,iface);
783     TRACE("(%p)->()\n",This);
784     return DD_OK;
785 }
786
787 HRESULT WINAPI
788 Main_DirectDraw_GetCaps(LPDIRECTDRAW7 iface, LPDDCAPS pDriverCaps,
789                         LPDDCAPS pHELCaps)
790 {
791     ICOM_THIS(IDirectDrawImpl,iface);
792     TRACE("(%p,%p,%p), stub\n",This,pDriverCaps,pHELCaps);
793     if (pDriverCaps != NULL)
794         DD_STRUCT_COPY_BYSIZE(pDriverCaps,&This->caps);
795     if (pHELCaps != NULL)
796         DD_STRUCT_COPY_BYSIZE(pHELCaps,&This->caps);
797     return DD_OK;
798 }
799
800 /* GetCaps */
801 /* GetDeviceIdentifier */
802 /* GetDIsplayMode */
803
804 HRESULT WINAPI
805 Main_DirectDraw_GetFourCCCodes(LPDIRECTDRAW7 iface, LPDWORD pNumCodes,
806                                LPDWORD pCodes)
807 {
808     ICOM_THIS(IDirectDrawImpl,iface);
809     if (*pNumCodes) {
810             *pNumCodes=0;
811     }
812     FIXME("(%p,%p,%p), stub\n",This,pNumCodes,pCodes);
813     return DD_OK;
814 }
815
816 HRESULT WINAPI
817 Main_DirectDraw_GetGDISurface(LPDIRECTDRAW7 iface,
818                               LPDIRECTDRAWSURFACE7 *lplpGDIDDSSurface)
819 {
820     ICOM_THIS(IDirectDrawImpl,iface);
821     TRACE("(%p)->(%p)\n", This, lplpGDIDDSSurface);
822     TRACE("returning primary (%p)\n", This->primary_surface);
823     *lplpGDIDDSSurface = ICOM_INTERFACE(This->primary_surface, IDirectDrawSurface7);
824     if (*lplpGDIDDSSurface)
825         IDirectDrawSurface7_AddRef(*lplpGDIDDSSurface);
826     return DD_OK;
827 }
828
829 HRESULT WINAPI
830 Main_DirectDraw_GetMonitorFrequency(LPDIRECTDRAW7 iface,LPDWORD freq)
831 {
832     ICOM_THIS(IDirectDrawImpl,iface);
833     FIXME("(%p)->(%p) returns 60 Hz always\n",This,freq);
834     *freq = 60*100; /* 60 Hz */
835     return DD_OK;
836 }
837
838 HRESULT WINAPI
839 Main_DirectDraw_GetScanLine(LPDIRECTDRAW7 iface, LPDWORD lpdwScanLine)
840 {
841     ICOM_THIS(IDirectDrawImpl,iface);
842     FIXME("(%p)->(%p)\n", This, lpdwScanLine);
843
844     *lpdwScanLine = 1;
845
846     return DD_OK;
847 }
848
849 HRESULT WINAPI
850 Main_DirectDraw_GetSurfaceFromDC(LPDIRECTDRAW7 iface, HDC hdc,
851                                  LPDIRECTDRAWSURFACE7 *lpDDS)
852 {
853     ICOM_THIS(IDirectDrawImpl,iface);
854     FIXME("(%p)->(%08ld,%p)\n", This, (DWORD) hdc, lpDDS);
855
856     return DD_OK;
857 }
858
859 HRESULT WINAPI
860 Main_DirectDraw_GetVerticalBlankStatus(LPDIRECTDRAW7 iface, LPBOOL status)
861 {
862     ICOM_THIS(IDirectDrawImpl,iface);
863     TRACE("(%p)->(%p)\n",This,status);
864     *status = TRUE;
865     return DD_OK;
866 }
867
868 /* If we were not initialised then Uninit_Main_IDirectDraw7_Initialize would
869  * have been called instead. */
870 HRESULT WINAPI
871 Main_DirectDraw_Initialize(LPDIRECTDRAW7 iface, LPGUID lpGuid)
872 {
873     TRACE("(%p)->(%s)\n", iface, debugstr_guid(lpGuid));
874
875     return DDERR_ALREADYINITIALIZED;
876 }
877
878 HRESULT WINAPI
879 Main_DirectDraw_RestoreAllSurfaces(LPDIRECTDRAW7 iface)
880 {
881     ICOM_THIS(IDirectDrawImpl,iface);
882     IDirectDrawSurfaceImpl* surf;
883
884     TRACE("(%p)->()\n", This);
885
886     for (surf = This->surfaces; surf != NULL; surf = surf->next_ddraw)
887         IDirectDrawSurface7_Restore(ICOM_INTERFACE(surf, IDirectDrawSurface7));
888
889     return DD_OK;
890 }
891
892 static void DDRAW_SubclassWindow(IDirectDrawImpl* This)
893 {
894     /* Well we don't actually subclass the window yet. */
895     SetPropA(This->window, ddProp, (LONG)This);
896 }
897
898 static void DDRAW_UnsubclassWindow(IDirectDrawImpl* This)
899 {
900     RemovePropA(This->window, ddProp);
901 }
902
903 HRESULT WINAPI
904 Main_DirectDraw_SetCooperativeLevel(LPDIRECTDRAW7 iface, HWND hwnd,
905                                     DWORD cooplevel)
906 {
907     ICOM_THIS(IDirectDrawImpl,iface);
908
909     FIXME("(%p)->(%08lx,%08lx)\n",This,(DWORD)hwnd,cooplevel);
910     DDRAW_dump_cooperativelevel(cooplevel);
911
912     /* Makes realMYST test happy. */
913     if (This->cooperative_level == cooplevel
914         && This->window == hwnd)
915         return DD_OK;
916
917     /* XXX "It cannot be reset while the process has surfaces or palettes
918      * created." Otherwise the window can be changed??? 
919      * 
920      * This appears to be wrong - comment it out for now.
921     if (This->window)
922         return DDERR_HWNDALREADYSET; 
923     */
924
925     if (!(cooplevel & (DDSCL_EXCLUSIVE|DDSCL_NORMAL)))
926         return DDERR_INVALIDPARAMS;
927
928     This->window = hwnd;
929     This->cooperative_level = cooplevel;
930
931     This->local.hWnd = hwnd;
932     This->local.dwLocalFlags |= DDRAWILCL_SETCOOPCALLED;
933     /* not entirely sure about these */
934     if (cooplevel & DDSCL_EXCLUSIVE)     This->local.dwLocalFlags |= DDRAWILCL_HASEXCLUSIVEMODE;
935     if (cooplevel & DDSCL_FULLSCREEN)    This->local.dwLocalFlags |= DDRAWILCL_ISFULLSCREEN;
936     if (cooplevel & DDSCL_ALLOWMODEX)    This->local.dwLocalFlags |= DDRAWILCL_ALLOWMODEX;
937     if (cooplevel & DDSCL_MULTITHREADED) This->local.dwLocalFlags |= DDRAWILCL_MULTITHREADED;
938     if (cooplevel & DDSCL_FPUSETUP)      This->local.dwLocalFlags |= DDRAWILCL_FPUSETUP;
939     if (cooplevel & DDSCL_FPUPRESERVE)   This->local.dwLocalFlags |= DDRAWILCL_FPUPRESERVE;
940
941     if (This->local.lpGbl) {
942         /* assume that this app is the active app (in wine, there's
943          * probably only one app per global ddraw object anyway) */
944         if (cooplevel & DDSCL_EXCLUSIVE) This->local.lpGbl->lpExclusiveOwner = &This->local;
945         else if (This->local.lpGbl->lpExclusiveOwner == &This->local)
946             This->local.lpGbl->lpExclusiveOwner = NULL;
947         if (This->set_exclusive_mode)
948             This->set_exclusive_mode(This, (cooplevel & DDSCL_EXCLUSIVE) != 0);
949     }
950
951     ShowWindow(hwnd, SW_SHOW);
952
953     DDRAW_SubclassWindow(This);
954
955     /* TODO Does it also get resized to the current screen size? */
956
957     return DD_OK;
958 }
959
960 HRESULT WINAPI
961 Main_DirectDraw_SetDisplayMode(LPDIRECTDRAW7 iface, DWORD dwWidth,
962                                DWORD dwHeight, LONG lPitch,
963                                DWORD dwRefreshRate, DWORD dwFlags,
964                                const DDPIXELFORMAT* pixelformat)
965 {
966     short screenX;
967     short screenY;
968     
969     ICOM_THIS(IDirectDrawImpl,iface);
970
971     TRACE("(%p)->SetDisplayMode(%ld,%ld)\n",This,dwWidth,dwHeight);
972
973     if (!(This->cooperative_level & DDSCL_EXCLUSIVE))
974         return DDERR_NOEXCLUSIVEMODE;
975
976     if (!IsWindow(This->window))
977         return DDERR_GENERIC; /* unchecked */
978
979     LosePrimarySurface(This);
980
981     screenX = GetSystemMetrics(SM_CXSCREEN);
982     screenY = GetSystemMetrics(SM_CYSCREEN);
983     
984     This->width = dwWidth;
985     This->height = dwHeight;
986     This->pitch = lPitch;
987     This->pixelformat = *pixelformat;
988
989     /* Position the window in the center of the screen - don't center for now */
990     /* MoveWindow(This->window, (screenX-dwWidth)/2, (screenY-dwHeight)/2, 
991                   dwWidth, dwHeight, TRUE);*/
992     MoveWindow(This->window, 0, 0, dwWidth, dwHeight, TRUE);
993
994     SetFocus(This->window);
995
996     return DD_OK;
997 }
998
999 HRESULT WINAPI
1000 Main_DirectDraw_RestoreDisplayMode(LPDIRECTDRAW7 iface)
1001 {
1002     ICOM_THIS(IDirectDrawImpl,iface);
1003
1004     TRACE("(%p)\n",This);
1005     if (!(This->cooperative_level & DDSCL_EXCLUSIVE))
1006         return DDERR_NOEXCLUSIVEMODE;
1007
1008     /* Lose the primary surface if the resolution changes. */
1009     if (This->orig_width != This->width || This->orig_height != This->height
1010         || This->orig_pitch != This->pitch
1011         || This->orig_pixelformat.dwFlags != This->pixelformat.dwFlags
1012         || !Main_DirectDraw_DDPIXELFORMAT_Match(&This->pixelformat,
1013                                                 &This->orig_pixelformat))
1014     {
1015         LosePrimarySurface(This);
1016     }
1017
1018     /* TODO Move the window back where it belongs. */
1019
1020     return DD_OK;
1021 }
1022
1023 HRESULT WINAPI
1024 Main_DirectDraw_WaitForVerticalBlank(LPDIRECTDRAW7 iface, DWORD dwFlags,
1025                                      HANDLE h)
1026 {
1027     ICOM_THIS(IDirectDrawImpl,iface);
1028     FIXME("(%p)->(flags=0x%08lx,handle=0x%08x)\n",This,dwFlags,h);
1029     return DD_OK;
1030 }
1031
1032 HRESULT WINAPI
1033 Main_DirectDraw_GetDisplayMode(LPDIRECTDRAW7 iface, LPDDSURFACEDESC2 pDDSD)
1034 {
1035     ICOM_THIS(IDirectDrawImpl,iface);
1036     TRACE("(%p)->GetDisplayMode(%p)\n",This,pDDSD);
1037
1038     pDDSD->dwFlags = DDSD_HEIGHT|DDSD_WIDTH|DDSD_PITCH|DDSD_PIXELFORMAT|DDSD_REFRESHRATE;
1039     pDDSD->dwHeight = This->height;
1040     pDDSD->dwWidth = This->width;
1041     pDDSD->u1.lPitch = This->pitch;
1042     pDDSD->u2.dwRefreshRate = 60;
1043     pDDSD->u4.ddpfPixelFormat = This->pixelformat;
1044     pDDSD->ddsCaps.dwCaps = 0;
1045
1046     return DD_OK;
1047 }
1048
1049 HRESULT WINAPI
1050 Main_DirectDraw_GetAvailableVidMem(LPDIRECTDRAW7 iface, LPDDSCAPS2 ddscaps,
1051                                    LPDWORD total, LPDWORD free)
1052 {
1053     ICOM_THIS(IDirectDrawImpl,iface);
1054     TRACE("(%p)->(%p,%p,%p)\n", This,ddscaps,total,free);
1055
1056     /* We have 16 MB videomemory */
1057     if (total)  *total= 16*1024*1024;
1058     if (free)   *free = 16*1024*1024;
1059     return DD_OK;
1060 }
1061
1062 HRESULT WINAPI Main_DirectDraw_TestCooperativeLevel(LPDIRECTDRAW7 iface) {
1063     ICOM_THIS(IDirectDrawImpl,iface);
1064     TRACE("(%p)->(): stub\n", This);
1065
1066     return DD_OK;
1067 }
1068
1069 HRESULT WINAPI
1070 Main_DirectDraw_StartModeTest(LPDIRECTDRAW7 iface, LPSIZE pModes,
1071                               DWORD dwNumModes, DWORD dwFlags)
1072 {
1073     ICOM_THIS(IDirectDrawImpl,iface);
1074     FIXME("(%p)->() stub\n", This);
1075
1076     return DD_OK;
1077 }
1078
1079 /*** Owned object management. */
1080
1081 void Main_DirectDraw_AddSurface(IDirectDrawImpl* This,
1082                                 IDirectDrawSurfaceImpl* surface)
1083 {
1084     assert(surface->ddraw_owner == NULL || surface->ddraw_owner == This);
1085
1086     surface->ddraw_owner = This;
1087
1088     /* where should it go? */
1089     surface->next_ddraw = This->surfaces;
1090     surface->prev_ddraw = NULL;
1091     if (This->surfaces)
1092         This->surfaces->prev_ddraw = surface;
1093     This->surfaces = surface;
1094 }
1095
1096 void Main_DirectDraw_RemoveSurface(IDirectDrawImpl* This,
1097                                    IDirectDrawSurfaceImpl* surface)
1098 {
1099     assert(surface->ddraw_owner == This);
1100
1101     if (This->surfaces == surface)
1102         This->surfaces = surface->next_ddraw;
1103
1104     if (This->primary_surface == surface)
1105         This->primary_surface = NULL;
1106
1107     if (surface->next_ddraw)
1108         surface->next_ddraw->prev_ddraw = surface->prev_ddraw;
1109     if (surface->prev_ddraw)
1110         surface->prev_ddraw->next_ddraw = surface->next_ddraw;
1111 }
1112
1113 static void Main_DirectDraw_DeleteSurfaces(IDirectDrawImpl* This)
1114 {
1115     while (This->surfaces != NULL)
1116         Main_DirectDrawSurface_ForceDestroy(This->surfaces);
1117 }
1118
1119 void Main_DirectDraw_AddClipper(IDirectDrawImpl* This,
1120                                 IDirectDrawClipperImpl* clipper)
1121 {
1122     assert(clipper->ddraw_owner == NULL || clipper->ddraw_owner == This);
1123
1124     clipper->ddraw_owner = This;
1125
1126     clipper->next_ddraw = This->clippers;
1127     clipper->prev_ddraw = NULL;
1128     if (This->clippers)
1129         This->clippers->prev_ddraw = clipper;
1130     This->clippers = clipper;
1131 }
1132
1133 void Main_DirectDraw_RemoveClipper(IDirectDrawImpl* This,
1134                                    IDirectDrawClipperImpl* clipper)
1135 {
1136     assert(clipper->ddraw_owner == This);
1137
1138     if (This->clippers == clipper)
1139         This->clippers = clipper->next_ddraw;
1140
1141     if (clipper->next_ddraw)
1142         clipper->next_ddraw->prev_ddraw = clipper->prev_ddraw;
1143     if (clipper->prev_ddraw)
1144         clipper->prev_ddraw->next_ddraw = clipper->next_ddraw;
1145 }
1146
1147 static void Main_DirectDraw_DeleteClippers(IDirectDrawImpl* This)
1148 {
1149     while (This->clippers != NULL)
1150         Main_DirectDrawClipper_ForceDestroy(This->clippers);
1151 }
1152
1153 void Main_DirectDraw_AddPalette(IDirectDrawImpl* This,
1154                                 IDirectDrawPaletteImpl* palette)
1155 {
1156     assert(palette->ddraw_owner == NULL || palette->ddraw_owner == This);
1157
1158     palette->ddraw_owner = This;
1159
1160     /* where should it go? */
1161     palette->next_ddraw = This->palettes;
1162     palette->prev_ddraw = NULL;
1163     if (This->palettes)
1164         This->palettes->prev_ddraw = palette;
1165     This->palettes = palette;
1166 }
1167
1168 void Main_DirectDraw_RemovePalette(IDirectDrawImpl* This,
1169                                    IDirectDrawPaletteImpl* palette)
1170 {
1171     assert(palette->ddraw_owner == This);
1172
1173     if (This->palettes == palette)
1174         This->palettes = palette->next_ddraw;
1175
1176     if (palette->next_ddraw)
1177         palette->next_ddraw->prev_ddraw = palette->prev_ddraw;
1178     if (palette->prev_ddraw)
1179         palette->prev_ddraw->next_ddraw = palette->next_ddraw;
1180 }
1181
1182 static void Main_DirectDraw_DeletePalettes(IDirectDrawImpl* This)
1183 {
1184     while (This->palettes != NULL)
1185         Main_DirectDrawPalette_ForceDestroy(This->palettes);
1186 }
1187
1188 /*** ??? */
1189
1190 static void
1191 LoseSurface(IDirectDrawSurfaceImpl *surface)
1192 {
1193     if (surface != NULL) surface->lose_surface(surface);
1194 }
1195
1196 static void
1197 LosePrimarySurface(IDirectDrawImpl *This)
1198 {
1199     /* MSDN: "If another application changes the display mode, the primary
1200      * surface is lost, and the method returns DDERR_SURFACELOST until the
1201      * primary surface is recreated to match the new display mode."
1202      *
1203      * We mark all the primary surfaces as lost as soon as the display
1204      * mode is changed (by any application). */
1205
1206     LoseSurface(This->primary_surface);
1207 }
1208
1209 /******************************************************************************
1210  * Uninitialised DirectDraw functions
1211  * 
1212  * This vtable is used when a DirectDraw object is created with
1213  * CoCreateInstance. The only usable method is Initialize.
1214  */
1215
1216 void Uninit_DirectDraw_final_release(IDirectDrawImpl *This)
1217 {
1218     Main_DirectDraw_final_release(This);
1219 }
1220
1221 static ICOM_VTABLE(IDirectDraw7) Uninit_DirectDraw_VTable;
1222
1223 /* Not called from the vtable. */
1224 HRESULT Uninit_DirectDraw_Construct(IDirectDrawImpl *This, BOOL ex)
1225 {
1226     HRESULT hr;
1227
1228     hr = Main_DirectDraw_Construct(This, ex);
1229     if (FAILED(hr)) return hr;
1230
1231     This->final_release = Uninit_DirectDraw_final_release;
1232     ICOM_INIT_INTERFACE(This, IDirectDraw7, Uninit_DirectDraw_VTable);
1233
1234     return S_OK;
1235 }
1236
1237 HRESULT Uninit_DirectDraw_Create(const GUID* pGUID,
1238                                        LPDIRECTDRAW7* pIface,
1239                                        IUnknown* pUnkOuter, BOOL ex)
1240 {
1241     HRESULT hr;
1242     IDirectDrawImpl* This;
1243
1244     assert(pUnkOuter == NULL); /* XXX no: we must check this */
1245
1246     This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1247                      sizeof(IDirectDrawImpl));
1248     if (This == NULL) return E_OUTOFMEMORY;
1249
1250     hr = Uninit_DirectDraw_Construct(This, ex);
1251     if (FAILED(hr))
1252         HeapFree(GetProcessHeap(), HEAP_ZERO_MEMORY, This);
1253     else
1254         *pIface = ICOM_INTERFACE(This, IDirectDraw7);
1255
1256     return hr;
1257 }
1258
1259 static HRESULT WINAPI
1260 Uninit_DirectDraw_Initialize(LPDIRECTDRAW7 iface, LPGUID pDeviceGuid)
1261 {
1262     const ddraw_driver* driver;
1263     ICOM_THIS(IDirectDrawImpl, iface);
1264
1265     TRACE("(%p)->(%p)\n", iface, pDeviceGuid);
1266
1267     driver = DDRAW_FindDriver(pDeviceGuid);
1268     /* XXX This return value is not documented. (Not checked.) */
1269     if (driver == NULL) return DDERR_INVALIDDIRECTDRAWGUID;
1270
1271     return driver->init(This, pDeviceGuid);
1272 }
1273
1274 static HRESULT WINAPI
1275 Uninit_DirectDraw_Compact(LPDIRECTDRAW7 iface)
1276 {
1277     return DDERR_NOTINITIALIZED;
1278 }
1279
1280 static HRESULT WINAPI
1281 Uninit_DirectDraw_CreateClipper(LPDIRECTDRAW7 iface, DWORD dwFlags,
1282                                 LPDIRECTDRAWCLIPPER *lplpDDClipper,
1283                                 IUnknown *pUnkOuter)
1284
1285 {
1286     return DDERR_NOTINITIALIZED;
1287 }
1288
1289 static HRESULT WINAPI
1290 Uninit_DirectDraw_CreatePalette(LPDIRECTDRAW7 iface, DWORD dwFlags,
1291                                 LPPALETTEENTRY lpColorTable,
1292                                 LPDIRECTDRAWPALETTE *lplpDDPalette,
1293                                 IUnknown *pUnkOuter)
1294 {
1295     return DDERR_NOTINITIALIZED;
1296 }
1297
1298 static HRESULT WINAPI
1299 Uninit_DirectDraw_CreateSurface(LPDIRECTDRAW7 iface,
1300                                 LPDDSURFACEDESC2 lpDDSurfaceDesc,
1301                                 LPDIRECTDRAWSURFACE7 *lplpDDSurface,
1302                                 IUnknown *pUnkOuter)
1303 {
1304     return DDERR_NOTINITIALIZED;
1305 }
1306
1307 static HRESULT WINAPI
1308 Uninit_DirectDraw_DuplicateSurface(LPDIRECTDRAW7 iface,
1309                                    LPDIRECTDRAWSURFACE7 pSurf,
1310                                    LPDIRECTDRAWSURFACE7 *pDupSurf)
1311
1312 {
1313     return DDERR_NOTINITIALIZED;
1314 }
1315
1316 static HRESULT WINAPI
1317 Uninit_DirectDraw_EnumDisplayModes(LPDIRECTDRAW7 iface, DWORD dwFlags,
1318                                    LPDDSURFACEDESC2 lpDDSD,
1319                                    LPVOID context,
1320                                    LPDDENUMMODESCALLBACK2 cb)
1321 {
1322     return DDERR_NOTINITIALIZED;
1323 }
1324
1325 static HRESULT WINAPI
1326 Uninit_DirectDraw_EnumSurfaces(LPDIRECTDRAW7 iface, DWORD dwFlags,
1327                                LPDDSURFACEDESC2 pDDSD, LPVOID context,
1328                                LPDDENUMSURFACESCALLBACK7 cb)
1329 {
1330     return DDERR_NOTINITIALIZED;
1331 }
1332
1333 static HRESULT WINAPI
1334 Uninit_DirectDraw_FlipToGDISurface(LPDIRECTDRAW7 iface)
1335 {
1336     return DDERR_NOTINITIALIZED;
1337 }
1338
1339 static HRESULT WINAPI
1340 Uninit_DirectDraw_GetCaps(LPDIRECTDRAW7 iface, LPDDCAPS pDriverCaps,
1341                           LPDDCAPS pHELCaps)
1342 {
1343     return DDERR_NOTINITIALIZED;
1344 }
1345
1346 static HRESULT WINAPI
1347 Uninit_DirectDraw_GetDisplayMode(LPDIRECTDRAW7 iface,
1348                                  LPDDSURFACEDESC2 pDDSD)
1349 {
1350     return DDERR_NOTINITIALIZED;
1351 }
1352
1353 static HRESULT WINAPI
1354 Uninit_DirectDraw_GetFourCCCodes(LPDIRECTDRAW7 iface, LPDWORD pNumCodes,
1355                                  LPDWORD pCodes)
1356 {
1357     return DDERR_NOTINITIALIZED;
1358 }
1359
1360 static HRESULT WINAPI
1361 Uninit_DirectDraw_GetGDISurface(LPDIRECTDRAW7 iface,
1362                                 LPDIRECTDRAWSURFACE7 *pGDISurf)
1363 {
1364     return DDERR_NOTINITIALIZED;
1365 }
1366
1367 static HRESULT WINAPI
1368 Uninit_DirectDraw_GetMonitorFrequency(LPDIRECTDRAW7 iface, LPDWORD pdwFreq)
1369 {
1370     return DDERR_NOTINITIALIZED;
1371 }
1372
1373 static HRESULT WINAPI
1374 Uninit_DirectDraw_GetScanLine(LPDIRECTDRAW7 iface, LPDWORD pdwScanLine)
1375 {
1376     return DDERR_NOTINITIALIZED;
1377 }
1378
1379 static HRESULT WINAPI
1380 Uninit_DirectDraw_GetVerticalBlankStatus(LPDIRECTDRAW7 iface, PBOOL pbIsInVB)
1381 {
1382     return DDERR_NOTINITIALIZED;
1383 }
1384
1385 static HRESULT WINAPI
1386 Uninit_DirectDraw_RestoreDisplayMode(LPDIRECTDRAW7 iface)
1387 {
1388     return DDERR_NOTINITIALIZED;
1389 }
1390
1391 static HRESULT WINAPI
1392 Uninit_DirectDraw_SetCooperativeLevel(LPDIRECTDRAW7 iface, HWND hWnd,
1393                                       DWORD dwFlags)
1394 {
1395     return DDERR_NOTINITIALIZED;
1396 }
1397
1398 static HRESULT WINAPI
1399 Uninit_DirectDraw_SetDisplayMode(LPDIRECTDRAW7 iface, DWORD dwWidth,
1400                                  DWORD dwHeight, DWORD dwBPP,
1401                                  DWORD dwRefreshRate, DWORD dwFlags)
1402 {
1403     return DDERR_NOTINITIALIZED;
1404 }
1405
1406 static HRESULT WINAPI
1407 Uninit_DirectDraw_WaitForVerticalBlank(LPDIRECTDRAW7 iface, DWORD dwFlags,
1408                                        HANDLE hEvent)
1409 {
1410     return DDERR_NOTINITIALIZED;
1411 }
1412
1413 static HRESULT WINAPI
1414 Uninit_DirectDraw_GetAvailableVidMem(LPDIRECTDRAW7 iface, LPDDSCAPS2 pDDCaps,
1415                                      LPDWORD pdwTotal, LPDWORD pdwFree)
1416 {
1417     return DDERR_NOTINITIALIZED;
1418 }
1419
1420 static HRESULT WINAPI
1421 Uninit_DirectDraw_GetSurfaceFromDC(LPDIRECTDRAW7 iface, HDC hDC,
1422                                    LPDIRECTDRAWSURFACE7 *pSurf)
1423 {
1424     return DDERR_NOTINITIALIZED;
1425 }
1426
1427 static HRESULT WINAPI
1428 Uninit_DirectDraw_RestoreAllSurfaces(LPDIRECTDRAW7 iface)
1429 {
1430     return DDERR_NOTINITIALIZED;
1431 }
1432
1433 static HRESULT WINAPI
1434 Uninit_DirectDraw_TestCooperativeLevel(LPDIRECTDRAW7 iface)
1435 {
1436     return DDERR_NOTINITIALIZED;
1437 }
1438
1439 static HRESULT WINAPI
1440 Uninit_DirectDraw_GetDeviceIdentifier(LPDIRECTDRAW7 iface,
1441                                       LPDDDEVICEIDENTIFIER2 pDDDI,
1442                                       DWORD dwFlags)
1443 {
1444     return DDERR_NOTINITIALIZED;
1445 }
1446
1447 static HRESULT WINAPI
1448 Uninit_DirectDraw_StartModeTest(LPDIRECTDRAW7 iface, LPSIZE pszModes,
1449                                 DWORD cModes, DWORD dwFlags)
1450 {
1451     return DDERR_NOTINITIALIZED;
1452 }
1453
1454 static HRESULT WINAPI
1455 Uninit_DirectDraw_EvaluateMode(LPDIRECTDRAW7 iface, DWORD dwFlags,
1456                                LPDWORD pTimeout)
1457 {
1458     return DDERR_NOTINITIALIZED;
1459 }
1460
1461 static ICOM_VTABLE(IDirectDraw7) Uninit_DirectDraw_VTable =
1462 {
1463     ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1464     Main_DirectDraw_QueryInterface,
1465     Main_DirectDraw_AddRef,
1466     Main_DirectDraw_Release,
1467     Uninit_DirectDraw_Compact,
1468     Uninit_DirectDraw_CreateClipper,
1469     Uninit_DirectDraw_CreatePalette,
1470     Uninit_DirectDraw_CreateSurface,
1471     Uninit_DirectDraw_DuplicateSurface,
1472     Uninit_DirectDraw_EnumDisplayModes,
1473     Uninit_DirectDraw_EnumSurfaces,
1474     Uninit_DirectDraw_FlipToGDISurface,
1475     Uninit_DirectDraw_GetCaps,
1476     Uninit_DirectDraw_GetDisplayMode,
1477     Uninit_DirectDraw_GetFourCCCodes,
1478     Uninit_DirectDraw_GetGDISurface,
1479     Uninit_DirectDraw_GetMonitorFrequency,
1480     Uninit_DirectDraw_GetScanLine,
1481     Uninit_DirectDraw_GetVerticalBlankStatus,
1482     Uninit_DirectDraw_Initialize,
1483     Uninit_DirectDraw_RestoreDisplayMode,
1484     Uninit_DirectDraw_SetCooperativeLevel,
1485     Uninit_DirectDraw_SetDisplayMode,
1486     Uninit_DirectDraw_WaitForVerticalBlank,
1487     Uninit_DirectDraw_GetAvailableVidMem,
1488     Uninit_DirectDraw_GetSurfaceFromDC,
1489     Uninit_DirectDraw_RestoreAllSurfaces,
1490     Uninit_DirectDraw_TestCooperativeLevel,
1491     Uninit_DirectDraw_GetDeviceIdentifier,
1492     Uninit_DirectDraw_StartModeTest,
1493     Uninit_DirectDraw_EvaluateMode
1494 };