dinput: Move SetEventNotification and associated event into base class.
[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 "winnls.h"
40 #include "winerror.h"
41 #include "wingdi.h"
42 #include "wine/exception.h"
43 #include "excpt.h"
44
45 #include "ddraw.h"
46 #include "d3d.h"
47
48 #include "ddraw_private.h"
49 #include "wine/debug.h"
50
51 WINE_DEFAULT_DEBUG_CHANNEL(ddraw);
52
53 /*****************************************************************************
54  * IUnknown parts follow
55  *****************************************************************************/
56
57 /*****************************************************************************
58  * IDirectDrawSurface7::QueryInterface
59  *
60  * A normal QueryInterface implementation. For QueryInterface rules
61  * see ddraw.c, IDirectDraw7::QueryInterface. This method
62  * can Query IDirectDrawSurface interfaces in all version, IDirect3DTexture
63  * in all versions, the IDirectDrawGammaControl interface and it can
64  * create an IDirect3DDevice. (Uses IDirect3D7::CreateDevice)
65  *
66  * Params:
67  *  riid: The interface id queried for
68  *  obj: Address to write the pointer to
69  *
70  * Returns:
71  *  S_OK on success
72  *  E_NOINTERFACE if the requested interface wasn't found
73  *
74  *****************************************************************************/
75 static HRESULT WINAPI
76 IDirectDrawSurfaceImpl_QueryInterface(IDirectDrawSurface7 *iface,
77                                       REFIID riid,
78                                       void **obj)
79 {
80     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
81
82     /* According to COM docs, if the QueryInterface fails, obj should be set to NULL */
83     *obj = NULL;
84
85     if(!riid)
86         return DDERR_INVALIDPARAMS;
87
88     TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),obj);
89     if (IsEqualGUID(riid, &IID_IUnknown)
90      || IsEqualGUID(riid, &IID_IDirectDrawSurface7)
91      || IsEqualGUID(riid, &IID_IDirectDrawSurface4) )
92     {
93         IUnknown_AddRef(iface);
94         *obj = ICOM_INTERFACE(This, IDirectDrawSurface7);
95         TRACE("(%p) returning IDirectDrawSurface7 interface at %p\n", This, *obj);
96         return S_OK;
97     }
98     else if( IsEqualGUID(riid, &IID_IDirectDrawSurface3)
99           || IsEqualGUID(riid, &IID_IDirectDrawSurface2)
100           || IsEqualGUID(riid, &IID_IDirectDrawSurface) )
101     {
102         IUnknown_AddRef(iface);
103         *obj = ICOM_INTERFACE(This, IDirectDrawSurface3);
104         TRACE("(%p) returning IDirectDrawSurface3 interface at %p\n", This, *obj);
105         return S_OK;
106     }
107     else if( IsEqualGUID(riid, &IID_IDirectDrawGammaControl) )
108     {
109         IUnknown_AddRef(iface);
110         *obj = ICOM_INTERFACE(This, IDirectDrawGammaControl);
111         TRACE("(%p) returning IDirectDrawGammaControl interface at %p\n", This, *obj);
112         return S_OK;
113     }
114     else if( IsEqualGUID(riid, &IID_D3DDEVICE_WineD3D) ||
115              IsEqualGUID(riid, &IID_IDirect3DHALDevice) )
116     {
117         IDirect3DDevice7 *d3d;
118
119         /* Call into IDirect3D7 for creation */
120         IDirect3D7_CreateDevice(ICOM_INTERFACE(This->ddraw, IDirect3D7),
121                                 riid,
122                                 ICOM_INTERFACE(This, IDirectDrawSurface7),
123                                 &d3d);
124
125         *obj = COM_INTERFACE_CAST(IDirect3DDeviceImpl, IDirect3DDevice7, IDirect3DDevice, d3d);
126         TRACE("(%p) Returning IDirect3DDevice interface at %p\n", This, *obj);
127
128         return S_OK;
129     }
130     else if (IsEqualGUID( &IID_IDirect3DTexture, riid ) ||
131              IsEqualGUID( &IID_IDirect3DTexture2, riid ))
132     {
133         if (IsEqualGUID( &IID_IDirect3DTexture, riid ))
134         {
135             *obj = ICOM_INTERFACE(This, IDirect3DTexture);
136             TRACE(" returning Direct3DTexture interface at %p.\n", *obj);
137         }
138         else
139         {
140             *obj = ICOM_INTERFACE(This, IDirect3DTexture2);
141             TRACE(" returning Direct3DTexture2 interface at %p.\n", *obj);
142         }
143         IUnknown_AddRef( (IUnknown *) *obj);
144         return S_OK;
145     }
146
147     ERR("No interface\n");
148     return E_NOINTERFACE;
149 }
150
151 /*****************************************************************************
152  * IDirectDrawSurface7::AddRef
153  *
154  * A normal addref implementation
155  *
156  * Returns:
157  *  The new refcount
158  *
159  *****************************************************************************/
160 static ULONG WINAPI
161 IDirectDrawSurfaceImpl_AddRef(IDirectDrawSurface7 *iface)
162 {
163     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
164     ULONG refCount = InterlockedIncrement(&This->ref);
165
166     TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
167     return refCount;
168 }
169
170 /*****************************************************************************
171  * IDirectDrawSurfaceImpl_Destroy
172  *
173  * A helper function for IDirectDrawSurface7::Release
174  *
175  * Frees the surface, regardless of its refcount.
176  *  See IDirectDrawSurface7::Release for more information
177  *
178  * Params:
179  *  This: Surface to free
180  *
181  *****************************************************************************/
182 static void IDirectDrawSurfaceImpl_Destroy(IDirectDrawSurfaceImpl *This)
183 {
184     TRACE("(%p)\n", This);
185
186     /* Check the refcount and give a warning */
187     if(This->ref > 1)
188     {
189         /* This can happen when a complex surface is destroyed,
190          * because the 2nd surface was addref()ed when the app
191          * called GetAttachedSurface
192          */
193         WARN("(%p): Destroying surface with refount %d\n", This, This->ref);
194     }
195
196     /* Check for attached surfaces and detach them */
197     if(This->first_attached != This)
198     {
199         /* Well, this shouldn't happen: The surface being attached is addref()ed
200           * in AddAttachedSurface, so it shouldn't be released until DeleteAttachedSurface
201           * is called, because the refcount is held. It looks like the app released()
202           * it often enough to force this
203           */
204         IDirectDrawSurface7 *root = ICOM_INTERFACE(This->first_attached, IDirectDrawSurface7);
205         IDirectDrawSurface7 *detach = ICOM_INTERFACE(This, IDirectDrawSurface7);
206
207         FIXME("(%p) Freeing a surface that is attached to surface %p\n", This, This->first_attached);
208
209         /* The refcount will drop to -1 here */
210         if(IDirectDrawSurface7_DeleteAttachedSurface(root, 0, detach) != DD_OK)
211         {
212             ERR("(%p) DeleteAttachedSurface failed!\n", This);
213         }
214     }
215
216     while(This->next_attached != NULL)
217     {
218         IDirectDrawSurface7 *root = ICOM_INTERFACE(This, IDirectDrawSurface7);
219         IDirectDrawSurface7 *detach = ICOM_INTERFACE(This->next_attached, IDirectDrawSurface7);
220
221         if(IDirectDrawSurface7_DeleteAttachedSurface(root, 0, detach) != DD_OK)
222         {
223             ERR("(%p) DeleteAttachedSurface failed!\n", This);
224             assert(0);
225         }
226     }
227
228     /* Now destroy the surface. Wait: It could have been released if we are a texture */
229     if(This->WineD3DSurface)
230         IWineD3DSurface_Release(This->WineD3DSurface);
231
232     /* Having a texture handle set implies that the device still exists */
233     if(This->Handle)
234     {
235         This->ddraw->d3ddevice->Handles[This->Handle - 1].ptr = NULL;
236         This->ddraw->d3ddevice->Handles[This->Handle - 1].type = DDrawHandle_Unknown;
237     }
238
239     /* Reduce the ddraw surface count */
240     InterlockedDecrement(&This->ddraw->surfaces);
241     list_remove(&This->surface_list_entry);
242
243     HeapFree(GetProcessHeap(), 0, This);
244 }
245
246 /*****************************************************************************
247  * IDirectDrawSurface7::Release
248  *
249  * Reduces the surface's refcount by 1. If the refcount falls to 0, the
250  * surface is destroyed.
251  *
252  * Destroying the surface is a bit tricky. For the connection between
253  * WineD3DSurfaces and DirectDrawSurfaces see IDirectDraw7::CreateSurface
254  * It has a nice graph explaining the connection.
255  *
256  * What happens here is basically this:
257  * When a surface is destroyed, its WineD3DSurface is released,
258  * and the refcount of the DirectDraw interface is reduced by 1. If it has
259  * complex surfaces attached to it, then these surfaces are destroyed too,
260  * regardless of their refcount. If any surface being destroyed has another
261  * surface attached to it (with a "soft" attachment, not complex), then
262  * this surface is detached with DeleteAttachedSurface.
263  *
264  * When the surface is a texture, the WineD3DTexture is released.
265  * If the surface is the Direct3D render target, then the D3D
266  * capabilities of the WineD3DDevice are uninitialized, which causes the
267  * swapchain to be released.
268  *
269  * Returns:
270  *  The new refcount
271  *
272  *****************************************************************************/
273 static ULONG WINAPI
274 IDirectDrawSurfaceImpl_Release(IDirectDrawSurface7 *iface)
275 {
276     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
277     ULONG ref;
278     TRACE("(%p) : Releasing from %d\n", This, This->ref);
279     ref = InterlockedDecrement(&This->ref);
280
281     if (ref == 0)
282     {
283
284         IDirectDrawSurfaceImpl *surf;
285         IDirectDrawImpl *ddraw;
286         IUnknown *ifaceToRelease = This->ifaceToRelease;
287
288         /* Complex attached surfaces are destroyed implicitely when the root is released */
289         if(This->first_complex != This)
290         {
291             WARN("(%p) Attempt to destroy a surface that is attached to a complex root %p\n", This, This->first_complex);
292             return ref;
293         }
294         ddraw = This->ddraw;
295
296         /* If it's a texture, destroy the WineD3DTexture.
297          * WineD3D will destroy the IParent interfaces
298          * of the sublevels, which destroys the WineD3DSurfaces.
299          * Set the surfaces to NULL to avoid destroying them again later
300          */
301         if(This->wineD3DTexture)
302         {
303             IWineD3DTexture_Release(This->wineD3DTexture);
304         }
305         /* If it's the RenderTarget, destroy the d3ddevice */
306         else if( (ddraw->d3d_initialized) && (This == ddraw->d3d_target))
307         {
308             TRACE("(%p) Destroying the render target, uninitializing D3D\n", This);
309
310             /* Unset any index buffer, just to be sure */
311             IWineD3DDevice_SetIndices(ddraw->wineD3DDevice, NULL, 0);
312
313             if(IWineD3DDevice_Uninit3D(ddraw->wineD3DDevice) != D3D_OK)
314             {
315                 /* Not good */
316                 ERR("(%p) Failed to uninit 3D\n", This);
317             }
318             else
319             {
320                 /* Free the d3d window if one was created */
321                 if(ddraw->d3d_window != 0)
322                 {
323                     TRACE(" (%p) Destroying the hidden render window %p\n", This, ddraw->d3d_window);
324                     DestroyWindow(ddraw->d3d_window);
325                     ddraw->d3d_window = 0;
326                 }
327                 /* Unset the pointers */
328             }
329
330             ddraw->d3d_initialized = FALSE;
331             ddraw->d3d_target = NULL;
332
333             /* Write a trace because D3D unloading was the reason for many
334              * crashes during development.
335              */
336             TRACE("(%p) D3D unloaded\n", This);
337         }
338         else if(This->surface_desc.ddsCaps.dwCaps & (DDSCAPS_PRIMARYSURFACE |
339                                                      DDSCAPS_3DDEVICE       |
340                                                      DDSCAPS_TEXTURE        ) )
341         {
342             /* It's a render target, but no swapchain was created.
343              * The IParent interfaces have to be released manually.
344              * The same applies for textures without an
345              * IWineD3DTexture object attached
346              */
347             surf = This;
348             while(surf)
349             {
350                 IParent *Parent;
351
352                 IWineD3DSurface_GetParent(surf->WineD3DSurface,
353                                           (IUnknown **) &Parent);
354                 IParent_Release(Parent);  /* For the getParent */
355                 IParent_Release(Parent);  /* To release it */
356                 surf = surf->next_complex;
357             }
358         }
359
360         /* The refcount test shows that the palette is detached when the surface is destroyed */
361         IDirectDrawSurface7_SetPalette(ICOM_INTERFACE(This, IDirectDrawSurface7),
362                                                       NULL);
363
364         /* Loop through all complex attached surfaces,
365          * and destroy them
366          */
367         while( (surf = This->next_complex) )
368         {
369             This->next_complex = surf->next_complex;  /* Unchain it from the complex listing */
370             IDirectDrawSurfaceImpl_Destroy(surf);     /* Destroy it */
371         }
372
373         /* Destroy the surface.
374          */
375         IDirectDrawSurfaceImpl_Destroy(This);
376
377         /* Reduce the ddraw refcount */
378         IUnknown_Release(ifaceToRelease);
379     }
380
381     return ref;
382 }
383
384 /*****************************************************************************
385  * IDirectDrawSurface7::GetAttachedSurface
386  *
387  * Returns an attached surface with the requested caps. Surface attachment
388  * and complex surfaces are not clearly described by the MSDN or sdk,
389  * so this method is tricky and likely to contain problems.
390  * This implementation searches the complex chain first, then the
391  * attachment chain, and then it checks if the caps match to itself.
392  *
393  * The chains are searched from This down to the last surface in the chain,
394  * not from the first element in the chain. The first surface found is
395  * returned. The MSDN says that this method fails if more than one surface
396  * matches the caps, but apparently this is incorrect.
397  *
398  * The found surface is AddRef-ed before it is returned.
399  *
400  * Params:
401  *  Caps: Pointer to a DDCAPS2 structure describing the caps asked for
402  *  Surface: Address to store the found surface
403  *
404  * Returns:
405  *  DD_OK on success
406  *  DDERR_INVALIDPARAMS if Caps or Surface is NULL
407  *  DDERR_NOTFOUND if no surface was found
408  *
409  *****************************************************************************/
410 static HRESULT WINAPI
411 IDirectDrawSurfaceImpl_GetAttachedSurface(IDirectDrawSurface7 *iface,
412                                           DDSCAPS2 *Caps,
413                                           IDirectDrawSurface7 **Surface)
414 {
415     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
416     IDirectDrawSurfaceImpl *surf;
417     DDSCAPS2 our_caps;
418
419     TRACE("(%p)->(%p,%p)\n", This, Caps, Surface);
420
421     our_caps = *Caps;
422
423     if(This->version < 7)
424     {
425         /* Earlier dx apps put garbage into these members, clear them */
426         our_caps.dwCaps2 = 0;
427         our_caps.dwCaps3 = 0;
428         our_caps.dwCaps4 = 0;
429     }
430
431     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 */
432
433     /* First, look at the complex chain */
434     surf = This;
435
436     while( (surf = surf->next_complex) )
437     {
438         if (TRACE_ON(ddraw))
439         {
440             TRACE("Surface: (%p) caps: %x,%x,%x,%x\n", surf,
441                    surf->surface_desc.ddsCaps.dwCaps,
442                    surf->surface_desc.ddsCaps.dwCaps2,
443                    surf->surface_desc.ddsCaps.dwCaps3,
444                    surf->surface_desc.ddsCaps.dwCaps4);
445         }
446
447         if (((surf->surface_desc.ddsCaps.dwCaps & our_caps.dwCaps) == our_caps.dwCaps) &&
448             ((surf->surface_desc.ddsCaps.dwCaps2 & our_caps.dwCaps2) == our_caps.dwCaps2)) {
449
450             /* MSDN: "This method fails if more than one surface is attached
451              * that matches the capabilities requested."
452              *
453              * The mipmap demo of the DirectX7 sdk shows what to do here:
454              * apparently apps expect the first found surface to be returned.
455              */
456
457             TRACE("(%p): Returning surface %p\n", This, surf);
458             TRACE("(%p): mipmapcount=%d\n", This, surf->mipmap_level);
459             *Surface = ICOM_INTERFACE(surf, IDirectDrawSurface7);
460             IDirectDrawSurface7_AddRef(*Surface);
461             return DD_OK;
462         }
463     }
464
465     /* Next, look at the attachment chain */
466     surf = This;
467
468     while( (surf = surf->next_attached) )
469     {
470         if (TRACE_ON(ddraw))
471         {
472             TRACE("Surface: (%p) caps: %x,%x,%x,%x\n", surf,
473                    surf->surface_desc.ddsCaps.dwCaps,
474                    surf->surface_desc.ddsCaps.dwCaps2,
475                    surf->surface_desc.ddsCaps.dwCaps3,
476                    surf->surface_desc.ddsCaps.dwCaps4);
477         }
478
479         if (((surf->surface_desc.ddsCaps.dwCaps & our_caps.dwCaps) == our_caps.dwCaps) &&
480             ((surf->surface_desc.ddsCaps.dwCaps2 & our_caps.dwCaps2) == our_caps.dwCaps2)) {
481
482             /* MSDN: "This method fails if more than one surface is attached
483              * that matches the capabilities requested."
484              *
485              * The mipmap demo of the DirectX7 sdk shows what to do here:
486              * apparently apps expect the first found surface to be returned.
487              */
488
489             TRACE("(%p): Returning surface %p\n", This, surf);
490             *Surface = ICOM_INTERFACE(surf, IDirectDrawSurface7);
491             IDirectDrawSurface7_AddRef(*Surface);
492             return DD_OK;
493         }
494     }
495
496     /* Is this valid? */
497 #if 0
498     if (((This->surface_desc.ddsCaps.dwCaps & our_caps.dwCaps) == our_caps.dwCaps) &&
499         ((This->surface_desc.ddsCaps.dwCaps2 & our_caps.dwCaps2) == our_caps.dwCaps2) && 
500         This == This->first_complex)
501     {
502
503         TRACE("(%p): Returning surface %p\n", This, This);
504         *Surface = ICOM_INTERFACE(This, IDirectDrawSurface7);
505         IDirectDrawSurface7_AddRef(*Surface);
506         return DD_OK;
507     }
508 #endif
509
510     /* What to do here? Continue with the surface root?? */
511
512     TRACE("(%p) Didn't find a valid surface\n", This);
513     return DDERR_NOTFOUND;
514 }
515
516 /*****************************************************************************
517  * IDirectDrawSurface7::Lock
518  *
519  * Locks the surface and returns a pointer to the surface's memory
520  *
521  * Params:
522  *  Rect: Rectangle to lock. If NULL, the whole surface is locked
523  *  DDSD: Pointer to a DDSURFACEDESC2 which shall receive the surface's desc.
524  *  Flags: Locking flags, e.g Read only or write only
525  *  h: An event handle that's not used and must be NULL
526  *
527  * Returns:
528  *  DD_OK on success
529  *  DDERR_INVALIDPARAMS if DDSD is NULL
530  *  For more details, see IWineD3DSurface::LockRect
531  *
532  *****************************************************************************/
533 static HRESULT WINAPI
534 IDirectDrawSurfaceImpl_Lock(IDirectDrawSurface7 *iface,
535                             RECT *Rect,
536                             DDSURFACEDESC2 *DDSD,
537                             DWORD Flags,
538                             HANDLE h)
539 {
540     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
541     WINED3DLOCKED_RECT LockedRect;
542     HRESULT hr;
543     TRACE("(%p)->(%p,%p,%x,%p)\n", This, Rect, DDSD, Flags, h);
544
545     if(!DDSD)
546         return DDERR_INVALIDPARAMS;
547
548     /* Should I check for the handle to be NULL?
549      *
550      * The DDLOCK flags and the D3DLOCK flags are equal
551      * for the supported values. The others are ignored by WineD3D
552      */
553
554     /* Hmm. Anarchy online passes an uninitialized surface descriptor,
555      * that means it doesn't have dwSize set. Init it to some sane
556      * value
557      */
558     if(DDSD->dwSize <= sizeof(DDSURFACEDESC))
559     {
560         DDSD->dwSize = sizeof(DDSURFACEDESC);
561     }
562     else
563     {
564         DDSD->dwSize = sizeof(DDSURFACEDESC2);
565     }
566
567     DD_STRUCT_COPY_BYSIZE(DDSD,&(This->surface_desc));
568     hr = IWineD3DSurface_LockRect(This->WineD3DSurface,
569                                   &LockedRect,
570                                   Rect,
571                                   Flags);
572     if(hr != D3D_OK) return hr;
573
574     /* Override the memory area and the pitch */
575     DDSD->dwFlags |= DDSD_LPSURFACE;
576     DDSD->lpSurface = LockedRect.pBits;
577     DDSD->dwFlags |= DDSD_PITCH;
578     DDSD->u1.lPitch = LockedRect.Pitch;
579
580     TRACE("locked surface returning description :\n");
581     if (TRACE_ON(ddraw)) DDRAW_dump_surface_desc(DDSD);
582
583     return DD_OK;
584 }
585
586 /*****************************************************************************
587  * IDirectDrawSurface7::Unlock
588  *
589  * Unlocks an locked surface
590  *
591  * Params:
592  *  Rect: Not used by this implementation
593  *
594  * Returns:
595  *  D3D_OK on success
596  *  For more details, see IWineD3DSurface::UnlockRect
597  *
598  *****************************************************************************/
599 static HRESULT WINAPI
600 IDirectDrawSurfaceImpl_Unlock(IDirectDrawSurface7 *iface,
601                               RECT *pRect)
602 {
603     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
604     TRACE("(%p)->(%p)\n", This, pRect);
605
606     return IWineD3DSurface_UnlockRect(This->WineD3DSurface);
607 }
608
609 /*****************************************************************************
610  * IDirectDrawSurface7::Flip
611  *
612  * Flips a surface with the DDSCAPS_FLIP flag. The flip is relayed to
613  * IWineD3DSurface::Flip. Because WineD3D doesn't handle attached surfaces,
614  * the flip target is passed to WineD3D, even if the app didn't specify one
615  *
616  * Params:
617  *  DestOverride: Specifies the surface that will become the new front
618  *                buffer. If NULL, the current back buffer is used
619  *  Flags: some DirectDraw flags, see include/ddraw.h
620  *
621  * Returns:
622  *  DD_OK on success
623  *  DDERR_NOTFLIPPABLE if no flip target could be found
624  *  DDERR_INVALIDOBJECT if the surface isn't a front buffer
625  *  For more details, see IWineD3DSurface::Flip
626  *
627  *****************************************************************************/
628 static HRESULT WINAPI
629 IDirectDrawSurfaceImpl_Flip(IDirectDrawSurface7 *iface,
630                             IDirectDrawSurface7 *DestOverride,
631                             DWORD Flags)
632 {
633     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
634     IDirectDrawSurfaceImpl *Override = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, DestOverride);
635     IDirectDrawSurface7 *Override7;
636     HRESULT hr;
637     TRACE("(%p)->(%p,%x)\n", This, DestOverride, Flags);
638
639     /* Flip has to be called from a front buffer
640      * What about overlay surfaces, AFAIK they can flip too?
641      */
642     if( !(This->surface_desc.ddsCaps.dwCaps & DDSCAPS_FRONTBUFFER) )
643         return DDERR_INVALIDOBJECT; /* Unckecked */
644
645     /* WineD3D doesn't keep track of attached surface, so find the target */
646     if(!Override)
647     {
648         DDSCAPS2 Caps;
649
650         memset(&Caps, 0, sizeof(Caps));
651         Caps.dwCaps |= DDSCAPS_BACKBUFFER;
652         hr = IDirectDrawSurface7_GetAttachedSurface(iface, &Caps, &Override7);
653         if(hr != DD_OK)
654         {
655             ERR("Can't find a flip target\n");
656             return DDERR_NOTFLIPPABLE; /* Unchecked */
657         }
658         Override = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, Override7);
659
660         /* For the GetAttachedSurface */
661         IDirectDrawSurface7_Release(Override7);
662     }
663
664     return  IWineD3DSurface_Flip(This->WineD3DSurface,
665                                  Override->WineD3DSurface,
666                                  Flags);
667 }
668
669 /*****************************************************************************
670  * IDirectDrawSurface7::Blt
671  *
672  * Performs a blit on the surface
673  *
674  * Params:
675  *  DestRect: Destination rectangle, can be NULL
676  *  SrcSurface: Source surface, can be NULL
677  *  SrcRect: Source rectange, can be NULL
678  *  Flags: Blt flags
679  *  DDBltFx: Some extended blt parameters, connected to the flags
680  *
681  * Returns:
682  *  D3D_OK on success
683  *  See IWineD3DSurface::Blt for more details
684  *
685  *****************************************************************************/
686 static HRESULT WINAPI
687 IDirectDrawSurfaceImpl_Blt(IDirectDrawSurface7 *iface,
688                            RECT *DestRect,
689                            IDirectDrawSurface7 *SrcSurface,
690                            RECT *SrcRect,
691                            DWORD Flags,
692                            DDBLTFX *DDBltFx)
693 {
694     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
695     IDirectDrawSurfaceImpl *Src = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, SrcSurface);
696     TRACE("(%p)->(%p,%p,%p,%x,%p)\n", This, DestRect, Src, SrcRect, Flags, DDBltFx);
697
698     return IWineD3DSurface_Blt(This->WineD3DSurface,
699                                DestRect,
700                                Src ? Src->WineD3DSurface : NULL,
701                                SrcRect,
702                                Flags,
703                                DDBltFx);
704 }
705
706 /*****************************************************************************
707  * IDirectDrawSurface7::AddAttachedSurface
708  *
709  * Attaches a surface to another surface. Surface attachments are
710  * incorrectly described in the SDK and the MSDN, and this method
711  * is prone to bugs. The surface that is attached is AddRef-ed.
712  *
713  * The attachment list consists of a first surface (first_attached) and
714  * for each surface a pointer to the next attached surface (next_attached).
715  * For the first surface, and a surface that has no attachments
716  * first_attached points to the surface itself. A surface that has
717  * no successors in the chain has next_attached set to NULL.
718  *
719  * Newly attached surfaces are attached right after the root surface. The
720  * complex chains are handled separately in a similar chain, with
721  * first_complex and next_complex. If a surface is attached to a complex
722  * surface compound, it's attached to the surface that the app requested,
723  * not the complex root. See GetAttachedSurface for a description
724  * how surfaces are found.
725  *
726  * This is how the current implementation works, and it was coded by looking
727  * at the needs of the applications.
728  *
729  * So far only Z-Buffer attachments are tested, but there's no code yet
730  * to activate them. Mipmaps could be tricky to activate in WineD3D.
731  * Back buffers should work in 2D mode, but they are not tested.
732  * Rendering to the primary surface and switching between that and
733  * double buffering is not yet implemented in WineD3D, so for 3D it might
734  * have unexpected results.
735  *
736  * Params:
737  *  Attach: Surface to attach to iface
738  *
739  * Returns:
740  *  DD_OK on success
741  *  DDERR_CANNOTATTACHSURFACE if the surface can't be attached for some reason
742  *
743  *****************************************************************************/
744 static HRESULT WINAPI
745 IDirectDrawSurfaceImpl_AddAttachedSurface(IDirectDrawSurface7 *iface,
746                                           IDirectDrawSurface7 *Attach)
747 {
748     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
749     IDirectDrawSurfaceImpl *Surf = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, Attach);
750     TRACE("(%p)->(%p)\n", This, Surf);
751
752     /* Should I make sure to add it to the first complex surface? */
753
754     if(Surf == This)
755         return DDERR_CANNOTATTACHSURFACE; /* unchecked */
756
757     /* TODO MSDN: "You can attach only z-buffer surfaces with this method."
758      * But apparently backbuffers and mipmaps can be attached too. */
759
760     /* Set MIPMAPSUBLEVEL if this seems to be one */
761     if (This->surface_desc.ddsCaps.dwCaps &
762         Surf->surface_desc.ddsCaps.dwCaps & DDSCAPS_MIPMAP)
763     {
764         Surf->surface_desc.ddsCaps.dwCaps2 |= DDSCAPS2_MIPMAPSUBLEVEL;
765         /* FIXME: we should probably also add to dwMipMapCount of this
766           * and all parent surfaces (update create_texture if you do) */
767     }
768
769     /* Check if the surface is already attached somewhere */
770     if( (Surf->next_attached != NULL) ||
771         (Surf->first_attached != Surf) )
772     {
773          ERR("(%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);
774         return DDERR_CANNOTATTACHSURFACE;
775     }
776
777     /* This inserts the new surface at the 2nd position in the chain, right after the root surface */
778     Surf->next_attached = This->next_attached;
779     Surf->first_attached = This->first_attached;
780     This->next_attached = Surf;
781
782     /* MSDN: 
783      * "This method increments the reference count of the surface being attached."
784      */
785     IDirectDrawSurface7_AddRef(Attach);
786     return DD_OK;
787 }
788
789 /*****************************************************************************
790  * IDirectDrawSurface7::DeleteAttachedSurface
791  *
792  * Removes a surface from the attachment chain. The surface's refcount
793  * is decreased by one after it has been removed
794  *
795  * Params:
796  *  Flags: Some flags, not used by this implementation
797  *  Attach: Surface to detach
798  *
799  * Returns:
800  *  DD_OK on success
801  *  DDERR_SURFACENOTATTACHED if the surface isn't attached to
802  *
803  *****************************************************************************/
804 static HRESULT WINAPI
805 IDirectDrawSurfaceImpl_DeleteAttachedSurface(IDirectDrawSurface7 *iface,
806                                              DWORD Flags,
807                                              IDirectDrawSurface7 *Attach)
808 {
809     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
810     IDirectDrawSurfaceImpl *Surf = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, Attach);
811     IDirectDrawSurfaceImpl *Prev = This;
812     TRACE("(%p)->(%08x,%p)\n", This, Flags, Surf);
813
814     if (!Surf || (Surf->first_attached != This) || (Surf == This) )
815         return DDERR_SURFACENOTATTACHED; /* unchecked */
816
817     /* Remove MIPMAPSUBLEVEL if this seemed to be one */
818     if (This->surface_desc.ddsCaps.dwCaps &
819         Surf->surface_desc.ddsCaps.dwCaps & DDSCAPS_MIPMAP)
820     {
821         Surf->surface_desc.ddsCaps.dwCaps2 &= ~DDSCAPS2_MIPMAPSUBLEVEL;
822         /* FIXME: we should probably also subtract from dwMipMapCount of this
823          * and all parent surfaces */
824     }
825
826     /* Find the predecessor of the detached surface */
827     while(Prev)
828     {
829         if(Prev->next_attached == Surf) break;
830         Prev = Prev->next_attached;
831     }
832
833     /* There must be a surface, otherwise there's a bug */
834     assert(Prev != NULL);
835
836     /* Unchain the surface */
837     Prev->next_attached = Surf->next_attached;
838     Surf->next_attached = NULL;
839     Surf->first_attached = Surf;
840
841     IDirectDrawSurface7_Release(Attach);
842     return DD_OK;
843 }
844
845 /*****************************************************************************
846  * IDirectDrawSurface7::AddOverlayDirtyRect
847  *
848  * "This method is not currently implemented"
849  *
850  * Params:
851  *  Rect: ?
852  *
853  * Returns:
854  *  DDERR_UNSUPPORTED
855  *
856  *****************************************************************************/
857 static HRESULT WINAPI
858 IDirectDrawSurfaceImpl_AddOverlayDirtyRect(IDirectDrawSurface7 *iface,
859                                            LPRECT Rect)
860 {
861     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
862     TRACE("(%p)->(%p)\n",This,Rect);
863
864     /* MSDN says it's not implemented. I could forward it to WineD3D, 
865      * then we'd implement it, but I don't think that's a good idea
866      * (Stefan Dösinger)
867      */
868 #if 0
869     return IWineD3DSurface_AddOverlayDirtyRect(This->WineD3DSurface, pRect);
870 #endif
871     return DDERR_UNSUPPORTED; /* unchecked */
872 }
873
874 /*****************************************************************************
875  * IDirectDrawSurface7::GetDC
876  *
877  * Returns a GDI device context for the surface
878  *
879  * Params:
880  *  hdc: Address of a HDC variable to store the dc to
881  *
882  * Returns:
883  *  DD_OK on success
884  *  DDERR_INVALIDPARAMS if hdc is NULL
885  *  For details, see IWineD3DSurface::GetDC
886  *
887  *****************************************************************************/
888 static HRESULT WINAPI
889 IDirectDrawSurfaceImpl_GetDC(IDirectDrawSurface7 *iface,
890                              HDC *hdc)
891 {
892     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
893     TRACE("(%p)->(%p): Relay\n", This, hdc);
894
895     if(!hdc)
896         return DDERR_INVALIDPARAMS;
897
898     return IWineD3DSurface_GetDC(This->WineD3DSurface,
899                                  hdc);
900 }
901
902 /*****************************************************************************
903  * IDirectDrawSurface7::ReleaseDC
904  *
905  * Releases the DC that was constructed with GetDC
906  *
907  * Params:
908  *  hdc: HDC to release
909  *
910  * Returns:
911  *  DD_OK on success
912  *  For more details, see IWineD3DSurface::ReleaseDC
913  *
914  *****************************************************************************/
915 static HRESULT WINAPI
916 IDirectDrawSurfaceImpl_ReleaseDC(IDirectDrawSurface7 *iface,
917                                  HDC hdc)
918 {
919     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
920     TRACE("(%p)->(%p): Relay\n", This, hdc);
921
922     return IWineD3DSurface_ReleaseDC(This->WineD3DSurface, hdc);
923 }
924
925 /*****************************************************************************
926  * IDirectDrawSurface7::GetCaps
927  *
928  * Returns the surface's caps
929  *
930  * Params:
931  *  Caps: Address to write the caps to
932  *
933  * Returns:
934  *  DD_OK on success
935  *  DDERR_INVALIDPARAMS if Caps is NULL
936  *
937  *****************************************************************************/
938 static HRESULT WINAPI
939 IDirectDrawSurfaceImpl_GetCaps(IDirectDrawSurface7 *iface,
940                                DDSCAPS2 *Caps)
941 {
942     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
943     TRACE("(%p)->(%p)\n",This,Caps);
944
945     if(!Caps)
946         return DDERR_INVALIDPARAMS;
947
948     *Caps = This->surface_desc.ddsCaps;
949     return DD_OK;
950 }
951
952 /*****************************************************************************
953  * IDirectDrawSurface7::SetPriority
954  *
955  * Sets a texture priority for managed textures.
956  *
957  * Params:
958  *  Priority: The new priority
959  *
960  * Returns:
961  *  DD_OK on success
962  *  For more details, see IWineD3DSurface::SetPriority
963  *
964  *****************************************************************************/
965 static HRESULT WINAPI
966 IDirectDrawSurfaceImpl_SetPriority(IDirectDrawSurface7 *iface, DWORD Priority)
967 {
968     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
969     TRACE("(%p)->(%d): Relay!\n",This,Priority);
970
971     return IWineD3DSurface_SetPriority(This->WineD3DSurface, Priority);
972 }
973
974 /*****************************************************************************
975  * IDirectDrawSurface7::GetPriority
976  *
977  * Returns the surface's priority
978  *
979  * Params:
980  *  Priority: Address of a variable to write the priority to
981  *
982  * Returns:
983  *  D3D_OK on success
984  *  DDERR_INVALIDPARAMS if Priority == NULL
985  *  For more details, see IWineD3DSurface::GetPriority
986  *
987  *****************************************************************************/
988 static HRESULT WINAPI
989 IDirectDrawSurfaceImpl_GetPriority(IDirectDrawSurface7 *iface,
990                                    DWORD *Priority)
991 {
992     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
993     TRACE("(%p)->(%p): Relay\n",This,Priority);
994
995     if(!Priority)
996         return DDERR_INVALIDPARAMS;
997
998     *Priority = IWineD3DSurface_GetPriority(This->WineD3DSurface);
999     return DD_OK;
1000 }
1001
1002 /*****************************************************************************
1003  * IDirectDrawSurface7::SetPrivateData
1004  *
1005  * Stores some data in the surface that is intended for the application's
1006  * use.
1007  *
1008  * Params:
1009  *  tag: GUID that identifies the data
1010  *  Data: Pointer to the private data
1011  *  Size: Size of the private data
1012  *  Flags: Some flags
1013  *
1014  * Returns:
1015  *  D3D_OK on success
1016  *  For more details, see IWineD3DSurface::SetPrivateData
1017  *
1018  *****************************************************************************/
1019 static HRESULT WINAPI
1020 IDirectDrawSurfaceImpl_SetPrivateData(IDirectDrawSurface7 *iface,
1021                                       REFGUID tag,
1022                                       void *Data,
1023                                       DWORD Size,
1024                                       DWORD Flags)
1025 {
1026     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1027     TRACE("(%p)->(%s,%p,%d,%x): Relay\n", This, debugstr_guid(tag), Data, Size, Flags);
1028
1029     return IWineD3DSurface_SetPrivateData(This->WineD3DSurface,
1030                                           tag,
1031                                           Data,
1032                                           Size,
1033                                           Flags);
1034 }
1035
1036 /*****************************************************************************
1037  * IDirectDrawSurface7::GetPrivateData
1038  *
1039  * Returns the private data set with IDirectDrawSurface7::SetPrivateData
1040  *
1041  * Params:
1042  *  tag: GUID of the data to return
1043  *  Data: Address where to write the data to
1044  *  Size: Size of the buffer at Data
1045  *
1046  * Returns:
1047  *  DD_OK on success
1048  *  DDERR_INVALIDPARAMS if Data is NULL
1049  *  For more details, see IWineD3DSurface::GetPrivateData
1050  *
1051  *****************************************************************************/
1052 static HRESULT WINAPI
1053 IDirectDrawSurfaceImpl_GetPrivateData(IDirectDrawSurface7 *iface,
1054                                       REFGUID tag,
1055                                       void *Data,
1056                                       DWORD *Size)
1057 {
1058     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1059     TRACE("(%p)->(%s,%p,%p): Relay\n", This, debugstr_guid(tag), Data, Size);
1060
1061     if(!Data)
1062         return DDERR_INVALIDPARAMS;
1063
1064     return IWineD3DSurface_GetPrivateData(This->WineD3DSurface,
1065                                           tag,
1066                                           Data,
1067                                           Size);
1068 }
1069
1070 /*****************************************************************************
1071  * IDirectDrawSurface7::FreePrivateData
1072  *
1073  * Frees private data stored in the surface
1074  *
1075  * Params:
1076  *  tag: Tag of the data to free
1077  *
1078  * Returns:
1079  *  D3D_OK on success
1080  *  For more details, see IWineD3DSurface::FreePrivateData
1081  *
1082  *****************************************************************************/
1083 static HRESULT WINAPI
1084 IDirectDrawSurfaceImpl_FreePrivateData(IDirectDrawSurface7 *iface,
1085                                        REFGUID tag)
1086 {
1087     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1088     TRACE("(%p)->(%s): Relay\n", This, debugstr_guid(tag));
1089
1090     return IWineD3DSurface_FreePrivateData(This->WineD3DSurface, tag);
1091 }
1092
1093 /*****************************************************************************
1094  * IDirectDrawSurface7::PageLock
1095  *
1096  * Prevents a sysmem surface from being paged out
1097  *
1098  * Params:
1099  *  Flags: Not used, must be 0(unchecked)
1100  *
1101  * Returns:
1102  *  DD_OK, because it's a stub
1103  *
1104  *****************************************************************************/
1105 static HRESULT WINAPI
1106 IDirectDrawSurfaceImpl_PageLock(IDirectDrawSurface7 *iface,
1107                                 DWORD Flags)
1108 {
1109     TRACE("(%p)->(%x)\n", iface, Flags);
1110
1111     /* This is Windows memory management related - we don't need this */
1112     return DD_OK;
1113 }
1114
1115 /*****************************************************************************
1116  * IDirectDrawSurface7::PageUnlock
1117  *
1118  * Allows a sysmem surface to be paged out
1119  *
1120  * Params:
1121  *  Flags: Not used, must be 0(unckeched)
1122  *
1123  * Returns:
1124  *  DD_OK, because it's a stub
1125  *
1126  *****************************************************************************/
1127 static HRESULT WINAPI
1128 IDirectDrawSurfaceImpl_PageUnlock(IDirectDrawSurface7 *iface,
1129                                   DWORD Flags)
1130 {
1131     TRACE("(%p)->(%x)\n", iface, Flags);
1132
1133     return DD_OK;
1134 }
1135
1136 /*****************************************************************************
1137  * IDirectDrawSurface7::BltBatch
1138  *
1139  * An unimplemented function
1140  *
1141  * Params:
1142  *  ?
1143  *
1144  * Returns:
1145  *  DDERR_UNSUPPORTED
1146  *
1147  *****************************************************************************/
1148 static HRESULT WINAPI IDirectDrawSurfaceImpl_BltBatch(IDirectDrawSurface7 *iface, DDBLTBATCH *Batch, DWORD Count, DWORD Flags)
1149 {
1150     TRACE("(%p)->(%p,%d,%08x)\n",iface,Batch,Count,Flags);
1151
1152     /* MSDN: "not currently implemented" */
1153     return DDERR_UNSUPPORTED;
1154 }
1155
1156 /*****************************************************************************
1157  * IDirectDrawSurface7::EnumAttachedSurfaces
1158  *
1159  * Enumerates all surfaces attached to this surface
1160  *
1161  * Params:
1162  *  context: Pointer to pass unmodified to the callback
1163  *  cb: Callback function to call for each surface
1164  *
1165  * Returns:
1166  *  DD_OK on success
1167  *  DDERR_INVALIDPARAMS if cb is NULL
1168  *
1169  *****************************************************************************/
1170 static HRESULT WINAPI
1171 IDirectDrawSurfaceImpl_EnumAttachedSurfaces(IDirectDrawSurface7 *iface,
1172                                             void *context,
1173                                             LPDDENUMSURFACESCALLBACK7 cb)
1174 {
1175     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1176     IDirectDrawSurfaceImpl *surf;
1177     DDSURFACEDESC2 desc;
1178
1179     /* Attached surfaces aren't handled in WineD3D */
1180     TRACE("(%p)->(%p,%p)\n",This,context,cb);
1181
1182     if(!cb)
1183         return DDERR_INVALIDPARAMS;
1184
1185     for (surf = This->next_complex; surf != NULL; surf = surf->next_complex)
1186     {
1187         IDirectDrawSurface7_AddRef(ICOM_INTERFACE(surf, IDirectDrawSurface7));
1188         desc = surf->surface_desc;
1189         /* check: != DDENUMRET_OK or == DDENUMRET_CANCEL? */
1190         if (cb(ICOM_INTERFACE(surf, IDirectDrawSurface7), &desc, context) == DDENUMRET_CANCEL)
1191             return DD_OK;
1192     }
1193
1194     for (surf = This->next_attached; surf != NULL; surf = surf->next_attached)
1195     {
1196         IDirectDrawSurface7_AddRef(ICOM_INTERFACE(surf, IDirectDrawSurface7));
1197         desc = surf->surface_desc;
1198         /* check: != DDENUMRET_OK or == DDENUMRET_CANCEL? */
1199         if (cb( ICOM_INTERFACE(surf, IDirectDrawSurface7), &desc, context) == DDENUMRET_CANCEL)
1200             return DD_OK;
1201     }
1202
1203     TRACE(" end of enumeration.\n");
1204
1205     return DD_OK;
1206 }
1207
1208 /*****************************************************************************
1209  * IDirectDrawSurface7::EnumOverlayZOrders
1210  *
1211  * "Enumerates the overlay surfaces on the specified destination"
1212  *
1213  * Params:
1214  *  Flags: DDENUMOVERLAYZ_BACKTOFRONT  or DDENUMOVERLAYZ_FRONTTOBACK
1215  *  context: context to pass back to the callback
1216  *  cb: callback function to call for each enumerated surface
1217  *
1218  * Returns:
1219  *  DD_OK, because it's a stub
1220  *
1221  *****************************************************************************/
1222 static HRESULT WINAPI
1223 IDirectDrawSurfaceImpl_EnumOverlayZOrders(IDirectDrawSurface7 *iface,
1224                                           DWORD Flags,
1225                                           void *context,
1226                                           LPDDENUMSURFACESCALLBACK7 cb)
1227 {
1228      FIXME("(%p)->(%x,%p,%p): Stub!\n", iface, Flags, context, cb);
1229
1230     return DD_OK;
1231 }
1232
1233 /*****************************************************************************
1234  * IDirectDrawSurface7::GetBltStatus
1235  *
1236  * Returns the blitting status
1237  *
1238  * Params:
1239  *  Flags: DDGBS_CANBLT or DDGBS_ISBLTDONE
1240  *
1241  * Returns:
1242  *  See IWineD3DSurface::Blt
1243  *
1244  *****************************************************************************/
1245 static HRESULT WINAPI
1246 IDirectDrawSurfaceImpl_GetBltStatus(IDirectDrawSurface7 *iface,
1247                                     DWORD Flags)
1248 {
1249     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1250     TRACE("(%p)->(%x): Relay\n", This, Flags);
1251
1252     return IWineD3DSurface_GetBltStatus(This->WineD3DSurface, Flags);
1253 }
1254
1255 /*****************************************************************************
1256  * IDirectDrawSurface7::GetColorKey
1257  *
1258  * Returns the color key assigned to the surface
1259  *
1260  * Params:
1261  *  Flags: Some flags
1262  *  CKey: Address to store the key to
1263  *
1264  * Returns:
1265  *  DD_OK on success
1266  *  DDERR_INVALIDPARAMS if CKey is NULL
1267  *
1268  *****************************************************************************/
1269 static HRESULT WINAPI
1270 IDirectDrawSurfaceImpl_GetColorKey(IDirectDrawSurface7 *iface,
1271                                    DWORD Flags,
1272                                    DDCOLORKEY *CKey)
1273 {
1274     /* There is a DDERR_NOCOLORKEY error, but how do we know if a color key
1275      * isn't there? That's like saying that an int isn't there. (Which MS
1276      * has done in other docs.) */
1277
1278     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1279
1280     if(!CKey)
1281         return DDERR_INVALIDPARAMS;
1282
1283     switch (Flags)
1284     {
1285     case DDCKEY_DESTBLT:
1286         *CKey = This->surface_desc.ddckCKDestBlt;
1287         break;
1288
1289     case DDCKEY_DESTOVERLAY:
1290         *CKey = This->surface_desc.u3.ddckCKDestOverlay;
1291         break;
1292
1293     case DDCKEY_SRCBLT:
1294         *CKey = This->surface_desc.ddckCKSrcBlt;
1295         break;
1296
1297     case DDCKEY_SRCOVERLAY:
1298         *CKey = This->surface_desc.ddckCKSrcOverlay;
1299         break;
1300
1301     default:
1302         return DDERR_INVALIDPARAMS;
1303     }
1304
1305     return DD_OK;
1306 }
1307
1308 /*****************************************************************************
1309  * IDirectDrawSurface7::GetFlipStatus
1310  *
1311  * Returns the flipping status of the surface
1312  *
1313  * Params:
1314  *  Flags: DDGFS_CANFLIP of DDGFS_ISFLIPDONE
1315  *
1316  * Returns:
1317  *  See IWineD3DSurface::GetFlipStatus
1318  *
1319  *****************************************************************************/
1320 static HRESULT WINAPI
1321 IDirectDrawSurfaceImpl_GetFlipStatus(IDirectDrawSurface7 *iface,
1322                                      DWORD Flags)
1323 {
1324     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1325     TRACE("(%p)->(%x): Relay\n", This, Flags);
1326
1327     return IWineD3DSurface_GetFlipStatus(This->WineD3DSurface, Flags);
1328 }
1329
1330 /*****************************************************************************
1331  * IDirectDrawSurface7::GetOverlayPosition
1332  *
1333  * Returns the display coordinates of a visible and active overlay surface
1334  *
1335  * Params:
1336  *  X
1337  *  Y
1338  *
1339  * Returns:
1340  *  DDERR_NOTAOVERLAYSURFACE, because it's a stub
1341  *****************************************************************************/
1342 static HRESULT WINAPI
1343 IDirectDrawSurfaceImpl_GetOverlayPosition(IDirectDrawSurface7 *iface,
1344                                           LONG *X,
1345                                           LONG *Y) {
1346     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1347     TRACE("(%p)->(%p,%p): Relay\n", This, X, Y);
1348
1349     return IWineD3DSurface_GetOverlayPosition(This->WineD3DSurface,
1350                                               X,
1351                                               Y);
1352 }
1353
1354 /*****************************************************************************
1355  * IDirectDrawSurface7::GetPixelFormat
1356  *
1357  * Returns the pixel format of the Surface
1358  *
1359  * Params:
1360  *  PixelFormat: Pointer to a DDPIXELFORMAT structure to which the pixel
1361  *               format should be written
1362  *
1363  * Returns:
1364  *  DD_OK on success
1365  *  DDERR_INVALIDPARAMS if PixelFormat is NULL
1366  *
1367  *****************************************************************************/
1368 static HRESULT WINAPI
1369 IDirectDrawSurfaceImpl_GetPixelFormat(IDirectDrawSurface7 *iface,
1370                                       DDPIXELFORMAT *PixelFormat)
1371 {
1372     /* What is DDERR_INVALIDSURFACETYPE for here? */
1373     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1374     TRACE("(%p)->(%p)\n",This,PixelFormat);
1375
1376     if(!PixelFormat)
1377         return DDERR_INVALIDPARAMS;
1378
1379     DD_STRUCT_COPY_BYSIZE(PixelFormat,&This->surface_desc.u4.ddpfPixelFormat);
1380
1381     return DD_OK;
1382 }
1383
1384
1385 /*****************************************************************************
1386  * IDirectDrawSurface7::GetSurfaceDesc
1387  *
1388  * Returns the description of this surface
1389  *
1390  * Params:
1391  *  DDSD: Address of a DDSURFACEDESC2 structure that is to be filled with the
1392  *        surface desc
1393  *
1394  * Returns:
1395  *  DD_OK on success
1396  *  DDERR_INVALIDPARAMS if DDSD is NULL
1397  *
1398  *****************************************************************************/
1399 static HRESULT WINAPI
1400 IDirectDrawSurfaceImpl_GetSurfaceDesc(IDirectDrawSurface7 *iface,
1401                                       DDSURFACEDESC2 *DDSD)
1402 {
1403     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1404
1405     TRACE("(%p)->(%p)\n",This,DDSD);
1406
1407     if(!DDSD)
1408         return DDERR_INVALIDPARAMS;
1409
1410     if ((DDSD->dwSize < sizeof(DDSURFACEDESC)) ||
1411         (DDSD->dwSize > sizeof(DDSURFACEDESC2)))
1412     {
1413         ERR("Impossible/Strange struct size %d.\n",DDSD->dwSize);
1414         return DDERR_GENERIC;
1415     }
1416
1417     DD_STRUCT_COPY_BYSIZE(DDSD,&This->surface_desc);
1418     TRACE("Returning surface desc:\n");
1419     if (TRACE_ON(ddraw)) DDRAW_dump_surface_desc(DDSD);
1420
1421     return DD_OK;
1422 }
1423
1424 /*****************************************************************************
1425  * IDirectDrawSurface7::Initialize
1426  *
1427  * Initializes the surface. This is a no-op in Wine
1428  *
1429  * Params:
1430  *  DD: Pointer to an DirectDraw interface
1431  *  DDSD: Surface description for initialization
1432  *
1433  * Returns:
1434  *  DDERR_ALREADYINITIALIZED
1435  *
1436  *****************************************************************************/
1437 static HRESULT WINAPI
1438 IDirectDrawSurfaceImpl_Initialize(IDirectDrawSurface7 *iface,
1439                                   IDirectDraw *DD,
1440                                   DDSURFACEDESC2 *DDSD)
1441 {
1442     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1443     IDirectDrawImpl *ddimpl = ICOM_OBJECT(IDirectDrawImpl, IDirectDraw, DD);
1444     TRACE("(%p)->(%p,%p)\n",This,ddimpl,DDSD);
1445
1446     return DDERR_ALREADYINITIALIZED;
1447 }
1448
1449 /*****************************************************************************
1450  * IDirectDrawSurface7::IsLost
1451  *
1452  * Checks if the surface is lost
1453  *
1454  * Returns:
1455  *  DD_OK, if the surface is useable
1456  *  DDERR_ISLOST if the surface is lost
1457  *  See IWineD3DSurface::IsLost for more details
1458  *
1459  *****************************************************************************/
1460 static HRESULT WINAPI
1461 IDirectDrawSurfaceImpl_IsLost(IDirectDrawSurface7 *iface)
1462 {
1463     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1464     TRACE("(%p)\n", This);
1465
1466     /* We lose the surface if the implementation was changed */
1467     if(This->ImplType != This->ddraw->ImplType)
1468     {
1469         /* But this shouldn't happen. When we change the implementation,
1470          * all surfaces are re-created automatically, and their content
1471          * is copied
1472          */
1473         ERR(" (%p) Implementation was changed from %d to %d\n", This, This->ImplType, This->ddraw->ImplType);
1474         return DDERR_SURFACELOST;
1475     }
1476
1477     return IWineD3DSurface_IsLost(This->WineD3DSurface);
1478 }
1479
1480 /*****************************************************************************
1481  * IDirectDrawSurface7::Restore
1482  *
1483  * Restores a lost surface. This makes the surface usable again, but
1484  * doesn't reload its old contents
1485  *
1486  * Returns:
1487  *  DD_OK on success
1488  *  See IWineD3DSurface::Restore for more details
1489  *
1490  *****************************************************************************/
1491 static HRESULT WINAPI
1492 IDirectDrawSurfaceImpl_Restore(IDirectDrawSurface7 *iface)
1493 {
1494     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1495     TRACE("(%p)\n", This);
1496
1497     if(This->ImplType != This->ddraw->ImplType)
1498     {
1499         /* Call the recreation callback. Make sure to AddRef first */
1500         IDirectDrawSurface_AddRef(iface);
1501         IDirectDrawImpl_RecreateSurfacesCallback(iface,
1502                                                  &This->surface_desc,
1503                                                  NULL /* Not needed */);
1504     }
1505     return IWineD3DSurface_Restore(This->WineD3DSurface);
1506 }
1507
1508 /*****************************************************************************
1509  * IDirectDrawSurface7::SetOverlayPosition
1510  *
1511  * Changes the display coordinates of an overlay surface
1512  *
1513  * Params:
1514  *  X:
1515  *  Y:
1516  *
1517  * Returns:
1518  *   DDERR_NOTAOVERLAYSURFACE, because we don't support overlays right now
1519  *****************************************************************************/
1520 static HRESULT WINAPI
1521 IDirectDrawSurfaceImpl_SetOverlayPosition(IDirectDrawSurface7 *iface,
1522                                           LONG X,
1523                                           LONG Y)
1524 {
1525     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1526     TRACE("(%p)->(%d,%d): Relay\n", This, X, Y);
1527
1528     return IWineD3DSurface_SetOverlayPosition(This->WineD3DSurface,
1529                                               X,
1530                                               Y);
1531 }
1532
1533 /*****************************************************************************
1534  * IDirectDrawSurface7::UpdateOverlay
1535  *
1536  * Modifies the attributes of an overlay surface.
1537  *
1538  * Params:
1539  *  SrcRect: The section of the source being used for the overlay
1540  *  DstSurface: Address of the surface that is overlaid
1541  *  DstRect: Place of the overlay
1542  *  Flags: some DDOVER_* flags
1543  *
1544  * Returns:
1545  *  DDERR_UNSUPPORTED, because we don't support overlays
1546  *
1547  *****************************************************************************/
1548 static HRESULT WINAPI
1549 IDirectDrawSurfaceImpl_UpdateOverlay(IDirectDrawSurface7 *iface,
1550                                      LPRECT SrcRect,
1551                                      IDirectDrawSurface7 *DstSurface,
1552                                      LPRECT DstRect,
1553                                      DWORD Flags,
1554                                      LPDDOVERLAYFX FX)
1555 {
1556     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1557     IDirectDrawSurfaceImpl *Dst = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, DstSurface);
1558     TRACE("(%p)->(%p,%p,%p,%x,%p): Relay\n", This, SrcRect, Dst, DstRect, Flags, FX);
1559
1560     return IWineD3DSurface_UpdateOverlay(This->WineD3DSurface,
1561                                          SrcRect,
1562                                          Dst ? Dst->WineD3DSurface : NULL,
1563                                          DstRect,
1564                                          Flags,
1565                                          (WINEDDOVERLAYFX *) FX);
1566 }
1567
1568 /*****************************************************************************
1569  * IDirectDrawSurface7::UpdateOverlayDisplay
1570  *
1571  * The DX7 sdk says that it's not implemented
1572  *
1573  * Params:
1574  *  Flags: ?
1575  *
1576  * Returns: DDERR_UNSUPPORTED, because we don't support overlays
1577  *
1578  *****************************************************************************/
1579 static HRESULT WINAPI
1580 IDirectDrawSurfaceImpl_UpdateOverlayDisplay(IDirectDrawSurface7 *iface,
1581                                             DWORD Flags)
1582 {
1583     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1584     TRACE("(%p)->(%x)\n", This, Flags);
1585     return DDERR_UNSUPPORTED;
1586 }
1587
1588 /*****************************************************************************
1589  * IDirectDrawSurface7::UpdateOverlayZOrder
1590  *
1591  * Sets an overlay's Z order
1592  *
1593  * Params:
1594  *  Flags: DDOVERZ_* flags
1595  *  DDSRef: Defines the relative position in the overlay chain
1596  *
1597  * Returns:
1598  *  DDERR_NOTOVERLAYSURFACE, because we don't support overlays
1599  *
1600  *****************************************************************************/
1601 static HRESULT WINAPI
1602 IDirectDrawSurfaceImpl_UpdateOverlayZOrder(IDirectDrawSurface7 *iface,
1603                                            DWORD Flags,
1604                                            IDirectDrawSurface7 *DDSRef)
1605 {
1606     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1607     IDirectDrawSurfaceImpl *Ref = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, DDSRef);
1608
1609     TRACE("(%p)->(%x,%p): Relay\n", This, Flags, Ref);
1610     return IWineD3DSurface_UpdateOverlayZOrder(This->WineD3DSurface,
1611                                                Flags,
1612                                                Ref ? Ref->WineD3DSurface : NULL);
1613 }
1614
1615 /*****************************************************************************
1616  * IDirectDrawSurface7::GetDDInterface
1617  *
1618  * Returns the IDirectDraw7 interface pointer of the DirectDraw object this
1619  * surface belongs to
1620  *
1621  * Params:
1622  *  DD: Address to write the interface pointer to
1623  *
1624  * Returns:
1625  *  DD_OK on success
1626  *  DDERR_INVALIDPARAMS if DD is NULL
1627  *
1628  *****************************************************************************/
1629 static HRESULT WINAPI
1630 IDirectDrawSurfaceImpl_GetDDInterface(IDirectDrawSurface7 *iface,
1631                                       void **DD)
1632 {
1633     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1634
1635     /* It is not quite correct to use the same lpVtable for the different
1636      * IDirectDrawSurface versions because the GetDDInterface return different interfaces
1637      */
1638     FIXME("(%p)->(%p)\n",This,DD);
1639
1640     if(!DD)
1641         return DDERR_INVALIDPARAMS;
1642
1643     switch(This->version)
1644     {
1645         case 7:
1646             *((IDirectDraw7 **) DD) = ICOM_INTERFACE(This->ddraw, IDirectDraw7);
1647             IDirectDraw7_AddRef(*(IDirectDraw7 **) DD);
1648             break;
1649
1650         case 4:
1651             *((IDirectDraw4 **) DD) = ICOM_INTERFACE(This->ddraw, IDirectDraw4);
1652             IDirectDraw4_AddRef(*(IDirectDraw4 **) DD);
1653
1654         case 2:
1655         case 1:
1656             *((IDirectDraw **) DD) = ICOM_INTERFACE(This->ddraw, IDirectDraw);
1657             IDirectDraw_AddRef( *(IDirectDraw **) DD);
1658             break;
1659
1660     }
1661
1662     return DD_OK;
1663 }
1664
1665 /* This seems also windows implementation specific - I don't think WineD3D needs this */
1666 static HRESULT WINAPI IDirectDrawSurfaceImpl_ChangeUniquenessValue(IDirectDrawSurface7 *iface)
1667 {
1668     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1669     volatile IDirectDrawSurfaceImpl* vThis = This;
1670
1671     TRACE("(%p)\n",This);
1672     /* A uniqueness value of 0 is apparently special.
1673     * This needs to be checked. */
1674     while (1) {
1675         DWORD old_uniqueness_value = vThis->uniqueness_value;
1676         DWORD new_uniqueness_value = old_uniqueness_value+1;
1677
1678         if (old_uniqueness_value == 0) break;
1679         if (new_uniqueness_value == 0) new_uniqueness_value = 1;
1680
1681         if (InterlockedCompareExchange((LONG*)&vThis->uniqueness_value,
1682                                       old_uniqueness_value,
1683                                       new_uniqueness_value)
1684             == old_uniqueness_value)
1685             break;
1686     }
1687
1688     return DD_OK;
1689 }
1690
1691 static HRESULT WINAPI IDirectDrawSurfaceImpl_GetUniquenessValue(IDirectDrawSurface7 *iface, LPDWORD pValue)
1692 {
1693     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1694
1695     TRACE("(%p)->(%p)\n",This,pValue);
1696     *pValue = This->uniqueness_value;
1697     return DD_OK;
1698 }
1699
1700 /*****************************************************************************
1701  * IDirectDrawSurface7::SetLOD
1702  *
1703  * Sets the level of detail of a texture
1704  *
1705  * Params:
1706  *  MaxLOD: LOD to set
1707  *
1708  * Returns:
1709  *  DD_OK on success
1710  *  DDERR_INVALIDOBJECT if the surface is invalid for this method
1711  *
1712  *****************************************************************************/
1713 static HRESULT WINAPI
1714 IDirectDrawSurfaceImpl_SetLOD(IDirectDrawSurface7 *iface,
1715                               DWORD MaxLOD)
1716 {
1717     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1718     TRACE("(%p)->(%d)\n", This, MaxLOD);
1719
1720     if (!(This->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_TEXTUREMANAGE))
1721         return DDERR_INVALIDOBJECT;
1722
1723     if(!This->wineD3DTexture)
1724     {
1725         ERR("(%p) The DirectDraw texture has no WineD3DTexture!\n", This);
1726         return DDERR_INVALIDOBJECT;
1727     }
1728
1729     return IWineD3DTexture_SetLOD(This->wineD3DTexture,
1730                                   MaxLOD);
1731 }
1732
1733 /*****************************************************************************
1734  * IDirectDrawSurface7::GetLOD
1735  *
1736  * Returns the level of detail of a Direct3D texture
1737  *
1738  * Params:
1739  *  MaxLOD: Address to write the LOD to
1740  *
1741  * Returns:
1742  *  DD_OK on success
1743  *  DDERR_INVALIDPARAMS if MaxLOD is NULL
1744  *  DDERR_INVALIDOBJECT if the surface is invalid for this method
1745  *
1746  *****************************************************************************/
1747 static HRESULT WINAPI
1748 IDirectDrawSurfaceImpl_GetLOD(IDirectDrawSurface7 *iface,
1749                               DWORD *MaxLOD)
1750 {
1751     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1752     TRACE("(%p)->(%p)\n", This, MaxLOD);
1753
1754     if(!MaxLOD)
1755         return DDERR_INVALIDPARAMS;
1756
1757     if (!(This->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_TEXTUREMANAGE))
1758         return DDERR_INVALIDOBJECT;
1759
1760     *MaxLOD = IWineD3DTexture_GetLOD(This->wineD3DTexture);
1761     return DD_OK;
1762 }
1763
1764 /*****************************************************************************
1765  * IDirectDrawSurface7::BltFast
1766  *
1767  * Performs a fast Blit.
1768  *
1769  * Params:
1770  *  dstx: The x coordinate to blit to on the destination
1771  *  dsty: The y coordinate to blit to on the destination
1772  *  Source: The source surface
1773  *  rsrc: The source rectangle
1774  *  trans: Type of transfer. Some DDBLTFAST_* flags
1775  *
1776  * Returns:
1777  *  DD_OK on success
1778  *  For more details, see IWineD3DSurface::BltFast
1779  *
1780  *****************************************************************************/
1781 static HRESULT WINAPI
1782 IDirectDrawSurfaceImpl_BltFast(IDirectDrawSurface7 *iface,
1783                                DWORD dstx,
1784                                DWORD dsty,
1785                                IDirectDrawSurface7 *Source,
1786                                RECT *rsrc,
1787                                DWORD trans)
1788 {
1789     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1790     IDirectDrawSurfaceImpl *src = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, Source);
1791     TRACE("(%p)->(%d,%d,%p,%p,%d): Relay\n", This, dstx, dsty, Source, rsrc, trans);
1792
1793     return IWineD3DSurface_BltFast(This->WineD3DSurface,
1794                                    dstx, dsty,
1795                                    src ? src->WineD3DSurface : NULL,
1796                                    rsrc,
1797                                    trans);
1798 }
1799
1800 /*****************************************************************************
1801  * IDirectDrawSurface7::GetClipper
1802  *
1803  * Returns the IDirectDrawClipper interface of the clipper assigned to this
1804  * surface
1805  *
1806  * Params:
1807  *  Clipper: Address to store the interface pointer at
1808  *
1809  * Returns:
1810  *  DD_OK on success
1811  *  DDERR_INVALIDPARAMS if Clipper is NULL
1812  *  DDERR_NOCLIPPERATTACHED if there's no clipper attached
1813  *
1814  *****************************************************************************/
1815 static HRESULT WINAPI
1816 IDirectDrawSurfaceImpl_GetClipper(IDirectDrawSurface7 *iface,
1817                                   IDirectDrawClipper **Clipper)
1818 {
1819     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1820     TRACE("(%p)->(%p)\n", This, Clipper);
1821
1822     if(!Clipper)
1823         return DDERR_INVALIDPARAMS;
1824
1825     if(This->clipper == NULL)
1826         return DDERR_NOCLIPPERATTACHED;
1827
1828     *Clipper = ICOM_INTERFACE(This->clipper, IDirectDrawClipper);
1829     IDirectDrawClipper_AddRef(*Clipper);
1830     return DD_OK;
1831 }
1832
1833 /*****************************************************************************
1834  * IDirectDrawSurface7::SetClipper
1835  *
1836  * Sets a clipper for the surface
1837  *
1838  * Params:
1839  *  Clipper: IDirectDrawClipper interface of the clipper to set
1840  *
1841  * Returns:
1842  *  DD_OK on success
1843  *
1844  *****************************************************************************/
1845 static HRESULT WINAPI
1846 IDirectDrawSurfaceImpl_SetClipper(IDirectDrawSurface7 *iface,
1847                                   IDirectDrawClipper *Clipper)
1848 {
1849     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1850
1851     TRACE("(%p)->(%p)\n",This,Clipper);
1852     if (ICOM_OBJECT(IDirectDrawClipperImpl, IDirectDrawClipper, Clipper) == This->clipper)
1853         return DD_OK;
1854
1855     if (This->clipper != NULL)
1856         IDirectDrawClipper_Release(ICOM_INTERFACE(This->clipper, IDirectDrawClipper) );
1857
1858     This->clipper = ICOM_OBJECT(IDirectDrawClipperImpl, IDirectDrawClipper, Clipper);
1859     if (Clipper != NULL)
1860         IDirectDrawClipper_AddRef(Clipper);
1861
1862     return DD_OK;
1863 }
1864
1865 /*****************************************************************************
1866  * IDirectDrawSurface7::SetSurfaceDesc
1867  *
1868  * Sets the surface description. It can override the pixel format, the surface
1869  * memory, ...
1870  * It's not really tested.
1871  *
1872  * Params:
1873  * DDSD: Pointer to the new surface description to set
1874  * Flags: Some flags
1875  *
1876  * Returns:
1877  *  DD_OK on success
1878  *  DDERR_INVALIDPARAMS if DDSD is NULL
1879  *
1880  *****************************************************************************/
1881 static HRESULT WINAPI
1882 IDirectDrawSurfaceImpl_SetSurfaceDesc(IDirectDrawSurface7 *iface,
1883                                       DDSURFACEDESC2 *DDSD,
1884                                       DWORD Flags)
1885 {
1886     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1887     WINED3DFORMAT newFormat = WINED3DFMT_UNKNOWN;
1888     HRESULT hr;
1889     TRACE("(%p)->(%p,%x)\n", This, DDSD, Flags);
1890
1891     if(!DDSD)
1892         return DDERR_INVALIDPARAMS;
1893
1894     if (DDSD->dwFlags & DDSD_LPSURFACE && DDSD->lpSurface)
1895     {
1896         ERR("Setting the surface memory isn't supported yet\n");
1897         return DDERR_INVALIDPARAMS;
1898
1899     }
1900     if (DDSD->dwFlags & DDSD_PIXELFORMAT)
1901     {
1902         newFormat = PixelFormat_DD2WineD3D(&DDSD->u4.ddpfPixelFormat);
1903
1904         if(newFormat == WINED3DFMT_UNKNOWN)
1905         {
1906             ERR("Requested to set an unknown pixelformat\n");
1907             return DDERR_INVALIDPARAMS;
1908         }
1909         if(newFormat != PixelFormat_DD2WineD3D(&This->surface_desc.u4.ddpfPixelFormat) )
1910         {
1911             hr = IWineD3DSurface_SetFormat(This->WineD3DSurface,
1912                                            newFormat);
1913             if(hr != DD_OK) return hr;
1914         }
1915     }
1916     if (DDSD->dwFlags & DDSD_CKDESTOVERLAY)
1917     {
1918         IWineD3DSurface_SetColorKey(This->WineD3DSurface,
1919                                     DDCKEY_DESTOVERLAY,
1920                                     &DDSD->u3.ddckCKDestOverlay);
1921     }
1922     if (DDSD->dwFlags & DDSD_CKDESTBLT)
1923     {
1924         IWineD3DSurface_SetColorKey(This->WineD3DSurface,
1925                                     DDCKEY_DESTBLT,
1926                                     &DDSD->ddckCKDestBlt);
1927     }
1928     if (DDSD->dwFlags & DDSD_CKSRCOVERLAY)
1929     {
1930         IWineD3DSurface_SetColorKey(This->WineD3DSurface,
1931                                     DDCKEY_SRCOVERLAY,
1932                                     &DDSD->ddckCKSrcOverlay);
1933     }
1934     if (DDSD->dwFlags & DDSD_CKSRCBLT)
1935     {
1936         IWineD3DSurface_SetColorKey(This->WineD3DSurface,
1937                                     DDCKEY_SRCBLT,
1938                                     &DDSD->ddckCKSrcBlt);
1939     }
1940     if (DDSD->dwFlags & DDSD_LPSURFACE)
1941     {
1942         hr = IWineD3DSurface_SetMem(This->WineD3DSurface, DDSD->lpSurface);
1943         if(hr != WINED3D_OK)
1944         {
1945             /* No need for a trace here, wined3d does that for us */
1946             return hr;
1947         }
1948     }
1949
1950     This->surface_desc = *DDSD;
1951
1952     return DD_OK;
1953 }
1954
1955 /*****************************************************************************
1956  * IDirectDrawSurface7::GetPalette
1957  *
1958  * Returns the IDirectDrawPalette interface of the palette currently assigned
1959  * to the surface
1960  *
1961  * Params:
1962  *  Pal: Address to write the interface pointer to
1963  *
1964  * Returns:
1965  *  DD_OK on success
1966  *  DDERR_INVALIDPARAMS if Pal is NULL
1967  *
1968  *****************************************************************************/
1969 static HRESULT WINAPI
1970 IDirectDrawSurfaceImpl_GetPalette(IDirectDrawSurface7 *iface,
1971                                   IDirectDrawPalette **Pal)
1972 {
1973     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1974     IWineD3DPalette *wPal;
1975     HRESULT hr;
1976     TRACE("(%p)->(%p): Relay\n", This, Pal);
1977
1978     if(!Pal)
1979         return DDERR_INVALIDPARAMS;
1980
1981     hr = IWineD3DSurface_GetPalette(This->WineD3DSurface, &wPal);
1982     if(hr != DD_OK) return hr;
1983
1984     if(wPal)
1985     {
1986         hr = IWineD3DPalette_GetParent(wPal, (IUnknown **) Pal);
1987     }
1988     else
1989     {
1990         *Pal = NULL;
1991         hr = DDERR_NOPALETTEATTACHED;
1992     }
1993
1994     return hr;
1995 }
1996
1997 /*****************************************************************************
1998  * IDirectDrawSurface7::SetColorKey
1999  *
2000  * Sets the color keying options for the surface. Observations showed that
2001  * in case of complex surfaces the color key has to be assigned to all
2002  * sublevels.
2003  *
2004  * Params:
2005  *  Flags: DDCKEY_*
2006  *  CKey: The new color key
2007  *
2008  * Returns:
2009  *  DD_OK on success
2010  *  See IWineD3DSurface::SetColorKey for details
2011  *
2012  *****************************************************************************/
2013 static HRESULT WINAPI
2014 IDirectDrawSurfaceImpl_SetColorKey(IDirectDrawSurface7 *iface,
2015                                    DWORD Flags,
2016                                    DDCOLORKEY *CKey)
2017 {
2018     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
2019     IDirectDrawSurfaceImpl *surf;
2020     HRESULT hr;
2021     TRACE("(%p)->(%x,%p)\n", This, Flags, CKey);
2022
2023     for(surf = This->first_complex; surf; surf = surf->next_complex)
2024     {
2025         hr = IWineD3DSurface_SetColorKey(surf->WineD3DSurface,
2026                                          Flags,
2027                                          CKey);
2028         if(FAILED(hr))
2029         {
2030             WARN("IWineD3DSurface::SetColorKey for surface %p failed with hr=%08x\n",
2031                  surf->WineD3DSurface, hr);
2032             return hr;
2033         }
2034     }
2035     return DD_OK;
2036 }
2037
2038 /*****************************************************************************
2039  * IDirectDrawSurface7::SetPalette
2040  *
2041  * Assigns a DirectDrawPalette object to the surface
2042  *
2043  * Params:
2044  *  Pal: Interface to the palette to set
2045  *
2046  * Returns:
2047  *  DD_OK on success
2048  *
2049  *****************************************************************************/
2050 static HRESULT WINAPI
2051 IDirectDrawSurfaceImpl_SetPalette(IDirectDrawSurface7 *iface,
2052                                   IDirectDrawPalette *Pal)
2053 {
2054     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
2055     IDirectDrawPalette *oldPal;
2056     IDirectDrawSurfaceImpl *surf;
2057     IDirectDrawPaletteImpl *PalImpl = ICOM_OBJECT(IDirectDrawPaletteImpl, IDirectDrawPalette, Pal);
2058     HRESULT hr;
2059     TRACE("(%p)->(%p)\n", This, Pal);
2060
2061     /* Find the old palette */
2062     hr = IDirectDrawSurface_GetPalette(iface, &oldPal);
2063     if(hr != DD_OK && hr != DDERR_NOPALETTEATTACHED) return hr;
2064     if(oldPal) IDirectDrawPalette_Release(oldPal);  /* For the GetPalette */
2065
2066     /* Set the new Palette */
2067     IWineD3DSurface_SetPalette(This->WineD3DSurface,
2068                                PalImpl ? PalImpl->wineD3DPalette : NULL);
2069     /* AddRef the Palette */
2070     if(Pal) IDirectDrawPalette_AddRef(Pal);
2071
2072     /* Release the old palette */
2073     if(oldPal) IDirectDrawPalette_Release(oldPal);
2074
2075     /* If this is a front buffer, also update the back buffers */
2076     if(This->surface_desc.ddsCaps.dwCaps & DDSCAPS_FRONTBUFFER)
2077     {
2078         for(surf = This->next_complex; surf != NULL; surf = surf->next_complex)
2079         {
2080             IDirectDrawSurface7_SetPalette(ICOM_INTERFACE(surf, IDirectDrawSurface7),
2081                                            Pal);
2082         }
2083     }
2084
2085     return DD_OK;
2086 }
2087
2088 /*****************************************************************************
2089  * The VTable
2090  *****************************************************************************/
2091
2092 const IDirectDrawSurface7Vtbl IDirectDrawSurface7_Vtbl =
2093 {
2094     /*** IUnknown ***/
2095     IDirectDrawSurfaceImpl_QueryInterface,
2096     IDirectDrawSurfaceImpl_AddRef,
2097     IDirectDrawSurfaceImpl_Release,
2098     /*** IDirectDrawSurface ***/
2099     IDirectDrawSurfaceImpl_AddAttachedSurface,
2100     IDirectDrawSurfaceImpl_AddOverlayDirtyRect,
2101     IDirectDrawSurfaceImpl_Blt,
2102     IDirectDrawSurfaceImpl_BltBatch,
2103     IDirectDrawSurfaceImpl_BltFast,
2104     IDirectDrawSurfaceImpl_DeleteAttachedSurface,
2105     IDirectDrawSurfaceImpl_EnumAttachedSurfaces,
2106     IDirectDrawSurfaceImpl_EnumOverlayZOrders,
2107     IDirectDrawSurfaceImpl_Flip,
2108     IDirectDrawSurfaceImpl_GetAttachedSurface,
2109     IDirectDrawSurfaceImpl_GetBltStatus,
2110     IDirectDrawSurfaceImpl_GetCaps,
2111     IDirectDrawSurfaceImpl_GetClipper,
2112     IDirectDrawSurfaceImpl_GetColorKey,
2113     IDirectDrawSurfaceImpl_GetDC,
2114     IDirectDrawSurfaceImpl_GetFlipStatus,
2115     IDirectDrawSurfaceImpl_GetOverlayPosition,
2116     IDirectDrawSurfaceImpl_GetPalette,
2117     IDirectDrawSurfaceImpl_GetPixelFormat,
2118     IDirectDrawSurfaceImpl_GetSurfaceDesc,
2119     IDirectDrawSurfaceImpl_Initialize,
2120     IDirectDrawSurfaceImpl_IsLost,
2121     IDirectDrawSurfaceImpl_Lock,
2122     IDirectDrawSurfaceImpl_ReleaseDC,
2123     IDirectDrawSurfaceImpl_Restore,
2124     IDirectDrawSurfaceImpl_SetClipper,
2125     IDirectDrawSurfaceImpl_SetColorKey,
2126     IDirectDrawSurfaceImpl_SetOverlayPosition,
2127     IDirectDrawSurfaceImpl_SetPalette,
2128     IDirectDrawSurfaceImpl_Unlock,
2129     IDirectDrawSurfaceImpl_UpdateOverlay,
2130     IDirectDrawSurfaceImpl_UpdateOverlayDisplay,
2131     IDirectDrawSurfaceImpl_UpdateOverlayZOrder,
2132     /*** IDirectDrawSurface2 ***/
2133     IDirectDrawSurfaceImpl_GetDDInterface,
2134     IDirectDrawSurfaceImpl_PageLock,
2135     IDirectDrawSurfaceImpl_PageUnlock,
2136     /*** IDirectDrawSurface3 ***/
2137     IDirectDrawSurfaceImpl_SetSurfaceDesc,
2138     /*** IDirectDrawSurface4 ***/
2139     IDirectDrawSurfaceImpl_SetPrivateData,
2140     IDirectDrawSurfaceImpl_GetPrivateData,
2141     IDirectDrawSurfaceImpl_FreePrivateData,
2142     IDirectDrawSurfaceImpl_GetUniquenessValue,
2143     IDirectDrawSurfaceImpl_ChangeUniquenessValue,
2144     /*** IDirectDrawSurface7 ***/
2145     IDirectDrawSurfaceImpl_SetPriority,
2146     IDirectDrawSurfaceImpl_GetPriority,
2147     IDirectDrawSurfaceImpl_SetLOD,
2148     IDirectDrawSurfaceImpl_GetLOD
2149 };