server: Store debugging output strings as client_ptr_t instead of void pointers.
[wine] / dlls / ddraw / surface.c
1 /* DirectDraw Surface Implementation
2  *
3  * Copyright (c) 1997-2000 Marcus Meissner
4  * Copyright (c) 1998-2000 Lionel Ulmer
5  * Copyright (c) 2000-2001 TransGaming Technologies Inc.
6  * Copyright (c) 2006 Stefan Dösinger
7  *
8  * This file contains the (internal) driver registration functions,
9  * driver enumeration APIs and DirectDraw creation functions.
10  *
11  * This library is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public
13  * License as published by the Free Software Foundation; either
14  * version 2.1 of the License, or (at your option) any later version.
15  *
16  * This library is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public
22  * License along with this library; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24  */
25
26 #include "config.h"
27 #include "wine/port.h"
28
29 #include <assert.h>
30 #include <stdarg.h>
31 #include <string.h>
32 #include <stdlib.h>
33
34 #define COBJMACROS
35 #define NONAMELESSUNION
36
37 #include "windef.h"
38 #include "winbase.h"
39 #include "winerror.h"
40 #include "wingdi.h"
41 #include "wine/exception.h"
42
43 #include "ddraw.h"
44 #include "d3d.h"
45
46 #include "ddraw_private.h"
47 #include "wine/debug.h"
48
49 WINE_DEFAULT_DEBUG_CHANNEL(ddraw);
50
51 /*****************************************************************************
52  * IUnknown parts follow
53  *****************************************************************************/
54
55 /*****************************************************************************
56  * IDirectDrawSurface7::QueryInterface
57  *
58  * A normal QueryInterface implementation. For QueryInterface rules
59  * see ddraw.c, IDirectDraw7::QueryInterface. This method
60  * can Query IDirectDrawSurface interfaces in all version, IDirect3DTexture
61  * in all versions, the IDirectDrawGammaControl interface and it can
62  * create an IDirect3DDevice. (Uses IDirect3D7::CreateDevice)
63  *
64  * Params:
65  *  riid: The interface id queried for
66  *  obj: Address to write the pointer to
67  *
68  * Returns:
69  *  S_OK on success
70  *  E_NOINTERFACE if the requested interface wasn't found
71  *
72  *****************************************************************************/
73 static HRESULT WINAPI
74 IDirectDrawSurfaceImpl_QueryInterface(IDirectDrawSurface7 *iface,
75                                       REFIID riid,
76                                       void **obj)
77 {
78     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
79
80     /* According to COM docs, if the QueryInterface fails, obj should be set to NULL */
81     *obj = NULL;
82
83     if(!riid)
84         return DDERR_INVALIDPARAMS;
85
86     TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),obj);
87     if (IsEqualGUID(riid, &IID_IUnknown)
88      || IsEqualGUID(riid, &IID_IDirectDrawSurface7)
89      || IsEqualGUID(riid, &IID_IDirectDrawSurface4) )
90     {
91         IUnknown_AddRef(iface);
92         *obj = ICOM_INTERFACE(This, IDirectDrawSurface7);
93         TRACE("(%p) returning IDirectDrawSurface7 interface at %p\n", This, *obj);
94         return S_OK;
95     }
96     else if( IsEqualGUID(riid, &IID_IDirectDrawSurface3)
97           || IsEqualGUID(riid, &IID_IDirectDrawSurface2)
98           || IsEqualGUID(riid, &IID_IDirectDrawSurface) )
99     {
100         IUnknown_AddRef(iface);
101         *obj = ICOM_INTERFACE(This, IDirectDrawSurface3);
102         TRACE("(%p) returning IDirectDrawSurface3 interface at %p\n", This, *obj);
103         return S_OK;
104     }
105     else if( IsEqualGUID(riid, &IID_IDirectDrawGammaControl) )
106     {
107         IUnknown_AddRef(iface);
108         *obj = ICOM_INTERFACE(This, IDirectDrawGammaControl);
109         TRACE("(%p) returning IDirectDrawGammaControl interface at %p\n", This, *obj);
110         return S_OK;
111     }
112     else if( IsEqualGUID(riid, &IID_D3DDEVICE_WineD3D) ||
113              IsEqualGUID(riid, &IID_IDirect3DHALDevice)||
114              IsEqualGUID(riid, &IID_IDirect3DRGBDevice) )
115     {
116         IDirect3DDevice7 *d3d;
117
118         /* Call into IDirect3D7 for creation */
119         IDirect3D7_CreateDevice(ICOM_INTERFACE(This->ddraw, IDirect3D7),
120                                 riid,
121                                 ICOM_INTERFACE(This, IDirectDrawSurface7),
122                                 &d3d);
123
124         *obj = COM_INTERFACE_CAST(IDirect3DDeviceImpl, IDirect3DDevice7, IDirect3DDevice, d3d);
125         TRACE("(%p) Returning IDirect3DDevice interface at %p\n", This, *obj);
126
127         return S_OK;
128     }
129     else if (IsEqualGUID( &IID_IDirect3DTexture, riid ) ||
130              IsEqualGUID( &IID_IDirect3DTexture2, riid ))
131     {
132         if (IsEqualGUID( &IID_IDirect3DTexture, riid ))
133         {
134             *obj = ICOM_INTERFACE(This, IDirect3DTexture);
135             TRACE(" returning Direct3DTexture interface at %p.\n", *obj);
136         }
137         else
138         {
139             *obj = ICOM_INTERFACE(This, IDirect3DTexture2);
140             TRACE(" returning Direct3DTexture2 interface at %p.\n", *obj);
141         }
142         IUnknown_AddRef( (IUnknown *) *obj);
143         return S_OK;
144     }
145
146     ERR("No interface\n");
147     return E_NOINTERFACE;
148 }
149
150 /*****************************************************************************
151  * IDirectDrawSurface7::AddRef
152  *
153  * A normal addref implementation
154  *
155  * Returns:
156  *  The new refcount
157  *
158  *****************************************************************************/
159 static ULONG WINAPI
160 IDirectDrawSurfaceImpl_AddRef(IDirectDrawSurface7 *iface)
161 {
162     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
163     ULONG refCount = InterlockedIncrement(&This->ref);
164
165     TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
166     return refCount;
167 }
168
169 /*****************************************************************************
170  * IDirectDrawSurfaceImpl_Destroy
171  *
172  * A helper function for IDirectDrawSurface7::Release
173  *
174  * Frees the surface, regardless of its refcount.
175  *  See IDirectDrawSurface7::Release for more information
176  *
177  * Params:
178  *  This: Surface to free
179  *
180  *****************************************************************************/
181 void IDirectDrawSurfaceImpl_Destroy(IDirectDrawSurfaceImpl *This)
182 {
183     TRACE("(%p)\n", This);
184
185     /* Check the refcount and give a warning */
186     if(This->ref > 1)
187     {
188         /* This can happen when a complex surface is destroyed,
189          * because the 2nd surface was addref()ed when the app
190          * called GetAttachedSurface
191          */
192         WARN("(%p): Destroying surface with refount %d\n", This, This->ref);
193     }
194
195     /* Check for attached surfaces and detach them */
196     if(This->first_attached != This)
197     {
198         /* Well, this shouldn't happen: The surface being attached is addref()ed
199           * in AddAttachedSurface, so it shouldn't be released until DeleteAttachedSurface
200           * is called, because the refcount is held. It looks like the app released()
201           * it often enough to force this
202           */
203         IDirectDrawSurface7 *root = ICOM_INTERFACE(This->first_attached, IDirectDrawSurface7);
204         IDirectDrawSurface7 *detach = ICOM_INTERFACE(This, IDirectDrawSurface7);
205
206         FIXME("(%p) Freeing a surface that is attached to surface %p\n", This, This->first_attached);
207
208         /* The refcount will drop to -1 here */
209         if(IDirectDrawSurface7_DeleteAttachedSurface(root, 0, detach) != DD_OK)
210         {
211             ERR("(%p) DeleteAttachedSurface failed!\n", This);
212         }
213     }
214
215     while(This->next_attached != NULL)
216     {
217         IDirectDrawSurface7 *root = ICOM_INTERFACE(This, IDirectDrawSurface7);
218         IDirectDrawSurface7 *detach = ICOM_INTERFACE(This->next_attached, IDirectDrawSurface7);
219
220         if(IDirectDrawSurface7_DeleteAttachedSurface(root, 0, detach) != DD_OK)
221         {
222             ERR("(%p) DeleteAttachedSurface failed!\n", This);
223             assert(0);
224         }
225     }
226
227     /* Now destroy the surface. Wait: It could have been released if we are a texture */
228     if(This->WineD3DSurface)
229         IWineD3DSurface_Release(This->WineD3DSurface);
230
231     /* Having a texture handle set implies that the device still exists */
232     if(This->Handle)
233     {
234         This->ddraw->d3ddevice->Handles[This->Handle - 1].ptr = NULL;
235         This->ddraw->d3ddevice->Handles[This->Handle - 1].type = DDrawHandle_Unknown;
236     }
237
238     /* Reduce the ddraw surface count */
239     InterlockedDecrement(&This->ddraw->surfaces);
240     list_remove(&This->surface_list_entry);
241
242     HeapFree(GetProcessHeap(), 0, This);
243 }
244
245 /*****************************************************************************
246  * IDirectDrawSurface7::Release
247  *
248  * Reduces the surface's refcount by 1. If the refcount falls to 0, the
249  * surface is destroyed.
250  *
251  * Destroying the surface is a bit tricky. For the connection between
252  * WineD3DSurfaces and DirectDrawSurfaces see IDirectDraw7::CreateSurface
253  * It has a nice graph explaining the connection.
254  *
255  * What happens here is basically this:
256  * When a surface is destroyed, its WineD3DSurface is released,
257  * and the refcount of the DirectDraw interface is reduced by 1. If it has
258  * complex surfaces attached to it, then these surfaces are destroyed too,
259  * regardless of their refcount. If any surface being destroyed has another
260  * surface attached to it (with a "soft" attachment, not complex), then
261  * this surface is detached with DeleteAttachedSurface.
262  *
263  * When the surface is a texture, the WineD3DTexture is released.
264  * If the surface is the Direct3D render target, then the D3D
265  * capabilities of the WineD3DDevice are uninitialized, which causes the
266  * swapchain to be released.
267  *
268  * When a complex sublevel falls to ref zero, then this is ignored.
269  *
270  * Returns:
271  *  The new refcount
272  *
273  *****************************************************************************/
274 static ULONG WINAPI
275 IDirectDrawSurfaceImpl_Release(IDirectDrawSurface7 *iface)
276 {
277     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
278     ULONG ref;
279     TRACE("(%p) : Releasing from %d\n", This, This->ref);
280     ref = InterlockedDecrement(&This->ref);
281
282     if (ref == 0)
283     {
284
285         IDirectDrawSurfaceImpl *surf;
286         IDirectDrawImpl *ddraw;
287         IUnknown *ifaceToRelease = This->ifaceToRelease;
288         UINT i;
289
290         /* Complex attached surfaces are destroyed implicitly when the root is released */
291         EnterCriticalSection(&ddraw_cs);
292         if(!This->is_complex_root)
293         {
294             WARN("(%p) Attempt to destroy a surface that is not a complex root\n", This);
295             LeaveCriticalSection(&ddraw_cs);
296             return ref;
297         }
298         ddraw = This->ddraw;
299
300         /* If it's a texture, destroy the WineD3DTexture.
301          * WineD3D will destroy the IParent interfaces
302          * of the sublevels, which destroys the WineD3DSurfaces.
303          * Set the surfaces to NULL to avoid destroying them again later
304          */
305         if(This->wineD3DTexture)
306         {
307             IWineD3DBaseTexture_Release(This->wineD3DTexture);
308         }
309         /* If it's the RenderTarget, destroy the d3ddevice */
310         else if(This->wineD3DSwapChain)
311         {
312             if((ddraw->d3d_initialized) && (This == ddraw->d3d_target)) {
313                 TRACE("(%p) Destroying the render target, uninitializing D3D\n", This);
314
315                 /* Unset any index buffer, just to be sure */
316                 IWineD3DDevice_SetIndices(ddraw->wineD3DDevice, NULL);
317                 IWineD3DDevice_SetDepthStencilSurface(ddraw->wineD3DDevice, NULL);
318                 IWineD3DDevice_SetVertexDeclaration(ddraw->wineD3DDevice, NULL);
319                 for(i = 0; i < ddraw->numConvertedDecls; i++)
320                 {
321                     IWineD3DVertexDeclaration_Release(ddraw->decls[i].decl);
322                 }
323                 HeapFree(GetProcessHeap(), 0, ddraw->decls);
324                 ddraw->numConvertedDecls = 0;
325
326                 if(IWineD3DDevice_Uninit3D(ddraw->wineD3DDevice, D3D7CB_DestroyDepthStencilSurface, D3D7CB_DestroySwapChain) != D3D_OK)
327                 {
328                     /* Not good */
329                     ERR("(%p) Failed to uninit 3D\n", This);
330                 }
331                 else
332                 {
333                     /* Free the d3d window if one was created */
334                     if(ddraw->d3d_window != 0 && ddraw->d3d_window != ddraw->dest_window)
335                     {
336                         TRACE(" (%p) Destroying the hidden render window %p\n", This, ddraw->d3d_window);
337                         DestroyWindow(ddraw->d3d_window);
338                         ddraw->d3d_window = 0;
339                     }
340                     /* Unset the pointers */
341                 }
342
343                 This->wineD3DSwapChain = NULL; /* Uninit3D releases the swapchain */
344                 ddraw->d3d_initialized = FALSE;
345                 ddraw->d3d_target = NULL;
346             } else {
347                 IWineD3DDevice_UninitGDI(ddraw->wineD3DDevice, D3D7CB_DestroySwapChain);
348                 This->wineD3DSwapChain = NULL;
349             }
350
351             /* Reset to the default surface implementation type. This is needed if apps use
352              * non render target surfaces and expect blits to work after destroying the render
353              * target.
354              *
355              * TODO: Recreate existing offscreen surfaces
356              */
357             ddraw->ImplType = DefaultSurfaceType;
358
359             /* Write a trace because D3D unloading was the reason for many
360              * crashes during development.
361              */
362             TRACE("(%p) D3D unloaded\n", This);
363         }
364         else if(This->surface_desc.ddsCaps.dwCaps & (DDSCAPS_PRIMARYSURFACE |
365                                                      DDSCAPS_3DDEVICE       |
366                                                      DDSCAPS_TEXTURE        ) )
367         {
368             /* It's a render target, but no swapchain was created.
369              * The IParent interfaces have to be released manually.
370              * The same applies for textures without an
371              * IWineD3DTexture object attached
372              */
373             IParent *Parent;
374
375             for(i = 0; i < MAX_COMPLEX_ATTACHED; i++)
376             {
377                 if(This->complex_array[i])
378                 {
379                     /* Only the topmost level can have more than 1 surfaces in the complex
380                      * attachment array(Cube texture roots), for all others there is only
381                      * one
382                      */
383                     surf = This->complex_array[i];
384                     while(surf)
385                     {
386                         IWineD3DSurface_GetParent(surf->WineD3DSurface,
387                                                   (IUnknown **) &Parent);
388                         IParent_Release(Parent);  /* For the getParent */
389                         IParent_Release(Parent);  /* To release it */
390                         surf = surf->complex_array[0];
391                     }
392                 }
393             }
394
395             /* Now the top-level surface */
396             IWineD3DSurface_GetParent(This->WineD3DSurface,
397                                       (IUnknown **) &Parent);
398             IParent_Release(Parent);  /* For the getParent */
399             IParent_Release(Parent);  /* To release it */
400         }
401
402         /* The refcount test shows that the palette is detached when the surface is destroyed */
403         IDirectDrawSurface7_SetPalette(ICOM_INTERFACE(This, IDirectDrawSurface7),
404                                                       NULL);
405
406         /* Loop through all complex attached surfaces,
407          * and destroy them.
408          *
409          * Yet again, only the root can have more than one complexly attached surface, all the others
410          * have a total of one;
411          */
412         for(i = 0; i < MAX_COMPLEX_ATTACHED; i++)
413         {
414             if(!This->complex_array[i]) break;
415
416             surf = This->complex_array[i];
417             This->complex_array[i] = NULL;
418             while(surf)
419             {
420                 IDirectDrawSurfaceImpl *destroy = surf;
421                 surf = surf->complex_array[0];              /* Iterate through the "tree" */
422                 IDirectDrawSurfaceImpl_Destroy(destroy);    /* Destroy it */
423             }
424         }
425
426         /* Destroy the root surface.
427          */
428         IDirectDrawSurfaceImpl_Destroy(This);
429
430         /* Reduce the ddraw refcount */
431         if(ifaceToRelease) IUnknown_Release(ifaceToRelease);
432         LeaveCriticalSection(&ddraw_cs);
433     }
434
435     return ref;
436 }
437
438 /*****************************************************************************
439  * IDirectDrawSurface7::GetAttachedSurface
440  *
441  * Returns an attached surface with the requested caps. Surface attachment
442  * and complex surfaces are not clearly described by the MSDN or sdk,
443  * so this method is tricky and likely to contain problems.
444  * This implementation searches the complex list first, then the
445  * attachment chain.
446  *
447  * The chains are searched from This down to the last surface in the chain,
448  * not from the first element in the chain. The first surface found is
449  * returned. The MSDN says that this method fails if more than one surface
450  * matches the caps, but it is not sure if that is right. The attachment
451  * structure may not even allow two matching surfaces.
452  *
453  * The found surface is AddRef-ed before it is returned.
454  *
455  * Params:
456  *  Caps: Pointer to a DDCAPS2 structure describing the caps asked for
457  *  Surface: Address to store the found surface
458  *
459  * Returns:
460  *  DD_OK on success
461  *  DDERR_INVALIDPARAMS if Caps or Surface is NULL
462  *  DDERR_NOTFOUND if no surface was found
463  *
464  *****************************************************************************/
465 static HRESULT WINAPI
466 IDirectDrawSurfaceImpl_GetAttachedSurface(IDirectDrawSurface7 *iface,
467                                           DDSCAPS2 *Caps,
468                                           IDirectDrawSurface7 **Surface)
469 {
470     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
471     IDirectDrawSurfaceImpl *surf;
472     DDSCAPS2 our_caps;
473     int i;
474
475     TRACE("(%p)->(%p,%p)\n", This, Caps, Surface);
476     EnterCriticalSection(&ddraw_cs);
477
478     if(This->version < 7)
479     {
480         /* Earlier dx apps put garbage into these members, clear them */
481         our_caps.dwCaps = Caps->dwCaps;
482         our_caps.dwCaps2 = 0;
483         our_caps.dwCaps3 = 0;
484         our_caps.dwCaps4 = 0;
485     }
486     else
487     {
488         our_caps = *Caps;
489     }
490
491     TRACE("(%p): Looking for caps: %x,%x,%x,%x\n", This, our_caps.dwCaps, our_caps.dwCaps2, our_caps.dwCaps3, our_caps.dwCaps4); /* FIXME: Better debugging */
492
493     for(i = 0; i < MAX_COMPLEX_ATTACHED; i++)
494     {
495         surf = This->complex_array[i];
496         if(!surf) break;
497
498         if (TRACE_ON(ddraw))
499         {
500             TRACE("Surface: (%p) caps: %x,%x,%x,%x\n", surf,
501                    surf->surface_desc.ddsCaps.dwCaps,
502                    surf->surface_desc.ddsCaps.dwCaps2,
503                    surf->surface_desc.ddsCaps.dwCaps3,
504                    surf->surface_desc.ddsCaps.dwCaps4);
505         }
506
507         if (((surf->surface_desc.ddsCaps.dwCaps & our_caps.dwCaps) == our_caps.dwCaps) &&
508             ((surf->surface_desc.ddsCaps.dwCaps2 & our_caps.dwCaps2) == our_caps.dwCaps2)) {
509
510             /* MSDN: "This method fails if more than one surface is attached
511              * that matches the capabilities requested."
512              *
513              * Not sure how to test this.
514              */
515
516             TRACE("(%p): Returning surface %p\n", This, surf);
517             TRACE("(%p): mipmapcount=%d\n", This, surf->mipmap_level);
518             *Surface = ICOM_INTERFACE(surf, IDirectDrawSurface7);
519             IDirectDrawSurface7_AddRef(*Surface);
520             LeaveCriticalSection(&ddraw_cs);
521             return DD_OK;
522         }
523     }
524
525     /* Next, look at the attachment chain */
526     surf = This;
527
528     while( (surf = surf->next_attached) )
529     {
530         if (TRACE_ON(ddraw))
531         {
532             TRACE("Surface: (%p) caps: %x,%x,%x,%x\n", surf,
533                    surf->surface_desc.ddsCaps.dwCaps,
534                    surf->surface_desc.ddsCaps.dwCaps2,
535                    surf->surface_desc.ddsCaps.dwCaps3,
536                    surf->surface_desc.ddsCaps.dwCaps4);
537         }
538
539         if (((surf->surface_desc.ddsCaps.dwCaps & our_caps.dwCaps) == our_caps.dwCaps) &&
540             ((surf->surface_desc.ddsCaps.dwCaps2 & our_caps.dwCaps2) == our_caps.dwCaps2)) {
541
542             TRACE("(%p): Returning surface %p\n", This, surf);
543             *Surface = ICOM_INTERFACE(surf, IDirectDrawSurface7);
544             IDirectDrawSurface7_AddRef(*Surface);
545             LeaveCriticalSection(&ddraw_cs);
546             return DD_OK;
547         }
548     }
549
550     TRACE("(%p) Didn't find a valid surface\n", This);
551     LeaveCriticalSection(&ddraw_cs);
552
553     *Surface = NULL;
554     return DDERR_NOTFOUND;
555 }
556
557 /*****************************************************************************
558  * IDirectDrawSurface7::Lock
559  *
560  * Locks the surface and returns a pointer to the surface's memory
561  *
562  * Params:
563  *  Rect: Rectangle to lock. If NULL, the whole surface is locked
564  *  DDSD: Pointer to a DDSURFACEDESC2 which shall receive the surface's desc.
565  *  Flags: Locking flags, e.g Read only or write only
566  *  h: An event handle that's not used and must be NULL
567  *
568  * Returns:
569  *  DD_OK on success
570  *  DDERR_INVALIDPARAMS if DDSD is NULL
571  *  For more details, see IWineD3DSurface::LockRect
572  *
573  *****************************************************************************/
574 static HRESULT WINAPI
575 IDirectDrawSurfaceImpl_Lock(IDirectDrawSurface7 *iface,
576                             RECT *Rect,
577                             DDSURFACEDESC2 *DDSD,
578                             DWORD Flags,
579                             HANDLE h)
580 {
581     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
582     WINED3DLOCKED_RECT LockedRect;
583     HRESULT hr;
584     TRACE("(%p)->(%p,%p,%x,%p)\n", This, Rect, DDSD, Flags, h);
585
586     if(!DDSD)
587         return DDERR_INVALIDPARAMS;
588
589     /* This->surface_desc.dwWidth and dwHeight are changeable, thus lock */
590     EnterCriticalSection(&ddraw_cs);
591
592     /* Should I check for the handle to be NULL?
593      *
594      * The DDLOCK flags and the D3DLOCK flags are equal
595      * for the supported values. The others are ignored by WineD3D
596      */
597
598     if(DDSD->dwSize != sizeof(DDSURFACEDESC) &&
599        DDSD->dwSize != sizeof(DDSURFACEDESC2))
600     {
601         WARN("Invalid structure size %d, returning DDERR_INVALIDPARAMS\n", DDERR_INVALIDPARAMS);
602         LeaveCriticalSection(&ddraw_cs);
603         return DDERR_INVALIDPARAMS;
604     }
605
606     /* Windows zeroes this if the rect is invalid */
607     DDSD->lpSurface = 0;
608
609     if (Rect)
610     {
611         if ((Rect->left < 0)
612                 || (Rect->top < 0)
613                 || (Rect->left > Rect->right)
614                 || (Rect->top > Rect->bottom)
615                 || (Rect->right > This->surface_desc.dwWidth)
616                 || (Rect->bottom > This->surface_desc.dwHeight))
617         {
618             WARN("Trying to lock an invalid rectangle, returning DDERR_INVALIDPARAMS\n");
619             LeaveCriticalSection(&ddraw_cs);
620             return DDERR_INVALIDPARAMS;
621         }
622     }
623
624     hr = IWineD3DSurface_LockRect(This->WineD3DSurface,
625                                   &LockedRect,
626                                   Rect,
627                                   Flags);
628     if(hr != D3D_OK)
629     {
630         LeaveCriticalSection(&ddraw_cs);
631         switch(hr)
632         {
633             /* D3D8 and D3D9 return the general D3DERR_INVALIDCALL error, but ddraw has a more
634              * specific error. But since IWineD3DSurface::LockRect returns that error in this
635              * only occasion, keep d3d8 and d3d9 free from the return value override. There are
636              * many different places where d3d8/9 would have to catch the DDERR_SURFACEBUSY, it
637              * is much easier to do it in one place in ddraw
638              */
639             case WINED3DERR_INVALIDCALL:    return DDERR_SURFACEBUSY;
640             default:                        return hr;
641         }
642     }
643
644     /* Override the memory area. The pitch should be set already. Strangely windows
645      * does not set the LPSURFACE flag on locked surfaces !?!.
646      * DDSD->dwFlags |= DDSD_LPSURFACE;
647      */
648     This->surface_desc.lpSurface = LockedRect.pBits;
649     DD_STRUCT_COPY_BYSIZE(DDSD,&(This->surface_desc));
650
651     TRACE("locked surface returning description :\n");
652     if (TRACE_ON(ddraw)) DDRAW_dump_surface_desc(DDSD);
653
654     LeaveCriticalSection(&ddraw_cs);
655     return DD_OK;
656 }
657
658 /*****************************************************************************
659  * IDirectDrawSurface7::Unlock
660  *
661  * Unlocks an locked surface
662  *
663  * Params:
664  *  Rect: Not used by this implementation
665  *
666  * Returns:
667  *  D3D_OK on success
668  *  For more details, see IWineD3DSurface::UnlockRect
669  *
670  *****************************************************************************/
671 static HRESULT WINAPI
672 IDirectDrawSurfaceImpl_Unlock(IDirectDrawSurface7 *iface,
673                               RECT *pRect)
674 {
675     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
676     HRESULT hr;
677     TRACE("(%p)->(%p)\n", This, pRect);
678
679     EnterCriticalSection(&ddraw_cs);
680     hr = IWineD3DSurface_UnlockRect(This->WineD3DSurface);
681     if(SUCCEEDED(hr))
682     {
683         This->surface_desc.lpSurface = NULL;
684     }
685     LeaveCriticalSection(&ddraw_cs);
686     return hr;
687 }
688
689 /*****************************************************************************
690  * IDirectDrawSurface7::Flip
691  *
692  * Flips a surface with the DDSCAPS_FLIP flag. The flip is relayed to
693  * IWineD3DSurface::Flip. Because WineD3D doesn't handle attached surfaces,
694  * the flip target is passed to WineD3D, even if the app didn't specify one
695  *
696  * Params:
697  *  DestOverride: Specifies the surface that will become the new front
698  *                buffer. If NULL, the current back buffer is used
699  *  Flags: some DirectDraw flags, see include/ddraw.h
700  *
701  * Returns:
702  *  DD_OK on success
703  *  DDERR_NOTFLIPPABLE if no flip target could be found
704  *  DDERR_INVALIDOBJECT if the surface isn't a front buffer
705  *  For more details, see IWineD3DSurface::Flip
706  *
707  *****************************************************************************/
708 static HRESULT WINAPI
709 IDirectDrawSurfaceImpl_Flip(IDirectDrawSurface7 *iface,
710                             IDirectDrawSurface7 *DestOverride,
711                             DWORD Flags)
712 {
713     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
714     IDirectDrawSurfaceImpl *Override = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, DestOverride);
715     IDirectDrawSurface7 *Override7;
716     HRESULT hr;
717     TRACE("(%p)->(%p,%x)\n", This, DestOverride, Flags);
718
719     /* Flip has to be called from a front buffer
720      * What about overlay surfaces, AFAIK they can flip too?
721      */
722     if( !(This->surface_desc.ddsCaps.dwCaps & (DDSCAPS_FRONTBUFFER | DDSCAPS_OVERLAY)) )
723         return DDERR_INVALIDOBJECT; /* Unchecked */
724
725     EnterCriticalSection(&ddraw_cs);
726
727     /* WineD3D doesn't keep track of attached surface, so find the target */
728     if(!Override)
729     {
730         DDSCAPS2 Caps;
731
732         memset(&Caps, 0, sizeof(Caps));
733         Caps.dwCaps |= DDSCAPS_BACKBUFFER;
734         hr = IDirectDrawSurface7_GetAttachedSurface(iface, &Caps, &Override7);
735         if(hr != DD_OK)
736         {
737             ERR("Can't find a flip target\n");
738             LeaveCriticalSection(&ddraw_cs);
739             return DDERR_NOTFLIPPABLE; /* Unchecked */
740         }
741         Override = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, Override7);
742
743         /* For the GetAttachedSurface */
744         IDirectDrawSurface7_Release(Override7);
745     }
746
747     hr = IWineD3DSurface_Flip(This->WineD3DSurface,
748                               Override->WineD3DSurface,
749                               Flags);
750     LeaveCriticalSection(&ddraw_cs);
751     return hr;
752 }
753
754 /*****************************************************************************
755  * IDirectDrawSurface7::Blt
756  *
757  * Performs a blit on the surface
758  *
759  * Params:
760  *  DestRect: Destination rectangle, can be NULL
761  *  SrcSurface: Source surface, can be NULL
762  *  SrcRect: Source rectangle, can be NULL
763  *  Flags: Blt flags
764  *  DDBltFx: Some extended blt parameters, connected to the flags
765  *
766  * Returns:
767  *  D3D_OK on success
768  *  See IWineD3DSurface::Blt for more details
769  *
770  *****************************************************************************/
771 static HRESULT WINAPI
772 IDirectDrawSurfaceImpl_Blt(IDirectDrawSurface7 *iface,
773                            RECT *DestRect,
774                            IDirectDrawSurface7 *SrcSurface,
775                            RECT *SrcRect,
776                            DWORD Flags,
777                            DDBLTFX *DDBltFx)
778 {
779     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
780     HRESULT hr;
781     IDirectDrawSurfaceImpl *Src = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, SrcSurface);
782     TRACE("(%p)->(%p,%p,%p,%x,%p)\n", This, DestRect, Src, SrcRect, Flags, DDBltFx);
783
784     /* Check for validity of the flags here. WineD3D Has the software-opengl selection path and would have
785      * to check at 2 places, and sometimes do double checks. This also saves the call to wined3d :-)
786      */
787     if((Flags & DDBLT_KEYSRCOVERRIDE) && (!DDBltFx || Flags & DDBLT_KEYSRC)) {
788         WARN("Invalid source color key parameters, returning DDERR_INVALIDPARAMS\n");
789         return DDERR_INVALIDPARAMS;
790     }
791
792     if((Flags & DDBLT_KEYDESTOVERRIDE) && (!DDBltFx || Flags & DDBLT_KEYDEST)) {
793         WARN("Invalid destination color key parameters, returning DDERR_INVALIDPARAMS\n");
794         return DDERR_INVALIDPARAMS;
795     }
796
797     /* Sizes can change, therefore hold the lock when testing the rectangles */
798     EnterCriticalSection(&ddraw_cs);
799     if(DestRect)
800     {
801         if(DestRect->top >= DestRect->bottom || DestRect->left >= DestRect->right ||
802            DestRect->right > This->surface_desc.dwWidth ||
803            DestRect->bottom > This->surface_desc.dwHeight)
804         {
805             WARN("Destination rectangle is invalid, returning DDERR_INVALIDRECT\n");
806             LeaveCriticalSection(&ddraw_cs);
807             return DDERR_INVALIDRECT;
808         }
809     }
810     if(Src && SrcRect)
811     {
812         if(SrcRect->top >= SrcRect->bottom || SrcRect->left >=SrcRect->right ||
813            SrcRect->right > Src->surface_desc.dwWidth ||
814            SrcRect->bottom > Src->surface_desc.dwHeight)
815         {
816             WARN("Source rectangle is invalid, returning DDERR_INVALIDRECT\n");
817             LeaveCriticalSection(&ddraw_cs);
818             return DDERR_INVALIDRECT;
819         }
820     }
821
822     if(Flags & DDBLT_KEYSRC && (!Src || !(Src->surface_desc.dwFlags & DDSD_CKSRCBLT))) {
823         WARN("DDBLT_KEYDEST blit without color key in surface, returning DDERR_INVALIDPARAMS\n");
824         LeaveCriticalSection(&ddraw_cs);
825         return DDERR_INVALIDPARAMS;
826     }
827
828     /* TODO: Check if the DDBltFx contains any ddraw surface pointers. If it does, copy the struct,
829      * and replace the ddraw surfaces with the wined3d surfaces
830      * So far no blitting operations using surfaces in the bltfx struct are supported anyway.
831      */
832     hr = IWineD3DSurface_Blt(This->WineD3DSurface,
833                              DestRect,
834                              Src ? Src->WineD3DSurface : NULL,
835                              SrcRect,
836                              Flags,
837                              (WINEDDBLTFX *) DDBltFx,
838                              WINED3DTEXF_POINT);
839
840     LeaveCriticalSection(&ddraw_cs);
841     switch(hr)
842     {
843         case WINED3DERR_NOTAVAILABLE:       return DDERR_UNSUPPORTED;
844         case WINED3DERR_WRONGTEXTUREFORMAT: return DDERR_INVALIDPIXELFORMAT;
845         default:                            return hr;
846     }
847 }
848
849 /*****************************************************************************
850  * IDirectDrawSurface7::AddAttachedSurface
851  *
852  * Attaches a surface to another surface. How the surface attachments work
853  * is not totally understood yet, and this method is prone to problems.
854  * he surface that is attached is AddRef-ed.
855  *
856  * Tests with complex surfaces suggest that the surface attachments form a
857  * tree, but no method to test this has been found yet.
858  *
859  * The attachment list consists of a first surface (first_attached) and
860  * for each surface a pointer to the next attached surface (next_attached).
861  * For the first surface, and a surface that has no attachments
862  * first_attached points to the surface itself. A surface that has
863  * no successors in the chain has next_attached set to NULL.
864  *
865  * Newly attached surfaces are attached right after the root surface.
866  * If a surface is attached to a complex surface compound, it's attached to
867  * the surface that the app requested, not the complex root. See
868  * GetAttachedSurface for a description how surfaces are found.
869  *
870  * This is how the current implementation works, and it was coded by looking
871  * at the needs of the applications.
872  *
873  * So far only Z-Buffer attachments are tested, and they are activated in
874  * WineD3D. Mipmaps could be tricky to activate in WineD3D.
875  * Back buffers should work in 2D mode, but they are not tested(They can be
876  * attached in older iface versions). Rendering to the front buffer and
877  * switching between that and double buffering is not yet implemented in
878  * WineD3D, so for 3D it might have unexpected results.
879  *
880  * IDirectDrawSurfaceImpl_AddAttachedSurface is the real thing,
881  * IDirectDrawSurface7Impl_AddAttachedSurface is a wrapper around it that
882  * performs additional checks. Version 7 of this interface is much more restrictive
883  * than its predecessors.
884  *
885  * Params:
886  *  Attach: Surface to attach to iface
887  *
888  * Returns:
889  *  DD_OK on success
890  *  DDERR_CANNOTATTACHSURFACE if the surface can't be attached for some reason
891  *
892  *****************************************************************************/
893 HRESULT WINAPI
894 IDirectDrawSurfaceImpl_AddAttachedSurface(IDirectDrawSurfaceImpl *This,
895                                           IDirectDrawSurfaceImpl *Surf)
896 {
897     TRACE("(%p)->(%p)\n", This, Surf);
898
899     if(Surf == This)
900         return DDERR_CANNOTATTACHSURFACE; /* unchecked */
901
902     EnterCriticalSection(&ddraw_cs);
903
904     /* Check if the surface is already attached somewhere */
905     if( (Surf->next_attached != NULL) ||
906         (Surf->first_attached != Surf) )
907     {
908         /* TODO: Test for the structure of the manual attachment. Is it a chain or a list?
909          * What happens if one surface is attached to 2 different surfaces?
910          */
911         FIXME("(%p) The Surface %p is already attached somewhere else: next_attached = %p, first_attached = %p, can't handle by now\n", This, Surf, Surf->next_attached, Surf->first_attached);
912         LeaveCriticalSection(&ddraw_cs);
913         return DDERR_SURFACEALREADYATTACHED;
914     }
915
916     /* This inserts the new surface at the 2nd position in the chain, right after the root surface */
917     Surf->next_attached = This->next_attached;
918     Surf->first_attached = This->first_attached;
919     This->next_attached = Surf;
920
921     /* Check if the WineD3D depth stencil needs updating */
922     if(This->ddraw->d3ddevice)
923     {
924         IDirect3DDeviceImpl_UpdateDepthStencil(This->ddraw->d3ddevice);
925     }
926
927     /* MSDN: 
928      * "This method increments the reference count of the surface being attached."
929      */
930     IDirectDrawSurface7_AddRef(ICOM_INTERFACE(Surf, IDirectDrawSurface7));
931     LeaveCriticalSection(&ddraw_cs);
932     return DD_OK;
933 }
934
935 static HRESULT WINAPI
936 IDirectDrawSurface7Impl_AddAttachedSurface(IDirectDrawSurface7 *iface,
937                                            IDirectDrawSurface7 *Attach)
938 {
939     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
940     IDirectDrawSurfaceImpl *Surf = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, Attach);
941
942     /* Version 7 of this interface seems to refuse everything except z buffers, as per msdn */
943     if(!(Surf->surface_desc.ddsCaps.dwCaps & DDSCAPS_ZBUFFER))
944     {
945
946         WARN("Application tries to attach a non Z buffer surface. caps %08x\n",
947               Surf->surface_desc.ddsCaps.dwCaps);
948         return DDERR_CANNOTATTACHSURFACE;
949     }
950
951     return IDirectDrawSurfaceImpl_AddAttachedSurface(This,
952                                                      Surf);
953 }
954 /*****************************************************************************
955  * IDirectDrawSurface7::DeleteAttachedSurface
956  *
957  * Removes a surface from the attachment chain. The surface's refcount
958  * is decreased by one after it has been removed
959  *
960  * Params:
961  *  Flags: Some flags, not used by this implementation
962  *  Attach: Surface to detach
963  *
964  * Returns:
965  *  DD_OK on success
966  *  DDERR_SURFACENOTATTACHED if the surface isn't attached to
967  *
968  *****************************************************************************/
969 static HRESULT WINAPI
970 IDirectDrawSurfaceImpl_DeleteAttachedSurface(IDirectDrawSurface7 *iface,
971                                              DWORD Flags,
972                                              IDirectDrawSurface7 *Attach)
973 {
974     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
975     IDirectDrawSurfaceImpl *Surf = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, Attach);
976     IDirectDrawSurfaceImpl *Prev = This;
977     TRACE("(%p)->(%08x,%p)\n", This, Flags, Surf);
978
979     EnterCriticalSection(&ddraw_cs);
980     if (!Surf || (Surf->first_attached != This) || (Surf == This) )
981     {
982         LeaveCriticalSection(&ddraw_cs);
983         return DDERR_CANNOTDETACHSURFACE;
984     }
985
986     /* Remove MIPMAPSUBLEVEL if this seemed to be one */
987     if (This->surface_desc.ddsCaps.dwCaps &
988         Surf->surface_desc.ddsCaps.dwCaps & DDSCAPS_MIPMAP)
989     {
990         Surf->surface_desc.ddsCaps.dwCaps2 &= ~DDSCAPS2_MIPMAPSUBLEVEL;
991         /* FIXME: we should probably also subtract from dwMipMapCount of this
992          * and all parent surfaces */
993     }
994
995     /* Find the predecessor of the detached surface */
996     while(Prev)
997     {
998         if(Prev->next_attached == Surf) break;
999         Prev = Prev->next_attached;
1000     }
1001
1002     /* There must be a surface, otherwise there's a bug */
1003     assert(Prev != NULL);
1004
1005     /* Unchain the surface */
1006     Prev->next_attached = Surf->next_attached;
1007     Surf->next_attached = NULL;
1008     Surf->first_attached = Surf;
1009
1010     /* Check if the WineD3D depth stencil needs updating */
1011     if(This->ddraw->d3ddevice)
1012     {
1013         IDirect3DDeviceImpl_UpdateDepthStencil(This->ddraw->d3ddevice);
1014     }
1015
1016     IDirectDrawSurface7_Release(Attach);
1017     LeaveCriticalSection(&ddraw_cs);
1018     return DD_OK;
1019 }
1020
1021 /*****************************************************************************
1022  * IDirectDrawSurface7::AddOverlayDirtyRect
1023  *
1024  * "This method is not currently implemented"
1025  *
1026  * Params:
1027  *  Rect: ?
1028  *
1029  * Returns:
1030  *  DDERR_UNSUPPORTED
1031  *
1032  *****************************************************************************/
1033 static HRESULT WINAPI
1034 IDirectDrawSurfaceImpl_AddOverlayDirtyRect(IDirectDrawSurface7 *iface,
1035                                            LPRECT Rect)
1036 {
1037     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1038     TRACE("(%p)->(%p)\n",This,Rect);
1039
1040     /* MSDN says it's not implemented. I could forward it to WineD3D, 
1041      * then we'd implement it, but I don't think that's a good idea
1042      * (Stefan Dösinger)
1043      */
1044 #if 0
1045     return IWineD3DSurface_AddOverlayDirtyRect(This->WineD3DSurface, pRect);
1046 #endif
1047     return DDERR_UNSUPPORTED; /* unchecked */
1048 }
1049
1050 /*****************************************************************************
1051  * IDirectDrawSurface7::GetDC
1052  *
1053  * Returns a GDI device context for the surface
1054  *
1055  * Params:
1056  *  hdc: Address of a HDC variable to store the dc to
1057  *
1058  * Returns:
1059  *  DD_OK on success
1060  *  DDERR_INVALIDPARAMS if hdc is NULL
1061  *  For details, see IWineD3DSurface::GetDC
1062  *
1063  *****************************************************************************/
1064 static HRESULT WINAPI
1065 IDirectDrawSurfaceImpl_GetDC(IDirectDrawSurface7 *iface,
1066                              HDC *hdc)
1067 {
1068     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1069     HRESULT hr;
1070     TRACE("(%p)->(%p): Relay\n", This, hdc);
1071
1072     if(!hdc)
1073         return DDERR_INVALIDPARAMS;
1074
1075     EnterCriticalSection(&ddraw_cs);
1076     hr = IWineD3DSurface_GetDC(This->WineD3DSurface,
1077                                hdc);
1078     LeaveCriticalSection(&ddraw_cs);
1079     return hr;
1080 }
1081
1082 /*****************************************************************************
1083  * IDirectDrawSurface7::ReleaseDC
1084  *
1085  * Releases the DC that was constructed with GetDC
1086  *
1087  * Params:
1088  *  hdc: HDC to release
1089  *
1090  * Returns:
1091  *  DD_OK on success
1092  *  For more details, see IWineD3DSurface::ReleaseDC
1093  *
1094  *****************************************************************************/
1095 static HRESULT WINAPI
1096 IDirectDrawSurfaceImpl_ReleaseDC(IDirectDrawSurface7 *iface,
1097                                  HDC hdc)
1098 {
1099     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1100     HRESULT hr;
1101     TRACE("(%p)->(%p): Relay\n", This, hdc);
1102
1103     EnterCriticalSection(&ddraw_cs);
1104     hr = IWineD3DSurface_ReleaseDC(This->WineD3DSurface, hdc);
1105     LeaveCriticalSection(&ddraw_cs);
1106     return hr;
1107 }
1108
1109 /*****************************************************************************
1110  * IDirectDrawSurface7::GetCaps
1111  *
1112  * Returns the surface's caps
1113  *
1114  * Params:
1115  *  Caps: Address to write the caps to
1116  *
1117  * Returns:
1118  *  DD_OK on success
1119  *  DDERR_INVALIDPARAMS if Caps is NULL
1120  *
1121  *****************************************************************************/
1122 static HRESULT WINAPI
1123 IDirectDrawSurfaceImpl_GetCaps(IDirectDrawSurface7 *iface,
1124                                DDSCAPS2 *Caps)
1125 {
1126     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1127     TRACE("(%p)->(%p)\n",This,Caps);
1128
1129     if(!Caps)
1130         return DDERR_INVALIDPARAMS;
1131
1132     *Caps = This->surface_desc.ddsCaps;
1133     return DD_OK;
1134 }
1135
1136 /*****************************************************************************
1137  * IDirectDrawSurface7::SetPriority
1138  *
1139  * Sets a texture priority for managed textures.
1140  *
1141  * Params:
1142  *  Priority: The new priority
1143  *
1144  * Returns:
1145  *  DD_OK on success
1146  *  For more details, see IWineD3DSurface::SetPriority
1147  *
1148  *****************************************************************************/
1149 static HRESULT WINAPI
1150 IDirectDrawSurfaceImpl_SetPriority(IDirectDrawSurface7 *iface, DWORD Priority)
1151 {
1152     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1153     HRESULT hr;
1154     TRACE("(%p)->(%d): Relay!\n",This,Priority);
1155
1156     EnterCriticalSection(&ddraw_cs);
1157     hr = IWineD3DSurface_SetPriority(This->WineD3DSurface, Priority);
1158     LeaveCriticalSection(&ddraw_cs);
1159     return hr;
1160 }
1161
1162 /*****************************************************************************
1163  * IDirectDrawSurface7::GetPriority
1164  *
1165  * Returns the surface's priority
1166  *
1167  * Params:
1168  *  Priority: Address of a variable to write the priority to
1169  *
1170  * Returns:
1171  *  D3D_OK on success
1172  *  DDERR_INVALIDPARAMS if Priority == NULL
1173  *  For more details, see IWineD3DSurface::GetPriority
1174  *
1175  *****************************************************************************/
1176 static HRESULT WINAPI
1177 IDirectDrawSurfaceImpl_GetPriority(IDirectDrawSurface7 *iface,
1178                                    DWORD *Priority)
1179 {
1180     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1181     TRACE("(%p)->(%p): Relay\n",This,Priority);
1182
1183     if(!Priority)
1184     {
1185         return DDERR_INVALIDPARAMS;
1186     }
1187
1188     EnterCriticalSection(&ddraw_cs);
1189     *Priority = IWineD3DSurface_GetPriority(This->WineD3DSurface);
1190     LeaveCriticalSection(&ddraw_cs);
1191     return DD_OK;
1192 }
1193
1194 /*****************************************************************************
1195  * IDirectDrawSurface7::SetPrivateData
1196  *
1197  * Stores some data in the surface that is intended for the application's
1198  * use.
1199  *
1200  * Params:
1201  *  tag: GUID that identifies the data
1202  *  Data: Pointer to the private data
1203  *  Size: Size of the private data
1204  *  Flags: Some flags
1205  *
1206  * Returns:
1207  *  D3D_OK on success
1208  *  For more details, see IWineD3DSurface::SetPrivateData
1209  *
1210  *****************************************************************************/
1211 static HRESULT WINAPI
1212 IDirectDrawSurfaceImpl_SetPrivateData(IDirectDrawSurface7 *iface,
1213                                       REFGUID tag,
1214                                       void *Data,
1215                                       DWORD Size,
1216                                       DWORD Flags)
1217 {
1218     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1219     HRESULT hr;
1220     TRACE("(%p)->(%s,%p,%d,%x): Relay\n", This, debugstr_guid(tag), Data, Size, Flags);
1221
1222     EnterCriticalSection(&ddraw_cs);
1223     hr = IWineD3DSurface_SetPrivateData(This->WineD3DSurface,
1224                                         tag,
1225                                         Data,
1226                                         Size,
1227                                         Flags);
1228     LeaveCriticalSection(&ddraw_cs);
1229     switch(hr)
1230     {
1231         case WINED3DERR_INVALIDCALL:        return DDERR_INVALIDPARAMS;
1232         default:                            return hr;
1233     }
1234 }
1235
1236 /*****************************************************************************
1237  * IDirectDrawSurface7::GetPrivateData
1238  *
1239  * Returns the private data set with IDirectDrawSurface7::SetPrivateData
1240  *
1241  * Params:
1242  *  tag: GUID of the data to return
1243  *  Data: Address where to write the data to
1244  *  Size: Size of the buffer at Data
1245  *
1246  * Returns:
1247  *  DD_OK on success
1248  *  DDERR_INVALIDPARAMS if Data is NULL
1249  *  For more details, see IWineD3DSurface::GetPrivateData
1250  *
1251  *****************************************************************************/
1252 static HRESULT WINAPI
1253 IDirectDrawSurfaceImpl_GetPrivateData(IDirectDrawSurface7 *iface,
1254                                       REFGUID tag,
1255                                       void *Data,
1256                                       DWORD *Size)
1257 {
1258     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1259     HRESULT hr;
1260     TRACE("(%p)->(%s,%p,%p): Relay\n", This, debugstr_guid(tag), Data, Size);
1261
1262     if(!Data)
1263         return DDERR_INVALIDPARAMS;
1264
1265     EnterCriticalSection(&ddraw_cs);
1266     hr = IWineD3DSurface_GetPrivateData(This->WineD3DSurface,
1267                                         tag,
1268                                         Data,
1269                                         Size);
1270     LeaveCriticalSection(&ddraw_cs);
1271     return hr;
1272 }
1273
1274 /*****************************************************************************
1275  * IDirectDrawSurface7::FreePrivateData
1276  *
1277  * Frees private data stored in the surface
1278  *
1279  * Params:
1280  *  tag: Tag of the data to free
1281  *
1282  * Returns:
1283  *  D3D_OK on success
1284  *  For more details, see IWineD3DSurface::FreePrivateData
1285  *
1286  *****************************************************************************/
1287 static HRESULT WINAPI
1288 IDirectDrawSurfaceImpl_FreePrivateData(IDirectDrawSurface7 *iface,
1289                                        REFGUID tag)
1290 {
1291     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1292     HRESULT hr;
1293     TRACE("(%p)->(%s): Relay\n", This, debugstr_guid(tag));
1294
1295     EnterCriticalSection(&ddraw_cs);
1296     hr = IWineD3DSurface_FreePrivateData(This->WineD3DSurface, tag);
1297     LeaveCriticalSection(&ddraw_cs);
1298     return hr;
1299 }
1300
1301 /*****************************************************************************
1302  * IDirectDrawSurface7::PageLock
1303  *
1304  * Prevents a sysmem surface from being paged out
1305  *
1306  * Params:
1307  *  Flags: Not used, must be 0(unchecked)
1308  *
1309  * Returns:
1310  *  DD_OK, because it's a stub
1311  *
1312  *****************************************************************************/
1313 static HRESULT WINAPI
1314 IDirectDrawSurfaceImpl_PageLock(IDirectDrawSurface7 *iface,
1315                                 DWORD Flags)
1316 {
1317     TRACE("(%p)->(%x)\n", iface, Flags);
1318
1319     /* This is Windows memory management related - we don't need this */
1320     return DD_OK;
1321 }
1322
1323 /*****************************************************************************
1324  * IDirectDrawSurface7::PageUnlock
1325  *
1326  * Allows a sysmem surface to be paged out
1327  *
1328  * Params:
1329  *  Flags: Not used, must be 0(unchecked)
1330  *
1331  * Returns:
1332  *  DD_OK, because it's a stub
1333  *
1334  *****************************************************************************/
1335 static HRESULT WINAPI
1336 IDirectDrawSurfaceImpl_PageUnlock(IDirectDrawSurface7 *iface,
1337                                   DWORD Flags)
1338 {
1339     TRACE("(%p)->(%x)\n", iface, Flags);
1340
1341     return DD_OK;
1342 }
1343
1344 /*****************************************************************************
1345  * IDirectDrawSurface7::BltBatch
1346  *
1347  * An unimplemented function
1348  *
1349  * Params:
1350  *  ?
1351  *
1352  * Returns:
1353  *  DDERR_UNSUPPORTED
1354  *
1355  *****************************************************************************/
1356 static HRESULT WINAPI IDirectDrawSurfaceImpl_BltBatch(IDirectDrawSurface7 *iface, DDBLTBATCH *Batch, DWORD Count, DWORD Flags)
1357 {
1358     TRACE("(%p)->(%p,%d,%08x)\n",iface,Batch,Count,Flags);
1359
1360     /* MSDN: "not currently implemented" */
1361     return DDERR_UNSUPPORTED;
1362 }
1363
1364 /*****************************************************************************
1365  * IDirectDrawSurface7::EnumAttachedSurfaces
1366  *
1367  * Enumerates all surfaces attached to this surface
1368  *
1369  * Params:
1370  *  context: Pointer to pass unmodified to the callback
1371  *  cb: Callback function to call for each surface
1372  *
1373  * Returns:
1374  *  DD_OK on success
1375  *  DDERR_INVALIDPARAMS if cb is NULL
1376  *
1377  *****************************************************************************/
1378 static HRESULT WINAPI
1379 IDirectDrawSurfaceImpl_EnumAttachedSurfaces(IDirectDrawSurface7 *iface,
1380                                             void *context,
1381                                             LPDDENUMSURFACESCALLBACK7 cb)
1382 {
1383     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1384     IDirectDrawSurfaceImpl *surf;
1385     DDSURFACEDESC2 desc;
1386     int i;
1387
1388     /* Attached surfaces aren't handled in WineD3D */
1389     TRACE("(%p)->(%p,%p)\n",This,context,cb);
1390
1391     if(!cb)
1392         return DDERR_INVALIDPARAMS;
1393
1394     EnterCriticalSection(&ddraw_cs);
1395     for(i = 0; i < MAX_COMPLEX_ATTACHED; i++)
1396     {
1397         surf = This->complex_array[i];
1398         if(!surf) break;
1399
1400         IDirectDrawSurface7_AddRef(ICOM_INTERFACE(surf, IDirectDrawSurface7));
1401         desc = surf->surface_desc;
1402         /* check: != DDENUMRET_OK or == DDENUMRET_CANCEL? */
1403         if (cb(ICOM_INTERFACE(surf, IDirectDrawSurface7), &desc, context) == DDENUMRET_CANCEL)
1404         {
1405             LeaveCriticalSection(&ddraw_cs);
1406             return DD_OK;
1407         }
1408     }
1409
1410     for (surf = This->next_attached; surf != NULL; surf = surf->next_attached)
1411     {
1412         IDirectDrawSurface7_AddRef(ICOM_INTERFACE(surf, IDirectDrawSurface7));
1413         desc = surf->surface_desc;
1414         /* check: != DDENUMRET_OK or == DDENUMRET_CANCEL? */
1415         if (cb( ICOM_INTERFACE(surf, IDirectDrawSurface7), &desc, context) == DDENUMRET_CANCEL)
1416         {
1417             LeaveCriticalSection(&ddraw_cs);
1418             return DD_OK;
1419         }
1420     }
1421
1422     TRACE(" end of enumeration.\n");
1423
1424     LeaveCriticalSection(&ddraw_cs);
1425     return DD_OK;
1426 }
1427
1428 /*****************************************************************************
1429  * IDirectDrawSurface7::EnumOverlayZOrders
1430  *
1431  * "Enumerates the overlay surfaces on the specified destination"
1432  *
1433  * Params:
1434  *  Flags: DDENUMOVERLAYZ_BACKTOFRONT  or DDENUMOVERLAYZ_FRONTTOBACK
1435  *  context: context to pass back to the callback
1436  *  cb: callback function to call for each enumerated surface
1437  *
1438  * Returns:
1439  *  DD_OK, because it's a stub
1440  *
1441  *****************************************************************************/
1442 static HRESULT WINAPI
1443 IDirectDrawSurfaceImpl_EnumOverlayZOrders(IDirectDrawSurface7 *iface,
1444                                           DWORD Flags,
1445                                           void *context,
1446                                           LPDDENUMSURFACESCALLBACK7 cb)
1447 {
1448      FIXME("(%p)->(%x,%p,%p): Stub!\n", iface, Flags, context, cb);
1449
1450     return DD_OK;
1451 }
1452
1453 /*****************************************************************************
1454  * IDirectDrawSurface7::GetBltStatus
1455  *
1456  * Returns the blitting status
1457  *
1458  * Params:
1459  *  Flags: DDGBS_CANBLT or DDGBS_ISBLTDONE
1460  *
1461  * Returns:
1462  *  See IWineD3DSurface::Blt
1463  *
1464  *****************************************************************************/
1465 static HRESULT WINAPI
1466 IDirectDrawSurfaceImpl_GetBltStatus(IDirectDrawSurface7 *iface,
1467                                     DWORD Flags)
1468 {
1469     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1470     HRESULT hr;
1471     TRACE("(%p)->(%x): Relay\n", This, Flags);
1472
1473     EnterCriticalSection(&ddraw_cs);
1474     hr = IWineD3DSurface_GetBltStatus(This->WineD3DSurface, Flags);
1475     LeaveCriticalSection(&ddraw_cs);
1476     switch(hr)
1477     {
1478         case WINED3DERR_INVALIDCALL:        return DDERR_INVALIDPARAMS;
1479         default:                            return hr;
1480     }
1481 }
1482
1483 /*****************************************************************************
1484  * IDirectDrawSurface7::GetColorKey
1485  *
1486  * Returns the color key assigned to the surface
1487  *
1488  * Params:
1489  *  Flags: Some flags
1490  *  CKey: Address to store the key to
1491  *
1492  * Returns:
1493  *  DD_OK on success
1494  *  DDERR_INVALIDPARAMS if CKey is NULL
1495  *
1496  *****************************************************************************/
1497 static HRESULT WINAPI
1498 IDirectDrawSurfaceImpl_GetColorKey(IDirectDrawSurface7 *iface,
1499                                    DWORD Flags,
1500                                    DDCOLORKEY *CKey)
1501 {
1502     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1503     TRACE("(%p)->(%08x,%p)\n", This, Flags, CKey);
1504
1505     if(!CKey)
1506         return DDERR_INVALIDPARAMS;
1507
1508     EnterCriticalSection(&ddraw_cs);
1509
1510     switch (Flags)
1511     {
1512     case DDCKEY_DESTBLT:
1513         if (!(This->surface_desc.dwFlags & DDSD_CKDESTBLT))
1514         {
1515             LeaveCriticalSection(&ddraw_cs);
1516             return DDERR_NOCOLORKEY;
1517         }
1518         *CKey = This->surface_desc.ddckCKDestBlt;
1519         break;
1520
1521     case DDCKEY_DESTOVERLAY:
1522         if (!(This->surface_desc.dwFlags & DDSD_CKDESTOVERLAY))
1523             {
1524             LeaveCriticalSection(&ddraw_cs);
1525             return DDERR_NOCOLORKEY;
1526             }
1527         *CKey = This->surface_desc.u3.ddckCKDestOverlay;
1528         break;
1529
1530     case DDCKEY_SRCBLT:
1531         if (!(This->surface_desc.dwFlags & DDSD_CKSRCBLT))
1532         {
1533             LeaveCriticalSection(&ddraw_cs);
1534             return DDERR_NOCOLORKEY;
1535         }
1536         *CKey = This->surface_desc.ddckCKSrcBlt;
1537         break;
1538
1539     case DDCKEY_SRCOVERLAY:
1540         if (!(This->surface_desc.dwFlags & DDSD_CKSRCOVERLAY))
1541         {
1542             LeaveCriticalSection(&ddraw_cs);
1543             return DDERR_NOCOLORKEY;
1544         }
1545         *CKey = This->surface_desc.ddckCKSrcOverlay;
1546         break;
1547
1548     default:
1549         LeaveCriticalSection(&ddraw_cs);
1550         return DDERR_INVALIDPARAMS;
1551     }
1552
1553     LeaveCriticalSection(&ddraw_cs);
1554     return DD_OK;
1555 }
1556
1557 /*****************************************************************************
1558  * IDirectDrawSurface7::GetFlipStatus
1559  *
1560  * Returns the flipping status of the surface
1561  *
1562  * Params:
1563  *  Flags: DDGFS_CANFLIP of DDGFS_ISFLIPDONE
1564  *
1565  * Returns:
1566  *  See IWineD3DSurface::GetFlipStatus
1567  *
1568  *****************************************************************************/
1569 static HRESULT WINAPI
1570 IDirectDrawSurfaceImpl_GetFlipStatus(IDirectDrawSurface7 *iface,
1571                                      DWORD Flags)
1572 {
1573     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1574     HRESULT hr;
1575     TRACE("(%p)->(%x): Relay\n", This, Flags);
1576
1577     EnterCriticalSection(&ddraw_cs);
1578     hr = IWineD3DSurface_GetFlipStatus(This->WineD3DSurface, Flags);
1579     LeaveCriticalSection(&ddraw_cs);
1580     switch(hr)
1581     {
1582         case WINED3DERR_INVALIDCALL:        return DDERR_INVALIDPARAMS;
1583         default:                            return hr;
1584     }
1585 }
1586
1587 /*****************************************************************************
1588  * IDirectDrawSurface7::GetOverlayPosition
1589  *
1590  * Returns the display coordinates of a visible and active overlay surface
1591  *
1592  * Params:
1593  *  X
1594  *  Y
1595  *
1596  * Returns:
1597  *  DDERR_NOTAOVERLAYSURFACE, because it's a stub
1598  *****************************************************************************/
1599 static HRESULT WINAPI
1600 IDirectDrawSurfaceImpl_GetOverlayPosition(IDirectDrawSurface7 *iface,
1601                                           LONG *X,
1602                                           LONG *Y) {
1603     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1604     HRESULT hr;
1605     TRACE("(%p)->(%p,%p): Relay\n", This, X, Y);
1606
1607     EnterCriticalSection(&ddraw_cs);
1608     hr = IWineD3DSurface_GetOverlayPosition(This->WineD3DSurface,
1609                                             X,
1610                                             Y);
1611     LeaveCriticalSection(&ddraw_cs);
1612     return hr;
1613 }
1614
1615 /*****************************************************************************
1616  * IDirectDrawSurface7::GetPixelFormat
1617  *
1618  * Returns the pixel format of the Surface
1619  *
1620  * Params:
1621  *  PixelFormat: Pointer to a DDPIXELFORMAT structure to which the pixel
1622  *               format should be written
1623  *
1624  * Returns:
1625  *  DD_OK on success
1626  *  DDERR_INVALIDPARAMS if PixelFormat is NULL
1627  *
1628  *****************************************************************************/
1629 static HRESULT WINAPI
1630 IDirectDrawSurfaceImpl_GetPixelFormat(IDirectDrawSurface7 *iface,
1631                                       DDPIXELFORMAT *PixelFormat)
1632 {
1633     /* What is DDERR_INVALIDSURFACETYPE for here? */
1634     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1635     TRACE("(%p)->(%p)\n",This,PixelFormat);
1636
1637     if(!PixelFormat)
1638         return DDERR_INVALIDPARAMS;
1639
1640     EnterCriticalSection(&ddraw_cs);
1641     DD_STRUCT_COPY_BYSIZE(PixelFormat,&This->surface_desc.u4.ddpfPixelFormat);
1642     LeaveCriticalSection(&ddraw_cs);
1643
1644     return DD_OK;
1645 }
1646
1647
1648 /*****************************************************************************
1649  * IDirectDrawSurface7::GetSurfaceDesc
1650  *
1651  * Returns the description of this surface
1652  *
1653  * Params:
1654  *  DDSD: Address of a DDSURFACEDESC2 structure that is to be filled with the
1655  *        surface desc
1656  *
1657  * Returns:
1658  *  DD_OK on success
1659  *  DDERR_INVALIDPARAMS if DDSD is NULL
1660  *
1661  *****************************************************************************/
1662 static HRESULT WINAPI
1663 IDirectDrawSurfaceImpl_GetSurfaceDesc(IDirectDrawSurface7 *iface,
1664                                       DDSURFACEDESC2 *DDSD)
1665 {
1666     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1667
1668     TRACE("(%p)->(%p)\n",This,DDSD);
1669
1670     if(!DDSD)
1671         return DDERR_INVALIDPARAMS;
1672
1673     if (DDSD->dwSize != sizeof(DDSURFACEDESC2))
1674     {
1675         WARN("Incorrect struct size %d, returning DDERR_INVALIDPARAMS\n",DDSD->dwSize);
1676         return DDERR_INVALIDPARAMS;
1677     }
1678
1679     EnterCriticalSection(&ddraw_cs);
1680     DD_STRUCT_COPY_BYSIZE(DDSD,&This->surface_desc);
1681     TRACE("Returning surface desc:\n");
1682     if (TRACE_ON(ddraw)) DDRAW_dump_surface_desc(DDSD);
1683
1684     LeaveCriticalSection(&ddraw_cs);
1685     return DD_OK;
1686 }
1687
1688 /*****************************************************************************
1689  * IDirectDrawSurface7::Initialize
1690  *
1691  * Initializes the surface. This is a no-op in Wine
1692  *
1693  * Params:
1694  *  DD: Pointer to an DirectDraw interface
1695  *  DDSD: Surface description for initialization
1696  *
1697  * Returns:
1698  *  DDERR_ALREADYINITIALIZED
1699  *
1700  *****************************************************************************/
1701 static HRESULT WINAPI
1702 IDirectDrawSurfaceImpl_Initialize(IDirectDrawSurface7 *iface,
1703                                   IDirectDraw *DD,
1704                                   DDSURFACEDESC2 *DDSD)
1705 {
1706     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1707     IDirectDrawImpl *ddimpl = ICOM_OBJECT(IDirectDrawImpl, IDirectDraw, DD);
1708     TRACE("(%p)->(%p,%p)\n",This,ddimpl,DDSD);
1709
1710     return DDERR_ALREADYINITIALIZED;
1711 }
1712
1713 /*****************************************************************************
1714  * IDirectDrawSurface7::IsLost
1715  *
1716  * Checks if the surface is lost
1717  *
1718  * Returns:
1719  *  DD_OK, if the surface is usable
1720  *  DDERR_ISLOST if the surface is lost
1721  *  See IWineD3DSurface::IsLost for more details
1722  *
1723  *****************************************************************************/
1724 static HRESULT WINAPI
1725 IDirectDrawSurfaceImpl_IsLost(IDirectDrawSurface7 *iface)
1726 {
1727     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1728     HRESULT hr;
1729     TRACE("(%p)\n", This);
1730
1731     EnterCriticalSection(&ddraw_cs);
1732     /* We lose the surface if the implementation was changed */
1733     if(This->ImplType != This->ddraw->ImplType)
1734     {
1735         /* But this shouldn't happen. When we change the implementation,
1736          * all surfaces are re-created automatically, and their content
1737          * is copied
1738          */
1739         ERR(" (%p) Implementation was changed from %d to %d\n", This, This->ImplType, This->ddraw->ImplType);
1740         LeaveCriticalSection(&ddraw_cs);
1741         return DDERR_SURFACELOST;
1742     }
1743
1744     hr = IWineD3DSurface_IsLost(This->WineD3DSurface);
1745     LeaveCriticalSection(&ddraw_cs);
1746     switch(hr)
1747     {
1748         /* D3D8 and 9 loose full devices, thus there's only a DEVICELOST error.
1749          * WineD3D uses the same error for surfaces
1750          */
1751         case WINED3DERR_DEVICELOST:         return DDERR_SURFACELOST;
1752         default:                            return hr;
1753     }
1754 }
1755
1756 /*****************************************************************************
1757  * IDirectDrawSurface7::Restore
1758  *
1759  * Restores a lost surface. This makes the surface usable again, but
1760  * doesn't reload its old contents
1761  *
1762  * Returns:
1763  *  DD_OK on success
1764  *  See IWineD3DSurface::Restore for more details
1765  *
1766  *****************************************************************************/
1767 static HRESULT WINAPI
1768 IDirectDrawSurfaceImpl_Restore(IDirectDrawSurface7 *iface)
1769 {
1770     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1771     HRESULT hr;
1772     TRACE("(%p)\n", This);
1773
1774     EnterCriticalSection(&ddraw_cs);
1775     if(This->ImplType != This->ddraw->ImplType)
1776     {
1777         /* Call the recreation callback. Make sure to AddRef first */
1778         IDirectDrawSurface_AddRef(iface);
1779         IDirectDrawImpl_RecreateSurfacesCallback(iface,
1780                                                  &This->surface_desc,
1781                                                  NULL /* Not needed */);
1782     }
1783     hr = IWineD3DSurface_Restore(This->WineD3DSurface);
1784     LeaveCriticalSection(&ddraw_cs);
1785     return hr;
1786 }
1787
1788 /*****************************************************************************
1789  * IDirectDrawSurface7::SetOverlayPosition
1790  *
1791  * Changes the display coordinates of an overlay surface
1792  *
1793  * Params:
1794  *  X:
1795  *  Y:
1796  *
1797  * Returns:
1798  *   DDERR_NOTAOVERLAYSURFACE, because we don't support overlays right now
1799  *****************************************************************************/
1800 static HRESULT WINAPI
1801 IDirectDrawSurfaceImpl_SetOverlayPosition(IDirectDrawSurface7 *iface,
1802                                           LONG X,
1803                                           LONG Y)
1804 {
1805     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1806     HRESULT hr;
1807     TRACE("(%p)->(%d,%d): Relay\n", This, X, Y);
1808
1809     EnterCriticalSection(&ddraw_cs);
1810     hr = IWineD3DSurface_SetOverlayPosition(This->WineD3DSurface,
1811                                             X,
1812                                             Y);
1813     LeaveCriticalSection(&ddraw_cs);
1814     return hr;
1815 }
1816
1817 /*****************************************************************************
1818  * IDirectDrawSurface7::UpdateOverlay
1819  *
1820  * Modifies the attributes of an overlay surface.
1821  *
1822  * Params:
1823  *  SrcRect: The section of the source being used for the overlay
1824  *  DstSurface: Address of the surface that is overlaid
1825  *  DstRect: Place of the overlay
1826  *  Flags: some DDOVER_* flags
1827  *
1828  * Returns:
1829  *  DDERR_UNSUPPORTED, because we don't support overlays
1830  *
1831  *****************************************************************************/
1832 static HRESULT WINAPI
1833 IDirectDrawSurfaceImpl_UpdateOverlay(IDirectDrawSurface7 *iface,
1834                                      LPRECT SrcRect,
1835                                      IDirectDrawSurface7 *DstSurface,
1836                                      LPRECT DstRect,
1837                                      DWORD Flags,
1838                                      LPDDOVERLAYFX FX)
1839 {
1840     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1841     IDirectDrawSurfaceImpl *Dst = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, DstSurface);
1842     HRESULT hr;
1843     TRACE("(%p)->(%p,%p,%p,%x,%p): Relay\n", This, SrcRect, Dst, DstRect, Flags, FX);
1844
1845     EnterCriticalSection(&ddraw_cs);
1846     hr = IWineD3DSurface_UpdateOverlay(This->WineD3DSurface,
1847                                        SrcRect,
1848                                        Dst ? Dst->WineD3DSurface : NULL,
1849                                        DstRect,
1850                                        Flags,
1851                                        (WINEDDOVERLAYFX *) FX);
1852     LeaveCriticalSection(&ddraw_cs);
1853     switch(hr) {
1854         case WINED3DERR_INVALIDCALL:        return DDERR_INVALIDPARAMS;
1855         case WINEDDERR_NOTAOVERLAYSURFACE:  return DDERR_NOTAOVERLAYSURFACE;
1856         case WINEDDERR_OVERLAYNOTVISIBLE:   return DDERR_OVERLAYNOTVISIBLE;
1857         default:
1858             return hr;
1859     }
1860 }
1861
1862 /*****************************************************************************
1863  * IDirectDrawSurface7::UpdateOverlayDisplay
1864  *
1865  * The DX7 sdk says that it's not implemented
1866  *
1867  * Params:
1868  *  Flags: ?
1869  *
1870  * Returns: DDERR_UNSUPPORTED, because we don't support overlays
1871  *
1872  *****************************************************************************/
1873 static HRESULT WINAPI
1874 IDirectDrawSurfaceImpl_UpdateOverlayDisplay(IDirectDrawSurface7 *iface,
1875                                             DWORD Flags)
1876 {
1877     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1878     TRACE("(%p)->(%x)\n", This, Flags);
1879     return DDERR_UNSUPPORTED;
1880 }
1881
1882 /*****************************************************************************
1883  * IDirectDrawSurface7::UpdateOverlayZOrder
1884  *
1885  * Sets an overlay's Z order
1886  *
1887  * Params:
1888  *  Flags: DDOVERZ_* flags
1889  *  DDSRef: Defines the relative position in the overlay chain
1890  *
1891  * Returns:
1892  *  DDERR_NOTOVERLAYSURFACE, because we don't support overlays
1893  *
1894  *****************************************************************************/
1895 static HRESULT WINAPI
1896 IDirectDrawSurfaceImpl_UpdateOverlayZOrder(IDirectDrawSurface7 *iface,
1897                                            DWORD Flags,
1898                                            IDirectDrawSurface7 *DDSRef)
1899 {
1900     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1901     HRESULT hr;
1902     IDirectDrawSurfaceImpl *Ref = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, DDSRef);
1903
1904     TRACE("(%p)->(%x,%p): Relay\n", This, Flags, Ref);
1905     EnterCriticalSection(&ddraw_cs);
1906     hr =  IWineD3DSurface_UpdateOverlayZOrder(This->WineD3DSurface,
1907                                               Flags,
1908                                               Ref ? Ref->WineD3DSurface : NULL);
1909     LeaveCriticalSection(&ddraw_cs);
1910     return hr;
1911 }
1912
1913 /*****************************************************************************
1914  * IDirectDrawSurface7::GetDDInterface
1915  *
1916  * Returns the IDirectDraw7 interface pointer of the DirectDraw object this
1917  * surface belongs to
1918  *
1919  * Params:
1920  *  DD: Address to write the interface pointer to
1921  *
1922  * Returns:
1923  *  DD_OK on success
1924  *  DDERR_INVALIDPARAMS if DD is NULL
1925  *
1926  *****************************************************************************/
1927 static HRESULT WINAPI
1928 IDirectDrawSurfaceImpl_GetDDInterface(IDirectDrawSurface7 *iface,
1929                                       void **DD)
1930 {
1931     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1932
1933     TRACE("(%p)->(%p)\n",This,DD);
1934
1935     if(!DD)
1936         return DDERR_INVALIDPARAMS;
1937
1938     switch(This->version)
1939     {
1940         case 7:
1941             *((IDirectDraw7 **) DD) = ICOM_INTERFACE(This->ddraw, IDirectDraw7);
1942             IDirectDraw7_AddRef(*(IDirectDraw7 **) DD);
1943             break;
1944
1945         case 4:
1946             *((IDirectDraw4 **) DD) = ICOM_INTERFACE(This->ddraw, IDirectDraw4);
1947             IDirectDraw4_AddRef(*(IDirectDraw4 **) DD);
1948             break;
1949
1950         case 2:
1951             *((IDirectDraw2 **) DD) = ICOM_INTERFACE(This->ddraw, IDirectDraw2);
1952             IDirectDraw_AddRef( *(IDirectDraw2 **) DD);
1953             break;
1954
1955         case 1:
1956             *((IDirectDraw **) DD) = ICOM_INTERFACE(This->ddraw, IDirectDraw);
1957             IDirectDraw_AddRef( *(IDirectDraw **) DD);
1958             break;
1959
1960     }
1961
1962     return DD_OK;
1963 }
1964
1965 /* This seems also windows implementation specific - I don't think WineD3D needs this */
1966 static HRESULT WINAPI IDirectDrawSurfaceImpl_ChangeUniquenessValue(IDirectDrawSurface7 *iface)
1967 {
1968     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1969     volatile IDirectDrawSurfaceImpl* vThis = This;
1970
1971     TRACE("(%p)\n",This);
1972     EnterCriticalSection(&ddraw_cs);
1973     /* A uniqueness value of 0 is apparently special.
1974      * This needs to be checked.
1975      * TODO: Write tests for this code and check if the volatile, interlocked stuff is really needed
1976      */
1977     while (1) {
1978         DWORD old_uniqueness_value = vThis->uniqueness_value;
1979         DWORD new_uniqueness_value = old_uniqueness_value+1;
1980
1981         if (old_uniqueness_value == 0) break;
1982         if (new_uniqueness_value == 0) new_uniqueness_value = 1;
1983
1984         if (InterlockedCompareExchange((LONG*)&vThis->uniqueness_value,
1985                                       old_uniqueness_value,
1986                                       new_uniqueness_value)
1987             == old_uniqueness_value)
1988             break;
1989     }
1990
1991     LeaveCriticalSection(&ddraw_cs);
1992     return DD_OK;
1993 }
1994
1995 static HRESULT WINAPI IDirectDrawSurfaceImpl_GetUniquenessValue(IDirectDrawSurface7 *iface, LPDWORD pValue)
1996 {
1997     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1998
1999     TRACE("(%p)->(%p)\n",This,pValue);
2000     EnterCriticalSection(&ddraw_cs);
2001     *pValue = This->uniqueness_value;
2002     LeaveCriticalSection(&ddraw_cs);
2003     return DD_OK;
2004 }
2005
2006 /*****************************************************************************
2007  * IDirectDrawSurface7::SetLOD
2008  *
2009  * Sets the level of detail of a texture
2010  *
2011  * Params:
2012  *  MaxLOD: LOD to set
2013  *
2014  * Returns:
2015  *  DD_OK on success
2016  *  DDERR_INVALIDOBJECT if the surface is invalid for this method
2017  *
2018  *****************************************************************************/
2019 static HRESULT WINAPI
2020 IDirectDrawSurfaceImpl_SetLOD(IDirectDrawSurface7 *iface,
2021                               DWORD MaxLOD)
2022 {
2023     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
2024     HRESULT hr;
2025     TRACE("(%p)->(%d)\n", This, MaxLOD);
2026
2027     EnterCriticalSection(&ddraw_cs);
2028     if (!(This->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_TEXTUREMANAGE))
2029     {
2030         LeaveCriticalSection(&ddraw_cs);
2031         return DDERR_INVALIDOBJECT;
2032     }
2033
2034     if(!This->wineD3DTexture)
2035     {
2036         ERR("(%p) The DirectDraw texture has no WineD3DTexture!\n", This);
2037         LeaveCriticalSection(&ddraw_cs);
2038         return DDERR_INVALIDOBJECT;
2039     }
2040
2041     hr = IWineD3DBaseTexture_SetLOD(This->wineD3DTexture,
2042                                     MaxLOD);
2043     LeaveCriticalSection(&ddraw_cs);
2044     return hr;
2045 }
2046
2047 /*****************************************************************************
2048  * IDirectDrawSurface7::GetLOD
2049  *
2050  * Returns the level of detail of a Direct3D texture
2051  *
2052  * Params:
2053  *  MaxLOD: Address to write the LOD to
2054  *
2055  * Returns:
2056  *  DD_OK on success
2057  *  DDERR_INVALIDPARAMS if MaxLOD is NULL
2058  *  DDERR_INVALIDOBJECT if the surface is invalid for this method
2059  *
2060  *****************************************************************************/
2061 static HRESULT WINAPI
2062 IDirectDrawSurfaceImpl_GetLOD(IDirectDrawSurface7 *iface,
2063                               DWORD *MaxLOD)
2064 {
2065     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
2066     TRACE("(%p)->(%p)\n", This, MaxLOD);
2067
2068     if(!MaxLOD)
2069         return DDERR_INVALIDPARAMS;
2070
2071     EnterCriticalSection(&ddraw_cs);
2072     if (!(This->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_TEXTUREMANAGE))
2073     {
2074         LeaveCriticalSection(&ddraw_cs);
2075         return DDERR_INVALIDOBJECT;
2076     }
2077
2078     *MaxLOD = IWineD3DBaseTexture_GetLOD(This->wineD3DTexture);
2079     LeaveCriticalSection(&ddraw_cs);
2080     return DD_OK;
2081 }
2082
2083 /*****************************************************************************
2084  * IDirectDrawSurface7::BltFast
2085  *
2086  * Performs a fast Blit.
2087  *
2088  * Params:
2089  *  dstx: The x coordinate to blit to on the destination
2090  *  dsty: The y coordinate to blit to on the destination
2091  *  Source: The source surface
2092  *  rsrc: The source rectangle
2093  *  trans: Type of transfer. Some DDBLTFAST_* flags
2094  *
2095  * Returns:
2096  *  DD_OK on success
2097  *  For more details, see IWineD3DSurface::BltFast
2098  *
2099  *****************************************************************************/
2100 static HRESULT WINAPI
2101 IDirectDrawSurfaceImpl_BltFast(IDirectDrawSurface7 *iface,
2102                                DWORD dstx,
2103                                DWORD dsty,
2104                                IDirectDrawSurface7 *Source,
2105                                RECT *rsrc,
2106                                DWORD trans)
2107 {
2108     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
2109     HRESULT hr;
2110     IDirectDrawSurfaceImpl *src = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, Source);
2111     TRACE("(%p)->(%d,%d,%p,%p,%d): Relay\n", This, dstx, dsty, Source, rsrc, trans);
2112
2113     /* Source must be != NULL, This is not checked by windows. Windows happily throws a 0xc0000005
2114      * in that case
2115      */
2116     if(rsrc)
2117     {
2118         if(rsrc->top > rsrc->bottom || rsrc->left > rsrc->right ||
2119            rsrc->right > src->surface_desc.dwWidth ||
2120            rsrc->bottom > src->surface_desc.dwHeight)
2121         {
2122             WARN("Source rectangle is invalid, returning DDERR_INVALIDRECT\n");
2123             return DDERR_INVALIDRECT;
2124         }
2125         if(dstx + rsrc->right - rsrc->left > This->surface_desc.dwWidth ||
2126            dsty + rsrc->bottom - rsrc->top > This->surface_desc.dwHeight)
2127         {
2128             WARN("Destination area out of bounds, returning DDERR_INVALIDRECT\n");
2129             return DDERR_INVALIDRECT;
2130         }
2131     }
2132     else
2133     {
2134         if(dstx + src->surface_desc.dwWidth > This->surface_desc.dwWidth ||
2135            dsty + src->surface_desc.dwHeight > This->surface_desc.dwHeight)
2136         {
2137             WARN("Destination area out of bounds, returning DDERR_INVALIDRECT\n");
2138             return DDERR_INVALIDRECT;
2139         }
2140     }
2141
2142     EnterCriticalSection(&ddraw_cs);
2143     hr = IWineD3DSurface_BltFast(This->WineD3DSurface,
2144                                  dstx, dsty,
2145                                  src ? src->WineD3DSurface : NULL,
2146                                  rsrc,
2147                                  trans);
2148     LeaveCriticalSection(&ddraw_cs);
2149     switch(hr)
2150     {
2151         case WINED3DERR_NOTAVAILABLE:           return DDERR_UNSUPPORTED;
2152         case WINED3DERR_WRONGTEXTUREFORMAT:     return DDERR_INVALIDPIXELFORMAT;
2153         default:                                return hr;
2154     }
2155 }
2156
2157 /*****************************************************************************
2158  * IDirectDrawSurface7::GetClipper
2159  *
2160  * Returns the IDirectDrawClipper interface of the clipper assigned to this
2161  * surface
2162  *
2163  * Params:
2164  *  Clipper: Address to store the interface pointer at
2165  *
2166  * Returns:
2167  *  DD_OK on success
2168  *  DDERR_INVALIDPARAMS if Clipper is NULL
2169  *  DDERR_NOCLIPPERATTACHED if there's no clipper attached
2170  *
2171  *****************************************************************************/
2172 static HRESULT WINAPI
2173 IDirectDrawSurfaceImpl_GetClipper(IDirectDrawSurface7 *iface,
2174                                   IDirectDrawClipper **Clipper)
2175 {
2176     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
2177     TRACE("(%p)->(%p)\n", This, Clipper);
2178
2179     if(!Clipper)
2180     {
2181         LeaveCriticalSection(&ddraw_cs);
2182         return DDERR_INVALIDPARAMS;
2183     }
2184
2185     EnterCriticalSection(&ddraw_cs);
2186     if(This->clipper == NULL)
2187     {
2188         LeaveCriticalSection(&ddraw_cs);
2189         return DDERR_NOCLIPPERATTACHED;
2190     }
2191
2192     *Clipper = ICOM_INTERFACE(This->clipper, IDirectDrawClipper);
2193     IDirectDrawClipper_AddRef(*Clipper);
2194     LeaveCriticalSection(&ddraw_cs);
2195     return DD_OK;
2196 }
2197
2198 /*****************************************************************************
2199  * IDirectDrawSurface7::SetClipper
2200  *
2201  * Sets a clipper for the surface
2202  *
2203  * Params:
2204  *  Clipper: IDirectDrawClipper interface of the clipper to set
2205  *
2206  * Returns:
2207  *  DD_OK on success
2208  *
2209  *****************************************************************************/
2210 static HRESULT WINAPI
2211 IDirectDrawSurfaceImpl_SetClipper(IDirectDrawSurface7 *iface,
2212                                   IDirectDrawClipper *Clipper)
2213 {
2214     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
2215     IDirectDrawClipperImpl *oldClipper = This->clipper;
2216     HWND clipWindow;
2217     HRESULT hr;
2218     TRACE("(%p)->(%p)\n",This,Clipper);
2219
2220     EnterCriticalSection(&ddraw_cs);
2221     if (ICOM_OBJECT(IDirectDrawClipperImpl, IDirectDrawClipper, Clipper) == This->clipper)
2222     {
2223         LeaveCriticalSection(&ddraw_cs);
2224         return DD_OK;
2225     }
2226
2227     This->clipper = ICOM_OBJECT(IDirectDrawClipperImpl, IDirectDrawClipper, Clipper);
2228
2229     if (Clipper != NULL)
2230         IDirectDrawClipper_AddRef(Clipper);
2231     if(oldClipper)
2232         IDirectDrawClipper_Release(ICOM_INTERFACE(oldClipper, IDirectDrawClipper));
2233
2234     hr = IWineD3DSurface_SetClipper(This->WineD3DSurface, This->clipper ? This->clipper->wineD3DClipper : NULL);
2235
2236     if(This->wineD3DSwapChain) {
2237         clipWindow = NULL;
2238         if(Clipper) {
2239             IDirectDrawClipper_GetHWnd(Clipper, &clipWindow);
2240         }
2241
2242         if(clipWindow) {
2243             IWineD3DSwapChain_SetDestWindowOverride(This->wineD3DSwapChain,
2244                                                     clipWindow);
2245         } else {
2246             IWineD3DSwapChain_SetDestWindowOverride(This->wineD3DSwapChain,
2247                                                     This->ddraw->d3d_window);
2248         }
2249     }
2250
2251     LeaveCriticalSection(&ddraw_cs);
2252     return hr;
2253 }
2254
2255 /*****************************************************************************
2256  * IDirectDrawSurface7::SetSurfaceDesc
2257  *
2258  * Sets the surface description. It can override the pixel format, the surface
2259  * memory, ...
2260  * It's not really tested.
2261  *
2262  * Params:
2263  * DDSD: Pointer to the new surface description to set
2264  * Flags: Some flags
2265  *
2266  * Returns:
2267  *  DD_OK on success
2268  *  DDERR_INVALIDPARAMS if DDSD is NULL
2269  *
2270  *****************************************************************************/
2271 static HRESULT WINAPI
2272 IDirectDrawSurfaceImpl_SetSurfaceDesc(IDirectDrawSurface7 *iface,
2273                                       DDSURFACEDESC2 *DDSD,
2274                                       DWORD Flags)
2275 {
2276     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
2277     WINED3DFORMAT newFormat = WINED3DFMT_UNKNOWN;
2278     HRESULT hr;
2279     TRACE("(%p)->(%p,%x)\n", This, DDSD, Flags);
2280
2281     if(!DDSD)
2282         return DDERR_INVALIDPARAMS;
2283
2284     EnterCriticalSection(&ddraw_cs);
2285     if (DDSD->dwFlags & DDSD_PIXELFORMAT)
2286     {
2287         newFormat = PixelFormat_DD2WineD3D(&DDSD->u4.ddpfPixelFormat);
2288
2289         if(newFormat == WINED3DFMT_UNKNOWN)
2290         {
2291             ERR("Requested to set an unknown pixelformat\n");
2292             LeaveCriticalSection(&ddraw_cs);
2293             return DDERR_INVALIDPARAMS;
2294         }
2295         if(newFormat != PixelFormat_DD2WineD3D(&This->surface_desc.u4.ddpfPixelFormat) )
2296         {
2297             hr = IWineD3DSurface_SetFormat(This->WineD3DSurface,
2298                                            newFormat);
2299             if(hr != DD_OK)
2300             {
2301                 LeaveCriticalSection(&ddraw_cs);
2302                 return hr;
2303             }
2304         }
2305     }
2306     if (DDSD->dwFlags & DDSD_CKDESTOVERLAY)
2307     {
2308         IWineD3DSurface_SetColorKey(This->WineD3DSurface,
2309                                     DDCKEY_DESTOVERLAY,
2310                                     (WINEDDCOLORKEY *) &DDSD->u3.ddckCKDestOverlay);
2311     }
2312     if (DDSD->dwFlags & DDSD_CKDESTBLT)
2313     {
2314         IWineD3DSurface_SetColorKey(This->WineD3DSurface,
2315                                     DDCKEY_DESTBLT,
2316                                     (WINEDDCOLORKEY *) &DDSD->ddckCKDestBlt);
2317     }
2318     if (DDSD->dwFlags & DDSD_CKSRCOVERLAY)
2319     {
2320         IWineD3DSurface_SetColorKey(This->WineD3DSurface,
2321                                     DDCKEY_SRCOVERLAY,
2322                                     (WINEDDCOLORKEY *) &DDSD->ddckCKSrcOverlay);
2323     }
2324     if (DDSD->dwFlags & DDSD_CKSRCBLT)
2325     {
2326         IWineD3DSurface_SetColorKey(This->WineD3DSurface,
2327                                     DDCKEY_SRCBLT,
2328                                     (WINEDDCOLORKEY *) &DDSD->ddckCKSrcBlt);
2329     }
2330     if (DDSD->dwFlags & DDSD_LPSURFACE && DDSD->lpSurface)
2331     {
2332         hr = IWineD3DSurface_SetMem(This->WineD3DSurface, DDSD->lpSurface);
2333         if(hr != WINED3D_OK)
2334         {
2335             /* No need for a trace here, wined3d does that for us */
2336             LeaveCriticalSection(&ddraw_cs);
2337             switch(hr)
2338             {
2339                 case WINED3DERR_INVALIDCALL:        return DDERR_INVALIDPARAMS;
2340                 default:                            break; /* Go on */
2341             }
2342         }
2343
2344     }
2345
2346     This->surface_desc = *DDSD;
2347
2348     LeaveCriticalSection(&ddraw_cs);
2349     return DD_OK;
2350 }
2351
2352 /*****************************************************************************
2353  * IDirectDrawSurface7::GetPalette
2354  *
2355  * Returns the IDirectDrawPalette interface of the palette currently assigned
2356  * to the surface
2357  *
2358  * Params:
2359  *  Pal: Address to write the interface pointer to
2360  *
2361  * Returns:
2362  *  DD_OK on success
2363  *  DDERR_INVALIDPARAMS if Pal is NULL
2364  *
2365  *****************************************************************************/
2366 static HRESULT WINAPI
2367 IDirectDrawSurfaceImpl_GetPalette(IDirectDrawSurface7 *iface,
2368                                   IDirectDrawPalette **Pal)
2369 {
2370     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
2371     IWineD3DPalette *wPal;
2372     HRESULT hr;
2373     TRACE("(%p)->(%p): Relay\n", This, Pal);
2374
2375     if(!Pal)
2376         return DDERR_INVALIDPARAMS;
2377
2378     EnterCriticalSection(&ddraw_cs);
2379     hr = IWineD3DSurface_GetPalette(This->WineD3DSurface, &wPal);
2380     if(hr != DD_OK)
2381     {
2382         LeaveCriticalSection(&ddraw_cs);
2383         return hr;
2384     }
2385
2386     if(wPal)
2387     {
2388         hr = IWineD3DPalette_GetParent(wPal, (IUnknown **) Pal);
2389     }
2390     else
2391     {
2392         *Pal = NULL;
2393         hr = DDERR_NOPALETTEATTACHED;
2394     }
2395
2396     LeaveCriticalSection(&ddraw_cs);
2397     return hr;
2398 }
2399
2400 /*****************************************************************************
2401  * SetColorKeyEnum
2402  *
2403  * EnumAttachedSurface callback for SetColorKey. Used to set color keys
2404  * recursively in the surface tree
2405  *
2406  *****************************************************************************/
2407 struct SCKContext
2408 {
2409     HRESULT ret;
2410     WINEDDCOLORKEY *CKey;
2411     DWORD Flags;
2412 };
2413
2414 static HRESULT WINAPI
2415 SetColorKeyEnum(IDirectDrawSurface7 *surface,
2416                 DDSURFACEDESC2 *desc,
2417                 void *context)
2418 {
2419     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, surface);
2420     struct SCKContext *ctx = context;
2421     HRESULT hr;
2422
2423     hr = IWineD3DSurface_SetColorKey(This->WineD3DSurface,
2424                                      ctx->Flags,
2425                                      ctx->CKey);
2426     if(hr != DD_OK)
2427     {
2428         WARN("IWineD3DSurface_SetColorKey failed, hr = %08x\n", hr);
2429         ctx->ret = hr;
2430     }
2431
2432     IDirectDrawSurface7_EnumAttachedSurfaces(surface,
2433                                              context,
2434                                              SetColorKeyEnum);
2435     IDirectDrawSurface7_Release(surface);
2436     return DDENUMRET_OK;
2437 }
2438
2439 /*****************************************************************************
2440  * IDirectDrawSurface7::SetColorKey
2441  *
2442  * Sets the color keying options for the surface. Observations showed that
2443  * in case of complex surfaces the color key has to be assigned to all
2444  * sublevels.
2445  *
2446  * Params:
2447  *  Flags: DDCKEY_*
2448  *  CKey: The new color key
2449  *
2450  * Returns:
2451  *  DD_OK on success
2452  *  See IWineD3DSurface::SetColorKey for details
2453  *
2454  *****************************************************************************/
2455 static HRESULT WINAPI
2456 IDirectDrawSurfaceImpl_SetColorKey(IDirectDrawSurface7 *iface,
2457                                    DWORD Flags,
2458                                    DDCOLORKEY *CKey)
2459 {
2460     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
2461     struct SCKContext ctx = { DD_OK, (WINEDDCOLORKEY *) CKey, Flags };
2462     TRACE("(%p)->(%x,%p)\n", This, Flags, CKey);
2463
2464     EnterCriticalSection(&ddraw_cs);
2465     if (CKey)
2466     {
2467         switch (Flags & ~DDCKEY_COLORSPACE)
2468         {
2469         case DDCKEY_DESTBLT:
2470             This->surface_desc.ddckCKDestBlt = *CKey;
2471             This->surface_desc.dwFlags |= DDSD_CKDESTBLT;
2472             break;
2473
2474         case DDCKEY_DESTOVERLAY:
2475             This->surface_desc.u3.ddckCKDestOverlay = *CKey;
2476             This->surface_desc.dwFlags |= DDSD_CKDESTOVERLAY;
2477             break;
2478
2479         case DDCKEY_SRCOVERLAY:
2480             This->surface_desc.ddckCKSrcOverlay = *CKey;
2481             This->surface_desc.dwFlags |= DDSD_CKSRCOVERLAY;
2482             break;
2483
2484         case DDCKEY_SRCBLT:
2485             This->surface_desc.ddckCKSrcBlt = *CKey;
2486             This->surface_desc.dwFlags |= DDSD_CKSRCBLT;
2487             break;
2488
2489         default:
2490             LeaveCriticalSection(&ddraw_cs);
2491             return DDERR_INVALIDPARAMS;
2492         }
2493     }
2494     else
2495     {
2496         switch (Flags & ~DDCKEY_COLORSPACE)
2497         {
2498         case DDCKEY_DESTBLT:
2499             This->surface_desc.dwFlags &= ~DDSD_CKDESTBLT;
2500             break;
2501
2502         case DDCKEY_DESTOVERLAY:
2503             This->surface_desc.dwFlags &= ~DDSD_CKDESTOVERLAY;
2504             break;
2505
2506         case DDCKEY_SRCOVERLAY:
2507             This->surface_desc.dwFlags &= ~DDSD_CKSRCOVERLAY;
2508             break;
2509
2510         case DDCKEY_SRCBLT:
2511             This->surface_desc.dwFlags &= ~DDSD_CKSRCBLT;
2512             break;
2513
2514         default:
2515             LeaveCriticalSection(&ddraw_cs);
2516             return DDERR_INVALIDPARAMS;
2517         }
2518     }
2519     ctx.ret = IWineD3DSurface_SetColorKey(This->WineD3DSurface,
2520                                           Flags,
2521                                           ctx.CKey);
2522     IDirectDrawSurface7_EnumAttachedSurfaces(iface,
2523                                              (void *) &ctx,
2524                                              SetColorKeyEnum);
2525     LeaveCriticalSection(&ddraw_cs);
2526     switch(ctx.ret)
2527     {
2528         case WINED3DERR_INVALIDCALL:        return DDERR_INVALIDPARAMS;
2529         default:                            return ctx.ret;
2530     }
2531 }
2532
2533 /*****************************************************************************
2534  * IDirectDrawSurface7::SetPalette
2535  *
2536  * Assigns a DirectDrawPalette object to the surface
2537  *
2538  * Params:
2539  *  Pal: Interface to the palette to set
2540  *
2541  * Returns:
2542  *  DD_OK on success
2543  *
2544  *****************************************************************************/
2545 static HRESULT WINAPI
2546 IDirectDrawSurfaceImpl_SetPalette(IDirectDrawSurface7 *iface,
2547                                   IDirectDrawPalette *Pal)
2548 {
2549     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
2550     IDirectDrawPalette *oldPal;
2551     IDirectDrawSurfaceImpl *surf;
2552     IDirectDrawPaletteImpl *PalImpl = ICOM_OBJECT(IDirectDrawPaletteImpl, IDirectDrawPalette, Pal);
2553     HRESULT hr;
2554     TRACE("(%p)->(%p)\n", This, Pal);
2555
2556     if (!(This->surface_desc.u4.ddpfPixelFormat.dwFlags & (DDPF_PALETTEINDEXED1 | DDPF_PALETTEINDEXED2 |
2557             DDPF_PALETTEINDEXED4 | DDPF_PALETTEINDEXED8 | DDPF_PALETTEINDEXEDTO8))) {
2558         return DDERR_INVALIDPIXELFORMAT;
2559     }
2560
2561     /* Find the old palette */
2562     EnterCriticalSection(&ddraw_cs);
2563     hr = IDirectDrawSurface_GetPalette(iface, &oldPal);
2564     if(hr != DD_OK && hr != DDERR_NOPALETTEATTACHED)
2565     {
2566         LeaveCriticalSection(&ddraw_cs);
2567         return hr;
2568     }
2569     if(oldPal) IDirectDrawPalette_Release(oldPal);  /* For the GetPalette */
2570
2571     /* Set the new Palette */
2572     IWineD3DSurface_SetPalette(This->WineD3DSurface,
2573                                PalImpl ? PalImpl->wineD3DPalette : NULL);
2574     /* AddRef the Palette */
2575     if(Pal) IDirectDrawPalette_AddRef(Pal);
2576
2577     /* Release the old palette */
2578     if(oldPal) IDirectDrawPalette_Release(oldPal);
2579
2580     /* If this is a front buffer, also update the back buffers
2581      * TODO: How do things work for palettized cube textures?
2582      */
2583     if(This->surface_desc.ddsCaps.dwCaps & DDSCAPS_FRONTBUFFER)
2584     {
2585         /* For primary surfaces the tree is just a list, so the simpler scheme fits too */
2586         DDSCAPS2 caps2 = { DDSCAPS_PRIMARYSURFACE, 0, 0, 0 };
2587
2588         surf = This;
2589         while(1)
2590         {
2591             IDirectDrawSurface7 *attach;
2592             HRESULT hr;
2593             hr = IDirectDrawSurface7_GetAttachedSurface(ICOM_INTERFACE(surf, IDirectDrawSurface7),
2594                                                         &caps2, &attach);
2595             if(hr != DD_OK)
2596             {
2597                 break;
2598             }
2599
2600             TRACE("Setting palette on %p\n", attach);
2601             IDirectDrawSurface7_SetPalette(attach,
2602                                            Pal);
2603             surf = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, attach);
2604             IDirectDrawSurface7_Release(attach);
2605         }
2606     }
2607
2608     LeaveCriticalSection(&ddraw_cs);
2609     return DD_OK;
2610 }
2611
2612 /*****************************************************************************
2613  * The VTable
2614  *****************************************************************************/
2615
2616 const IDirectDrawSurface7Vtbl IDirectDrawSurface7_Vtbl =
2617 {
2618     /*** IUnknown ***/
2619     IDirectDrawSurfaceImpl_QueryInterface,
2620     IDirectDrawSurfaceImpl_AddRef,
2621     IDirectDrawSurfaceImpl_Release,
2622     /*** IDirectDrawSurface ***/
2623     IDirectDrawSurface7Impl_AddAttachedSurface,
2624     IDirectDrawSurfaceImpl_AddOverlayDirtyRect,
2625     IDirectDrawSurfaceImpl_Blt,
2626     IDirectDrawSurfaceImpl_BltBatch,
2627     IDirectDrawSurfaceImpl_BltFast,
2628     IDirectDrawSurfaceImpl_DeleteAttachedSurface,
2629     IDirectDrawSurfaceImpl_EnumAttachedSurfaces,
2630     IDirectDrawSurfaceImpl_EnumOverlayZOrders,
2631     IDirectDrawSurfaceImpl_Flip,
2632     IDirectDrawSurfaceImpl_GetAttachedSurface,
2633     IDirectDrawSurfaceImpl_GetBltStatus,
2634     IDirectDrawSurfaceImpl_GetCaps,
2635     IDirectDrawSurfaceImpl_GetClipper,
2636     IDirectDrawSurfaceImpl_GetColorKey,
2637     IDirectDrawSurfaceImpl_GetDC,
2638     IDirectDrawSurfaceImpl_GetFlipStatus,
2639     IDirectDrawSurfaceImpl_GetOverlayPosition,
2640     IDirectDrawSurfaceImpl_GetPalette,
2641     IDirectDrawSurfaceImpl_GetPixelFormat,
2642     IDirectDrawSurfaceImpl_GetSurfaceDesc,
2643     IDirectDrawSurfaceImpl_Initialize,
2644     IDirectDrawSurfaceImpl_IsLost,
2645     IDirectDrawSurfaceImpl_Lock,
2646     IDirectDrawSurfaceImpl_ReleaseDC,
2647     IDirectDrawSurfaceImpl_Restore,
2648     IDirectDrawSurfaceImpl_SetClipper,
2649     IDirectDrawSurfaceImpl_SetColorKey,
2650     IDirectDrawSurfaceImpl_SetOverlayPosition,
2651     IDirectDrawSurfaceImpl_SetPalette,
2652     IDirectDrawSurfaceImpl_Unlock,
2653     IDirectDrawSurfaceImpl_UpdateOverlay,
2654     IDirectDrawSurfaceImpl_UpdateOverlayDisplay,
2655     IDirectDrawSurfaceImpl_UpdateOverlayZOrder,
2656     /*** IDirectDrawSurface2 ***/
2657     IDirectDrawSurfaceImpl_GetDDInterface,
2658     IDirectDrawSurfaceImpl_PageLock,
2659     IDirectDrawSurfaceImpl_PageUnlock,
2660     /*** IDirectDrawSurface3 ***/
2661     IDirectDrawSurfaceImpl_SetSurfaceDesc,
2662     /*** IDirectDrawSurface4 ***/
2663     IDirectDrawSurfaceImpl_SetPrivateData,
2664     IDirectDrawSurfaceImpl_GetPrivateData,
2665     IDirectDrawSurfaceImpl_FreePrivateData,
2666     IDirectDrawSurfaceImpl_GetUniquenessValue,
2667     IDirectDrawSurfaceImpl_ChangeUniquenessValue,
2668     /*** IDirectDrawSurface7 ***/
2669     IDirectDrawSurfaceImpl_SetPriority,
2670     IDirectDrawSurfaceImpl_GetPriority,
2671     IDirectDrawSurfaceImpl_SetLOD,
2672     IDirectDrawSurfaceImpl_GetLOD
2673 };