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